DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备 开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
STM32F4 最多有 2 个 DMA 控制器(DMA1 和 DMA2),共 16 个数据流(每个控制器 8 个),每 一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8 个通道(或称请求)。每个数据流通道都有一个仲裁器,用于处理 DMA 请求间的优先级。
DMA 的主要特性:
DMA框图
DMA 控制器执行直接存储器传输:因为采用 AHB 主总线,它可以控制 AHB 总线矩阵来启动 AHB 事务。它可以执行下列事务:外设到存储器的传输、存储器到外设的传输 、存储器到存储器的传输 。这里特别注意一下,存储器到存储器需要外设接口可以访问存储器,而仅 DMA2 的外设接口可以访问存储器,所以仅 DMA2 控制器支持存储器到存储器的传输,DMA1 不支持。
通道选择
每个数据流都与一个 DMA 请求相关联,此 DMA 请求可以从 8 个可能的通道请求中选出。 此选择由 DMA_SxCR 寄存器中的 CHSEL[2:0] 位控制。
来自外设的 8 个请求(TIM、ADC、SPI、I2C 等)独立连接到每个通道,具体的连接取决于产品实现情况。
DMA 请求映射
上表就列出了 DMA所有可能的选择情况,每个DMA总共 64 种组合,比如如果要实现串口 1 的 DMA 发送,即 USART1_TX,就必须选择 DMA2 的数据流 7,通道 4,来进行 DMA 传输。这里注 意一下,有的外设(比如 USART1_RX)可能有多个通道可以选择,随意选择一个就可以。
DMA 数据流
8 个 DMA 控制器数据流都能够提供源和目标之间的单向传输链路。 每个数据流配置后都可以执行:
常规类型事务:存储器到外设、外设到存储器或存储器到存储器的传输。
双缓冲区类型事务:使用存储器的两个存储器指针的双缓冲区传输(当 DMA 正在进行自/ 至缓冲区的读/写操作时,应用程序可以进行至/自其它缓冲区的写/读操作)。
要传输的数据量(多达 65535)可以编程,并与连接到外设 AHB 端口的外设(请求 DMA 传 输)的源宽度相关。每个事务完成后,包含要传输的数据项总量的寄存器都会递减。
DMA 事务
DMA 事务由给定数目的数据传输序列组成。要传输的数据项的数目及其宽度(8 位、16 位 或 32 位)可用软件编程。 每个 DMA 传输包含三项操作:
1.通过 DMA_SxPAR 或 DMA_SxM0AR 寄存器寻址,从外设数据寄存器或存储器单元中加载数据。
2.通过 DMA_SxPAR 或 DMA_SxM0AR 寄存器寻址,将加载的数据存储到外设数据寄存 器或存储器单元。
3.DMA_SxNDTR 计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数。
在产生事件后,外设会向 DMA 控制器发送请求信号。DMA 控制器根据通道优先级处理该请求。只要 DMA 控制器访问外设,DMA 控制器就会向外设发送确认信号。外设获得 DMA 控制器的确认信号后,便会立即释放其请求。一旦外设使请求失效,DMA 控制器就会释放确认信号。如果有更多请求,外设可以启动下一个事务。
仲裁器
仲裁器为两个 AHB 主端口(存储器和外设端口)提供基于请求优先级的 8 个 DMA 数据流请 求管理,并启动外设/存储器访问序列。 优先级管理分为两个阶段:
软件:每个数据流优先级都可以在 DMA_SxCR 寄存器中配置。分为四个级别:非常高优先级、高优先级、中优先级、低优先级。
硬件:如果两个请求具有相同的软件优先级,则编号低的数据流优先于编号高的数据 流。例如,数据流 2 的优先级高于数据流 4。
DMA_SxCR寄存器
指针递增
根据 DMA_SxCR 寄存器中 PINC 和 MINC 位的状态,外设和存储器指针在每次传输后可以自动向后递增或保持常量。 通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用。 如果使能了递增模式,则根据在 DMA_SxCR 寄存器 PSIZE 或 MSIZE 位中编程的数据宽度,下一次传输的地址将是前一次传输的地址递增 1(对于字节)、2(对于半字)或 4(对于字)。 为了优化封装操作,可以不管 AHB 外设端口上传输的数据的大小,将外设地址的增量偏移大小固定下来。DMA_SxCR 寄存器中的 PINCOS 位用于将增量偏移大小与外设 AHB 端口或 32 位地址(此时地址递增 4)上的数据大小对齐。PINCOS 位仅对 AHB 外设端口有影响。 如果将 PINCOS 位置 1,则不论 PSIZE 值是多少,下一次传输的地址总是前一次传输的地址递增 4(自动与 32 位地址对齐)。但是,AHB 存储器端口不受此操作影响。 如果 AHB 外设端口或 AHB 存储器端口分别请求突发事务,为了满足 AMBA 协议(在固定地 址模式下不允许突发事务),则需要将 PINC 或 MINC 位置 1。
DMA_SxCR寄存器
循环模式
循环模式可用于处理循环缓冲区和连续数据流(例如 ADC 扫描模式)。可以使用 DMA_SxCR 寄存器中的 CIRC 位使能此特性。 当激活循环模式时,要传输的数据项的数目在数据流配置阶段自动用设置的初始值进行加载, 并继续响应 DMA 请求。
DMA_SxCR寄存器
可编程数据宽度、封装/解封、字节序
要传输的数据项数目必须在使能数据流之前编程到 DMA_SxNDTR(要传输数据项数目位, NDT)中,当流控制器是外设且 DMA_SxCR 中的 PFCTRL 位置为 1 时除外。 当使用内部 FIFO 时,源和目标数据的数据宽度可以通过 DMA_SxCR 寄存器的 PSIZE 和 MSIZE 位(可以是 8、16 或32 位)编程。
当 PSIZE 和 MSIZE 不相等时:
1.在 DMA_SxNDTR 寄存器中配置的要传输的数据项数目的数据宽度等于外设总线的宽度 (由 DMA_SxCR 寄存器中的 PSIZE 位配置)。例如,在外设到存储器、存储器到外 设或存储器到存储器传输的情况下,如果将 PSIZE[1:0] 位配置为半字,则要传输的字节数等于 2 × NDT。
2.DMA 控制器仅按小字节序寻址源和目标。
在封装/解封数据的过程中,如果在数据完全封装/解封前中断操作,则有数据损坏的危险。 因此,为了确保数据一致性,可将数据流配置成生成突发传输:在这种情况下,属于一个突 发的每组传输不可分割。
在直接模式下(DMA_SxFCR 寄存器中的 DMDIS = 0),不能进行数据封装/解封。这种情 况下,不允许源与目标的传输数据宽度不同,二者必须相等,并由 DMA_SxCR 中的 PSIZE 位定义,MSIZE 位的状态是“无关”。
单次传输和突发传输
DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。 突发大小通过软件针对两个 AHB 端口独立配置,配置时使用 DMA_SxCR 寄存器中的 MBURST[1:0] 和 PBURST[1:0] 位。 突发大小指示突发中的节拍数,而不是传输的字节数。 为确保数据一致性,形成突发的每一组传输都不可分割:在突发传输序列期间,AHB 传输会 锁定,并且 AHB 总线矩阵的仲裁器不解除对 DMA 主总线的授权。
根据单次或突发配置的情况,每个 DMA 请求在 AHB 外设端口上相应地启动不同数量的传输。
1.当 AHB 外设端口被配置为单次传输时,根据 DMA_SxCR 寄存器 PSIZE[1:0] 位的值, 每个 DMA 请求产生一次字节、半字或字的数据传输。
2.当 AHB 外设端口被配置为突发传输时,根据 DMA_SxCR 寄存器 PBURST[1:0] 和 PSIZE[1:0] 位的值,每个 DMA 请求相应地生成 4 个、8 个或 16 个节拍的字节、半字或字的传输。
对于需要配置 MBURST 和 MSIZE 位的 AHB 存储器端口,必须考虑与上述相同的内容。 在直接模式下,数据流只能生成单次传输,而 MBURST[1:0] 和 PBURST[1:0] 位由硬件强制配置。
双缓冲区模式
此模式可用于所有 DMA1 和 DMA2 数据流。 通过将 DMA_SxCR 寄存器中的 DBM 位置 1,即可使能双缓冲区模式。 除了有两个存储器指针之外,双缓冲区数据流的工作方式与常规(单缓冲区)数据流的一样。 使能双缓冲区模式时,将自动使能循环模式(DMA_SxCR 中的 CIRC 位的状态是“无 关”),并在每次事务结束时交换存储器指针。 在此模式下,每次事务结束时,DMA 控制器都从一个存储器目标交换为另一个存储器目标。 这样,软件在处理一个存储器区域的同时,DMA 传输还可以填充/使用第二个存储器区域。双缓冲区数据流可以双向工作(存储器既可以是源也可以是目标)。
DMA 中断
对于每个 DMA 数据流,可在发生以下事件时产生中断:
达到半传输
传输完成
传输错误
FIFO 错误(上溢、下溢或 FIFO 级别错误)
直接模式错误
可以使用单独的中断使能位以实现灵活性。
流配置过程
配置 DMA 数据流 x(其中 x 是数据流编号)时应遵守下面的顺序:
1. 如果使能了数据流,通过重置 DMA_SxCR 寄存器中的 EN 位将其禁止,然后读取此位 以确认没有正在进行的数据流操作。将此位写为 0 不会立即生效,因为实际上只有所有 当前传输都已完成时才会将其写为 0。当所读取 EN 位的值为 0 时,才表示可以配置数 据流。因此在开始任何数据流配置之前,需要等待 EN 位置 0。应将先前的数据块 DMA 传输中在状态寄存器(DMA_LISR 和 DMA_HISR)中置 1 的所有数据流专用的位置 0, 然后才可重新使能数据流。
2. 在 DMA_SxPAR 寄存器中设置外设端口寄存器地址。外设事件发生后,数据会从此地址 移动到外设端口或从外设端口移动到此地址。
3. 在 DMA_SxMA0R 寄存器(在双缓冲区模式的情况下还有 DMA_SxMA1R 寄存器)中设 置存储器地址。外设事件发生后,将从此存储器读取数据或将数据写入此存储器。
4. 在 DMA_SxNDTR 寄存器中配置要传输的数据项的总数。每出现一次外设事件或每出现 一个节拍的突发传输,该值都会递减。
5. 使用 DMA_SxCR 寄存器中的 CHSEL[2:0] 选择 DMA 通道(请求)。
6. 如果外设用作流控制器而且支持此功能,请将 DMA_SxCR 寄存器中的 PFCTRL 位置 1。
7. 使用 DMA_SxCR 寄存器中的 PL[1:0] 位配置数据流优先级。
8. 配置 FIFO 的使用情况(使能或禁止,发送和接收阈值)。
9. 配置数据传输方向、外设和存储器增量 / 固定模式、单独或突发事务、外设和存储器数 据宽度、循环模式、双缓冲区模式和传输完成一半和/或全部完成,和/或 DMA_SxCR 寄存器中错误的中断。
10. 通过将 DMA_SxCR 寄存器中的 EN 位置 1 激活数据流。 一旦使能了流,即可响应连接到数据流的外设发出的任何 DMA 请求。 一旦在 AHB 目标端口上传输了一半数据,传输一半标志 (HTIF) 便会置 1,如果传输一半中 断使能位 (HTIE) 置 1,还会生成中断。传输结束时,传输完成标志 (TCIF) 便会置 1,如果 传输完成中断使能位 (TCIE) 置 1,还会生成中断。
警告: 要关闭连接到 DMA 数据流请求的外设,必须首先关闭外设连接 的 DMA 数据流,然后等待 EN 位 = 0。只有这样才能安全地禁止外设。