I2C 时序错误修复:优化 I2CTransfer 函数
该函数的 I2C 时序存在问题,需要进行修改:
-
在函数开始处,将设备地址设为函数的参数 deviceAddr,而不是硬编码为 BQ27441_G1_ADDR。
-
在发送地址时,应该先发送 START,再发送设备地址,而不是先发送设备地址。
-
在发送命令和数据时,应该先发送设备地址和命令,再发送数据。
-
在读取数据时,应该先发送设备地址和命令,再发送 RESTART,并将设备地址左移一位,表示读取操作。同时,应该在读取完数据后发送 STOP。
-
在读取数据时,应该先判断数据长度是否为 2,如果是,则不需要发送 ACK,而是直接发送 NACK 后发送 STOP。如果不是,则需要发送 ACK。
-
函数应该返回读取到的数据。
修改后的函数如下:
uint8_t I2CTransfer(uint16_t deviceAddr, uint8_t cmdArray[], uint8_t dataArray[], uint16_t cmdLen, uint16_t dataLen, uint16_t flag)
{
/* 1.I2C 空闲检测. */
while(LL_I2C_IsActiveFlag_BUSY(I2C_Handle));
/* 2.START 信号. */
LL_I2C_GenerateStartCondition(I2C_Handle);
while(!LL_I2C_IsActiveFlag_SB(I2C_Handle));
/* 3.发送设备地址和命令. */
LL_I2C_TransmitData8(I2C_Handle, deviceAddr << 1);
while(!LL_I2C_IsActiveFlag_ADDR(I2C_Handle));
LL_I2C_ClearFlag_ADDR(I2C_Handle);
for(uint16_t i = 0; i < cmdLen; i++)
{
LL_I2C_TransmitData8(I2C_Handle, cmdArray[i]);
while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
}
/* 4.发送数据. */
if(flag == I2C_FLAG_WRITE)
{
for(uint16_t i = 0; i < dataLen; i++)
{
LL_I2C_TransmitData8(I2C_Handle, dataArray[i]);
while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
}
}
/* 5.RESTART 信号. */
if(flag == I2C_FLAG_WRITE_READ)
{
LL_I2C_GenerateRestartCondition(I2C_Handle);
while(!LL_I2C_IsActiveFlag_SB(I2C_Handle));
LL_I2C_TransmitData8(I2C_Handle, (deviceAddr << 1) | 0x01);
while(!LL_I2C_IsActiveFlag_ADDR(I2C_Handle));
LL_I2C_ClearFlag_ADDR(I2C_Handle);
for(uint16_t i = 0; i < cmdLen; i++)
{
LL_I2C_TransmitData8(I2C_Handle, cmdArray[i]);
while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
}
/* 6.读取数据. */
uint8_t data = 0;
if(dataLen == 2)
{
LL_I2C_AcknowledgeNextData(I2C_Handle, LL_I2C_NACK);
LL_I2C_ClearFlag_ADDR(I2C_Handle);
LL_I2C_GenerateStopCondition(I2C_Handle);
while(!LL_I2C_IsActiveFlag_RXNE(I2C_Handle));
data = LL_I2C_ReceiveData8(I2C_Handle);
}
else
{
LL_I2C_AcknowledgeNextData(I2C_Handle, LL_I2C_ACK);
while(!LL_I2C_IsActiveFlag_RXNE(I2C_Handle));
data = LL_I2C_ReceiveData8(I2C_Handle);
LL_I2C_GenerateStopCondition(I2C_Handle);
while(LL_I2C_IsActiveFlag_STOP(I2C_Handle));
}
return data;
}
/* 7.STOP 信号. */
LL_I2C_GenerateStopCondition(I2C_Handle);
while(LL_I2C_IsActiveFlag_STOP(I2C_Handle));
return 0;
}
原文地址: https://www.cveoy.top/t/topic/m9fy 著作权归作者所有。请勿转载和采集!