当前位置:首页 > 嵌入式 > 嵌入式分享
[导读]在嵌入式系统开发中,DMA(直接内存访问)控制器作为硬件加速的核心模块,通过独立于CPU的数据搬运能力显著提升系统性能。以STM32H7系列为例,其双DMA控制器(各含8通道)可实现高达480MHz总线频率下的数据传输,本文将系统解析DMA寄存器配置的全流程。


在嵌入式系统开发中,DMA(直接内存访问)控制器作为硬件加速的核心模块,通过独立于CPU的数据搬运能力显著提升系统性能。以STM32H7系列为例,其双DMA控制器(各含8通道)可实现高达480MHz总线频率下的数据传输,本文将系统解析DMA寄存器配置的全流程。


一、硬件架构与初始化

DMA控制器由地址总线、数据总线和控制寄存器构成,其初始化需完成三步操作:


时钟使能

通过RCC(复位和时钟控制)寄存器激活DMA时钟:

c

__HAL_RCC_DMA1_CLK_ENABLE();  // 启用DMA1时钟

HAL_Delay(1);                 // 等待时钟稳定

通道复位

清除通道历史配置,避免残留状态干扰:

c

DMA_HandleTypeDef hdma;

hdma.Instance = DMA1_Stream0;  // 选择DMA1的Stream0

HAL_DMA_DeInit(&hdma);         // 复位通道

优先级仲裁

通过仲裁器寄存器设置通道优先级(软件阶段),STM32H7支持四级优先级(VERY_HIGH/HIGH/MEDIUM/LOW):

c

hdma.Init.Priority = DMA_PRIORITY_HIGH;  // 设置高优先级

二、核心传输参数配置

传输规则通过六组关键寄存器定义:


方向与地址模式

c

hdma.Init.Direction = DMA_MEMORY_TO_PERIPH;  // 内存→外设

hdma.Init.PeriphInc = DMA_PINC_DISABLE;       // 外设地址固定

hdma.Init.MemInc = DMA_MINC_ENABLE;           // 内存地址自增

数据对齐与突发传输

c

hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;  // 外设32位

hdma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;      // 内存32位

hdma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;             // 启用FIFO

hdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;    // 满阈值触发

传输模式与中断

c

hdma.Init.Mode = DMA_CIRCULAR;  // 循环模式(持续传输)

__HAL_DMA_ENABLE_IT(&hdma, DMA_IT_TC);  // 启用传输完成中断

三、地址与数据量配置

绑定外设与内存地址

c

hdma.Init.PeriphBaseAddr = (uint32_t)&SPI4->DR;  // SPI4数据寄存器

hdma.Init.Mem0BaseAddr = (uint32_t)display_buffer; // 显示缓冲区

设置传输数据量

c

#define BUFFER_SIZE 1024  // 1024个32位数据

hdma.Init.NDTR = BUFFER_SIZE;  // 数据项数量

四、外设请求绑定与启动

关联DMA请求源

通过DMAMUX(DMA请求多路复用器)绑定外设:

c

HAL_DMAEx_ConfigMuxRequest(&hdma, DMA_REQUEST_SPI4_TX);  // 绑定SPI4发送请求

初始化与启动

c

HAL_DMA_Init(&hdma);                     // 初始化DMA

__HAL_LINKDMA(&hspi4, hdmatx, hdma);      // 关联SPI与DMA

HAL_SPI_Start_DMA(&hspi4, display_buffer, BUFFER_SIZE);  // 启动SPI+DMA

五、中断处理与状态监控

中断服务例程

c

void DMA1_Stream0_IRQHandler(void) {

 HAL_DMA_IRQHandler(&hdma);  // 调用HAL库处理中断

}

传输状态查询

c

if (HAL_DMA_GetState(&hdma) == HAL_DMA_STATE_BUSY) {

 uint32_t remaining = __HAL_DMA_GET_COUNTER(&hdma);  // 剩余数据量

 printf("Remaining: %lu\n", remaining);

}

六、性能优化实践

地址对齐优化

确保内存缓冲区地址为4字节对齐(如__attribute__((aligned(4)))),避免总线错误。

突发传输配置

设置FIFOThreshold为DMA_FIFO_THRESHOLD_1QUARTERFULL,当FIFO积累4个数据时触发传输,减少总线占用。

双缓冲机制

通过交替使用两个缓冲区实现无缝传输,避免屏幕撕裂:

c

HAL_SPI_Start_DMA(&hspi4, buffer1, BUFFER_SIZE);  // 启动第一缓冲区

// 在中断中切换缓冲区

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {

 static uint8_t toggle = 0;

 toggle ^= 1;

 HAL_SPI_Start_DMA(hspi, toggle ? buffer2 : buffer1, BUFFER_SIZE);

}

七、典型应用场景

在STM32H7驱动ST7789V显示屏的案例中,DMA实现每秒60帧的240x320像素刷新,CPU占用率从45%降至8%。关键配置包括:


使用TCM RAM存储显示缓冲区,减少总线竞争

启用SPI TX FIFO(32字节深度)缓冲数据

配置DMA突发传输为4字节(INCR4)

通过系统化的寄存器配置与优化策略,DMA控制器可成为嵌入式系统性能提升的核心引擎,为实时数据处理、高速通信等场景提供硬件级加速支持。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读
关闭