通俗版:DMA是什么?基于STM32如何用?(嵌入式)

目录

1、DMA的定义是什么

2、为什么可以高效传输?

 3、何时使用DMA?

4、DMA控制器框图​

4.1通道选择

4.2仲裁器

4.3其他

5、DMA配置


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博客

【STM32】DMA基本原理、寄存器、库函数(DMA一般步骤)_stm32 dma工作原理-CSDN博客

【11】STM32·HAL库·DMA_hal库dma-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值