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

STM32H723 SPI DMA底层驱动仅发送一帧后触发传输错误求助

STM32H723 SPI+DMA底层驱动传输异常问题

使用STM32H723的SPI结合DMA底层驱动时出现异常:SPI需每100ms触发一次,发送10字节帧,但仅第一帧能正常发送,后续每次传输都会因传输错误中断终止。硬件本身无问题(使用HAL驱动可正常收发数据),推测是SPI/DMA中断处理函数存在遗漏。程序重启后首次传输正常,但第一帧发送后DMA处于阻塞/锁定状态,后续请求触发传输错误。

硬件配置

  • SPI:全双工主模式,8位,Motorola格式,MSB优先,硬件NSS输出,FIFO阈值1数据
  • DMA:收发各一个通道,正常模式,数据宽度1字节,内存增量模式
  • 基础初始化及代码由Cube MX生成

代码

基础初始化(仅调用一次配置DMA)

void myDMA_init(void) {
   // DMA Basic Configuriation 
   LL_DMA_ConfigAddresses( DMA1, LL_DMA_STREAM_2, 
      LL_SPI_DMA_GetRxRegAddr(SPI2), 
      (uint32_t)RxBuffer,
      LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_2));

   LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_3,
      (uint32_t)TxBuffer,
      LL_SPI_DMA_GetTxRegAddr(SPI2),
      LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_3));
}

发送函数(主循环中周期性调用)

void SendData(void) {
   // configure RX DMA
   uint32_t rxAddr = (uint32_t)RxBuffer;
   LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_2, rxAddr);
   LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_2, DataSize);
   LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_2);
   LL_SPI_EnableDMAReq_RX(SPI2);
   // configure TX DMA
   uint32_t txAddr = (uint32_t)TxBuffer;
   LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_3, txAddr);
   LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, DataSize);
   LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3);
   LL_SPI_SetTransferSize(SPI2, DataSize);
   LL_SPI_EnableDMAReq_TX(SPI2); 
   // enable Transfer Complete and Transfer Error IT for RxDMA Stream
   LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_2);
   LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_2);
   // enable and start SPI Master Transfer
   LL_SPI_Enable(SPI2);
   LL_SPI_StartMasterTransfer(SPI2);
}

注:DataSize=10,uint8_t TxBuffer[10]和uint8_t RxBuffer[10]为全局变量,发送前会填充TxBuffer并清空RxBuffer,该函数仅首次有效,示波器可观测到传输。

中断处理函数

DMA1 Stream 2(Rx DMA)处理函数

void DMA1S2_IRQHandler(void) {
   // clear Transfer Complete and Transfer Error IRQ-Flag
   if(LL_DMA_IsActiveFlag_TC2(DMA1)) LL_DMA_ClearFlag_TC2(DMA1);
   if(LL_DMA_IsActiveFlag_TE2(DMA1)) LL_DMA_ClearFlag_TE2(DMA1);
   LL_DMA_DisableIT_TC(DMA1, LL_DMA_STREAM_2);
   LL_DMA_DisableIT_TE(DMA1, LL_DMA_STREAM_2);
   // enable SPI End of Transfer Interrupt
   LL_SPI_EnableIT_EOT(SPI2);
}

DMA1 Stream 3(Tx DMA)处理函数

void DMA1S3_IRQHandler(void) {
   // clear Transfer Complete and Transfer Error IRQ-Flag
   if(LL_DMA_IsActiveFlag_TC3(DMA1)) LL_DMA_ClearFlag_TC3(DMA1);
   if(LL_DMA_IsActiveFlag_TE3(DMA1)) LL_DMA_ClearFlag_TE3(DMA1);
   LL_DMA_DisableIT_TC(DMA1, LL_DMA_STREAM_2);
   LL_DMA_DisableIT_TE(DMA1, LL_DMA_STREAM_2);
}

SPI中断处理函数

void SPI2_myIRQHandler(void) {
   // clear the End of Transfer Interrupt Flag
   LL_SPI_ClearFlag_EOT(SPI2);
   LL_SPI_DisableIT_EOT(SPI2);
   // Disable SPI2
   LL_SPI_Disable(SPI2);
   // Disable DMA1 Stream 2 and DMA Request
   LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
   LL_SPI_DisableDMAReq_RX(SPI2);
   // Disable DMA1 Stream 3 and DMA Request
   LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3);
   LL_SPI_DisableDMAReq_TX(SPI2);
}

现象

首次运行时,DMA Rx中断触发,传输完成标志置位,无传输错误;处理函数末尾启用SPI传输结束中断,该中断随即触发。第二次及后续运行时,Rx DMA中断触发,同时置位TE和TC标志,SPI EOT中断不再触发,示波器仅能观测到一帧发送。

请问为何首次传输后DMA会立即因传输错误中止?谢谢!

备注

  • 此为测试程序,旨在简化逻辑以理解SPI DMA底层驱动工作原理
  • 此为STM论坛的重发帖(原帖被误判为垃圾帖)
  • 主循环仅包含HAL_Delay、LED闪烁、TxBuffer更新及SPI发送函数调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:24:56