STM32 I2C控制器使用库函数时卡在CheckEvent的解决建议

这几天刚好有用到STM32 I2C控制器. 之前有帮人调试了一段STM32 I2C读写的程序,当时有碰到一个问题就是用库函数的情况下,如果I2C通信速率设置成100K或以上,  经常会卡在I2C_CheckEvent这个函数上. 请看以下代码:

24 uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
25 {
26 /* 产生 I2C 起始信号 */
27 I2C_GenerateSTART(EEPROM_I2C, ENABLE);
28
29 /*设置超时等待时间*/
30 I2CTimeout = I2CT_FLAG_TIMEOUT;
31 /* 检测 EV5 事件并清除标志*/
32 while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
33 {
34 if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
35 }

36
37 /* 发送 EEPROM 设备地址 */
38 I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS,
39 I2C_Direction_Transmitter);
40
41 I2CTimeout = I2CT_FLAG_TIMEOUT;
42 /* 检测 EV6 事件并清除标志*/
43 while (!I2C_CheckEvent(EEPROM_I2C,
44 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
45 {
46 if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
47 }
48
49 /* 发送要写入的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
50 I2C_SendData(EEPROM_I2C, WriteAddr);
51
52 I2CTimeout = I2CT_FLAG_TIMEOUT;
53 /* 检测 EV8 事件并清除标志*/
54 while (!I2C_CheckEvent(EEPROM_I2C,
55 I2C_EVENT_MASTER_BYTE_TRANSMITTED))
56 {
57 if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
58 }
59 /* 发送一字节要写入的数据 */
60 I2C_SendData(EEPROM_I2C, *pBuffer);
61
62 I2CTimeout = I2CT_FLAG_TIMEOUT;
63 /* 检测 EV8 事件并清除标志*/
64 while (!I2C_CheckEvent(EEPROM_I2C,
65 I2C_EVENT_MASTER_BYTE_TRANSMITTED))
66 {
67 if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
68 }
69
70 /* 发送停止信号 */
71 I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
72
73 return 1;
74 }
注: 此处代码来自<<STM32--零死角玩转STM32--F429挑战者>>

仔细研究了下stm32 的reference manual (文档ID 018909第4版) 第654页(如果看不到本文图片的,可以自行下载reference manual, 不同的器件对应的文档ID可能不一样, 可以在目录-- I2C--主发送器里面找到对应的描述. 如果文档版本比较老, 可以下载最新版本的manual, 和对应的勘误表)

在检测EV5事件并清除标志的代码中,只进行了I2C_CheckEvent操作.  查看固件库中I2C_CheckEvent的代码:

ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
  uint32_t lastevent = 0;
  uint32_t flag1 = 0, flag2 = 0;
  ErrorStatus status = ERROR;

  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  assert_param(IS_I2C_EVENT(I2C_EVENT));

  /* Read the I2Cx status register */
  flag1 = I2Cx->SR1;
  flag2 = I2Cx->SR2;
  flag2 = flag2 << 16;

  /* Get the last event value from I2C status register */
  lastevent = (flag1 | flag2) & FLAG_MASK;

  /* Check whether the last event contains the I2C_EVENT */
  if ((lastevent & I2C_EVENT) == I2C_EVENT)
  {
    /* SUCCESS: last event is equal to I2C_EVENT */
    status = SUCCESS;
  }
  else
  {
    /* ERROR: last event is different from I2C_EVENT */
    status = ERROR;
  }
  /* Return status */
  return status;
}

代码中只对SR寄存器进行了操作,而并没有对DR寄存器操作.  在Reference manual当中, EV5 SB=1 需要对读取SR1, 再对DR写操作才能清零.   所以,这就时会卡再I2C_CHECKEVENT这里的原因了.(卡在其他事件上的情况也类似).

在对应的EVx检测及清零操作的时候, 除了对SR寄存器操作, 增加对应的其他寄存器的操作就可以避免卡在这里的尴尬.

 

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值