linux下編寫I2C驅動與stm32通信(二)

     接上一篇,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命令,於是加上該語句,解決問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章