PSoC4 MAX中I2C从机地址在RX缓冲区的处理疑问
PSoC4 MAX I2C从机地址填充固件缓冲区问题
问题背景
将基于英飞凌/Cypress PSoC4的旧项目移植到PSoC4 MAX芯片,设备作为I2C从机与主机通信:主机每秒发送3次仅包含从机地址的ping包,从机同时需要响应用户触发的特定命令。当前遇到的问题是:固件缓冲区被这些周期性的从机地址填满,导致用户命令被淹没丢失,而旧项目使用的旧版I2C库无此问题。
从机配置
当前I2C从机配置开启了acceptAddrInFifo=true:
const cy_stc_scb_i2c_config_t CYBSP_SCB_I2C_config = { .i2cMode = CY_SCB_I2C_SLAVE, .useRxFifo = true, .useTxFifo = true, .slaveAddress = 0x58, .slaveAddressMask = 0xFE, .acceptAddrInFifo = true, .ackGeneralAddr = false, .hsEnable = false, .enableWakeFromSleep = true, .enableDigitalFilter = false, .lowPhaseDutyCycle = 0, .highPhaseDutyCycle = 0, };
核心疑问
从机地址在ACK主机后是否应该进入固件缓冲区?若不应进入,该如何正确消耗这些地址?
代码逻辑分析
结合提供的ISR及相关处理函数,问题根源在于acceptAddrInFifo=true时的地址处理流程:
1. ISR处理逻辑
在Cy_SCB_I2C_SlaveInterrupt中:
- 当检测到
acceptAddrInFifo=true且触发地址匹配中断时,会设置slaveAddrInFifo=true,此时会跳过SlaveHandleDataReceive(避免在地址阶段就把地址写入固件缓冲区)。 - 当主机发送stop信号后,
SlaveHandleStop会检查RX FIFO是否有数据,若固件缓冲区有空间,会重新开启RX中断。此时slaveAddrInFifo已复位为false,后续RX中断触发时,SlaveHandleDataReceive会将FIFO中的地址字节写入固件缓冲区,导致地址不断积累。
2. SlaveHandleAddress处理逻辑
该函数负责地址匹配后的ACK/NACK处理:
- 如果未设置地址回调函数
cbAddr,则仅完成ACK/NACK操作,不会处理RX FIFO中的地址字节,导致地址留在FIFO中。 - 只有当设置了
cbAddr并触发CY_SCB_I2C_ADDR_IN_FIFO_EVENT时,才会在回调中处理地址,但默认逻辑中没有自动丢弃地址的操作。
3. SlaveHandleAck处理逻辑
该函数仅准备后续读写的缓冲区和中断配置,不会处理遗留的地址字节。
解决方案
针对上述问题,可通过以下方式解决:
方案1:关闭地址入FIFO功能
将配置中的acceptAddrInFifo设为false,此时硬件不会将匹配的从机地址存入RX FIFO,仅触发地址中断,由SlaveHandleAddress处理,地址不会进入固件缓冲区。此方案最直接,适合不需要在FIFO中获取地址的场景。
方案2:实现地址回调函数丢弃地址
如果必须开启acceptAddrInFifo,则实现cbAddr回调函数,在回调中手动读取并丢弃RX FIFO中的地址字节:
cy_en_scb_i2c_command_t addrCallback(uint32_t events) { if(events & CY_SCB_I2C_ADDR_IN_FIFO_EVENT) { // 读取并丢弃FIFO中的地址字节 Cy_SCB_ReadRxData(CYBSP_SCB_I2C_HW); } return CY_SCB_I2C_ACK; } // 初始化时注册回调 context.cbAddr = addrCallback;
方案3:在Stop事件中清理仅含地址的FIFO数据
在SlaveHandleStop或自定义的stop回调中,判断如果RX FIFO中仅存在地址字节(即ping包无后续数据),则直接清空FIFO,不写入固件缓冲区:
// 在Stop处理逻辑中添加 if(Cy_SCB_GetNumInRxFifo(base) == 1 && slaveAddrInFifo) { // 仅地址的ping包,清空FIFO Cy_SCB_ClearRxFifo(base); }
内容的提问来源于stack exchange,提问作者nobby
相关产品推荐
相关产品推荐

