十九、DMA 原理介绍
DMA 基础知识
数据传输方式
一般情况下实现存储器和外设之间的数据传输,有三种常用的方法:轮询法(polling),中断法(interrupt)以及 DMA。
轮询法(polling): 在主循环中,CPU 不断检查外设的相关标志位,来判断其是否需要进行数据的传输,如果需要,则 CPU 将数据在外设和内存之间搬运,实现数据传输。当数据传输服务请求频繁或者传输的数据量很大时,会影响其他任务的实时性。
中断法(interrupt): 当外设需要传输数据时,会触发中断,CPU 会暂停正在处理的任务,转而去执行中断服务函数,接着处理外设的数据传输任务。CPU 无需反复检查外设的标志位,中断机制会指示 CPU 何时去处理外设数据,但是依然需要 CPU 去完成数据搬运和传输过程。当外设数据传输服务不频繁且数据量不大时,中断法也是不错的选择。当中断连续不断且频繁发生时,中断法变得不再高效,因为在恢复主流程的执行和中断相应的上下文切换会占用大量的 CPU 时间。
DMA: DMA 控制器是单片机中的硬件单元,它在存储器和外设之间有专用的通道,允许外设和存储器之间高效传输数据,且传输过程无需 CPU 参与。
综上可见 DMA 是一种高效的数据传输方式。
什么是 DMA
DMA(Direct Memory Access)控制器提供了一种硬件的方式在外设和存储器之间或者存储器和存储器之间传输数据,而无需 CPU 的介入,避免了 CPU 多次进入中断进行大规模的数据拷贝,最终提高整体的系统性能。
DMA 是一种能够在无需 CPU 参与的情况下,将数据块在内存和外设之间高效传输的硬件机制。实现这种功能的集成电路单元叫做 DMA Controller,即 DMA 控制器。
DMA 控制器在没有 CPU 参与的情况下从一个地址向另一个地址传输数据,它支持多种数据宽度,突发类型,地址生成算法,优先级和传输模式,可以灵活的配置以满足应用的需求。
STM32-DMA 介绍
STM32F407VET6 有两个 DMA 控制器(DMA1,DMA2),每个 DMA 控制器包含了两个 AHB 总线接口和 8 个 4 字深度的 FIFO,使 DMA 可以高效的传输数据。每个 DMA 控制器有 8 个通道,一共是 16 个通道,每个通道可以被分配给一个或多个特定的外设进行数据传输。两个内置的总线仲裁器用来处理 DMA 请求的优先级问题。DMA 控制器支持 8 位,16 位和 32 位的数据宽度。
关于 DMA 的主要特性在用户手册的第 302 页,如图所示(部分截图)。
DMA 传输方式
STM32F407VET6 单片机的 DMA 控制器的两个 AHB 主机接口分别对应存储器和外设的数据访问。
DMA 支持三种传输模式,如下:
- 外设到存储器:通过 AHB 外设主机接口从外设读取数据,通过 AHB 存储器主机接口向存储器写入数据。比如串口的 DMA 接收,就是从外设到存储器。
- 存储器到外设:通过 AHB 存储器主机接口从存储器读取数据,通过 AHB 外设主机接口向外设写入数据。比如串口的 DMA 发送,就是存储器到外设。
- 存储器到存储器:通过 AHB 外设主机接口从存储器读取数据,通过 AHB 存储器主机接口向存储器写入数据。
存储区和外设都可以配置为源端和目的端。
存储器端数据传输如图所示。
外设端数据传输如图所示。
DMA 外设请求映射
每个 DMA 控制器有 8 个通道,每个通道有多个外设请求。DMA1 和 DMA2 的外设请求映射分别如图所示。
仲裁
每个 DMA 控制器有两个分别对应于外设和存储器的仲裁器。当 DMA 控制器在同一时间接收到多个外设请求时,仲裁器将根据外设请求的优先级来决定响应哪一个外设请求。
优先级规则如下:
- 软件优先级:分为 4 级,低,中,高和超高。可以通过寄存器的 DMA_CHxCTL 的 PRIO 位域配置。
- 硬件优先级:当通道具有相同的软件优先级时,编号低的通道优先级高。
FIFO
DMA 控制器的每个通道都有一个 4 字深度的 FIFO 用于缓冲数据,从源地址读取的数据会暂时保存在 FIFO 中,再传输到目的地址。根据 FIFO 的配置,DMA 控制器支持两种数据处理模式:单数据传输模式和多数据传输模式。在存储器到存储器模式下,DMA 控制器仅支持多数据传输模式。
地址生成算法
存储器和外设都独立的支持两种地址生成算法:固定模式和增量模式。
在固定模式中,地址一直固定为初始化的基地址。在增量模式中,下一次传输数据的地址是当前地址加 1(或 2,4),这个值取决于数据传输宽度。
外设地址就是外设寄存器映射的地址,而存储器地址就是内存缓冲区数组的起始地址。由于外设寄存器地址是固定的,所以外设地址生成算法应该选择固定地址模式。而存储器对应的缓冲数组是包含多个数据元素的矢量,所以存储器的地址生成算法应该选择增量地址模式。
循环模式
循环模式用来处理连续的外设请求。在循环模式中,当每次 DMA 传输完成后,CNT 值会被重新载入,且传输完成标志位会被置 1。DMA 会一直响应外设的请求,直到出现传输错误或者通道使能位被清 0。
单次传输模式:
当传输结束时,触发 DMA 中断,在中断程序中首先失能 DMA 通道,然后修改该通道的传输数据量,最后重新使能 DMA 通道,注意只有失能的 DMA 通道才能成功修改传输数据量。
循环传输模式:
当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。
中断
每个 DMA 通道都有专有的中断,包括 5 个中断事件,传输完成中断,半传输完成中断,传输错误中断,单数据传输模式异常中断,FIFO 错误和异常中断。任何一个中断事件都可以引发 DMA 中断。
这 5 个事件可以分为 3 种类型:
- 标志:传输完成和半传输完成
- 异常:单数据传输模式异常和 FIFO 异常
- 错误:传输错误和 FIFO 错误
发生异常事件时,正在进行的 DMA 传输不会被停止,仍将继续传输。发生错误事件时,正在进行的 DMA 传输会被停止。
2.实验原理
DMA 支持很多个外设,这里就以串口 DMA 接收进行介绍。
一般进行串口接收也有以下几种方式:
- 通过轮询接收数据
- 通过中断接收数据
- 通过 DMA 接收数据
一般使用情况可能是中断方式用的比较多,但是使用中断在数据量不大的时候使用效率是高的,但数据量一旦很大,这个效率就很低了。数据量很大的传输推荐使用 DMA 进行传输。
串口DMA接收数据思路
在串口检测到有数据输入的时候,直接让 DMA 往准备好的存储器中搬运接收到的数据,在这个过程中,CPU 还是在处理自己的事,在一帧数据传输完成后,通过空闲中断告诉主任务一帧数据已经传输完毕,主任务再对接收到的数据进行响应处理。整个过程中,程序代码只会触发一次中断,就是 DMA 搬移完数据后通知 CPU 的那一次中断,这种方法无论一帧数据的数据量有多大,都只会触发一次中断,且在传输过程中不占用 CPU 的时间,大大节省效率。