DMA(直接存储器访问)核心用法(实操指南)

📅 2026/7/3 17:29:31
DMA(直接存储器访问)核心用法(实操指南)
一、DMA核心原理(极简理解)DMA(Direct Memory Access,直接存储器访问)是一种硬件机制,核心作用是:无需CPU干预,直接实现「内存与外设」「内存与内存」之间的数据传输,将CPU从繁琐的IO传输任务中解放出来,让CPU专注于核心运算,这也是提升CPU利用率的关键手段。核心优势:传输过程不占用CPU资源,仅在传输开始和结束时,通过中断通知CPU(可选),大幅减少CPU的IO等待时间。二、DMA核心用法(按场景分类,嵌入式实操为主)2.1 核心适用场景(必记)DMA仅用于「数据传输」,不执行任何运算,以下场景优先使用,效果最明显:外设→内存:如UART串口接收数据、ADC采集数据,直接传输到RAM,无需CPU逐字节读取。内存→外设:如UART串口发送数据、DAC输出数据,直接从RAM读取数据传输到外设,无需CPU干预。内存→内存:如RAM中数据复制、缓存数据搬运,适合大量数据快速传输(如数组复制)。2.2 DMA核心操作步骤(通用流程,所有场景适配)无论哪种场景,DMA使用都遵循「初始化→配置→启动→中断(可选)→关闭」的核心流程,以STM32(嵌入式最常用)为例,步骤如下:开启DMA时钟:启动DMA控制器及对应外设的时钟(如UART、ADC时钟),确保硬件正常工作。配置DMA通道:选择对应的DMA通道(不同外设对应固定DMA通道,参考芯片手册),设置通道优先级(高/中/低)。配置传输参数:设置传输方向(如外设→内存)、数据宽度(8位/16位/32位)、传输数量(需传输的字节数/数据个数)。设置源地址与目标地址:源地址:传输数据的起始地址(如外设数据寄存器地址、RAM数组起始地址),需设置为「不可变」或「可变」(根据传输需求)。目标地址:接收数据的起始地址(如RAM数组起始地址、外设数据寄存器地址),同理设置地址变化模式。开启DMA中断(可选):若需要知道传输完成状态,开启「传输完成中断」,在中断服务函数中处理后续逻辑(如标记传输完成、启动下一次传输)。启动DMA传输:开启DMA通道,开始自动数据传输,此时CPU可执行其他运算任务。传输结束处理:传输完成后,关闭DMA通道(按需),清除中断标志(若开启中断)。2.3 三大核心场景实操示例(STM32,C语言)场景1:内存→外设(UART串口DMA发送数据)需求:将RAM中数组的数据,通过UART串口DMA发送,无需CPU干预。// 1. 定义发送数据(RAM中)uint8_t send_buf[] = “DMA UART Send Test”;uint16_t send_len = sizeof(send_buf) - 1; // 排除字符串结束符// 2. DMA初始化(STM32F103,DMA1_Channel4对应USART1_TX)voidDMA_UART_Send_Init(void){// 开启时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);// DMA配置结构体DMA_InitTypeDef DMA_InitStruct;DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)USART1-DR;// 外设地址(UART数据寄存器)DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)send_buf;// 内存地址(发送数组)DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST;// 传输方向:内存→外设DMA_InitStruct.DMA_BufferSize=send_len;// 传输数量DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;// 外设地址不变DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;// 内存地址递增(逐字节发送)DMA_InitStruct