运行时I2C超时但调试单步执行正常的AT24C32N问题求助
I2C起始条件超时问题:函数调用时失败,单步调试内部执行正常
问题描述
我正在开发基于I2C总线与AT24C32N EEPROM交互的代码,自行实现了I2C库,其中eeprom_write_data函数如下:
uint8_t eeprom_write_data(uint8_t *inputString[16]) { uint16_t eeAddr = 0; uint8_t err = 0; eeAddr = next_unused_addr(); // 读取0xFFF地址获取EEPROM中已存储的输入数量 if(eeAddr == TWI_ERROR_START || eeAddr == TWI_ERROR_RSTART) { return eeAddr; } err = EEPROM_write_handler(eeAddr, inputString, sizeof(inputString)/sizeof(inputString[0])); // 写入数据到EEPROM if(err == TWI_OK) { err = increment_eeprom_counter(eeAddr); // 更新0xFFF地址处的输入计数 } return err; }
核心问题:调用increment_eeprom_counter(甚至替换成已验证可用的EEPROM_write_handler)时,I2C发送起始条件会超时。但单步进入函数内部逐行执行一切正常,直接单步跳过函数调用则触发超时。
排查方向与解决方案
1. 补全EEPROM写周期等待
AT24C32N完成一页写入后需要至少5ms的写周期时间,如果连续发起I2C操作时总线还处于忙状态,就会导致起始条件超时。
- 确认
EEPROM_write_handler返回TWI_OK时,是否等待了EEPROM的写完成?很多I2C库不会自动处理这个等待逻辑,需要手动在写操作后加入5ms左右的延时,再执行下一次I2C操作。 - 单步调试时的时间间隔刚好满足了写周期要求,所以不会出问题;全速执行时两次操作间隔太短,触发超时。
2. 复位I2C外设状态寄存器
连续I2C操作后,硬件寄存器可能残留错误标志(比如未应答、仲裁丢失),导致新的起始条件无法正常发起:
- 在
increment_eeprom_counter执行前,检查并清除I2C(TWI)外设的错误状态位,必要时重新初始化I2C外设,确保总线处于空闲状态。
3. 修正参数长度计算错误
eeprom_write_data的参数uint8_t *inputString[16]是指针数组,sizeof(inputString)/sizeof(inputString[0])得到的是固定的16,但如果实际传入的是单个字符串指针,这个长度计算会导致EEPROM_write_handler写入超出预期的数据,破坏EEPROM状态进而影响后续操作:
- 建议修改参数为
uint8_t *inputString,并单独传入实际数据长度,避免依赖sizeof计算长度。
4. 排查栈溢出或内存异常
函数调用时的栈操作可能引发内存异常,间接影响I2C外设的配置:
- 检查
increment_eeprom_counter函数的栈使用情况,是否存在局部变量过多、递归调用等导致栈溢出的情况。 - 确认编译器的栈大小配置,确保栈空间足够支撑函数调用。
5. 调整编译器优化级别
部分编译器优化级别(如-O2)可能会改变代码执行顺序,或优化掉必要的延时/寄存器操作:
- 尝试降低优化级别至-O0,看问题是否消失。如果消失,再逐步排查被优化的代码部分,必要时用
volatile关键字标记I2C相关的寄存器或变量,避免被编译器优化。
内容的提问来源于stack exchange,提问作者David Hala
相关产品推荐
相关产品推荐

