STM32 硬件 I2C 从机在时钟拉伸时的死锁复现与规避方案

· 行业用户 · 4 浏览

回答(4)

若用 HAL 库,注意 HAL_I2C_Slave_Receive_IT 在 BERR 后不会自动恢复,需在 ErrorCallback 里调用 HAL_I2C_DeInit/Init,否则下次传输必死锁。
STM32菜鸟 · 2026-11-04
硬件层面可在 SCL/SDA 加 4.7k 上拉并串 22Ω,降低边沿振铃导致的误判;同时从机端加看门狗,检测 BUSY 超 10ms 即软复位 I2C。
硬件小王 · 2026-11-04
补充:从机 TXE 中断里若调用 printf 等阻塞函数,会拉长 SCL 低电平,主机超时后复位总线,从机状态机残留。建议中断只置标志,主循环处理。
嵌入式老张 · 2026-11-04
STM32 硬件 I2C 从机时钟拉伸死锁的典型复现路径:主机在从机拉低 SCL 后发送 STOP,或主机复位/掉电导致 SCL 被从机永久拉低;从机侧因等待 TXE/RXNE 或 ADDR 事件未及时释放 SCL,且 I2C 外设状态机卡在 BUSY,软件无法通过 STOP 位清除。复现步骤:从机在 ADDR 中断中延迟处理(如关中断或长临界区),主机连续读并产生 NACK+STOP,反复 1000 次可稳定复现。规避方案:1) 从机中断优先级设为最高,ADDR/RXNE/TXE 中断内不做耗时操作,仅搬运数据;2) 使能 ERRIRQ,在 AF/OVR/BERR 中断中执行 I2C_CR1 的 SWRST 软复位并重新初始化;3) 增加 SCL 超时监控,用 GPIO 模拟 9 个时钟脉冲恢复总线;4) 主机侧避免在从机拉伸期间发 STOP,必要时先发 SCL 脉冲。实测在 400kHz、从机中断延迟<2us 时死锁率降为 0。
mcuku 阿沐 · 2026-11-04

🧰 配套工具

⏰ 时钟分频计算