这几天在研究一个项目的I2C通讯,一开始无论怎么搞都读不了IC的ID或者写不进数据,搞的十分的焦灼,幸好最后还算是捣弄出来的了,然后趁着项目不是很紧,赶紧把这几天对I2C的研究心得记录一下,免得自己又忘记了。
在开始调试软件前,先要确认IC的供电,使能脚,复位脚等正确供电,先检查硬件!先检查硬件!先检查硬件!
1.我使用的ADK版本是4.3,和以前的ADK版本是一样的,I2C的接口没有修改,只是4.3多了一个I2C reset的函数可以用。
然后我们来讲解一下I2C给出的接口I2cTransfer()这个函数怎么用,当然大家可以自己看说明,CSR是有写的。
该函数uint16 I2cTransfer(uint16 address, const uint8 *tx, uint16 tx_len, uint8 *rx, uint16 rx_len);
uint16:返回的是和从机(csr867x只能做主机)通讯得到得ACK(确认回答)的次数;
address:该参数是从机的器件地址,一般器件规格书上会给出,但是这里有大坑,待会再细说;
tx:要发送的数据地址开头,一般载体是数组,所以这里一般填数组名字;
tx_len:要发送数据的总长度,一般直接拿数组的长度即可;
rx:要接收(读取)的数据载体,用来保存在从机寄存器里读取的数据;
rx_len:要读取数据的长度,一般看规格书上,需要读取多少个寄存器来定义;
2.函数的参数清楚了之后就直接用吧,我们以AW9523B这个LED IC来举例子:
该IC的规格书上有给出,地址如图:
其中AD1和AD0我们都设定为高,所以地址就是1011011(0x5B),最后的R/W位我们并不需处理,I2cTransfer函数会为我们处理。不过我们依然需要对这个地址做一个左移1位的动作,来使I2cTransfer函数能正确把地址发送出去,最后的地址就是10110110(0xB6),所以address就填这个参数就好了。
然后我们来读取一下IC的ID信息来验证是否正确:
void ReadAW9523BID(void)
{
uint8 version[1]={0};
uint8 regAddress[1]={0x10};
if(I2cTransfer(0xB6,regAddress,1,version,1))
{
UartDebug(version,1);
}
}
i2c的工作流程是:
主机发送ADDRESS给从机--->
从机收到验证地址是正确的,并返回一个ACK--->
主机收到ACK后,确认握手成功就开始发送寄存器的地址--->
从机接收到寄存器地址后也会返回一个ACK给主机,并开始处理该寄存器即将要处理的动作--->
主机接收到ACK后,就开始判断tx是否还有数据要写,如果没有就判断rx是否有指定缓存载体,如果都没有,结束本次通讯,如果tx有数据,即tx_len>1那主机就会继续发tx的数据给从机,直到达到最大长度,如果tx没有,rx有,就开始读取从机寄存器的数据,直到读取到rx_len的最大长度。
如上函数会读取到IC的芯片信息并从UART打印出来。
最后总结一下读写数据的用法吧:
写数据:
/*发送一个0xff给从机*/
void WriteI2CData(void)
{
uint8 txData[2];
txData[0] = registerAddress;
txData[1] = 0xff;
I2cTransfer(slaveDeviceAddress,txData,2,NULL,0);
}
读数据:
/*在从机某个寄存器上读取一个数据*/
void ReadI2CData(void)
{
uint8 rxBuff[2];
rxBuff[0] = registerAddress;/*rxBuff第一个数据用来存放寄存器地址*/
I2cTransfer(slaveDeviceAddress,rxBuff,1,rxBuff+1,1);/*rxBuff第二个数据用来接收*/
}