DMA

1、DMA 简介
  DMA(Direct Memory Access,直接存储区访问)为实现数据高速在外设寄存器与存储器之间或者存储器与存储器之间传输提供了高效的方法。之所以称之为高效,是因为 DMA 传输实现高速数据移动过程无需任何 CPU 操作控制,这样节省的 CPU 资源可供其它操作使用。从硬件层次上来说, DMA 控制器是独立于 Cortex-M4 内核的,有点类似 GPIO、 USART 外设一般,只是 DMA 的功能是可以快速移动内存数据。
  STM32F4xx 系列的 DMA 功能齐全,工作模式众多,适合不同编程环境要求。
  STM32F4xx 系列的 DMA 支持外设到存储器传输、存储器到外设传输和存储器到存储器传输三种传输模式。这里的外设一般指外设的数据寄存器,比如 ADC、 SPI、 I2C、 DCMI 等等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等等
  外设到存储器传输就是把外设数据寄存器内容转移到指定的内存空间。比如进行 ADC采集时我们可以利用 DMA 传输把 AD 转换数据转移到我们定义的存储区中,这样对于多通道采集、采样频率高、连续输出数据的 AD 采集是非常高效的处理方法。
  存储区到外设传输就是把特定存储区内容转移至外设的数据寄存器中,这种多用于外设的发送通信,比如串口发送数据。
  存储器到存储器传输就是把一个指定的存储区内容拷贝到另一个存储区空间。功能类似于 C 语言内存拷贝函数 memcpy,利用 DMA 传输可以达到更高的传输效率,特别是DMA 传输是不占用 CPU 的,可以节省很多 CPU 资源。

  DMA 主要特性是:
    ● 双 AHB 主总线架构,一个用于存储器访问,另一个用于外设访问
    ● 仅支持 32 位访问的 AHB 从编程接口
    ● 每个 DMA 控制器有 8 个数据流,每个数据流有多达 8 个通道(或称请求)
    ● 每个数据流有单独的四级 32 位先进先出存储器缓冲区 (FIFO),可用于 FIFO 模式或直接模式:
      — FIFO 模式:可通过软件将阈值级别选取为 FIFO 大小的 1/4、 1/2 或 3/4
      — 直接模式
      每个 DMA 请求会立即启动对存储器的传输。当在直接模式(禁止 FIFO)下将 DMA请求配置为以存储器到外设模式传输数据时, DMA 仅会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
    ● 通过硬件可以将每个数据流配置为:
      — 支持外设到存储器、存储器到外设和存储器到存储器传输的常规通道
      — 也支持在存储器方双缓冲的双缓冲区通道
    ● 8 个数据流中的每一个都连接到专用硬件 DMA 通道(请求)
    ● DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)
    ● 每个数据流也支持通过软件触发存储器到存储器的传输(仅限 DMA2 控制器)
    ● 可供每个数据流选择的通道请求多达 8 个。此选择可由软件配置,允许几个外设启动 DMA请求
    ● 要传输的数据项的数目可以由 DMA 控制器或外设管理:
      — DMA 流控制器:要传输的数据项的数目是 1 到 65535,可用软件编程
      — 外设流控制器:要传输的数据项的数目未知并由源或目标外设控制,这些外设通过硬件发出传输结束的信号
    ● 独立的源和目标传输宽度(字节、半字、字):源和目标的数据宽度不相等时, DMA 自动封装/解封必要的传输数据来优化带宽。这个特性仅在 FIFO 模式下可用

2、 DMA 功能框图
  STM32F4xx 系列的 DMA 可以实现外设寄存器与存储器之间或者存储器与存储器之间传输三种模式,这要得益于 DMA 控制器是采样 AHB 主总线的,可以控制 AHB 总线矩阵来启动 AHB 事务。 下图为 DMA 控制器的框图。

image

  (1)①外设通道选择
  STM32F4xx 系列资源丰富,具有两个 DMA 控制器,同时外设繁多,为实现正常传输,DMA 需要通道选择控制。每个 DMA 控制器具有 8 个数据流,每个数据流对应 8 个外设请求。在实现 DMA 传输之前, DMA 控制器会通过 DMA 数据流 x 配置寄存器 DMA_SxCR(x为 0~7,对应 8 个 DMA 数据流)的 CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。

  外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。原则:一个外设通道的请求可以映射到多个数据流上,但一个数据流在同一时间只能服务于一个外设通道。

  8个数据流可以各选一个对应的通道同时启用和请求,但不能绝对并行执行。 当多个数据流同时请求DMA传输时,它们会进入一个仲裁过程,根据预设的优先级,一个一个地顺序执行,但在宏观时间尺度上,它们可以被看作是“同时工作”的。

  可以同时工作的是8个数据流(Stream),而不是8个通道(Channel)。 但它们的“同时工作”是并发而非绝对的并行。

  数据流(Stream):这是DMA的执行单元或“工人”。一共有8个(Stream 0-7)。每个数据流都是一个独立的数据传输引擎,可以执行从源地址到目标地址的数据搬运。我们配置和使能的是数据流。
  通道(Channel):这是数据流的请求源选择器或“工作任务单”。每个数据流(Stream)都需要选择一个通道(Channel 0-7),这个选择决定了是哪个外设(如USART1、TIM2)可以触发这个数据流进行传输。

  8个数据流是独立的执行单元,所以它们可以同时被启用、同时等待请求、同时进行数据传输。但是,当它们真正开始传输数据时,会遇到一个瓶颈:共享的总线矩阵。DMA需要透过总线矩阵来访问内存(SRAM/Flash)和外设。
  如果资源不冲突:例如,Stream 0 从ADC读取数据到SRAM,而Stream 5 从GPIO读取数据到另一个GPIO。它们使用的源总线和目标总线不同,总线矩阵可以允许它们高度并行地工作。
  如果资源冲突:例如,Stream 1 和 Stream 4 都需要同时从SRAM(通过System总线)读取数据。那么它们就不能同时进行,必须进入仲裁。仲裁器会根据它们优先级寄存器(DMA_SxCR中的PL位)的高低,来决定谁先谁后。
  所以,8个数据流是并发工作的,在微观上可能因为总线冲突而顺序执行,但在宏观上,它们共同高效地分担了CPU的数据搬运任务。

  通道(Channel)不能“同时工作”,通道不是一个执行单元,它只是一个多路选择器。你可以理解为:
    一个通道(比如Channel 4)代表一个“外设老板”(比如USART1_TX)。
    这个“老板”可以把任务分配给多个“工人”(数据流),比如Stream 2和Stream 5都可以选择服务于Channel 4。
    但是,一个“工人”(数据流)在同一时间只能为一个“老板”(通道)干活。
    结论:讨论通道是否“同时工作”没有意义,因为通道本身不工作,工作是数据流在做的。

  35 36 给出了 DMA 请求映射的示例。

image

image

  每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。比如SPI3_RX 请求,即 SPI3 数据发送请求,占用 DMA1 的数据流 0 的通道 0,因此当我们使用该请求时,我们需要在把 DMA_S0CR 寄存器的 CHSEL[2:0]设置为“000”,此时相同数据流的其他通道不被选择,处于不可用状态,比如此时不能使用数据流 0 的通道 1 即I2C1_RX 请求等等。
  查阅表 22-1 可以发现 SPI3_RX 请求不仅仅在数据流 0 的通道 0,同时数据流 2 的通道0 也是 SPI3_RX 请求,实际上其他外设基本上都有两个对应数据流通道,这两个数据流通道都是可选的,这样设计是尽可能提供多个数据流同时使用情况选择。
  (2)②仲裁器
  一个 DMA 控制器对应 8 个数据流,数据流包含要传输数据的源地址、目标地址、数据等等信息。如果我们需要同时使用同一个 DMA 控制器(DMA1 或 DMA2)多个外设请求时,那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就需要仲裁器来管理判断了。

  每个通道都有一个仲裁器,用于处理 DMA 请求间的优先级。
  仲裁器管理数据流方法分为两个阶段。第一阶段属于软件阶段,我们在配置数据流时可以通过寄存器设定它的优先级别,具体配置 DMA_SxCR 寄存器 PL[1:0]位,可以设置为非常高、高、中和低四个级别。第二阶段属于硬件阶段,如果两个或以上数据流软件设置优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权,比如数据流 2 优先级高于数据流 3。
  (3)③FIFO
  每个数据流都独立拥有四级 32 位 FIFO(先进先出存储器缓冲区)。 DMA 传输具有 FIFO模式和直接模式。
  直接模式在每个外设请求都立即启动对存储器传输。在直接模式下,如果 DMA 配置为存储器到外设传输那 DMA 会见一个数据存放在 FIFO 内,如果外设启动 DMA 传输请求就可以马上将数据传输过去。
  FIFO 用于在源数据传输到目标地址之前临时存放这些数据。可以通过 DMA 数据流xFIFO 控制寄存器 DMA_SxFCR 的 FTH[1:0]位来控制 FIFO 的阈值,分别为 1/4、 1/2、 3/4和满。如果数据存储量达到阈值级别时, FIFO 内容将传输到目标中。
  FIFO 对于要求源地址和目标地址数据宽度不同时非常有用,比如源数据是源源不断的字节数据,而目标地址要求输出字宽度的数据,即在实现数据传输时同时把原来 4 个 8 位字节的数据拼凑成一个 32 位字数据。此时使用 FIFO 功能先把数据缓存起来,分别根据需要输出数据。
FIFO 另外一个作用使用于突发(burst)传输。
  (4)④存储器端口、⑤外设端口
  DMA 控制器实现双 AHB 主接口,更好利用总线矩阵和并行传输。 DMA 控制器通过存储器端口和外设端口与存储器和外设进行数据传输,关系见图 22-2。 DMA 控制器的功能是快速转移内存数据,需要一个连接至源数据地址的端口和一个连接至目标地址的端口。DMA2(DMA 控制器 2)的存储器端口和外设端口都是连接到 AHB 总线矩阵,可以使用AHB 总线矩阵功能。 DMA2 存储器和外设端口可以访问相关的内存地址,包括有内部Flash、内部 SRAM、 AHB1 外设、 AHB2 外设、 APB2 外设和外部存储器空间。
  DMA1 的存储区端口相比 DMA2 的要减少 AHB2 外设的访问权,同时 DMA1 外设端口是没有连接至总线矩阵的,只有连接到 APB1 外设,所以 DMA1 不能实现存储器到存储器传输。

image

  (5)⑥编程端口
  AHB 从器件编程端口是连接至 AHB2 外设的。 AHB2 外设在使用 DMA 传输时需要相关控制信号。

3、DMA 数据配置
  DMA 工作模式多样,具有多种可能工作模式,具体可能配置见表 22-3。

image

  (1)DMA 传输模式
  DMA2 支持全部三种传输模式,而 DMA1 只有外设到存储器和存储器到外设两种模式。
  模式选择可以通过 DMA_SxCR 寄存器的 DIR[1:0]位控制,进而将 DMA_SxCR 寄存器的EN 位置 1 就可以使能 DMA 传输。
  在 DMA_SxCR 寄存器的 PSIZE[1:0]和 MSIZE[1:0]位分别指定外设和存储器数据宽度大小,可以指定为字节(8 位)、半字(16 位)和字(32 位),我们可以根据实际情况设置。直接模式要求外设和存储器数据宽度大小一样,实际上在这种模式下 DMA 数据流直接使用PSIZE, MSIZE 不被使用。
  (2)源地址和目标地址
  DMA 数据流 x 外设地址 DMA_SxPAR(x 为 0~7)寄存器用来指定外设地址,它是一个32 位数据有效寄存器。 DMA 数据流 x 存储器 0 地址 DMA_SxM0AR(x 为 0~7) 寄存器和DMA 数据流 x 存储器 1 地址 DMA_SxM1AR(x 为 0~7) 寄存器用来存放存储器地址,其中DMA_SxM1AR 只用于双缓冲模式, DMA_SxM0AR 和 DMA_SxM1AR 都是 32 位数据有效的。
  当选择外设到存储器模式时,即设置 DMA_SxCR 寄存器的 DIR[1:0] 位为“00”,DMA_SxPAR 寄存器为外设地址,也是传输的源地址, DMA_SxM0AR 寄存器为存储器地址,也是传输的目标地址。对于存储器到存储器传输模式,即设置 DIR[1:0] 位为“10”时,采用与外设到存储器模式相同配置。而对于存储器到外设,即设置 DIR[1:0]位为“01”时,DMA_SxM0AR 寄存器作为为源地址, DMA_SxPAR 寄存器作为目标地址。
  (3)流控制器
  流控制器主要涉及到一个控制 DMA 传输停止问题。 DMA 传输在 DMA_SxCR 寄存器的 EN 位被置 1 后就进入准备传输状态,如果有外设请求 DMA 传输就可以进行数据传输。很多情况下,我们明确知道传输数据的数目,比如要传 1000 个或者 2000 个数据,这样我们就可以在传输之前设置 DMA_SxNDTR 寄存器为要传输数目值, DMA 控制器在传输完这么多数目数据后就可以控制 DMA 停止传输。
  DMA 数据流 x 数据项数 DMA_SxNDTR(x 为 0~7)寄存器用来记录当前仍需要传输数目,它是一个 16 位数据有效寄存器,即最大值为 65535,这个值在程序设计是非常有用也是需要注意的地方。我们在编程时一般都会明确指定一个传输数量,在完成一次数目传输后DMA_SxNDTR 计数值就会自减,当达到零时就说明传输完成。

  如果某些情况下在传输之前我们无法确定数据的数目,那 DMA 就无法自动控制传输停止了,此时需要外设通过硬件通信向 DMA 控制器发送停止传输信号。这里有一个大前提就是外设必须是可以发出这个停止传输信号,只有 SDIO 才有这个功能,其他外设不具备此功能。
  (4)循环模式
  循环模式相对应于一次模式。一次模式就是传输一次就停止传输,下一次传输需要手动控制,而循环模式在传输一次后会自动按照相同配置重新传输,周而复始直至被控制停止或传输发生错误。
  通过 DMA_SxCR 寄存器的 CIRC 位可以使能循环模式。
  (5)传输类型
  DMA 传输类型有单次(Single)传输和突发(Burst)传输。突发传输就是用非常短时间结合非常高数据信号率传输数据,相对正常传输速度,突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度,有点类似达到数据块“秒传”效果。为达到这个效果突发传输过程要占用 AHB 总线,保证要求每个数据项在传输过程不被分割,这样一次性把数据全部传输完才释放 AHB 总线;而单次传输时必须通过 AHB 的总线仲裁多次控制才传输完成。
  单次和突发传输数据使用具体情况参考表 22-4。其中 PBURST[1:0]和 MBURST[1:0]位是位于 DMA_SxCR 寄存器中的,用于分别设置外设和存储器不同节拍数的突发传输,对应为单次传输、 4 个节拍增量传输、 8 个节拍增量传输和 16 个节拍增量传输。 PINC 位和MINC 位是寄存器   DMA_SxCR 寄存器的第 9 和第 10 位,如果位被置 1 则在每次数据传输后数据地址指针自动递增,其增量由 PSIZE 和 MSIZE 值决定,比如,设置 PSIZE 为半字大小,那么下一次传输地址将是前一次地址递增 2。

image

   突发传输与 FIFO 密切相关,突发传输需要结合 FIFO 使用,具体要求 FIFO 阈值一定要是内存突发传输数据量的整数倍。 FIFO 阈值选择和存储器突发大小必须配合使用,具体参考表 22-5。

image

  (6)直接模式
  默认情况下, DMA 工作在直接模式,不使能 FIFO 阈值级别。
  直接模式在每个外设请求都立即启动对存储器传输的单次传输。直接模式要求源地址和目标地址的数据宽度必须一致,所以只有 PSIZE 控制,而 MSIZE 值被忽略。突发传输是基于 FIFO 的所以直接模式不被支持。另外直接模式不能用于存储器到存储器传输。
  在直接模式下,如果 DMA 配置为存储器到外设传输那 DMA 会见一个数据存放在FIFO 内,如果外设启动 DMA 传输请求就可以马上将数据传输过去。
  (7)双缓冲模式
  设置 DMA_SxCR 寄存器的 DBM 位为 1 可启动双缓冲传输模式,并自动激活循环模式。双缓冲不应用与存储器到存储器的传输。双缓冲模式下,两个存储器地址指针都有效,即DMA_SxM1AR 寄存器将被激活使用。开始传输使用 DMA_SxM0AR 寄存器的地址指针所对应的存储区,当这个存储区数据传输完 DMA 控制器会自动切换至 DMA_SxM1AR 寄存器的地址指针所对应的另一块存储区,如果这一块也传输完成就再切换至 DMA_SxM0AR寄存器的地址指针所对应的存储区,这样循环调用。
  当其中一个存储区传输完成时都会把传输完成中断标志 TCIF 位置 1,如果我们使能了DMA_SxCR 寄存器的传输完成中断,则可以产生中断信号,这个对我们编程非常有用。另外一个非常有用的信息是 DMA_SxCR 寄存器的 CT 位,当 DMA 控制器是在访问使用DMA_SxM0AR 时 CT=0,此时 CPU 不能访问 DMA_SxM0AR,但可以向 DMA_SxM1AR填充或者读取数据;当 DMA 控制器是在访问使用 DMA_SxM1AR 时 CT=1,此时 CPU 不能访问 DMA_SxM1AR,但可以向 DMA_SxM0AR 填充或者读取数据。另外在未使能DMA 数据流传输时,可以直接写 CT 位,改变开始传输的目标存储区。
  双缓冲模式应用在需要解码程序的地方是非常有效的。比如 MP3 格式音频解码播放,MP3 是被压缩的文件格式,我们需要特定的解码库程序来解码文件才能得到可以播放的PCM 信号,解码需要一定的实际,按照常规方法是读取一段原始数据到缓冲区,然后对缓冲区内容进行解码,解码后才输出到音频播放电路,这种流程对 CPU 运算速度要求高,很容易出现播放不流畅现象。如果我们使用 DMA 双缓冲模式传输数据就可以非常好的解决这个问题,达到解码和输出音频数据到音频电路同步进行的效果。
  (8)DMA 中断
  每个 DMA 数据流可以在发送以下事件时产生中断:
  1) 达到半传输: DMA 数据传输达到一半时 HTIF 标志位被置 1,如果使能 HTIE 中断控制位将产生达到半传输中断;
  2) 传输完成: DMA 数据传输完成时 TCIF 标志位被置 1,如果使能 TCIE 中断控制位将产生传输完成中断;
  3) 传输错误: DMA 访问总线发生错误或者在双缓冲模式下试图访问“受限”存储器地址寄存器时 TEIF 标志位被置 1,如果使能 TEIE 中断控制位将产生传输错误中断;
  4) FIFO 错误:发生 FIFO 下溢或者上溢时 FEIF 标志位被置 1,如果使能 FEIE 中断控制位将产生 FIFO 错误中断;
  5) 直接模式错误:在外设到存储器的直接模式下,因为存储器总线没得到授权,使得先前数据没有完成被传输到存储器空间上, 此时 DMEIF 标志位被置 1,如果使能 DMEIE 中断控制位将产生直接模式错误中断。

posted @ 2025-10-30 17:25  孤情剑客  阅读(62)  评论(0)    收藏  举报