STM32多主I2C场景下空起始-停止脉冲的成因及解决问询
STM32 I2C多主系统异常排查:F405作为主机仅产生起始-停止脉冲无数据发送
测试场景与异常现象
- 系统由STM32F769和STM32F405组成I2C多主设备系统,闲置状态下两台设备均配置为从机模式
- STM32F769以重复起始方式,依次执行
MasterTransmit和MasterReceive操作 - STM32F405作为从机接收数据后立即返回响应数据,处理完接收数据后切换为主机,向STM32F769发送数据
- 异常表现:STM32F405切换为主机后,仅产生起始-停止脉冲序列,无数据发送
相关配置及代码
STM32F769初始化代码
I2C_Initialize() { AttachAddressDetectHandler(&I2C_AddressDetect); AttachSlaveRecieveCpltHandler(&I2C_GetData); AttachListenCpltHandler(&I2C_StartListen); AttachMasterTransmitCpltHandler(&I2C_MasterReceive); AttachMasterReceiveCpltHandler(&I2C_ReleaseBus); I2C_StartListen(hi2c); }
注:Attach系列函数直接对接STM32 HAL库
STM32F405初始化代码
I2C_Initialize() { AttachAddressDetectHandler(&I2C_AddressDetect); AttachSlaveRecieveCpltHandler(&I2C_GetData); AttachListenCpltHandler(&I2C_StartListen); AttachMasterTransmitCpltHandler(&I2C_ReleaseBus); I2C_StartListen(hi2c); }
STM32F769主机操作逻辑
调用I2C_MasterTransmit启动传输,完成后通过HAL回调触发I2C_MasterReceive:
I2C_MasterTransmit(..) { I2C_StopListen(hi2c); // 关闭监听模式 I2C_AquireBus(hi2c); // 信号量锁定I2C总线 HAL_I2C_Master_Seq_Transmit_DMA(hi2c, stm32f405address, pData, size, I2C_FIRST_FRAME); } I2C_MasterReceive(..) { HAL_I2C_Master_Seq_Receive_DMA(hi2c, stm32f405address, pData, size, I2C_LAST_FRAME); }
STM32F405从机操作逻辑
作为从机时,地址检测回调中根据传输方向启动DMA操作,接收数据完成后处理数据:
I2C_AddressDetect(..) { switch (direction) { case I2C_DIRECTION_RECEIVE: HAL_I2C_Slave_Seq_Transmit_DMA(hi2c, rxedData, size, I2C_LAST_FRAME); break; case I2C_DIRECTION_TRANSMIT: HAL_I2C_Slave_Seq_Receive_DMA(hi2c, rxedData, size, I2C_FIRST_FRAME); break; } } I2C_GetData(..) { // 处理接收的数据 }
STM32F405主机操作逻辑
处理完从机接收的数据后,切换为主机向STM32F769发送数据:
I2C_MasterTransmit(..) { I2C_StopListen(hi2c); I2C_AquireBus(hi2c); HAL_I2C_Master_Transmit_DMA(hi2c, stm32f769address, pData, size); }
STM32F769从机操作逻辑
I2C_AddressDetect(..) { HAL_I2C_DisableListen_IT(hi2c); switch (direction) { case I2C_DIRECTION_RECEIVE: break; case I2C_DIRECTION_TRANSMIT: HAL_I2C_Slave_Receive_DMA(hi2c, rxedData, size); break; } I2C_GetData(..) { // 处理接收的数据 }
异常成因分析
- 从机状态残留:STM32F405从机操作完成后,I2C外设的从机相关状态标志位未彻底清除,切换为主机模式时,外设仍处于从机锁定状态,无法正常启动主机发送流程,仅能触发起始-停止脉冲。
- 监听模式退出不彻底:
I2C_StopListen或HAL_I2C_DisableListen_IT调用后,I2C外设的监听模式寄存器未完全复位,残留状态干扰主机模式初始化。 - 总线释放时机错误:STM32F769的
I2C_ReleaseBus信号量释放过早,在MasterReceive的停止位未完全发送、总线未真正空闲时就释放,导致STM32F405发起主机传输时总线仲裁失败,仅发送起始-停止序列就退出。 - DMA资源冲突:从机操作使用的DMA通道未在切换主机模式前复位,通道残留的从机传输状态导致主机发送的DMA请求未被响应,数据无法输出。
规避方法
- 彻底清除从机状态:STM32F405切换为主机前,先调用
HAL_I2C_DeInit复位I2C外设,再重新初始化I2C(保留地址、速率等配置参数),确保从机状态完全清除。 - 规范监听模式退出流程:退出监听模式时,除调用封装的
I2C_StopListen,需手动检查并清除I2C_CR2寄存器的LISTEN位,同时等待I2C_ISR寄存器的STOPF标志置位,确认总线处于空闲状态。 - 调整总线释放时机:STM32F769的
I2C_ReleaseBus需在MasterReceive完成且停止位发送完成后执行,可通过在I2C_ReleaseBus中检查I2C_ISR的STOPF标志,确认总线空闲后再释放信号量。 - 复位DMA资源:切换主机模式前,停止从机操作使用的DMA通道,调用
HAL_DMA_DeInit和HAL_DMA_Init重新配置DMA,避免通道状态残留。 - 添加总线空闲检测:STM32F405发起主机传输前,通过读取SDA和SCL引脚电平,或调用
HAL_I2C_IsDeviceReady函数确认总线空闲,再启动HAL_I2C_Master_Transmit_DMA操作。
内容的提问来源于stack exchange,提问作者krid
相关产品推荐
相关产品推荐

