[APM32F0] APM32F003 I2C从机传输不定长度数据

[复制链接]
7607|2
 楼主| defaultname 发表于 2023-2-28 11:26 | 显示全部楼层 |阅读模式
本帖最后由 defaultname 于 2023-2-28 11:25 编辑

项目遇到一个需求,需要I2C主机读取从机数据时,可以分段传输,每次长度不一。使用F003的I2C从机例程`I2C\I2C_TwoBoards\I2C_TwoBoards_Slave`作以下修改:
  1. #define DATA_BUF_SIZE       (9)
  2. uint8_t dataBufPt = 0;
  3. uint8_t dataBuf[DATA_BUF_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
  1. void I2CIsr(void)
  2. {
  3.     //...
  4.     /** STS1_TXBEF = 1 and STS3_RWMF = 1 */
  5.     if(I2C_ReadStatusFlag(I2C_FLAG_TXBE |I2C_FLAG_RWMF) == SET)
  6.     {
  7.         if (dataBufPt >= DATA_BUF_SIZE)
  8.             dataBufPt = 0;
  9.         I2C_TxData(dataBuf[dataBufPt++]);
  10.     }
  11.     //...
  12. }

测试主机读取两次数据的时序如下:
5130f7f124974053da3e0551b13e33c_1677549446342_0.png
7816aa323ed12d32ae88793463565b4_1677549454989_0.png
可以看到出问题了,第一次读取三个字节01, 02, 03,第二次读取到05, 06, 07,中间跳过了1个字节的数据,丢掉了04
调试代码发现,从机每次发送数据之后,都会进入I2C_FLAG_TXBE中断,所以实际上发送3个字节,中断会进入4次


但由于需求是每次传输的数据是不定长的,这次读3个字节,下次就可能读4个、2个……没办法通过字节长度来判断传输结束,所以得从I2C的停止位入手,所以在中断里添加以下代码:
  1. /** Stop condition is detected */
  2. if(I2C_ReadStatusFlag(I2C_FLAG_STOP) == SET)
  3. {
  4.     I2C->CTRL2 = I2C->CTRL2;
  5.     //判断到停止位,手动把数据指针减1
  6.     if (dataBufPt == 0)
  7.         dataBufPt = DATA_BUF_SIZE - 1;
  8.     else
  9.         dataBufPt--;
  10. }

运行之后现象依旧,进一步调试发现I2C_FLAG_STOP中断根本不会进入


于是转变思路,从主机的NAK非应答信号入手,判断本次传输结束:
image_1677551269506_0.png


根据手册,作出以下修改:
  1. void I2CInit(void)
  2. {
  3.     //...
  4.     /** Enable buffer and event interrupt */
  5.     i2cConfig.interrupt = I2C_INT_BUFFER | I2C_INT_EVENT | I2C_INT_ERROR;
  6.     //...
  7. }
  1. void I2CIsr(void)
  2. {
  3.     //...
  4.     /** STS1_TXBEF = 1 and STS3_RWMF = 1 */
  5.     if(I2C_ReadStatusFlag(I2C_FLAG_TXBE |I2C_FLAG_RWMF) == SET)
  6.     {
  7.         if (dataBufPt >= DATA_BUF_SIZE)
  8.             dataBufPt = 0;
  9.         I2C_TxData(dataBuf[dataBufPt++]);
  10.     }

  11.     if (I2C_ReadStatusFlag(I2C_FLAG_ACKERR) == SET)
  12.     {
  13.         I2C_ClearStatusFlag(I2C_FLAG_ACKERR);
  14.         if (dataBufPt == 0)
  15.             dataBufPt = DATA_BUF_SIZE - 1;
  16.         else
  17.             dataBufPt--;
  18.     }
  19.           //...
  20. }

最后测试成功:

b3982a77b54c35ce5fe1165fe46c9d9_1677551555235_0.png


主机改为每次读取两个字节时,测试时序也正确:
71d1bf89e7f4ff47b2c6b6c0e2fb9e6_1677551567998_0.png a952cadfada5a8f1ea3322abb1fd11d_1677551577414_0.png


问题解决。



零erer 发表于 2023-2-28 11:30 | 显示全部楼层
学习一手
Fanexs168 发表于 2023-2-28 13:51 | 显示全部楼层
点赞点赞
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

1

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部