I2C接口进入Busy状态不能退出问题:该问题由某客户提出,发生在STM32F103VDT6器件上。据其工程师讲述:在其产品设计中,使用了STM32的一个I2C接口与一个EEPROM通信。在系统靠性测试中发现,经过长时间运行后,STM32会出现不能读写EEPROM的现象。通过NRST管脚对STM32进行复位,复位后该现象依旧存在。关掉电源,然后重新上电,现象消失。通过进一步测试发现,如果对STM32反复做复位操作,会很容易复现这一现象。调研:修改软件,通过打印监控I2C通信程序的流程,及I2C接口的各个寄存器的状态。当出现上述现象时,I2C接口的状态寄存器SR2中的Busy位置‘1’,状态寄存器SR1中的ARLO位置‘1’。用示波器观察I2C总线,发现其SCL为高电平,SDA为低电平。将STM32的复位脚拉到地,SCL及SDA的状态不变。检查原理图,确认I2C总线上只有STM32和EEPROM两颗器件。结论:EEPROM驱动I2C总线进入了非空闲状态,使得STM32在接管总线时发生总线仲裁失败,进而失去对总线的控制,无法启动数据的传输。EEPROM的这种状态可能是通信被意外中断造成的。通过对STM32进行复位而重现这一现象,在一定程度上吻合了这种猜测。但没有实验和理论依据证实一定是该原因导致了这一问题,是否还有其它原因在起作用,不得而知。处理:修改软件,加入对I2C总线修复的功能。在每次发送起始条件之前首先检测SR2中Busy位,如果为‘1’,则说明总线上有异常。此时,可由GPIO的OD模式代替I2C通信口接管SCL及SDA两个管脚。通过翻转GPIO,向SCL信号线上发高电平脉冲,脉冲宽度及间隔匀为10uS。每发出一个脉冲之后,检测SDA信号是否为高电平。若SDA信号为已高电平,则将SCL拉高,然后向SDA信号线发出一个10uS宽的低电平脉冲。然后将SCL及SDA两个管脚交还给I2C接口,并通过将CR1中的SWRST位置‘1’后再清‘0’来复位I2C接口,使其退出Busy状态。如图(一)所示:A:将SCL和SDA切换成GPIO的OD模式;B:发送时钟脉冲并等待SDA跳变到高电平;C:在SDA上发出一个低电平脉冲;D:在SDA拉高后,将SCL的SDA切换回I2C接口;E:通过CR1中的SWRST位复位I2C接口;建议:STM32中的I2C接口被设计成为主从自适应接口,并充许多个主机共享一条I2C总线。I2C接口在被使能之后,会不断的检测SCL及SDA的电平与跳变。当发现有低脉冲出现在SCL或SDA上时,则认为总线进入了Busy状态,其Busy标志会置‘1’,直到在总线上检测到一个符合要的停止条件之后,才认为总线回到了空闲状态,这时由硬件清除Busy标志。当I2C接口认为总处于Busy状态且不是由自己占用时,会拒绝向总线上发送信号,因为它认为此刻I2C总线正在被其它的主机所使用。这时向I2C接口发命令,要求产生起始条件,会导致总线仲裁失败。要从这种状态退出,首先要保证总线是处于空闲状态,即SCL和SDA都为高电平。然后,通过将CR1的SWRST置‘1’然后清‘0’来复位I2C接口,以达到清除Busy标志回到空闲状态目的。