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
相关产品推荐
相关产品推荐

