linux下编写I2C驱动与stm32通信(二)

来源:互联网 发布:无情对 知乎 编辑:程序博客网 时间:2024/06/05 17:36

接上一篇,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命令,于是加上该语句,解决问题。

原创粉丝点击