ST意法半导体
直播中

大彭

11年用户 1133经验值
擅长:电源/新能源 嵌入式技术
私信 关注
[问答]

STM32H743定时器使用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-17 18:05:34

问题分析


当将 s_tim_dma 数组从 const 常量改为普通变量数组时,DMA 突发传输功能异常的根本原因是:变量数组被存储在 DMA 无法访问的内存区域(如 DTCM)或缓存(Cache)一致性未正确处理


具体原因与解决方案


1. 内存区域问题(DTCM 不可被 DMA 访问)



  • 原因

    • const 数组存储在 Flash 中(默认可被 DMA 访问)。

    • 变量数组可能被编译器分配到 DTCM(0x2000_0000 起始),而 DTCM 仅供 CPU 内核高速访问,DMA 无法通过总线矩阵访问 DTCM


  • 验证方法
    打印数组地址:
     printf("Array address: 0x%pn", s_tim_dma);


    • 若地址在 0x2000_0000–0x2001_FFFF → 位于 DTCM(问题所在)。


  • 解决方案

    • 显式指定数组存储区域(如 AXI SRAM)
      __attribute__((section(".dma_buffer"))) uint32_t s_tim_dma[] = {1600, 0, 500};

      在链接脚本(*.ld)中创建段并映射到 AXI SRAM:


      .dma_buffer :
      {
      *(.dma_buffer)
      } > RAM_D1  /* 0x24000000 (AXI SRAM) */



2. 缓存(Cache)一致性问题



  • 原因

    • STM32H7 的 SRAM 区域(如 AXI SRAM)支持 Cache

    • CPU 写入变量数组后数据可能留在 Cache 中,DMA 直接从内存读取时获取旧数据(未更新)。


  • 解决方案

    • 启动 DMA 前清理 Cache
      #include "stm32h7xx_hal.h"
      SCB_CleanDCache_by_Addr((uint32_t*)s_tim_dma, sizeof(s_tim_dma));


      • 关键点:地址必须按 32 字节对齐,数组大小需是 32 字节倍数(不足则填充)。




3. 地址对齐和突发传输要求



  • 要求

    • DMA 突发传输需要 32 位对齐的地址(最低两位为 0b00)。

    • 数组大小需匹配 DMA 传输宽度(如 32 位)。


  • 验证方法
     if ((uint32_t)s_tim_dma & 0x3) {
         printf("Unaligned address!n");
    }

  • 解决方案

    • 使用对齐宏定义:
      __ALIGNED(4) uint32_t s_tim_dma[] = {1600, 0, 500};



完整修复代码示例


#include "stm32h7xx_hal.h"

// 指定存储区域 + 对齐 + Cache处理
__attribute__((section(".dma_buffer"))) __ALIGNED(4) uint32_t s_tim_dma[] = {1600, 0, 500};

void Start_DMA_Transfer(void) {
    // 1. 清理Cache确保数据写入物理内存
    SCB_CleanDCache_by_Addr((uint32_t*)s_tim_dma, sizeof(s_tim_dma));

    // 2. 配置并启动DMA
    HAL_DMA_Start_IT(&hdma_tim, (uint32_t)s_tim_dma, (uint32_t)&TIM8->DMAR, 3);
}

其他排查建议



  1. 检查链接脚本

    • 确保 .dma_buffer 或类似的自定义段映射到 DMA 可访问内存(如 RAM_D1/AXI SRAM)。


  2. 关闭 Cache(调试用)

    • main() 中临时禁用 Cache 测试:
      SCB_DisableDCache();


  3. 确认 DMA 配置

    • 检查外设地址 TIM8->DMAR 是否正确。

    • 验证传输长度和数据宽度(需匹配数组)。



总结























问题原因 解决方案
数组位于 DTCM(DMA 不可访问) 重定位到 AXI/SRAM(使用 section 属性)
Cache 未更新到内存 启动 DMA 前调用 SCB_CleanDCache_by_Addr
地址未对齐 使用 __ALIGNED(4) 确保 32 位对齐

通过上述方法,即可解决 DMA 传输异常问题,并保证变量数组的正常传输。

举报

更多回帖

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