DMA + TIM 触发异常?别只怪时钟,看看 Update 与 TRGO
摘要:TIM 触发 DMA 搬运 ADC 数据,示波器看 ADC 在采样,但 DMA 缓冲区数据错位?不是 DMA 配置错了,而是 TIM 的Update Event 与TRGO 信号没对齐。本文解析 TIM 触发 DMA 的“隐形条件”。
一、问题描述(现象)
**TIM 配置 1kHz 触发 ADC;
DMA 配置 Circular 模式搬运;
运行一段时间后,ADC 数据在缓冲区里错位、重复或丢失。**
很多工程师的排查方向是:
DMA Burst 长度不对?
内存地址没对齐?
ADC 采样时间太短?
二、原理分析
1. 物理模型
TIM 触发 DMA 的信号链:
TIM Counter -> Update Event (UEV) -> TRGO (Trigger Output) -> DMA Request -> DMA Transfer2. 核心参数
UEV (Update Event):计数器溢出/下溢时产生的事件。
TRGO (Trigger Output):TIM 输出给其他外设的信号。
DMA Request:DMA 控制器接收到的请求源。
3. 反直觉真相
“Update Interrupt Enable” 不等于 “DMA Trigger”。
你开启了
TIM_IT_UPDATE,只能进中断。你没配置
TRGO = Update,DMA 永远收不到触发信号。结果:DMA 靠“猜”或者靠“相邻通道的副作用”在跑,迟早错位。
三、工程级解决方案
方案 1:明确配置 TRGO(最关键)
必须显式指定 TIM 的触发输出。
// STM32 HAL 示例 htim1.Init.RepetitionCounter = 0; HAL_TIM_Base_Init(&htim1); // 关键:选择 Update 作为 TRGO __HAL_TIM_SET_TRGO(&htim1, TIM_TRGO_UPDATE);方案 2:DMA 与 TIM 的同步点
DMA 传输发生在UEV 之后,不是 CNT=0 的瞬间。
正确时序:
CNT 计数到 ARR。
产生 UEV。
触发 DMA。
DMA 读取 ADC->DR。
错误理解:
认为 DMA 在 CNT=0 时触发 → 采样窗口未结束,数据未稳定。
方案 3:防止“鬼触发”
如果使用 TIM 的One Pulse Mode:
DMA 只会触发一次。
必须手动重启 TIM,或改用 Continuous 模式。
四、选型避坑建议
TRGO 源的选择:
TIM_TRGO_UPDATE:最常用,适合周期性采样。TIM_TRGO_OC1:适合相位可控的触发。
DMA Stream 优先级:
TIM 触发的 DMA 建议设为Very High,防止被 SPI/UART 抢占导致错位。
双缓冲(Double Buffer):
高频采样(> 100kHz)强烈建议开启 DMA 双缓冲。
五、总结 Checklist
[ ] 是否配置了
TIM_TRGO_UPDATE?[ ] DMA 请求是否映射到了正确的 TIM 触发源?
[ ] 是否在 Circular 模式下验证了长时间运行的稳定性?
[ ] ADC 采样时间是否足够在 TIM 周期内完成?
六、写在最后(关注我,少走弯路)
我是 gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。
TIM + DMA + ADC 是嵌入式里“铁三角”级别的联动,任何一个环节没对齐,数据就全乱。
关注我的专栏《嵌入式底层避坑指南》,下一篇我们将深入解析《编码器模式转得乱七八糟?别只怪电机,看看 TI1/TI2 极性》。
👉下一篇预告:《编码器计数忽多忽少?别只怪码盘,看看 TIM 的输入滤波与极性》
原创文章,转载请注明出处。
