I2C另类挂死分析 – AT24C256

/ 0评 / 0

平台是STM32L011 ~ Nucleo 板~

一般来说I2C挂死大家说的不是SDA恒低还是SCL恒低.但是,还有一种挂死的EEPROM,致使大家觉得EEPROM很容易挂死,明明就是操作不当啊,哪里容易挂死了.

其实是因为EEPROM他有个内部搬移Buffers时间,这个时候,EEPROM的I2C无效,看起来就像这个从机突然间不见了,这也是大家说的,I2C锁死,其实是因为从机根本就不见了.

那么如何应对呢?网上有一种方法,就是延迟5毫秒,这5毫秒刚好是最长编程时间,如果是AT24C256,岂不是要等20毫秒不成?一点都不环保.这里可以查询ACK位,确定设备是否在.其实可以使用查询ACK的方法,如果等到主机可以收到ACK.那么从机就是复活了.

另外因为STM32自身的BUG,这个确实存在的BUG,就是I2C还没收到ACK时候,NACK的标志位置位,明明还没来ACK的时刻,你怎么确定ACK来了没呢?方法1,多读几次,浪费也是在所不惜的,方法2,延迟一个合理时刻,再来查询.

对比下方法1和方法2的区别.

1)第一下,试探下EEPROM是否能正常ACK.如果ACK,给0x1234位置写入0x33.

2)内部编程期间,EEPROM是不会响应的.

3)直到EEPROM重新响应,读出数据.

4)红框位置是编程时间,我是1ms一次查询.

如果换用方法2,应该会快一点,因为他是不断查询,不是间隔查询.这个间隔查询优点就是不占掉整个总线,中途有别的任务,还可以通过插入MUTEX分时控制.但是如果编程是在2.1ms完成,那么还多浪费0.9ms.

方法2就是一直查询.查询的时间约2.1ms编程完成,之前方法还真多浪费了我足足0.9ms啊.

但是方法2带来了BUG.就是查询到ACK,而STM32还是觉得他没ACK,那么怎么办呢.有没有方法1方法2都完美结合的方法呢?有的.

既然方法1的浪费是因为1毫秒查一次,那么是否缩短一些会更好呢?又不至于一直在发数据,特别是洁癖党,看到这么多ACK还不立马用,感觉不爽.改成0.1ms,也就是100us,看起来就查询频繁一些了.

也没有浪费ACK的嫌疑了.不是查询越频繁越好,而是查询的时刻恰好就是最好.说了这么多,还是没贴代码啊.别急,首先,发出一个START,就能判断是否NACK了,但是STM32不能这么任性.因为CR2寄存器的NBYTES不能为0.

(不过好像也是合理,一般情况谁只发START不执行东西.)

有人问,为什么中间不跳出,因为在中间卡死的概率,我也没发现,这肯定就叫总线死锁了,还没发生过.

总线锁死,这个不能怪STM32,如果用过其他MCU就知道,实际是I2C自己太脆弱.不过问题也很好解决的.合适的上拉,程序靠谱,不随意复位MCU.就不会发生了.这代码我跑了一晚上,第二天醒来发现是EEPROM坏了1Bit,读取写入还是正常.

另外,题外话,我算了下,按4ms一次编程,1秒就是25次,一天86400秒,2160000次一天,就是2160K次一天,而现在新EEPROM才1KK次能力,这个超过2KK次了,岂不是可以很容易写挂他?另外有条件,最好是不修改SysTick而是再开个定时器做小于1ms的溢出,这样不破坏系统的LL_mDelay这些函数.

发表评论

电子邮件地址不会被公开。 必填项已用*标注