接上一篇,linux下GPIO模擬I2C驅動完成後,就是stm32的i2c配置了,由於hi3518e作爲i2c的主設備,stm32則作爲從設備,由於GPIO模擬i2c的從時序比模擬主時序要麻煩很多,所以採用stm32的硬件I2C。(stm32官網i2c例程主模式會莫名的卡死,從模式比較好用)
下載官網例程,將之設置爲從模式,使用i2c2,將SCL,SDA,GND與hi3518e板子上GPIO模擬的SCL,SDA和GND連起來,寫一個測試例程來驗證雙方的通信。
首先在linux下加載驅動,然後調用打開驅動,調用編寫的驅動接口函數,讀數據和寫數據。驅動接口代碼如下:
#include<stdio.h>
#include<ctype.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include"gpioi2c_ex.h"
#include"I2C_driver.h"
static int fd = -1;
//打開設備文件
int I2C_Open()
{
fd = open("/dev/gpioi2c_ex",O_RDWR);
if (fd<0)
{
printf("Open gpioi2c_ex deverror!\n");
return -1;
}
return 0;
}
//關閉設備
int I2C_Close()
{
close(fd);
return 0;
}
//從stm32獲取羅盤數據
int I2C_GetLooppad(short*yam,short *pitch,short *roll)
{
int ret;
I2C_DATA_S i2c_data ;
unsigned int device_addr=0x30,reg_addr=0x0, reg_addr_end=0x0, reg_value[3];
unsigned int reg_width = 1, data_width = 2;
int cur_addr;
for(reg_addr=0x01,reg_addr_end=0x01;reg_addr<0x04;reg_addr++,reg_addr_end++)
{
for (cur_addr = reg_addr; cur_addr< reg_addr_end + 1; cur_addr ++)
{
i2c_data.dev_addr = device_addr ;
i2c_data.reg_addr = cur_addr ;
i2c_data.addr_byte_num = reg_width ;
i2c_data.data_byte_num = data_width ;
ret = ioctl(fd, GPIO_I2C_READ,&i2c_data);
reg_value[cur_addr-1] = i2c_data.data ;
printf("0x%x 0x%x\n",cur_addr, reg_value[cur_addr-1]);
}
}
*yam = (short)reg_value[0];
*pitch = (short)reg_value[1];
*roll = (short)reg_value[2];
returnret;
}
//設置LED亮度,將亮度值傳給stm32
intI2C_SetLed(unsigned char light)
{
int ret;
I2C_DATA_S i2c_data ;
unsigned int reg_width = 0,data_width = 2;
unsigned int device_addr = 0x30,reg_addr = 0, reg_value = 0x0400+light;
i2c_data.dev_addr = device_addr ;
i2c_data.reg_addr= reg_addr ;
i2c_data.addr_byte_num= reg_width ;
i2c_data.data = reg_value ;
i2c_data.data_byte_num= data_width ;
ret= ioctl(fd, GPIO_I2C_WRITE, &i2c_data);
return ret;
}
測試代碼如下:
#include<stdio.h>
#include<ctype.h>
#include<sys/ioctl.h>
#include <sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include"gpioi2c_ex.h"
#include"I2C_driver.h"
int main()
{
short i = 0,yam,pitch,roll;
int ret;
ret = I2C_Open();
ret =I2C_GetLooppad(&yam,&pitch,&roll);
ret = I2C_SetLed(0x60);
printf("yam=%d,pitch=%d,roll=%d\n",yam,pitch,roll);
ret = I2C_Close();
return 0;
}
實際測試中發送,從stm32獲取數據的過程十分迅速,並且無亂碼;但是當hi3518e給stm32寫數據的時候,發現stm32會卡死在I2c中斷中,無法跑回主函數,十分不解。由於採用的硬件I2c中斷並且工作在從模式下,對於這種現象不知怎樣下手,從現象來看,猜測應該是stm32的i2c中斷被觸發了之後,一直在等待主機的某個ACK或者是停止命令,於是重新去看了GPIO模擬i2c的驅動源文件代碼,發現在write函數中發送完數據後等待從機的ACK的語句被註釋掉了,沒有等待從機ACK就直接發送了stop命令,而read函數中接收完數據都先回復NACK在發送stop命令,於是加上該語句,解決問題。