目录
1、DMA的定义是什么
DMA(Direct Memory Access,直接存储区访问),目的是:为实现数据在外设寄存器与存储器之间 或者 存储器到存储器之间高速传输,提供了一种高效传输的方法。
2、为什么可以高效传输?
DMA传输实现高速数据传输的过程不需要经过CPU的操作,从硬件层面来说,DMA控制器是独立于Cortex-M4内核的。
3、何时使用DMA?
当有下列需求时,即可考虑使用DMA:
(1)数据高速传输:需要快速传输大量数据,比如音视频,高速传感器
(2)实时性要求:确保数据传输不占用CPU的时间,让CPU处理其他实时性任务
(3)提高CPU效率:DMA可以帮助CPU减少数据传输的开销
4、DMA控制器框图
4.1通道选择
外设通道选择主要决定,哪个外设作为数据流的源地址或者目标地址。具体可以根据芯片型号,查看DMA请求映射表
4.2仲裁器
仲裁器对8个DMA数据流的传输请求优先级进行管理
每个数据流优先级在DMA_SxCR(x=0~7)寄存器中配置,分为:很高,高,中,低四个档次的
4.3其他
剩下还有FIFO、存储器端口、外设端口、编程端口
5、DMA配置
下列通过基于STM32 (hal库)配置DMA(ADC、USART)两个代码实例介绍
static void MX_DMA_Init(void) {
// 使能DMA1时钟,以便可以使用DMA1的通道和流
__HAL_RCC_DMA1_CLK_ENABLE();
// 配置USART1的DMA接收通道(DMA1流1)
hdma_usart1_rx.Instance = DMA1_Stream1;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
// DMA通道4对应USART1
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
// 数据传输方向:外设到内存
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
// 外设地址不增量
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
// 内存地址增量
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
// 外设数据对齐方式:字节(1字节) 对齐
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
// 内存数据对齐方式:字节(1个字节)对齐
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
// DMA模式:循环模式(即DMA传输完成后自动重新开始)
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
// DMA优先级:低
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
// 禁用FIFO模式
HAL_DMA_Init(&hdma_usart1_rx);
// 初始化DMA
// 配置DMA流(ADC1)
hdma_adc1.Instance = DMA2_Stream0;
// 选择DMA流为DMA2 Stream0。
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
// 选择DMA通道为通道0。
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
// 设置DMA传输方向为从外设到内存
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
// 禁用外设地址递增。在此配置中,外设地址(ADC的寄存器地址)在传输期间不递增,因为ADC地址是固定的。
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
// 启用内存地址递增。DMA传输将会把数据写入内存缓冲区中的不同位置,每次传输后内存地址递增,以便将多个数据值写入连续的内存地址。
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
// 设置外设数据对齐方式为字(4字节)。这表示ADC数据是以32位(4字节)对齐的,适用于32位宽的数据传输。
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
// 设置内存数据对齐方式为字(4字节)。这意味着在内存中存储的数据也是以32位(4字节)对齐的,以确保数据的一致性和高效传输。
hdma_adc1.Init.Mode = DMA_CIRCULAR;
// 循环模式,,DMA会在传输完成后自动重新开始,适用于需要持续数据流的场景,如实时数据采集。
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
//设置DMA流的优先级为高。DMA的优先级决定了在多个DMA请求同时发生时,该流处理请求的优先顺序。
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
// 关闭FIFO,FIFO(先进先出)模式用于缓存数据以提高传输效率,但在此配置中,我们禁用了FIFO模式,直接进行数据传输。
HAL_DMA_Init(&hdma_adc1);
// 调用HAL库函数初始化DMA流。`HAL_DMA_Init`函数将根据上面的配置初始化DMA硬件,使其能够正确地进行数据传输。
__HAL_LINKDMA(&huart1, hdmatx, hdma_usart1_tx);
// 将DMA发送通道与USART1绑定
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
// 连接DMA与ADC
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
// 配置DMA中断
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
// 配置DMA中断
}
参考以下内容:
STM32F4和STM32F1的串口DMA区别_f1和f4串口一样吗-CSDN博客
【DMA】DMA外设讲解-STM32_dma控制器和dma外设-CSDN博客