You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(..)
{
 // 处理接收的数据
}

异常成因分析

  1. 从机状态残留:STM32F405从机操作完成后,I2C外设的从机相关状态标志位未彻底清除,切换为主机模式时,外设仍处于从机锁定状态,无法正常启动主机发送流程,仅能触发起始-停止脉冲。
  2. 监听模式退出不彻底:I2C_StopListen或HAL_I2C_DisableListen_IT调用后,I2C外设的监听模式寄存器未完全复位,残留状态干扰主机模式初始化。
  3. 总线释放时机错误:STM32F769的I2C_ReleaseBus信号量释放过早,在MasterReceive的停止位未完全发送、总线未真正空闲时就释放,导致STM32F405发起主机传输时总线仲裁失败,仅发送起始-停止序列就退出。
  4. DMA资源冲突:从机操作使用的DMA通道未在切换主机模式前复位,通道残留的从机传输状态导致主机发送的DMA请求未被响应,数据无法输出。

规避方法

  1. 彻底清除从机状态:STM32F405切换为主机前,先调用HAL_I2C_DeInit复位I2C外设,再重新初始化I2C(保留地址、速率等配置参数),确保从机状态完全清除。
  2. 规范监听模式退出流程:退出监听模式时,除调用封装的I2C_StopListen,需手动检查并清除I2C_CR2寄存器的LISTEN位,同时等待I2C_ISR寄存器的STOPF标志置位,确认总线处于空闲状态。
  3. 调整总线释放时机:STM32F769的I2C_ReleaseBus需在MasterReceive完成且停止位发送完成后执行,可通过在I2C_ReleaseBus中检查I2C_ISR的STOPF标志,确认总线空闲后再释放信号量。
  4. 复位DMA资源:切换主机模式前,停止从机操作使用的DMA通道,调用HAL_DMA_DeInit和HAL_DMA_Init重新配置DMA,避免通道状态残留。
  5. 添加总线空闲检测:STM32F405发起主机传输前,通过读取SDA和SCL引脚电平,或调用HAL_I2C_IsDeviceReady函数确认总线空闲,再启动HAL_I2C_Master_Transmit_DMA操作。

内容的提问来源于stack exchange,提问作者krid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:47:33