一文彻底理解DMA

DMA(Direct Memory Acess)
1.什么是DMA,有什么作用?
2.DMA传输过程简述
2.1.DMA普通传输过程
2.2.DMA指针递增传输过程
2.3.DMA循环传输过程
2.4.DMA双缓冲区传输过程
3.STM32F4 DMA的主要特性
4.DMA功能说明
4.1.DMA框图
4.2.传输端口
4.3.通道选择——DMA_SxCR 寄存器中的 CHSEL[2:0]控制
4.4.仲裁器
4.5.FIFO——DMA_SxFCR 寄存器DMDIS位置0启用FIFO
4.6.DMA事务
4.7.传输模式
4.8.指针递增
4.9.单次传输和突发传输
4.10.循环模式
4.11.双缓冲区模式
4.12.FIFO阈值与突发配置
4.13.FIFO刷新
4.14.DMA 传输完成
4.15.传输暂停
4.16.流控制器
4.17.流配置过程
4.18.错误管理
4.19.DMA 中断
1.什么是DMA,有什么作用?
DMA用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。

我们用一个现实例子来做个类比。有一家冶炼公司,每天要不断的从矿场拉矿石进入厂区冶炼,以前通过公路运送的,但是这个公路除了他家的货运车以外,还有其他车,所以一般堵车严重,交通事故频发,影响工厂生产,货运成为该公司提高产能的一大瓶颈。公司思量再三,决定出资在矿场和公司间修建一条专用铁路来运矿石。虽然修建这条铁路价格昂贵,但是修好后,运送矿石的效率大大提高,公司迅速扩大产能,很快得到回报。同时原来运送矿石这条公路,也不堵车了。这条铁路的作用其实和DMA类似。

本文通过STM32F4对DMA相关原理做个介绍。
STM32F4共有2个 DMA 控制器,每个控制器均有8个数据流,每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8 个通道(或称请求)。每个通道都有一个仲裁器,用于处理 DMA 请求间的优先级。


2.DMA传输过程简述
DMA传输过程说起来很简单,每个DMA有2个端口:外设端口和存储器端口,通过这两个端口可以单向传输数据。

DMA1外设端口通过AHB总线连接到外设,存储器端口通过AHB总线连接到存储器, DMA1传输方向有二种:从外设向存储器传输数据,从存储器向外设传输数据。

DMA2外设端口通过AHB总线连接到外设以及存储器,存储器端口通过AHB总线连接到存储器。DMA2传输方向有三种:从外设向存储器传输数据,从存储器向外设传输数据,存储器向存储器传输数据。

ARM Cortex-M 处理器的存储系统使用32位寻址,共有4GB地址空间。ROM、RAM、外设以及处理器内的调试支持部件的地址均映射在这4GB存储空间内。所以不论哪种传输方向,DMA数据传输的本质是将数据从4GB空间内的一个地址传输到另一个地址上。

两个DMA各有1个4字(1字=4字节)大小的缓冲区(FIFO),用于数据在传输到目标之前,临时存储这些数据。缓冲区有一个可配置的阈值(可配置为1/4、1/2、3/4 或满),用来决定何时将缓冲区(FIFO)中数据发送到存储器(当从外设向存储器传输数据)或何时将存储器内的数据发送到缓冲区(FIFO)(从存储器向外设传输数据)。当从外设向存储器传输数据时,缓冲区(FIFO)内数据量达到阈值时,会将缓冲区(FIFO)数据发送到目标地址上。当从存储器向外设传输数据时,缓冲区内的数据量小于等于缓冲区(FIFO)阈值时,会使用存储器内的数据填充满FIFO。

通过DMA传输数据,需要以下信息:

DMA外设端口和存储器端口的数据宽度。所谓数据宽度是指从端口发送或从端口接收的数据是多少位的。我们在编写程序时,有时候有这样的需求(特别是在外设与存储器间传输数据),从一个地址将A个N位的数据传输到另一个地址,重合组合成B个M位的数据。用DMA传输数据时,通过配置其外设端口和存储器端口的数据宽度可完美解决此问题。DMA中数据宽度可配置为字节、半字(2字节)和字(4字节)。通过DMA_SxCR寄存器的 PSIZE(配置外设端口数据宽度) 和 MSIZE(配置内存端口数据宽度) 位配置。

传输的数据量。所谓数据量是指具体要传输多少个数据。有两种控制传输数据量的方法:(1)连接外设并且要传输的数据数据量未知时,可通过外设发送数据传输的结束信号停止传输,但此种方法需要外设具有SDIO接口。(2) 在已知需要传输的数据量时,通过设置需要传输的数据量。要传输的数据量在使能DMA数据流之前写入DMA_SxNDTR 寄存器。在两边数据宽度不一致情况下,DMA_SxNDTR中的数据量等于外设端的数据量。每传输一次后,DMA_SxNDTR中值递减1,递减为0时,DMA停止传输。通常情况下,使用第2中方法来控制数据量。

数据传输地址。所谓数据传输地址是指从什么地址发送数据,从什么地址接收数据。外设端口和存储器端口各自有自己的数据传输地址,分别通过寄存器DMA_SxPAR 和DMA_SxM0AR/ DMA_SxM1A(DMA_SxM1AR仅在双缓冲区模式下有效)来设置数据传输地址。

2.1.DMA普通传输过程
DMA有一个使能信号,通过使能信号来控制DMA工作,在使用DMA时,首先需要使能DMA。
针对于不同的传输方向,其传输过程略有不同。

从外设向存储器传输数据
DMA使能后,等待外设发出DMA请求信号,DMA收到请求,数据从外设端口数据传输地址(DMA_SxPAR)存储到DMA缓冲区(FIFO)内,当缓冲区(FIFO)内数据量达到缓冲区(FIFO)阈值后,缓冲区(FIFO)内数据移出到内存端口数据传输地址(DMA_SxM0AR)指定的存储器地址中,同时每传输一个数据,DMA_SxNDTR内的值会减1,DMA_SxNDTR值递减为0,DMA传输停止。
从存储器向外设传输数据
DMA使能后,立即会将内存端口数据传输地址(DMA_SxM0AR)指定的数据移动到DMA缓冲区(FIFO)内,完全填满DMA缓冲区(FIFO),等待外设端口DMA请求信号,每次发生外设请求,缓冲区内的数据以外设端口宽度指定的数据量移出到外设端数据传输地址(DMA_SxPAR)指定的目标地址上,同时每传输一个数据,DMA_SxNDTR内的值会减1,DMA_SxNDTR值递减为0,DMA停止传输。当DMA缓冲区(FIFO)内数据量小于等于缓冲区阈值时,会使用存储器内的数据再次填充满FIFO。
2.2.DMA指针递增传输过程
DMA的外设端口和内存端口各自有一个指针递增参数,可以单独设置是否启用。如果启用了指针递增,则每传输一次,相应端口的数据传输地址递增(递增数等于相应端口地址宽度的字节数),指向下一个地址,下次DMA传输会使用这个新地址来发送或接收数据。

2.3.DMA循环传输过程
DMA还有一个循环模式参数用来设置是否启用循环模式。在循环模式下,当DMA_SxNDTR递减为0后,外设端口、存储器端口的数据传输地址以及DMA_SxNDTR中的值会自动加载初始值后,开始新一轮的循环传输。

2.4.DMA双缓冲区传输过程
DMA在循环模式下,还可以设置为双缓冲区模式。在双缓冲区模式下,存储器端口可以利用DMA_SxM0AR和 DMA_SxM1AR 2个寄存器设置两个数据传输地址。DMA可以利用两个数据传输地址交替传输数据。我们使能指针递增情况下,将两个缓冲区首地址分别装入DMA_SxM0AR和 DMA_SxM1AR,这样在一个缓冲区传输数据的时候,可以对另一个缓冲区内的数据进行处理。
以上只是粗略简述整个传输过程,具体详细信息,后面具体描述。

3.STM32F4 DMA的主要特性
双 AHB 主总线架构,一个用于存储器访问,另一个用于外设访问。
每个 DMA 控制器有 8 个数据流,每个数据流有多达8个通道(或称请求)
每个数据流有单独的四级32位先进先出存储器缓冲区 (FIFO),可用于 FIFO 模式或直接模式:
—— FIFO 模式下,可通过软件将阈值级别选取为 FIFO 大小的 1/4、1/2 或 3/4。当FIFO中的数据量达到FIFO阈值时,才会将FIFO中的数据送出FIFO,进入外设或储存器端口。
—— 直接模式下,FIFO失去作用,不对数据进行缓存,每个 DMA 请求会立即启动对数据的传输。当在直接模式(禁止 FIFO)下将 DMA请求配置为以存储器向外设传输数据时,DMA 仅会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
通过硬件可以将每个数据流配置为:
—— 支持外设到存储器、存储器到外设和存储器到存储器传输的常规通道
—— 也支持在存储器方双缓冲的双缓冲区通道
DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)
要传输的数据项的数目可以由 DMA 控制器或外设管理:
—— DMA 流控制器下,要传输的数据项的数目是 1 到 65535,可用软件编程
—— 外设流控制器下,要传输的数据项的数目未知并由源或目标外设控制,外设通过硬件发出传输结束的信号
独立的源和目标传输宽度(字节、半字、字):源和目标的数据宽度不相等时,DMA 自动封装/解封必要的传输数据来优化带宽。这个特性仅在 FIFO 模式下可用,在直接模式下,数据宽度必须相等。
对源和目标的增量或非增量寻址
支持 4 个、8 个和 16 个节拍的增量突发传输。突发增量的大小可由软件配置,通常等于外设 FIFO 大小的一半
每个数据流都支持循环缓冲区管理 5 个事件标志(DMA 半传输、DMA 传输完成、DMA 传输错误、DMA FIFO 错误、直接模式错误),进行逻辑或运算,从而产生每个数据流的单个中断请求
4.DMA功能说明
4.1.DMA框图


4.2.传输端口
每个DMA均有两个传输端口:存储器传输端口和外设传输端口,这两个端口间可以单向传输数据,任何一方均可作为发送方,另一方作为接收方。DMA2的外设端口还可连接存储器,实现存储器到存储器的传输。
DMA_SxCR 寄存器中的 DIR[1:0]控制传输方向。


源传输和目标传输在整个 4 GB 区域(地址在 0x0000 0000 和 0xFFFF FFFF 之间)都可以寻址外设和存储器。

源和目标端口数据宽度可配置。通过DMA_SxCR 寄存器的 PSIZE 和 MSIZE 位可分别控制外设端口和存储器端口宽度,可配置为字节、半字(2字节)和字(4字节)。当数据宽度分别是半字或字时,写入DMA_SxPAR 或 DMA_SxM0AR/M1AR 寄存器的外设或存储器地址必须分别在字或半字地址边界对齐。例如当数据宽度为字时,写入 DMA_SxPAR 或 DMA_SxM0AR/M1AR地址必须是4的倍数。

DMA_SxPAR (外设地址配置寄存器)或 DMA_SxM0AR(内存地址配置寄存器0)/ DMA_SxM1AR(内存地址寄存器1——只在双缓冲区模式下有效)用来存放外设或内存数据传输地址。DMA_SxPAR 寄存器中设置外设端口寄存器地址,外设事件发生后,数据会从此地址移动到外设端口或从外设端口移动到此地址。在 DMA_SxMA0R 寄存器(在双缓冲区模式的情况下还有 DMA_SxMA1R 寄存器)中设置存储器地址。外设事件发生后,将从此存储器读取数据或将数据写入此存储器。

4.3.通道选择——DMA_SxCR 寄存器中的 CHSEL[2:0]控制
每个数据流都与1个 DMA 请求相关联,此 DMA 请求可以从 8 个可能的通道请求中选出。

来自外设的 8 个请求(TIM、ADC、SPI、I2C 等)独立连接到每个通道,具体的连接取决于产品实现情况。
如下图,选择DMA1的数据流6的通道5,则意味着UART8_RX外设请求。
如果我们需要通过TIM3_CH2通道发出DMA请求,则应选择数据流5的通道5。则在TIM2定时器中使能捕获/比较DMA请求使能(寄存器TIM2_DIER中断使能寄位CC2DE置1),则在发生输入捕获事件或者输出比较事件时,会通过DMA1数据流5通道5发出请求DMA请求。


4.4.仲裁器
仲裁器有两个功能:(1)为两个 AHB 主端口(存储器和外设端口)提供基于请求优先级的 8 个 DMA 数据流请求管理。(2)启动外设/存储器访问序列。
优先级管理分为两个阶段:
● 软件:每个数据流优先级都可以在DMA_SxCR寄存器中PL位配置。分为四个级别:非常高、高、中、低优先级
● 硬件:如果两个请求具有相同的软件优先级,则编号低的数据流优先于编号高的数据流。例如,数据流 2 的优先级高于数据流 4。

4.5.FIFO——DMA_SxFCR 寄存器DMDIS位置0启用FIFO
FIFO 用于在源数据传输到目标之前临时存储这些数据。
每个数据流都有一个独立的 4 字 FIFO,阈值级别可由软件配置为 1/4、1/2、3/4 或满(由DMA_SxFCR 寄存器的位 FTH[1:0]设置)。
将 DMA_SxFCR 寄存器中的 DMDIS 位置 1 可禁止直接模式,使能FIFO。
FIFO 的结构随源与目标数据宽度而不同。


在开启FIFO时,源端口数据宽度和目的端口数据宽度可不同,FIFO会自动封装/解封数据,以匹配端口数据宽度;不开启FIFO时,源宽度和目的宽度必须相同。

4.6.DMA事务
DMA 事务由给定数目的数据传输序列组成。要传输的数据项的数目及其宽度(8 位、16 位或 32 位)可用软件编程。
每个 DMA 传输包含三项操作:

(1)通过 DMA_SxPAR (外设地址配置寄存器)或 DMA_SxM0AR(内存地址配置寄存器0)寻址,从外设数据寄存器或存储器单元中加载数据。

(2) 通过 DMA_SxPAR (外设地址配置寄存器)或 DMA_SxM0AR(内存地址配置寄存器0)寻址,将加载的数据存储到外设数据寄存器或存储器单元。

(3) DMA_SxNDTR 计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数。DMA_SxNDTR中的事务数等于AHB外设端口上要传输的数据项的数目(传送的总字节数=DMA_SxNDTR * PSIZE定义的字节数(外设端口数据宽度))。

在外设产生事件后,外设会向 DMA 控制器发送请求信号。DMA 控制器根据通道优先级处理该请求。只要 DMA 控制器访问外设,DMA 控制器就会向外设发送确认信号。外设获得 DMA 控制器的确认信号后,便会立即释放其请求。一旦外设使请求失效,DMA 控制器就会释放确认信号。如果有更多请求,外设可以启动下一个事务。

4.7.传输模式
(1)外设到存储器模式
A.FIFO模式下
使能这种模式时,每次产生外设请求,数据流都会启动数据源到 FIFO 的传输。达到 FIFO 的阈值级别时,FIFO 的内容移出并存储到目标中。

B.直接模式下
每完成一次从外设到 FIFO 的数据传输后,相应的数据立即就会移出并存储到目标中。
如果 DMA_SxNDTR 寄存器达到零、外设请求传输终止(在使用外设流控制器的情况下)或DMA_SxCR 寄存器中的 EN 位由软件清零,传输即会停止。

(2)存储器到外设模式
A.FIFO模式下
使能这种模式时,数据流会立即启动传输,从源完全填充 FIFO。每次发生外设请求,FIFO 的内容都会按外设端口宽度移出并存储到目标中。当 FIFO 的数据量小于或等于预定义的阈值级别时,将使用存储器中的数据完全填满FIFO。

B.直接模式下
一旦使能了数据流,DMA 便会预装载第一个数据,将其传输到内部 FIFO。一旦外设请求数据传输,DMA 便会将预装载的值传输到配置的目标。然后,它会使用要传输的下一个数据再次重载内部空 FIFO。预装载的数据大小为 DMA_SxCR 寄存器中 PSIZE 位字段的值。

(3)存储器到存储器模式
该模式必须启用FIFO,不允许在循环模式和直接模式下运行。
只有 DMA2 控制器能够执行存储器到存储器的传输。
DMA 通道在没有外设请求触发的情况下同样可以工作。通过将 DMA_SxCR 寄存器中的使能位 (EN) 置 1 来使能数据流时,数据流会立即开始填充FIFO,直至达到阈值级别。达到阈值级别后,FIFO 的内容便会移出,并存储到目标中。
如果 DMA_SxNDTR 寄存器达到零或 DMA_SxCR 寄存器中的 EN 位由软件清零,传输即会停止。

4.8.指针递增
通过DMA传输数据的时候,很多情况下需要传输数据序列。例如,通过SPI控制ADC来连续采集数据,采集的数据存入缓冲区内,如果我们将缓冲区首地址放入DMA_SxM0AR寄存器内,数据连续传输的时候,DMA自动递增缓冲区地址,则数据会连续的存入缓冲区内,不需要CPU干预,这就是所谓的指针递增。当然外设端口的指针也可以递增,例如我们连续访问多个外设寄存器时,就可以使用指针递增功能。

DMA_SxCR 寄存器中 PINC 和 MINC 位分别控制外设和存储器指针在每次传输后是否自动向后递增。

一般通过单个寄存器访问外设源或目标数据时,禁止递增模式。

地址递增多少个字节是相应端口的数据宽度决定的。根据DMA_SxCR 寄存器 PSIZE 或 MSIZE 位中定义的数据宽度,下一次传输的地址将是前一次传输的地址递增 1(对于字节)、2(对于半字)或 4(对于字)。

另外,对于AHB外设端口,可以不管外设端口上传输的数据的大小,将外设端口地址增量大小固定下来。DMA_SxCR 寄存器中的 PINCOS 位等于1时,地址偏移大小32 位地址(此时地址递增 4)上的数据大小对齐,PINCOS 位等于0时与外设 AHB 端口数据宽度对齐。内存端口无此功能。

4.9.单次传输和突发传输
所谓突发传输是指传输一个数据序列期间,为确保数据一致性, AHB 传输被会锁定,并且 AHB 总线矩阵的仲裁器不解除对 DMA 主总线的授权。整个序列是一个不可分割的整体,传输过程中不可被打断或者禁止。

DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。

突发传输大小通过软件针对两个 AHB 端口独立配置,配置时使用 DMA_SxCR 寄存器中的MBURST[1:0] 和 PBURST[1:0] 位。
根据单次或突发配置的情况,每个 DMA 请求在 AHB 外设端口上相应地启动不同数量的传输。
●单次传输:根据 DMA_SxCR 寄存器 PSIZE[1:0] 位的值,每个 DMA 请求产生一次字节、半字或字的数据传输。
●突发传输:根据 DMA_SxCR 寄存器 PBURST[1:0] 和PSIZE[1:0] 位的值,每个 DMA 请求相应地生成 4 个、8 个或 16 个节拍的字节、半字或字的传输。

对于需要配置 MBURST 和 MSIZE 位的 AHB 存储器端口,必须考虑与上述相同的内容。
在直接模式下,数据流只能生成单次传输,而 MBURST[1:0] 和 PBURST[1:0] 位由硬件强制配置。

仅在使能指针递增模式时允许突发模式:
—— 当 PINC 位为“ 0 ”时,也应将 PBURST 位清为“ 00 ”
—— 当 MINC 位为“ 0 ”时,也应将 MBURST 位清为“ 00 ”指针递增
通过DMA传输数据的时候,大多时候传输的数据都是多个数据。例如需要通过SPI控制ADC来连续采集数据,采集的数据

4.10.循环模式
所谓循环模式就是传输一组数据完成(DMA_SxNDTR中值递减为0)后,重新将端口传输地址填充为初始化时的值,DMA_SxNDTR值恢复为初始值,自动进行连续传输。如果是在非循环模式下配置数据流,传输结束后(DMA_SxNDTR中值递减为0),除非软件重新对数据流编程并重新使能数据流(通过将 DMA_SxCR 寄存器中的 EN 位置 1),否则DMA 即会停止传输(通过硬件将 DMA_SxCR 寄存器中的 EN 位清零)并且不再响应任何DMA 请求。

DMA_SxCR寄存器中的 CIRC 位控制循环模式使能。

在循环模式下,如果为存储器配置了突发模式,必须遵循下列规则:
DMA_SxNDTR = ((Mburst 的节拍值 ) × (Msize)/(Psize)) 的倍数,即DMA_SxNDTR 值等于外设端口上要传输的数据项的数目。DMA_SxNDTR 值设计为等于外设端口数据项的数目而不是内存端口的值是因为具体外设的数据宽度是固定的,需要DMA去适配,而内存端口数据宽度可随意设置。

DMA_SxNDTR还必须是外设突发大小与外设数据大小乘积的倍数,否则会导致错误的 DMA行为。

4.11.双缓冲区模式
使用存储器的两个存储器指针(DMA_SxM0AR和DMA_SxM1AR)可以双缓冲区方式传输数据,其好处是DMA正在对一个缓冲区操作时,应用程序可以对另一个其它缓冲区操作。

通过将 DMA_SxCR 寄存器中的 DBM 位置 1,即可使能双缓冲区模式。
除了有两个存储器指针之外,双缓冲区数据流的工作方式与常规单缓冲区数据流一样。

使能双缓冲区模式时,将自动使能循环模式(DMA_SxCR 中的 CIRC 位的状态是“无关”),并在每次事务结束(DMA_SxNDTR中值递减为0)时交换存储器指针。

在双缓冲区模式下使能数据流时,可遵循下列条件,实时更新 AHB存储器的基址( DMA_SxM0AR 或 DMA_SxM1AR ):

● 当 DMA_SxCR 寄存器中的 CT 位为“ 0 ”时,可以写入 DMA_SxM1AR 寄存器。当 CT= “ 1 ”时,试图写入此寄存器会将错误标志位 (TEIF) 置 1 ,并自动禁止数据流。

● 当 DMA_SxCR 寄存器中的 CT 位为“ 1 ”时,可以写入 DMA_SxM0AR 寄存器。当 CT= “ 0 ”时,试图写入此寄存器会将错误标志位 (TEIF) 置 1 ,并自动禁止数据流。

为避免出现任何错误状态,建议在 TCIF 标志位置位时立即更改基址。因为此时根据上述两个条件之一,目标存储器依据 DMA_SxCR 寄存器中 CT 值的情况,已从存储器 0更改为存储器 1 (或从存储器 1 更改为存储器 0 )。

4.12.FIFO阈值与突发配置
选择FIFO 阈值(DMA_SxFCR 寄存器的位 FTH[1:0])和存储器突发大小(DMA_SxCR 寄存器的 MBURST[1:0] 位)时需要小心:FIFO 阈值指向的内容必须与整数个存储器突发传输完全匹配,也就是说实际使用的FIFO容量刚好应该是突发传输的倍数。FIFO容量至少要容纳一次突发传输的字节数。如果FIFO容量如果不是突发传输的整数倍,当使能数据流时将生成一个 FIFO 错误(DMA_HISR 或 DMA_LISR寄存器的标志 FEIFx),然后将自动禁止数据流。允许的和禁止的配置如下表所示。


如果发生下列一种情况,会导致 DMA 传输结束时出现不完整的突发传输:

● 对于 AHB 外设端口配置:数据项总数(在 DMA_SxNDTR 寄存器中设置)不是突发大小与数据大小乘积的倍数。

● 对于 AHB 存储器端口配置:要传输到存储器的 FIFO 中的剩余数据项的数目不是突发大小与数据大小乘积的倍数。

在这些情况下,即使在 DMA 数据流配置期间请求突发事务,要传输的剩余数据也将由 DMA在单独模式下管理。

4.13.FIFO刷新
所谓FIFO刷新就是指禁止DMA 数据流以后,仍有某些数据留存在FIFO中,则DMA控制器会将剩余的数据继续传输到目标(即使已经禁止了数据流),刷新完成后,会将 DMA_LISR 或 DMA_HISR 寄存器中的传输完成状态位 (TCIFx) 置 1指示所有数据传输完成。

在这种情况下,剩余数据计数器 DMA_SxNDTR 保持的值指示在目标存储器现有多少可用数据项。

在 FIFO 刷新操作期间,如果 FIFO 中要传输到存储器的剩余数据项的数目(以字节为单位)小于存储器数据宽度(例如在 MSIZE 配置为字时 FIFO 中为 2 个字节),则会使用在 DMA_SxCR 寄存器中的 MSIZE 位设置的数据宽度发送数据。这意味着将使用非预期值写入存储器。软件可以读取 DMA_SxNDTR 寄存器来确定包含良好数据的存储器区域(起始地址和最后地址)。

如果 FIFO 中剩余数据项的数目小于突发大小,并且数据流通过将 DMA_SxCR 寄存器MBURST 位置 1 进行配置来管理在 AHB 存储器端口上的突发传输,则使用单次传输来完成FIFO 的刷新。

4.14.DMA 传输完成
以下各种事件均可以结束传输过程,并将 DMA_LISR 或 DMA_HISR 状态寄存器中的 TCIFx位置 1:
● 在 DMA流控制器模式下:
—— 存储器到外设模式:传输结束前禁止了数据流(通过将 DMA_SxCR 寄存器中的 EN 位清零)或者DMA_SxNDTR 计数器已达到零
—— 外设到存储器模式或者存储器到存储器模式:传输结束前禁止了数据流(通过将 DMA_SxCR 寄存器中的 EN 位清零),并所有的剩余数据均已从 FIFO 刷新到存储器

● 在外设流控制器模式下:
—— 存储器到外设模式:已从外设生成最后的外部突发请求或单独请求或者数据流由软件禁止
—— 外设到存储器模式:已从外设生成最后的外部突发请求或单独请求或者数据流由软件禁止,而剩余数据已从 FIFO 传输到存储器

4.15.传输暂停
数据流禁止传输后,不从停止点重新开始。这种情况下,要禁止数据流,除了将 DMA_SxCR 寄存器中的 EN 位清零外,不需要做任何其他操作。禁止数据流可能要花费一些时间(需要首先完成正在进行的传输)。需要将传输完成中断标志(DMA_LISR 或DMA_HISR 寄存器中的 TCIF)置 1 来指示传输结束。可通过DMA_SxCR 中的 EN 位的值是否是“0”,确认数据流已经终止传输。DMA_SxNDTR 寄存器包含数据流停止时剩余数据项的数目,这样软件便可以确定数据流中断前已传输了多少数据项。

数据流在 DMA_SxNDTR 寄存器中要传输的剩余数据项数目达到 0 之前暂停传输,以后通过重新使能数据流重新开始传输。为了在传输停止点重新开始传输,软件必须在通过写入 DMA_SxCR 寄存器中的 EN 位(然后检查确认该位为‘0’)禁止数据流之后,首先读取 DMA_SxNDTR 寄存器来了解已经收集的数据项的数目。然后更新外设和/或存储器地址以调整地址指针,使用要传输的剩余数据项的数目(禁止数据流时读取的值)更新 SxNDTR 寄存器,重新使能数据流,从停止点重新开始传输

4.16.流控制器
流控制器是用来控制要传输的数据数目。
其可以是DMA控制器、外设源或目标。
● DMA 控制器:要传输的数据项的数目在使能 DMA 数据流之前由软件编程到 DMA_SxNDTR 寄存器。
● 外设源或目标:当要传输的数据项的数目未知时属于这种情况。当所传输的是最后的数据时,外设通过硬件向 DMA 控制器发出指示。仅限能够发出传输结束信号的外设支持此功能,也就是:SDIO。在这种情况下,写入 DMA_SxNDTR 的值对 DMA 传输没有作用。实际上,不论写入什么值,一旦使能数据流,硬件即会将该值强制置为 0xFFFF。传输过程中,DMA_SxNDTR会递减,传输结束后,实际传输的数据数目 = 0xFFFF — DMA_SxNDTR。若DMA_SxNDTR 寄存器递减到0时,状态寄存器中相应数据流的 TCIFx 标志置 1 以指示强制的 DMA 传输完成。即使尚未置位最后的数据硬件信号(单独或突发),也会自动关闭数据流。已传输的数据不会丢失。这意味着即使在外设流控制模式下,DMA 在单独的事务中最多处理 65535 个数据项。在外设流控制器模式下禁止循环模式。

4.17.流配置过程
配置 DMA 数据流 x(其中 x 是数据流编号)时应遵守下面的顺序:

如果已使能数据流,则先通过重置 DMA_SxCR 寄存器中的 EN 位将其禁止,然后读取此位以确认没有正在进行的数据流操作。将此位写为 0 不会立即生效,因为实际上只有所有当前传输都已完成时才会将其写为 0。当所读取 EN 位的值为 0 时,才表示可以配置数据流。因此在开始任何数据流配置之前,需要等待 EN 位置 0。应将先前的数据块 DMA传输中在状态寄存器(DMA_LISR 和 DMA_HISR)中置 1 的所有数据流专用的位置 0,然后才可重新使能数据流。

在DMA_SxPAR 寄存器中设置外设端口寄存器地址。外设事件发生后,数据会从此地址移动到外设端口或从外设端口移动到此地址。

在 DMA_SxMA0R 寄存器(在双缓冲区模式的情况下还有 DMA_SxMA1R 寄存器)中设置存储器地址。外设事件发生后,将从此存储器读取数据或将数据写入此存储器。

在 DMA_SxNDTR 寄存器中配置要传输的数据项的总数。每出现一次外设事件或每出现一个节拍的突发传输,该值都会递减。

使用 DMA_SxCR 寄存器中的 CHSEL[2:0] 选择 DMA 通道(请求)。

如果外设用作流控制器而且支持此功能,请将 DMA_SxCR 寄存器中的 PFCTRL 位置 1。

使用 DMA_SxCR 寄存器中的 PL[1:0] 位配置数据流优先级。

配置 FIFO 的使用情况(使能或禁止,发送和接收阈值)。

配置数据传输方向、外设和存储器增量 / 固定模式、单独或突发事务、外设和存储器数据宽度、循环模式、双缓冲区模式和传输完成一半和/或全部完成,和/或 DMA_SxCR寄存器中错误的中断。

通过将 DMA_SxCR 寄存器中的 EN 位置 1 激活数据流。

4.18.错误管理
DMA 控制器可以检测到以下错误:

● 传输错误:当发生下列情况时,传输错误中断标志 (TEIFx) 将置 1:
—— DMA 读或写访问期间发生总线错误
—— 软件请求在双缓冲区模式下写访问存储器地址寄存器,但是,已使能数据流,并且当前目标存储器是受写入存储器地址寄存器操作影响的存储器

● FIFO 错误:如果发生下列情况,FIFO 错误中断标志 (FEIFx) 将置 1:
—— 检测到 FIFO 下溢情况
—— 检测到 FIFO 上溢情况(在存储器到存储器模式下由 DMA 内部管理请求和传输,所以在此模式下不检测溢出情况)
—— 当 FIFO 阈值级别与存储器突发大小不兼容时使能流(请参见 表 41 : FIFO 阈值配置 )

● 直接模式错误:只有当在直接模式下工作并且已将 DMA_SxCR 寄存器中的 MINC 位清零时,才能在外设到存储器模式下将直接模式错误中断标志 (DMEIFx) 置 1。当在先前数据未完全传输到存储器(因为存储器总线未得到授权)的情况下发生 DMA 请求时,该标志将置 1。在这种情况下,该标志指示有两个数据项相继传输到相同的目标地址,如果目标不能管理这种情况,会发生问题。

4.19.DMA 中断
一旦在 AHB 目标端口上传输了一半数据,传输一半标志 (HTIF) 便会置 1,如果传输一半中断使能位 (HTIE) 置 1,还会生成中断。传输结束时,传输完成标志 (TCIF) 便会置 1,如果传输完成中断使能位 (TCIE) 置 1,还会生成中断。

可以使用单独的中断使能位以实现灵活性。
在将使能控制位置‘1’前,应将相应的事件标志清零,否则会立即产生中断。

————————————————
版权声明:本文为CSDN博主「天启而凡」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yingzhefengyuzou/article/details/123594928

猜你喜欢

转载自blog.csdn.net/u012294613/article/details/131300446