I2C死锁原因及解决方法

一、死锁总线表现

      SCL为高,SDA一直为低

二、背景知识

1.  I2C总线空闲状态

     I2C总线中,当SCL和SDA都为高电平时,总线处于空闲状态。

2. I2C总线起始信号

     I2C总线中,当处于空闲状态情况下时,SCL为高,SDA由高到低的变化为起始信号。

3. I2C总线停止信号

     I2C总线中,当传输完数据后,SCL为高,SDA由低变为高,这个信号为停止信号。停止信号都为主机发出。

4. scl为低时可以传送数据,传送完后SCL会被拉高,在scl上升沿开始传数据。scl为高时要保持sda数据稳定。

5. 发送完数据,读完数据,发送完stop信号,都要delay一会,等设备反应。

三、I2C死锁现象

      在正常情况下,I2C总线协议能够保证总线正常的读写操作。但是,当I2C主设备异常复位时(看门狗动作,板上电源异常导致复位芯片动作,手动按钮复位等等)有可能导致I2C总线死锁产生。下面详细说明一下总线死锁产生的原因。

      在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于I2C主设备来说.复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态。同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导致I2C总线进入死锁状态。

SCL为高,SDA一直为低原因

从:正常时序下:SDA信号是在SCL为低的状态下改变,即从应答SDA为低电平时,此时SCL应为为低电平(即从设备是先拉低SDA信号,等待主设备SCL由高变低,“取走”ACK信号后,从再释放SDA为高)。但如果此时时序被打乱,例如单片机i2c通信时突然复位,SCL突然变高,则从设备SDA一直为低,等待SCL变低。

主:SDA被从拉低,故主认为i2c总线占用,一直等待SDA变高

这样主从进入一个相互等待的死锁过程。

四、I2C死锁解决方法

    最好用模拟I2C实现,则不会死锁

    (1) 尽量选用带复位输人的I2C从器件。

    (2) 将所有的从I2C设备的电源连接在一起,通过MOS管连接到主电源,而MOS管的导通关断由I2C主设备来实现。

    (3) 在I2C从设备设计看门狗的功能。

    (4) 在I2C主设备中增加I2C总线恢复程序。每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情          况),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。这种方法有很大的局限性,因为大部分主设备的I2C模块由内置的硬件电路来实               现,软件并不能够直接控制SCL信号模拟产生需要时钟脉冲。

    (5) 在I2C总线上增加一个额外的总线恢复设备。这个设备监视I2C总线。当设备检测到SDA信号被拉低超过指定时间时,就在SCL总线上产生9个时钟脉冲,使              I2C从设备完成读操作,从死锁状态上恢复出来。总线恢复设备需要有具有编程功能,一般可以用单片机或CPLD实现这一功能。

   (6) 在I2C上串人一个具有死锁恢复的I2C缓冲器,如Linear公司的LTC4307如图2所示:LTC4307是一个双向的I2C总线缓冲器,并且具有I2C总线死锁恢复的功能。          LTC4307总线输人侧连接主设备,总线输出侧连接所有从设备。当LTC4307检测到输出侧SDA或SCL信号被拉低30ms时,就自动断开I2C总线输人侧与输出            侧 的连接.并且在输出侧SCL信号上产生16个时钟脉冲来释放总线。当总线成功恢复后,LTC4307会再次连接输人输出侧,使总线能够正常工作。

部分转自:http://blog.csdn.net/zyboy2000/article/details/5603091

I2C总线中的**死锁(Deadlock)**是一种常见但危险的状态,通常发生在多主设备或复杂通信场景中,导致总线无法正常工作,所有设备均无法完成数据传输。以下是I2C死锁的成因、典型场景、解决方案及预防措施的详细说明: --- ### **1. I2C死锁的成因** I2C死锁的核心原因是**总线被异常占用**,导致SCL(时钟线)或SDA(数据线)被持续拉低,无法释放总线。常见成因包括: - **主设备异常中断**:主设备在传输过程中崩溃、复位或断电,未释放总线(未发送停止条件)。 - **从设备未释放SDA**:从设备在ACK/NACK响应时故障(如硬件损坏),导致SDA被持续拉低。 - **时钟同步冲突**:多主设备竞争总线时,时钟信号(SCL)被不同设备拉低,导致时钟停滞。 - **电气干扰**:总线受到噪声干扰,导致SCL/SDA被误拉低。 --- ### **2. 典型死锁场景** #### **场景1:主设备崩溃未释放总线** - **过程**: 1. 主设备发送起始条件(Start),开始传输数据。 2. 传输过程中,主设备因软件错误、断电或复位而崩溃。 3. 主设备未发送停止条件(Stop),导致SDA或SCL被持续拉低。 - **结果**:总线被锁定,其他设备无法发起新传输。 #### **场景2:从设备故障卡住SDA** - **过程**: 1. 主设备发送地址帧,从设备应答(ACK)。 2. 从设备在接收数据时故障(如内部看门狗触发),导致SDA被持续拉低。 - **结果**:主设备无法继续传输,总线死锁。 #### **场景3:多主设备时钟冲突** - **过程**: 1. 两个主设备同时检测到总线空闲,尝试发起传输。 2. 主设备A拉低SCL发送时钟,主设备B也尝试拉低SCL,导致时钟线冲突。 - **结果**:SCL被持续拉低,总线无法前进。 --- ### **3. 死锁的后果** - **总线瘫痪**:所有设备无法发起新传输,通信完全中断。 - **硬件损坏风险**:长期死锁可能导致总线电压异常,损坏设备。 - **系统崩溃**:依赖I2C的关键外设(如EEPROM、传感器)无法工作,导致系统故障。 --- ### **4. 解决方案** #### **方法1:硬件复位总线** - **原理**:通过强制拉高SCL和SDA线,释放被锁定的总线。 - **实现**: 1. 使用**总线复位电路**(如MOSFET或专用芯片,如PCA9548)。 2. 手动复位:断电后重新上电,或通过GPIO强制拉高SCL/SDA。 - **示例电路**: ``` [总线复位电路] VCC --[上拉电阻]-- SCL/SDA --[NMOS]-- GND 控制信号(如MCU GPIO)连接NMOS栅极,高电平时强制拉低SCL/SDA(复位时序需符合I2C规范)。 ``` #### **方法2:超时机制** - **原理**:在软件中设置超时时间,若传输超时则主动释放总线。 - **实现**: ```c // 伪代码示例 void i2c_write(uint8_t addr, uint8_t data) { uint32_t timeout = 1000; // 超时阈值 while (timeout--) { if (i2c_start()) break; // 尝试发送起始条件 if (i2c_send_addr(addr)) break; // 发送地址 if (i2c_send_data(data)) break; // 发送数据 if (i2c_stop()) break; // 发送停止条件 } if (timeout == 0) { i2c_reset_bus(); // 超时后复位总线 } } ``` #### **方法3:时钟拉伸(Clock Stretching)优化** - **原理**:从设备通过拉低SCL暂停传输,主设备需等待SCL释放后再继续。 - **优化**: - 确保从设备时钟拉伸时间合理(避免过长)。 - 主设备检测SCL被拉低时,插入延时或重试机制。 #### **方法4:使用看门狗定时器** - **原理**:在主设备中启用看门狗,若传输卡死则触发复位。 - **实现**: - 配置硬件看门狗,超时后强制复位MCU。 - 复位后重新初始化I2C总线。 --- ### **5. 预防措施** #### **措施1:设计健壮的软件协议** - 在每次传输后强制检查ACK/NACK。 - 实现重试机制(如最多重试3次)。 - 避免在中断上下文中执行I2C传输(防止中断嵌套导致死锁)。 #### **措施2:硬件保护** - 添加总线保护二极管,防止电压反冲。 - 使用带死锁恢复功能的I2C控制器(如部分MCU内置硬件I2C模块)。 #### **措施3:限制多主设备竞争** - 避免多主设备同时操作总线。 - 使用仲裁机制(如优先级分配或令牌传递)。 #### **措施4:监控总线状态** - 通过GPIO实时监测SCL/SDA电平。 - 若检测到异常低电平,触发复位流程。 --- ### **6. 实际案例:STM32I2C死锁恢复** 在STM32中,若I2C外设死锁,可通过以下步骤恢复: 1. **禁用I2C外设**: ```c HAL_I2C_DeInit(&hi2c1); ``` 2. **手动复位总线**: - 拉低SCL和SDA(通过GPIO)。 - 延迟10ms后释放。 3. **重新初始化I2C**: ```c HAL_I2C_Init(&hi2c1); ``` --- ### **总结** I2C死锁是总线通信中的高危问题,需通过**硬件复位、超时机制、软件健壮性设计**综合预防。关键点包括: - 确保每次传输后正确释放总线(发送停止条件)。 - 在软件中实现超时和重试逻辑。 - 必要时使用专用芯片或GPIO辅助复位总线。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值