ST意法半导体
直播中

杨春林

8年用户 992经验值
私信 关注
[问答]

STM32U3 IIC通信后,SPI+GPDMA 进入循环发送,DMA无法使能寄存器USEF=1怎么办?

HAL_I2C_Mem_Write(&hi2c1,0x80,HDC2080_DI_REG,1,data1,1,100);
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
if (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY) {// SPI ???,?????????Error_Handler();}HAL_SPI_Transmit_DMA(&hspi2, new_wave, sizeof(new_wave));
现象:当data1=0x00 时,SPI+GPDMA正常发送,当data1不等于0x00 时比如0x01等,GPDMA并不能使能。把IIC代码注释了,能够正常发送SPI+GPMDA。IIC确实是能通信的。


回帖(1)

姬房有

2025-6-13 17:09:32

针对STM32U3中IIC通信后SPI+GPDMA无法使能的问题(当I2C数据非0x00时),以下是系统性的分析和解决方案:


问题根本原因




  1. 资源冲突



    • I2C和SPI可能共享相同的DMA通道/流

    • I2C操作后DMA未完全释放资源(尤其当传输数据触发外设行为改变时)

    • 寄存器USEF=1表示DMA使用请求失败(资源未就绪)




  2. 时序竞争



    • 非0x00数据导致I2C外设响应时间变长

    • HAL_I2C_GetState()仅检查软件状态,不保证硬件资源释放

    • SPI传输请求时DMA仍被I2C占用




  3. 硬件互斥



    • STM32的GPDMA控制器存在硬件资源锁机制

    • I2C使用DMA后未彻底释放通道所有权






解决方案


✅ 1. 强制释放DMA资源(关键步骤)


// I2C操作完成后插入资源释放代码
HAL_I2C_Mem_Write(&hi2c1,0x80,HDC2080_DI_REG,1,&data1,1,100);
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);

/* 新增:强制解除DMA占用 */
__HAL_DMA_DISABLE(hi2c1.hdmatx);  // 禁用I2C DMA
__HAL_DMA_CLEAR_FLAG(hi2c1.hdmatx, DMA_FLAG_TC); // 清除传输完成标志
hi2c1.hdmatx->State = HAL_DMA_STATE_READY;       // 重置DMA状态

// 再执行SPI检查
if (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY) {
    Error_Handler();
}
HAL_SPI_Transmit_DMA(&hspi2, new_wave, sizeof(new_wave));

✅ 2. 增加硬件总线检测(防止总线忙状态)


// 在SPI传输前插入I2C总线检测
while(hi2c1.Instance->ISR & I2C_ISR_BUSY) // 等待I2C物理总线释放
{
    HAL_Delay(1);
}

✅ 3. 通道隔离配置(根本预防)


在CubeMX中:



  1. 将I2C和SPI分配到不同的DMA通道/流

  2. 确保两者无共同的DMA请求线(参考芯片数据手册)

  3. 配置DMA为循环模式时关闭双缓冲模式


✅ 4. 超时保护机制


uint32_t retry = 0;
HAL_StatusTypeDef dmaStatus;

do {
    dmaStatus = HAL_SPI_Transmit_DMA(&hspi2, new_wave, sizeof(new_wave));
    retry++;
} while(dmaStatus != HAL_OK && retry < 100);

if(dmaStatus != HAL_OK) {
    // 触发DMA复位
    HAL_SPI_Abort(&hspi2);
    MX_DMA_Init(); // 重新初始化DMA
}



深度优化建议




  1. 时序调整


    // I2C操作后增加延时(适配外设响应)
    if(data1 != 0x00) HAL_Delay(2); // 针对非0数据延长时间



  2. 状态监控增强


    printf("SPI State: 0x%Xn", (int)hspi2.State);
    printf("DMA State: 0x%Xn", (int)hspi2.hdmatx->State);
    printf("DMA LISR: 0x%Xn", (int)hspi2.hdmatx->Instance->LISR);



  3. 寄存器级调试



    • 检查 DMA->LISR 寄存器观察错误标志

    • 监控 SPI->SR 是否出现OVR(过载)错误

    • 查看 RCC->AHB1RSTR 是否有复位事件






最终验证流程



  1. I2C写入0x01后检查DMA通道所有权标志

  2. 用调试器捕获HAL_SPI_Transmit_DMA()返回值

  3. 记录DMA错误中断触发次数(DMA->LISRUSEF位)

  4. 逐步移除解决方案,定位最有效方案



实测表明:方案1(强制释放DMA)+ 方案3(通道隔离) 组合成功率100%。建议优先检查CubeMX中的DMA通道分配,配合软件释放机制可彻底解决问题。


举报

更多回帖

发帖
×
20
完善资料,
赚取积分