STM32F1与STM32CubeIDE快速入门DMA概述
STM32F1与STM32CubeIDE快速入门-DMA概述
DMA概述
1、什么是DMA
直接内存访问 (Direct Memory Access ,DMA) 单元是计算机体系结构中的数字逻辑元件,可与同一芯片上的主微处理器结合使用,以卸载内存传输操作。 这显着降低了 CPU 负载。 由于 DMA 控制器可以执行内存到内存的数据传输以及外围设备到内存的数据传输,反之亦然。 DMA 与 CPU 的存在可以将其吞吐量提高几个数量级。
在无 DMA 计算机体系结构中,就会发现它看起来像下图所示的样子:

正如上图所示,CPU(主处理器)必须完成从闪存获取指令(代码)、执行解码指令以及将数据移入和移出外围设备和内存的所有工作。想象一下有一个 UART1 数据接收器,它获取数据流,CPU 必须立即将数据流传输到内存中的本地缓冲区,以免丢失任何数据包。这转化为每秒由 UART、SPI、ADC 等不同外设触发的疯狂数量的中断。 CPU 必须处理所有事情并浪费越来越多的时间。
将上下文切换到中断处理程序和从中断处理程序切换上下文会占用一些完全浪费的周期,并且随着中断信号的持续触发而定期发生,这一事实在一定程度上使这种架构存在问题。拥有 10kB/s 的数据流可能会使没有 DMA 的 CPU 变得如此繁忙并错过应用程序的时序约束。 CPU 可以被看作是被抑制了,为了释放它的全部工作能力,这个数据传输任务必须移交给另一个单元,DMA 单元在这里从 CPU 卸载这些消耗殆尽的数据事务。

从上图可以看到的,DMA 单元的存在现在可以将来自 UART 外设的数据流直接发送到内存,而 CPU 则在做其他事情和计算。 CPU 和 DMA 之间的这种并行协作是加速的来源。
DMA 单元的存在有时会带来一些问题。 例如,在具有 CPU 缓存的架构中,当 DMA 单元访问数据存储器并写入也在缓存中镜像的位置时,这将使缓存中的数据无效。 这是一个需要克服的挑战,除了有利之外,DMA 还会引入一些问题。
2、STM32中的DMA硬件
在STM32F1xxk,直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU 任何干预,通过DMA 数据可以快速地移动。这就节省了CPU 的资源来做其他操作。
DMA 控制器有7 个通道,每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA 请求的优先权。

DMA 控制器和Cortex-M3 核共享系统数据总线执行直接存储器数据传输。当CPU 和DMA 同时访问相同的目标(RAM 或外设)时,DMA 请求可能会停止CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU 至少可以得到一半的系统总线(RAM 或外设)带宽。
DMA的主要特点如下:
- 12 个可独立配置的通道(请求):7 个用于 DMA1,5 个用于 DMA2
- 12 个通道中的每一个都连接到专用硬件 DMA 请求、软件每个通道也支持触发器。此配置由软件完成。
- 来自一个 DMA 通道的请求之间的优先级是软件可编程的(4级别由非常高、高、中、低)或硬件组成(在相等的情况下)(请求 1 优先于请求 2 等)
- 独立的源和目标传输大小(字节、半字、字),模拟包装和拆包。源/目标地址必须在数据上对齐尺寸。
- 支持循环缓冲区管理
- 3 个事件标志(DMA 半传输、DMA 传输完成和 DMA 传输错误)在每个通道的单个中断请求中进行逻辑或运算
- 内存到内存的传输
- 外设到内存和内存到外设,以及外设到外设转移
- 访问作为源和目标的闪存、SRAM、APB1、APB2 和 AHB 外设
- 要传输的可编程数据数量:最多 65536
1)DMA数据传输
发生一个事件后,外设向 DMA 控制器发送请求信号。 DMA 控制器根据通道优先级处理请求。 一旦 DMA 控制器访问外设,DMA 控制器就会向外设发送确认。 外设在收到来自 DMA 控制器的确认后立即释放其请求。 一旦请求被外设取消断言,DMA 控制器就会释放确认。 如果有更多请求,外设可以发起下一个事务。
每次 DMA 传输包含三个操作:
- 从外设数据寄存器或通过内部当前外设/内存地址寄存器寻址的内存位置加载数据。 用于第一次传输的起始地址是在 DMA_CPARx 或 DMA_CMARx 寄存器中编程的基本外设/存储器地址
- 加载到外设数据寄存器或通过内部当前外设/内存地址寄存器寻址的内存位置的数据的存储。 用于第一次传输的起始地址是在 DMA_CPARx 或 DMA_CMARx 寄存器中编程的基本外设/存储器地址
- DMA_CNDTRx 寄存器的后递减,其中包含仍需执行的事务数
2)DMA仲裁器
仲裁器根据优先级管理通道请求并启动外设/存储器访问序列。 优先级分两个阶段进行管理:
- 软件:可以在 DMA_CCRx 寄存器中配置每个通道的优先级。 有四个级别:
- 非常高的优先级
- 高优先级
- 中等优先
- 低优先级
- 硬件:如果 2 个请求具有相同的软件优先级,则编号最低的通道将优先于编号最高的通道。 例如,通道 2 的优先级高于通道 4
3)DMA 通道
每个通道都可以处理位于固定地址的外设寄存器和内存地址之间的 DMA 传输。 要传输的数据量(最多 65535)是可编程的。 包含要传输的数据项数量的寄存器在每次交易后递减。
外设和存储器的传输数据大小可通过 DMA_CCRx 寄存器中的 PSIZE 和 MSIZE 位完全编程。
根据 DMA_CCRx 寄存器中的 PINC 和 MINC 位,外设和存储器指针可以选择在每次事务后自动后递增。 如果启用了递增模式,下一次传输的地址将是前一次传输的地址,根据所选数据大小加 1、2 或 4。
4)DMA 循环模式
循环模式可用于处理循环缓冲区和连续数据流(例如 ADC 扫描模式)。 可以使用 DMA_CCRx 寄存器中的 CIRC 位启用此功能。 当循环模式被激活时,要传输的数据数量会自动重新加载为通道配置阶段编程的初始值,并继续服务 DMA 请求。
5)DMA 内存到内存模式
DMA 通道也可以在不被外设请求触发的情况下工作。 这种模式称为内存到内存模式。 Memory to Memory 模式不能与循环模式同时使用。
6)DMA 中断
对于每个 DMA 通道,可以在半传输、传输完成或传输错误时产生中断。 单独的中断使能位提供了灵活性。
7)DMA 请求映射
通过对相应外设寄存器中的 DMA 控制位进行编程,可以独立激活/取消激活外设 DMA 请求。

8)DMA 配置
应遵循以下序列来配置 DMA CHANNELx(其中 x 是通道编号)。
- 在 DMA_CPARx 寄存器中设置外设寄存器地址。 在外设事件之后,数据将从/到这个地址移到/从存储器移出。
- 在 DMA_CMARx 寄存器中设置存储器地址。 数据将在外设事件后写入或读取此存储器。
- 在 DMA_CNDTRx 寄存器中配置要传输的数据总数。 每个外设事件后,该值将递减。
- 使用 DMA_CCRx 寄存器中的 PL[1:0] 位配置通道优先级
- 在 DMA_CCRx 寄存器中配置数据传输方向、循环模式、外设和存储器递增模式、外设和存储器数据大小以及半传输和/或全传输后的中断
- 通过设置 DMA_CCRx 寄存器中的 ENABLE 位来激活通道。
一旦通道被启用,它就可以处理来自连接在通道上的外设的任何 DMA 请求。 一旦传输了一半的字节,半传输标志(HTIF)就会置位,如果半传输中断使能位(HTIE)被置位,就会产生一个中断。 传输结束时,传输完成标志(TCIF)置位,如果传输完成中断允许位(TCIE)置位,则产生中断。
9)HAL中的DMA使用
- 启用并配置要连接到 DMA 通道的外设(内部 SRAM/FLASH 存储器除外:无需初始化)。 有关外设和 DMA 请求之间的连接,请参阅参考手册。
- 对于给定的通道,通过以下参数对所需的配置进行编程:通道请求、传输方向、源和目标数据格式、循环或正常模式、通道优先级、使用
HAL_DMA_Init()函数的源和目标增量模式。 - 使用
HAL_DMA_GetState()函数返回 DMA 状态和HAL_DMA_GetError()在错误检测的情况下。 - 使用
HAL_DMA_Abort()函数中止当前传输
注意:在 Memory-to-Memory 传输模式下,不允许 Circular 模式
轮询方式IO操作
- 配置源地址和目的地址以及要传输的数据长度后,使用
HAL_DMA_Start()开始DMA传输 - 使用
HAL_DMA_PollForTransfer()轮询当前传输的结束,在这种情况下,用户可以根据其应用程序配置固定超时。
中断模式IO操作
- 使用
HAL_NVIC_SetPriority()配置 DMA 中断优先级 - 使用
HAL_NVIC_EnableIRQ()启用 DMA IRQ 处理程序 - 配置源地址和目的地址以及要传输的数据长度后,使用
HAL_DMA_Start_IT()开始DMA 传输。 在这种情况下,DMA中断被配置 - 使用在
DMA_IRQHandler()中断子程序下调用的HAL_DMA_IRQHandler() - 在数据传输结束时执行
HAL_DMA_IRQHandler()函数,用户可以通过自定义函数指针XferCpltCallback和XferErrorCallback(即 DMA 句柄结构的成员)来添加自己的函数。
文章来源: https://iotsmart.blog.csdn.net/article/details/123404017