本帖最后由 defaultname 于 2023-2-28 11:25 编辑
项目遇到一个需求,需要I2C主机读取从机数据时,可以分段传输,每次长度不一。使用F003的I2C从机例程`I2C\I2C_TwoBoards\I2C_TwoBoards_Slave`作以下修改:
#define DATA_BUF_SIZE (9)
uint8_t dataBufPt = 0;
uint8_t dataBuf[DATA_BUF_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
void I2CIsr(void)
{
//...
/** STS1_TXBEF = 1 and STS3_RWMF = 1 */
if(I2C_ReadStatusFlag(I2C_FLAG_TXBE |I2C_FLAG_RWMF) == SET)
{
if (dataBufPt >= DATA_BUF_SIZE)
dataBufPt = 0;
I2C_TxData(dataBuf[dataBufPt++]);
}
//...
}
测试主机读取两次数据的时序如下:
可以看到出问题了,第一次读取三个字节01, 02, 03,第二次读取到05, 06, 07,中间跳过了1个字节的数据,丢掉了04
调试代码发现,从机每次发送数据之后,都会进入I2C_FLAG_TXBE中断,所以实际上发送3个字节,中断会进入4次
但由于需求是每次传输的数据是不定长的,这次读3个字节,下次就可能读4个、2个……没办法通过字节长度来判断传输结束,所以得从I2C的停止位入手,所以在中断里添加以下代码:
/** Stop condition is detected */
if(I2C_ReadStatusFlag(I2C_FLAG_STOP) == SET)
{
I2C->CTRL2 = I2C->CTRL2;
//判断到停止位,手动把数据指针减1
if (dataBufPt == 0)
dataBufPt = DATA_BUF_SIZE - 1;
else
dataBufPt--;
}
运行之后现象依旧,进一步调试发现I2C_FLAG_STOP中断根本不会进入
于是转变思路,从主机的NAK非应答信号入手,判断本次传输结束:
根据手册,作出以下修改:
void I2CInit(void)
{
//...
/** Enable buffer and event interrupt */
i2cConfig.interrupt = I2C_INT_BUFFER | I2C_INT_EVENT | I2C_INT_ERROR;
//...
}
void I2CIsr(void)
{
//...
/** STS1_TXBEF = 1 and STS3_RWMF = 1 */
if(I2C_ReadStatusFlag(I2C_FLAG_TXBE |I2C_FLAG_RWMF) == SET)
{
if (dataBufPt >= DATA_BUF_SIZE)
dataBufPt = 0;
I2C_TxData(dataBuf[dataBufPt++]);
}
if (I2C_ReadStatusFlag(I2C_FLAG_ACKERR) == SET)
{
I2C_ClearStatusFlag(I2C_FLAG_ACKERR);
if (dataBufPt == 0)
dataBufPt = DATA_BUF_SIZE - 1;
else
dataBufPt--;
}
//...
}
最后测试成功:
主机改为每次读取两个字节时,测试时序也正确:
问题解决。
|