linux下编写I2C驱动与stm32通信(二)
2017-12-15 13:56
363 查看
接上一篇,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命令,于是加上该语句,解决问题。
下载官网例程,将之设置为从模式,使用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命令,于是加上该语句,解决问题。
相关文章推荐
- linux下编写I2C驱动与stm32通信(一)
- linux下编写I2C驱动与stm32通信(二)
- linux下编写I2C驱动与stm32通信(一)
- Linux I2C设备驱动编写(一)
- Linux I2C设备驱动编写(一)【转】
- Linux I2C设备驱动编写(三)-实例分析AM3359
- Linux I2C设备驱动编写(二)
- 【转】Linux I2C设备驱动编写(一)
- Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写
- 【转】Linux I2C设备驱动编写(二)
- Linux i2c设备驱动编写(二)
- Linux I2C设备驱动编写
- linux中关于i2c驱动编写的注意事项
- Linux I2C设备驱动编写(一)
- 【转】Linux I2C设备驱动编写(三)-实例分析AM3359
- Linux I2C设备驱动编写(一)
- Linux I2C设备驱动编写(一)
- Linux I2C设备驱动编写(一)
- 编写i2c驱动-基于Linux3.10
- Linux I2C设备驱动编写(二)