最近调stm32 的 I2C 程序。
采用中断方式,
顺便监控了一下I2C中断事件,
读EEPROM的时候,数据如下:
0x00030001 I2C_EVENT_MASTER_MODE_SELECT
0x00070082 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED
0x00070080 I2C_EVENT_MASTER_BYTE_TRANSMITTING
0x00070084 I2C_EVENT_MASTER_BYTE_TRANSMITTED
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00070084
0x00030001
0x00030002 I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED
0x00030040(30个) I2C_EVENT_MASTER_BYTE_RECEIVED
非常奇怪的是当写完eeprom内存地址,restart以后,
stm32还连续产生了15次 I2C_EVENT_MASTER_BYTE_TRANSMITTED事件,
才能进入从模式选择,
进了14次中断重复
I2C_GenerateSTART(I2C1, ENABLE);
好像不大应该啊
这就要看你每个case下,如何处理的咯。
我是在0x70080这个case中,就判断,如果是读数据,则发送restart。
这样,退出0x70080后,会进一个0x70084,然后就0x30001了。
LZ得到这样的flag sequence,我估计你是在0x70084的case中才发送restart。
如果果真如此,你要是把I2C时钟,以及系统主频时钟再降低些,你的到的0x70084会更多,不止15个了。
LS,
果然高手,
实在0x70084的case中才发送restart,
但是按说也应该会立即进入 0x00030001 I2C_EVENT_MASTER_MODE_SELECT
不知两者到底有何差别?
在0x70084(TRA,BUSY,MSL,TXE,BTF)的case中执行发送restart的操作,退出ISR后,一方面I2C硬件开始在I2C总线上发出这个Start信号,注意这个过程相对于MCU运行速度来说,要持续一段时间。另一方面,在这段时间内,STM32一直在运行着,以上5个flag一直被置位着,所以退出ISR后,又进去,又退出,又进去,你这里进去了14次多余的0x70084。
直到Restart信号出现在I2C总线上了,h/w将TXE,BTF,TRA清零,同时置位SB,于是此时在进入中断,就走到0x30001的case了。
但是 ,我写eeprom,
写完第一页,开始写第二页,
如果写完成时直接在I2C_EVENT_MASTER_BYTE_TRANSMITTED处,
发I2C_GenerateSTOP(I2C1, ENABLE);
则第二页不能写,
中断事件如下:
如果写完成时直接在I2C_EVENT_MASTER_BYTE_TRANSMITTED处,发I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetLastEvent(I2C1) != 0) ;等一下,则只产生一个0x70084,以后各页可以写入,事件监控如下:
说明产生多个0x70084和stm32的工作错乱有一定的关系。
但是我直接在I2C_EVENT_MASTER_BYTE_TRANSMITTING中,
最后一个字节发送完成后处理I2C_GenerateSTOP(I2C1, ENABLE);
程序不能正常工作
更正:
有调了一下,
以上现象可能eeprom写入时间间隔有关系,
和0x70084不一定有关
又调试一下,
看来多个0x70084对程序还是有影响,
如果发
I2C_GenerateSTOP(I2C1, ENABLE);
while(I2C_GetLastEvent(I2C1) != 0)
;
等一下,只产生一个0x70084,
则再第二次页写之前,延时一会等待EEPROM可写,
则程序正常,
否则不管第二次页写之前,延时多长时间,
都不能第二次写。
看来STM32发停止位以后,不能立即停止总线,对EEPROM还是产生了影响。
可能我概念理解不对。
但是中断直接发送停止位,不等待,导致多个0x70084事件进入中断,
确实会对EEPROM第二次写产生影响。
哇哇哇!
为什么你6楼的能够正确运行呢。因为:
当代码进入,0x70084(transmitted,i2cEventGroup[10])时,总线上已经被要写的数据全部发送出去了。在这个case里,你的代码执行发送STOP的操作,然后通过你的while(I2C_GetLastEvent(I2C1) != 0),把eeprom它内部的写逻辑周期(写第一页)等待完成了。SR1/SR2都为0,可见此时总线已经处于idle状态了,接着你发送Start信号也是在这个while()之后吧。由此再进入0x30001(i2cEventGroup[11]),继续通信。。。
为什么你5楼“会对EEPROM第二次写产生影响”呢,要看你在每次0x70084的case中都作了什么操作了。
贴那个case的代码吧。
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* With BTF EV8-2 */
I2C_GenerateSTOP(I2C1, ENABLE);
//while(I2C_GetLastEvent(I2C1) == I2C_EVENT_MASTER_BYTE_TRANSMITTED)
// ;
wrTaskState = 3; //一帧写完毕标志
如果不加
while(I2C_GetLastEvent(I2C1) == I2C_EVENT_MASTER_BYTE_TRANSMITTED)
;
再下一次写数据,不论延时多少时间,I2C中断I2C_EVENT_MASTER_MODE_SELECT以后,
再也不能进入中断了!
下一页数据写,
在主程序里面判断
wrTaskState = =3,
延时一会写start
其实现在程序读写都OK了,
就是不明白需要屏蔽多个I2C_EVENT_MASTER_BYTE_TRANSMITTED中断的道理
手册上说:
EV8_2(I2C_EVENT_MASTER_BYTE_TRANSMITTED):TxE=1,BTF=1,请求设置停止位。TxE和BTF位由硬件在产生停止条件时清除。
看来设置停止操作以后,STM32确实就撒手不管了(导致多次检测到EV8_2事件,多次进入中断),
经过很长时间以后硬件检测到停止条件以后,TxE=1,BTF=1,才被清除。