SAM3x8e I2C从设备发送MSB为0的读字节后持续拉低SDA问题
SAM3X8E I2C从机发送低字节后SDA持续拉低的问题解决
问题核心
Arduino Due上的SAM3X8E作为I2C从机时,主设备写操作及发送高位为1(≥0x80)的读字节均正常,但发送最高位为0(<0x80)的字节后,SAM3X会持续拉低SDA线,导致后续I2C操作失败。已通过重置控制器确认是SAM3X自身拉低SDA,示波器解码显示传输成功,但总线无法恢复正常状态。
可能的原因及修复方案
1. 中断处理逻辑缺失关键步骤
当前仅在TXRDY触发时写入THR寄存器,未处理控制器的状态确认及传输结束后的标志清除,这可能导致控制器错误占用SDA总线。
修复代码示例:
void TWI1_Handler(void) { uint32_t sr = TWI1->TWI_SR; // 先读取状态寄存器,清除挂起的中断标志 if (sr & TWI_SR_TXRDY) { TWI1->TWI_THR = (uint32_t)iByteSent; // 若为最后一个待发送字节,临时禁用TXRDY中断,避免误触发 if (is_last_byte_flag) { TWI1->TWI_IDR = TWI_IDR_TXRDY; } } if (sr & TWI_SR_NACK) { // 主设备发送NACK,说明读传输结束,重置总线状态 TWI1->TWI_RHR; // 清空接收缓冲 // 重新启用TXRDY中断,等待下一次读请求 TWI1->TWI_IER = TWI_IER_TXRDY; } if (sr & TWI_SR_RXRDY) { // 处理主设备写操作的接收逻辑 uint8_t received_byte = TWI1->TWI_RHR; // ... 自定义接收处理代码 } }
2. 初始化流程未彻底清除状态标志
预加载THR解决了初始TXRDY持续触发的问题,但可能残留异常状态。调整初始化步骤:
void Configure12cAsSlave(void) { PMC->PMC_PCER1 |= PMC_PCER1_PID37; PMC->PMC_PCER0 |= PMC_PCER0_PID23; // TWI1 power ON PIOB->PIO_PDR |= PIO_PDR_P13 | PIO_PDR_P12; // 启用外设控制 PIOB->PIO_ABSR &= ~(PIO_PB12A_TWD1 | PIO_PB13A_TWCK1); // 配置为TWI功能 PIOB->PIO_ODER |= PIO_ODER_P12 | PIO_ODER_P13; // 显式设置开漏模式 TWI1->TWI_CR = TWI_CR_SWRST; // 软件重置 delay_us(1); // 给控制器足够重置时间 TWI1->TWI_RHR; // 清空接收缓冲 TWI1->TWI_SR; // 读取状态寄存器,清除所有挂起标志 TWI1->TWI_CR = TWI_CR_SVDIS | TWI_CR_MSDIS; // 禁用主/从模式 // 启用从机模式 TWI1->TWI_SMR = TWI_SMR_SADR(I2C_SLAVE_ADDRESS); TWI1->TWI_CR = TWI_CR_SVEN; // 开启从机模式 // 启用中断 TWI1->TWI_IER = TWI_IER_RXRDY | TWI_IER_TXRDY; NVIC_EnableIRQ(TWI1_IRQn); NVIC_SetPriority(TWI1_IRQn, IRQ_PRIORITY__I2C); }
3. 确认NACK状态的处理
SAM3X的TWI控制器在收到主设备的NACK后,若未及时处理,会保持对SDA的驱动。必须在中断中捕获TWI_SR_NACK标志,完成总线状态重置。
验证步骤
- 替换中断处理代码,加入状态寄存器读取和NACK逻辑
- 调整初始化流程,确保所有状态标志被彻底清除
- 用示波器观察发送<0x80字节后的SDA状态,确认传输结束后总线是否正常释放
内容的提问来源于stack exchange,提问作者thecowster
相关产品推荐
相关产品推荐

