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

STM32F429ZI调整PWM频率时DMA读取GPIO出现数据丢失问题咨询

问题描述

示例波形图
我首次接触DMA开发,目前遇到DMA读取过程中变更PWM信号频率时发生数据丢失的问题。DMA请求由16MHz时钟触发,硬件平台为STM32F429ZI,使用DMA2控制器。

DMA方向配置为外设到内存,目标是读取整个GPIOE端口数据传输到内存。调整PWM频率时,DMA读取起始阶段会出现明显数据丢失;若注释掉PWM频率调整相关代码(见下方代码片段),DMA读取无可见数据丢失。

从附图可见,上方波形的正弦波存在数据点丢失(每周期应采样4个点),下方波形无数据丢失。

我认知中DMA应独立于CPU运行,不受CPU操作影响,但当前现象与之不符。请问该问题是否由工作时钟频率过高导致?还是我遗漏了其他配置要点?

相关代码片段

/*------------------- Comment out when not changing PWM frequency --------------------------------------------------------------------*/
//  /* Start 40 MHz */
//  TIM3->CCR1 = 1; // 40 MHz
/*------------------------------------------------------------------------------------------------------------------------------------*/

/* Start DMA for ping signal with length BUFFER_SIZE (PA9 (channel 2) is clockout+ of ADC, sampling on falling edge of PA9) */

if (HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC2], (uint32_t)&(GPIOF->IDR), (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
{
 /* Transfer Error */
 Error_Handler();
}

/*------------------- Comment out when not changing PWM frequency --------------------------------------------------------------------*/
//  /* Continue while timer is lower than 1,3 us */
//  while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 13)
//  {
//  }
//  /* Start ping, 4 MHz */
//  TIM3->ARR = 20; // period
//  TIM3->CCR1 = 9;  // pulse
//  timer_val1 = __HAL_TIM_GET_COUNTER(&htim5);
//  while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 9) // 5 pulses
//  {
//  }
//
//  TIM3->ARR = 1;  // 40Mhz
//  TIM3->CCR1 = 1;
//  while (__HAL_TIM_GET_COUNTER(&htim5) - timer_val1 < 25)
//  {
//  }

/*------------------------------------------------------------------------------------------------------------------------------------*/

问题根因&解决方案

DMA独立于CPU运行是对的,但STM32F4架构下有几个容易忽略的特性,就是这些点导致了数据丢失:

  • 总线仲裁优先级问题:STM32F4的总线矩阵默认CPU的访问优先级高于DMA,你在DMA启动后连续修改TIM3寄存器、循环读TIM5计数器的操作都会占用AHB1总线带宽,16MHz的DMA触发频率很高,刚好赶上总线被CPU占用时,边沿触发的DMA请求就会被直接丢弃。
  • 定时器寄存器修改时序错误:你没有开启TIM3的ARR和CCR预装载功能,直接修改寄存器会导致当前PWM周期输出异常,要么多产生触发沿要么漏触发沿,直接影响DMA采样的点数。
  • 操作顺序不合理:你在DMA启动后还在做PWM频率调整和空转等待,DMA启动后已经在等待触发信号,这段时间的时序异常都会直接体现在采样结果里。

修复步骤:

  1. 调整操作顺序:如果不需要在DMA传输过程中调整PWM频率,把所有PWM参数配置的代码全部移到HAL_DMA_Start_IT调用之前,DMA传输过程中不要操作定时器相关寄存器。如果必须动态调整频率,要等单次DMA传输完成中断触发后再改参数。
  2. 开启定时器预装载功能:TIM3初始化的时候打开ARR和CCR的预装载位,让寄存器修改只会在定时器更新事件生效,避免中途改值产生异常波形:
TIM3->CR1 |= TIM_CR1_ARPE; // 开启ARR预装载
TIM3->CCMR1 |= TIM_CCMR1_OC1PE; // 开启通道1 CCR预装载
  1. 提高DMA总线优先级:初始化DMA的时候把对应stream的优先级提到最高,避免CPU抢占总线:
hdma_tim1_cc2.Init.Priority = DMA_PRIORITY_VERY_HIGH;
  1. 优化GPIO配置:把GPIOE的OSPEEDR寄存器配置为100MHz高速模式,避免高速采样时输入同步延迟导致的采样错误。

按照上面的步骤调整后,数据丢失的问题基本可以解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:15:05