基于 EEPROM 通信的 I2C 总线锁死解决方法

1. 简介

MCU 经常作为主机与 EEPROM 之间使用 I2C 进行通信,当 I2C 主机在通信的过程中发生异 常复位时,会有概率出现再无法与 EEPROM 通信,我们称之为总线锁死。为解决此问题,本文提供了采用软件配置释放 I2C 总线的方法。

2. I2C 总线锁死

2.1. I2C 总线锁死现象

I2C 的主从机之间若要完成一次正常的通信任务,在建立通信之前,首先需要主机检测 I2C 总 线的状态。当 I2C 总线的 SCL 和 SDA 线均为高电平时,I2C 总线为空闲状态,主机在 SCLA 为高电平时,拉低 SDA 信号,从而产生一个 START 起始信号。 I2C 主从机在结束一次通信任务时,需要主机产生一个停止信号,即在 SCL 为高电平时,拉高 SDA 信号。

图 2-1. I2C 总线的起始和停止信号

在正常情况下,I2C 总线协议能够保证总线正常的读写操作。但是,当 I2C 主设备复位时(看门 狗动作,板上电源异常导致复位芯片动作,手动按钮复位等等),而从机未复位,可能导致 I2C 总线死锁。在总线锁死的状态下,SCL 保持高电平状态,SDA 保持低电平状态。

2.2. I2C 总线锁死原因

在 I2C 主机读写的过程中,有两种情况会导致总线锁死。

1. 主机在发送 START 信号后,控制 SCL 产生 8 个时钟脉冲,然后拉低 SCL 信号为低电平, 在这个时候,从设备输出应答信号,将 SDA 信号拉为低电平。如果这个时候主机异常复 位,SCL 就会被释放为高电平。此时,如果从机没有复位,就会继续 I2C 的应答,将 SDA 一直拉为低电平,直到 SCL 变为低电平,才会结束应答信号。而由于 I2C 主机复位后检 测总线的状态,如果 SDA 信号为低电平,则 I2C 总线被占用,会一直等待 SCL 和 SDA 信号变为高电平。因此,在 I2C 主机等待从机释放 SDA 信号时,I2C 从机又在等待主机 将 SCL 信号拉低以释放应答信号,两者相互等待,I2C 总线进入死锁状态。

2. 当 I2C 主机在读数据时,I2C 从机应答后输出数据,如果在这个时刻 I2C 主机异常复位, 而此时 I2C 从机输出的数据位正好为 0,也会导致 I2C 总线进入死锁状态。

图 2-2. I2C 总线锁死时序

3. I2C 总线锁死解决方法

I2C 总线锁死状态下。通过复位从机也可实现释放总线。但 EEPROM 作为从机时,无法使用 软件复位从机的方法,而在某些场合又无法使用硬件的方法进行复位。故需要在 I2C 主机在建 立新的通信时,增加总线释放功能。由于总线锁死是概率性的,可以增加总线 BUSY 态超时功 能。二者结合可以提高系统的鲁棒性。以下提供两种软件解决方法。

3.1. 强制拉高 SDA 和 SCL

在 I2C 主机复位后,主机检测 I2C 总线一直为 BUSY 状态,且超过设定的时间,则总线被锁 死。可通过将 I2C 的 SCL 和 SDA 引脚初始化成普通 GPIO 功能,配置成推挽输出。先拉高 SCL 信号,在拉高 SDA 信号,模拟产生一个 STOP 信号,然后再配置为 I2C 的引脚复用功 能。GD32 工程下的软件配置如下表所示。

表 3-1. GD 工程下强制拉高 SDA 和 SCL 的配置

/*!
 \brief reset i2c bus
 \param[in] none
 \param[out] none
 \retval none
*/
void i2c_bus_reset()
{
 GPIO_BC(GPIOB) |= GPIO_PIN_6 | GPIO_PIN_7;
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_6|GPIO_PIN_7);
 __nop();
 __nop();
 __nop();
 __nop();
 __nop();
 GPIO_BOP(GPIOB) |= GPIO_PIN_6;
 __nop();
 __nop();
 __nop();
 __nop();
 __nop();
 GPIO_BOP(GPIOB) |= GPIO_PIN_7;
 gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | 
GPIO_PIN_7);
} 

/*!
 \brief check the I2C is or not busy
 \param[in] none
 \param[out] none
 \retval none
*/
void check_bus_status(void)
{
 while(i2c_flag_get(I2C0,I2C_FLAG_I2CBSY))
 {
 if(--time_out == 0){
 i2c_bus_reset();
 }
 }
}

3.2. SCL 时钟信号释放总线

在 I2C 主机中增加 I2C 总线恢复程序。每次 I2C 主设备复位后,如果检测到 SDA 数据线被拉 低,则控制 I2C 中的 SCL 时钟线产生 9 个时钟脉冲(针对 8 位数据的情况),这样 I2C 从设备 就可以完成被挂起的操作,从死锁状态中恢复过来。 I2C 主机通过将 SCL 引脚初始化为普通 GPIO 功能,配置成推挽输出。保证连续发送 9 个时 钟脉冲,为保证后续 I2C 正常通信,先将 I2C 模块复位,再置位,最后再配置为 I2C 的引脚复 用功能。GD32 工程下的软件配置如下表所示。

表 3-2. GD 工程下的 SCL 时钟信号释放总线配置

/*!
 \brief reset i2c bus
 \param[in] none
 \param[out] none
 \retval none
*/
void i2c_bus_reset()
{
 uint8_t I = 0;
 gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
 /* SCL output clock signal */
 for(I = 0; I < 10; i++){
 gpio_bit_reset(GPIOB, GPIO_PIN_6);
 delay_1us(2);
 gpio_bit_set(GPIOB, GPIO_PIN_6);
 delay_1us(2);
 }
 /* reset I2C */
 i2c_software_reset_config(I2C0, I2C_SRESET_RESET);
 i2c_software_reset_config(I2C0, I2C_SRESET_SET);
 gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | 
GPIO_PIN_7);
} 
/*!
 \brief check the I2C is or not busy
 \param[in] none
 \param[out] none
 \retval none
*/
void check_bus_status(void)
{
 while(i2c_flag_get(I2C0,I2C_FLAG_I2CBSY))
 {
 if(--time_out == 0){
 i2c_bus_reset();
 }
 }
}

3.3. 测试结果

在 GD32F303 的平台上测试两种总线释放的方法。其测试结果如图 3-1. 强制拉高 SDA 和 SCL 测试和图 3-2. SCL 时钟信号释放总线测试所示。

强制拉高 SDA 和 SCL 测试如下图所示,I2C 总线锁死时,SDA 为低电平状态,SCL 为高电 平状态。总线释放时,将 SCL 先拉低,再拉高,然后再将 SDA 拉高。最后 I2C 总线上出现 STOP 信号,总线被释放。主机可以开始建立新的通信。

图 3-1. 强制拉高 SDA 和 SCL 测试

SCL 时钟信号释放总线测试如下图所示,I2C 总线锁死后,连续发送 9 个时钟信号,最后 SDA 和 SCL 均被拉高,主机检测到总线为空闲状态,可以开始建立新的通信。

图 3-2. SCL 时钟信号释放总线测试

参考连接

AN036_CN_Rev1.0.pdf (gd32mcu.com)icon-default.png?t=N7T8https://www.gd32mcu.com/data/documents/userManual/AN036_CN_Rev1.0.pdf一个判断 I2C 总线通信异常原因的方法_i2c通信正常和通信不正常-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/anlog/article/details/131660862?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171593218516800213071294%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171593218516800213071294&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-131660862-null-null.nonecase&utm_term=%E6%AD%BB%E9%94%81&spm=1018.2226.3001.4450

总结:简单发送脉冲的方案最简单。

特此记录

anlog

2024年5月17日

  • 39
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
I2C(Inter-Integrated Circuit)总线是一种串行通信协议,常用于连接微控制器、传感器和其他外围设备。I2C总线应用系统设计手册是一本详细介绍了如何设计和应用I2C总线的参考书籍。 该手册首先介绍了I2C总线的基本原理和工作方式。它解释了I2C总线是如何通过两根线(一根为数据线SDA,一根为时钟线SCL)实现数据传输的,并阐述了I2C总线的工作速度和容量的限制。 接下来,该手册探讨了I2C总线在不同应用场景中的具体设计方法。例如,在微控制器和外围设备之间建立I2C通信连接时,需要考虑如何设置合适的时钟速率、地址分配和通信协议。此外,该手册还介绍了如何应用I2C总线来实现特定功能,比如温度传感器和数字陀螺仪的数据采集、EEPROM的读写以及其他外围设备的控制。 除了具体的应用设计,该手册还提供了一些常见的问题和解决方案,帮助读者更好地理解和应用I2C总线。例如,如何避免I2C总线上的通信冲突和噪声干扰,以及如何实现多主机系统的同步通信等问题。 总的来说,I2C总线应用系统设计PDF是一本详细介绍了I2C总线基本原理、应用设计和问题解决方案的参考书籍,适用于工程师、学生和研究人员等对I2C总线感兴趣的人群。阅读该手册可以帮助读者更好地理解和应用I2C总线,从而设计出高效可靠的I2C总线应用系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值