
1、前言 某客户发现修改代码后,STM32U59 SPI DMA 发送未产生传输完成中断,但修改的代码跟 SPI 以及 DMA 毫无关联。 2、调研 回退代码修改后问题消失,可以确认硬件正常。检查 SPI 发送对应的 DMA 句柄的 ErrorCode,发现 HAL_DMA_ERROR_DTE(Date Transfer Error)置位。尝试修改软件,发现调整下某个全局变量初值,或屏蔽某些变量,都能解决问题。 为屏蔽 RTOS 及应用代码可能带来的影响,调整客户 SPI 和 DMA 初始化代码位置到紧跟 MCU 复位后配置时钟,初始化全局变量,并在初始化完成后立即发送一包数据,测试下来问题仍存在,说明问题和后续 RTOS 及应用代码代码无关。 为澄清全局变量初始化对 SPI 和 DMA 的影响,在全局变量初始化完成、初始化 SPI 和 DMA 前、后,分别检查 RCC、SPI 和 DMA 寄存器,和正常时对比无差异。 3、分析 客户使用的是 GPDMA 的 Linked List 模式,此模式下 DMA 传输相关的 8 个寄存器不通过软件直接设置,而是需要软件把待设定的寄存器参数先放入缓冲区,再将缓冲区地址赋到 DMA 寄存器 CxLBAR(高 16 位)和 CxLLR(低 16 位),使能 DMA 时硬件自动将这些参数加载到 DMA 通道对应的寄存器中。 跟踪代码执行,在 DMA 使能前,查看参数缓冲区(地址:0x2001 FFF0)。确认 DMA 参数缓冲区中源地址寄存器参数 0x200 e0618、目标地址寄存器参数 0x4001 3020都是正确的;使能 DMA 后,发现 DMA CxDAR 寄存器数据异常 0x1382 932e。 ![]() ![]() 查阅参考手册,找到其对对缓冲区限制的描述:必须 4 字节对齐,且不能跨 64Kbyte边界;而用户的缓冲区地址 0x2001 FFF0(32 字节)刚好跨了 64Kbyte 边界。链接器分配的地址范围是 0x2001 FFF0 ~ 0x2002 0010,而 GPDMA 实际访问的数据区间是0x2001 FFF0 ~ 0x2001 FFFF 和 0x20010000 ~ 0x2001000F,把 2001 0000 对应的数据加载到了 DAR 中,随即引发了 DTE 错误。 ![]() 4、处理 处由于增减全局变量、修改变量初值为零或非零,都会影响最终链接结果,故通过设置预编译选项对所有 DMA 链表数据结构变量的地址作出限制,来满足 4 字节对齐且不跨64K Byte 边界这个约束条件,再次编译链接后进行测试,SPI DMA 功能恢复正常。 5、小结 对这种看似怪异的问题,需要仔细观察并记录整个数据传输过程,各个关键操作前后相关寄存器的变化来获取第一手资料,对比正常情况并结合参考手册寻找具体原因。 |
经验分享 | STM32 DAC+TIMER+DMA应用演示
经验分享 | 为何实现不了定时器DMA Burst传输?
经验分享|STM32 DMA编程时的一个应用小提醒
【STM32U3评测】SPIDMA发送
实战经验 | TrustZone应用中串口通信的DMA传输失败问题
狂欢三】STM32C031使用TIM定时器DMA方式实现WS2812彩灯输出(三)
stm32使用定时器触发dma传输,启动dma没反应的几种情况的解决方法
STM32的DMA双缓冲模式详解
基于STM32的心率计以DMA方式获取传感器数据经验分享
基于STM32利用ADC+DMA采样显示经验分享