I.MX6ULL的裸机I2C驱动transfer函数(原作者:左钟凯)

i2c_master_transfer函数,原作者左钟凯。可以借鉴一下。

 1 /*
 2  * @description    : I2C数据传输,包括读和写
 3  * @param - base: 要使用的IIC
 4  * @param - xfer: 传输结构体
 5  * @return         : 传输结果,0 成功,其他值 失败;
 6  */
 7 unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
 8 {
 9     unsigned char ret = 0;
10     enum i2c_direction direction = xfer->direction;    
11     base->I2SR &= ~((1 << 1) | (1 << 4));    /* 清除标志位 */
12     while(!((base->I2SR >> 7) & 0X1)){};     //等待传输完成
13     if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))    //如果是读的话,要先发送寄存器地址,所以要先将方向改为写
14     {
15         direction = kI2C_Write;
16     }
17     ret = i2c_master_start(base, xfer->slaveAddress, direction); //发送开始信号
18     if(ret){    
19         return ret;
20     }
21     while(!(base->I2SR & (1 << 1))){};            /* 等待传输完成 */
22     ret = i2c_check_and_clear_error(base, base->I2SR);    /* 检查是否出现传输错误 */
23     if(ret){
24         i2c_master_stop(base);    /* 发送出错,发送停止信号 */
25         return ret;
26     }
27     if(xfer->subaddressSize)    //发送寄存器地址
28     {
29         do
30         {
31             base->I2SR &= ~(1 << 1);            /* 清除标志位 */
32             xfer->subaddressSize--;                /* 地址长度减一 */
33             base->I2DR =  ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器写入子地址
34             while(!(base->I2SR & (1 << 1)));      /* 等待传输完成 */
35             ret = i2c_check_and_clear_error(base, base->I2SR);/* 检查是否有错误发生 */
36             if(ret){
37                  i2c_master_stop(base);    //发送停止信号
38                  return ret;
39             }  
40         } while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));
41 
42         if(xfer->direction == kI2C_Read)         /* 读取数据 */
43         {
44             base->I2SR &= ~(1 << 1);            /* 清除中断挂起位 */
45             i2c_master_repeated_start(base, xfer->slaveAddress, kI2C_Read); /* 发送重复开始信号和从机地址 */
46             while(!(base->I2SR & (1 << 1))){};/* 等待传输完成 */
47             ret = i2c_check_and_clear_error(base, base->I2SR);/* 检查是否有错误发生 */
48             if(ret){
49                 ret = I2C_STATUS_ADDRNAK;
50                 i2c_master_stop(base);         /* 发送停止信号 */
51                 return ret;  
52             }          
53         }
54     }
55     if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)){    /* 发送数据 */
56         i2c_master_write(base, xfer->data, xfer->dataSize);
57     }
58     if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)){   /* 读取数据 */
59         i2c_master_read(base, xfer->data, xfer->dataSize);
60     }
61     return 0;    
62 }

 

个人总结,有如下两点需要注意。

1.改变传输方向(读过程)

transfer包含了读写两个方向。读和写两个过程在transfer函数中的代码差异如下:

从中可得到,读过程多了3个步骤,分别为:“将数据传输方向先改为写”,“发送重复开始信号”,“发送从机地址”。

2.等待传输完成和错误检查。

发送寄存器地址前,需要确认总线不忙(即步骤b)。依据可在I.MX6ULL手册的P1453找到:

Depending on the relative frequencies of the system clock and the SCL period, it may be necessary to wait until the I2C is not busy after writing the calling address to the data register(I2C_I2DR),before proceeding to load data into the data register(I2C_I2DR).

原文地址:https://www.cnblogs.com/kunshanpipixia/p/14289236.html