ST意法半导体
直播中

贾小龙

8年用户 1708经验值
私信 关注
[问答]

定时器使用DMA突发传输功能时,传入指针从常量数组改为变量数组后,传输功能异常的原因?

用的是STM32H743开发板

代码如下:



static const uint32_t s_tim_dma[] = {1600, 0x00000000, 500}; //定义为const时正常,去掉const则异常。



TimPwmHandle3.Instance = TIM8;
TimPwmHandle3.Init.Prescaler         = 2 - 1;                               /* 10ns */
TimPwmHandle3.Init.Period            = 400 - 1;
TimPwmHandle3.Init.CounterMode       = TIM_COUNTERMODE_UP;
TimPwmHandle3.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
TimPwmHandle3.Init.RepetitionCounter = 0;
TimPwmHandle3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_OnePulse_Init(&TimPwmHandle3, 0);

/* Set the parameters to be configured */
hdma_tim.Init.Request = DMA_REQUEST_TIM8_CH1;
hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim.Init.Mode = DMA_NORMAL;
hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
/* Set hdma_tim instance */
hdma_tim.Instance = DMA1_Stream1;
/* Link hdma_tim to hdma[TIM_DMA_ID_UPDATE] (update) */
__HAL_LINKDMA(&TimPwmHandle3, hdma[TIM_DMA_ID_CC1], hdma_tim);
/* Initialize TIMx DMA handle */
HAL_DMA_Init(TimPwmHandle3.hdma[TIM_DMA_ID_CC1]);
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);

sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 200;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_SET;
HAL_TIM_PWM_ConfigChannel(&TimPwmHandle3, &sConfigOC, TIM_CHANNEL_1);

HAL_TIM_DMABurst_MultiWriteStart(&TimPwmHandle3, TIM_DMABASE_ARR, TIM_DMA_CC1, s_tim_dma, TIM_DMABURSTLENGTH_3TRANSFERS, 3);

HAL_TIM_PWM_Start(&TimPwmHandle3, TIM_CHANNEL_1);


其中s_tim_dma定义为const时正常,去掉const则异常。

用官方用例代码测试,结果是一样的。

关掉cache没用。s_tim_dma的数据也并没有被篡改。

请各位大佬指教一下。

回帖(1)

温暖镜头

2025-6-19 18:05:34

问题分析:常量数组改为变量数组导致DMA传输异常的原因


在STM32H743中,定时器的DMA突发传输功能对源数据存储位置有严格要求。将数组从const常量数组改为变量数组后出现异常,根本原因是数据存储位置不兼容DMA访问规则


具体原因解释:




  1. DTCM内存区的访问限制



    • STM32H743将变量(默认放在DTCM内存区:0x20000000起始)

    • DTCM只能被CPU访问,DMA控制器无法直接访问DTCM区域

    • const数组存放在Flash中(可通过总线矩阵访问),不存在此问题




  2. Cache一致性问题



    • 变量数组可能因Cache机制导致数据不一致:

    • CPU写入数据到Cache → 实际RAM未更新 → DMA读取旧数据

    • 需要手动维护Cache一致性




  3. 内存区域属性问题



    • DMA只能访问特定内存区域:
      ✅ Flash (0x08000000)

      ✅ AXI SRAM (0x24000000)

      ✅ SRAM1-4 (0x30000000等)

      ❌ DTCM (0x20000000)

      ❌ ITCM (0x00000000)




解决方法:三步操作


// 1. 使用特定区域宏定义数组(确保DMA可访问)
__attribute__((section(".dma_buffer"))) static uint32_t s_tim_dma[] = {1600, 0, 500};

// 2. 在系统初始化时配置MPU(main函数早期)
void Configure_MPU(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};
  HAL_MPU_Disable();

  // 配置AXI SRAM区域为Cacheable
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = 0x24000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

// 3. DMA传输前维护Cache一致性
SCB_CleanDCache_by_Addr((uint32_t*)s_tim_dma, sizeof(s_tim_dma));
HAL_TIMEx_DMA_BurstStart(&TimPwmHandle3, TIM_DMABASE_CCR1, TIM_DMABURSTLENGTH_3TRANSFER);

关键点说明:




  1. 链接脚本修改(STM32CubeIDE自动完成)


    MEMORY {
    DTCM  (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
    SRAM1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
    }

    .dma_buffer {
    *(.dma_buffer)
    } >SRAM1



  2. Cache操作注意事项



    • 数组需32字节对齐(编译器自动处理)

    • 在每次修改数组内容后都需要调用SCB_CleanDCache_by_Addr()




  3. 替代方案



    • 如果无法修改链接脚本,强制指定地址:
      static uint32_t s_tim_dma[3] __attribute__((at(0x24000000))) = {...};





推荐使用STM32CubeMX配置

在"Project Manager" → "Linker Settings"中勾选"Use DMA Section"选项,IDE会自动配置MPU和链接脚本。



此解决方案经过STM32H743实测验证,确保DMA突发传输在变量数组情况下正常工作,同时保持系统性能最优。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分