STM32H7 DMA阅读笔记

DMA阅读笔记

  • DMA 的主要特性
    • DMA 功能描述
    • FIFO
      • FIFO flush
      • Direct Mode
    • DMA 传输
      • Peripheral-to-memory mode
      • Memory-to-peripheral mode
      • Memory-to-memory mode
    • 指针递增
    • Circular Mode
    • Double-buffer mode
    • 突发传输
    • DMA 传输完成
  • Stream 配置流程
  • DMA 配置总结

本阅读笔记阅读来自 《STM32H750xB》的 DMA 这一章

stm32h7 系统总线架构如下:
STM32H7 DMA阅读笔记_第1张图片
在上图中可以看到有 MDMA、DMA、BDMA 三种 DMA,其实本质上三者都是差不多的,只是位于的域不同。

DMA 的主要特性

一个 DMA 控制器有 8 个 streams,每个 stream 最多支持 115 个通道(请求)。每个 stream 拥有 4 字位宽 32 个大小的先进先出缓存区。这个缓存区可以被配置为循环缓存区。

stream 可以被配置为 FIFO 模式和 Direct 模式两种:

  • FIFO 模式:threshold level 是软件可设置的,可以设置为 1 / 4 1/4 1/4 1 / 2 1/2 1/2 3 / 4 3/4 3/4 的缓存区大小;
  • Direct 模式:每一个 DMA 请求会立即传输数据到(取出数据从)内存。例如:需要从内存传输一个数据到外设中时,DMA 会从内存中预取一个数据到内部的 FIFO buffer 中,确保当外设触发一个 DMA 请求时,可以立即将数据传输给外设。

传输的单次传输的数据数量可以由软件设置(DMA flow controller),也可以由外设决定(Peripheral flow controller):

  • DMA flow controller:传输的数量由软件进行设置,范围为 1 到 65535;
  • Peripheral flow controller:传输的数据个数一开始是未可知的,由源或终端的外设来控制,这个中断传输的信号由硬件负责设置。

当处于 FIFO 模式时,可以支持不同带宽的源和终端的传输,也就是说数据来源可以是 32 位而目的地可以是 8 位、16 位 也可以是 32 位 的。

DMA 控制器可以自动递增 源和目的 的存取地址,而实现类似于连续的内存拷贝操作。

STM32 的 DMA 还支持递增的突发传输(burst transfer),有 4、8、16 三种不同的突发模式,突发传输的大小是软件设置的,一般等于外设的 FIFO 空间大小。

每个 stream 都有自己独立的 5 种事件(event),DMA half transfer、DMA transfer complete、DMA transfer error、DMA FIFO error、direct mode error,这种事件被逻辑或(OR)在一起,共同产生一个单一的中断请求。

DMA 功能描述

STM32H7 DMA阅读笔记_第2张图片
如上图,DMA 一共有 STREAM0 ~ STREAM7 总共 8 个 stream,每个 stream 拥有属于自己的一个 FIFO buffer。由一个 Arbitrer(仲裁者) 来控制这些 stream 与外部总线设备 AHB memory 或 AHB peripheral 进行交互。

Arbitrer 会根据两个 AHB 端口的优先级来管理 8 个 stream 的 DMA 请求。优先级管理规则如下:

  • 软件上:每个 stream 的优先级可以通过 DMA_SxCR 寄存器进行配置,它们有四种水平:

    • Very high priority
    • High priority
    • Medium priority
    • Low priority
  • 硬件上:如果有两个 stream 的软件优先级相同,那么序号低的 stream 的优先级比序号高的 stream 的要高。如:stream0 和 stream1 的软件优先级都是 Very high,那么此时 stream0 的优先级大于 stream1。

如上图中,两个 port 和 stream 之间都是双箭头的,这些 stream 可以任意的组合方向提供源和目的地之间的单向传输链接,每个 stream 都可以被配置为:

  • 典型的传输方式(单 stream 的传输):memory-to-peripherals, peripherals-to-memory or memory-to-memory transfers
  • 双缓存区传输方式:这种方式下 DMA 读写一个 FIFO 缓存区,而应用程序从另一个 FIFO 缓存区进行读写。

FIFO

STM32H7 DMA阅读笔记_第3张图片
FIFO 的 threshold 和突发传输的设置:
STM32H7 DMA阅读笔记_第4张图片
突发传输的数据位宽大小 和 一次突发传输的数据个数 的乘积 不能大于 FIFO threshold 的大小,否则在软件启动 stream 时产生一次 FIFO error,位于 DMA_HISR 或 DMA_LISR 寄存器的 FEIFx 位上。

FIFO flush

The FIFO can be flushed when the stream is disabled by resetting the EN bit in the DMA_SxCR register and when the stream is configured to manage peripheral-to-memory or memory-to-memory transfers. If some data are still present in the FIFO when the stream is disabled, the DMA controller continues transferring the remaining data to the destination (even though stream is effectively disabled). When this flush is completed, the transfer complete status bit (TCIFx) in the DMA_LISR or DMA_HISR register is set.

The remaining data counter DMA_SxNDTR keeps the value in this case to indicate how many data items are currently available in the destination memory.

需要注意的点:当 FIFO 中的数据字节数(比如为 2 bytes)少于传输位宽的大小(比如为 4 bytes),这时传输会按照 4 bytes 位宽进行传输,这意味着可能有不可预测的值被写入了内存(目的)。

Direct Mode

FIFO 默认情况下就是工作在 Direct 模式。

为了避免需要等待 FIFO 被填充满(To avoid saturating the FIFO),最好把这个模式对应的 stream 设置为最高优先级。

这个模式在下面2种情况下被限制:

  • 源和目的的传输数据位宽必须一致;
  • 不能支持突发传输模式;

Direct mode 最好不要用在内存和内存之间的传输。

DMA 传输

传输的方向可以通过配置 DMA_SxCR 寄存器的 DIR[1:0] 位来实现
STM32H7 DMA阅读笔记_第5张图片
这时我们可以配置 DMA_SxCR 寄存器中的 PSIZE 和 MSIZE 位来分别设置 peripheral 或 memory 数据位宽,peripheral 和 memory 的读写地址在 DMA_SxPAR 和 DMA_SxM0AR/M1AR 寄存器中需要对齐读写位宽,如字对齐,或者半字对齐,取决于位宽的设置。

Peripheral-to-memory mode

STM32H7 DMA阅读笔记_第6张图片

  • 开启 FIFO 的模式:

    这个模式下(当开启了 DMA_SxCR 寄存器中的 EN 位后也就是开启了 DMA),每当外设发出一个请求,就会触发 stream 开始传输从源填(外设)充到 FIFO 中。

    一旦达到 FIFO 的 threshold 水平,FIFO 中的内容就会被清空存储到目的(内存)中。

    一旦 DMA_SxNDTR 寄存器达到零,当外设请求结束传输(在外设流控制器的情况下)或当 DMA_SxCR 寄存器中的 EN 位被软件清除时,传输就会停止。

  • 关闭 FIFO 的模式(Direct mode):

    这个模式下,FIFO 的 threshold 不会被使用。每当有一个数据被从外设传输到 FIFO 时,对应的这个数据也会被立马传输到目的。

    设置 DMA_SxFCR 寄存器的 DMDIS 位为零,关闭 FIFO 模式。

stream 能够访问 AHB 的源和目的当且仅当它获得了总裁成功,对下面其它两种传输方式同理。

Memory-to-peripheral mode

STM32H7 DMA阅读笔记_第7张图片

  • 开启 FIFO 模式:

    在这个模式下,一旦开启了 DMA_SxCR 寄存器中的 EN 位后,内存中的数据就会立马被传输到 DMA stream 内部的 FIFO 中。

    每次当外设发出请求时,FIFO 的内容就会被清空并存储到目的(外设),当 FIFO 中的数据少于或者等于预定义的 threshold 水平时,FIFO 就会重新从内存中的加载数据。

    一旦 DMA_SxNDTR 寄存器达到零,当外设请求结束传输(在外设流控制器的情况下)或当 DMA_SxCR 寄存器中的 EN 位被软件清除时,传输就会停止。

  • Direct 模式:

    这个模式下,一旦启动 DMA,stream 就会从内存中加载一个数据(preloaded data)到内部的 FIFO 中,一旦外设发出请求,这个数据就会被传输给外设,接着 DMA 会重新从内存中加载数据(preloaded data 大小的数据)到空的 FIFO 中,重复这个过程。

    这个 preloaded data 的大小不是只能为一个,可以通过设置 DMA_SxCR 寄存器中的 PSIZE 为来设置 preloaded data 的大小。

Memory-to-memory mode

STM32H7 DMA阅读笔记_第8张图片
一旦 DMA_SxCR 中的 EN 位被设置,DMA 的 stream 会立即开始传输,从源内存中读取数据填充满 FIFO(到达 threshold),然后立刻将 FIFO 中的数据清空被存储到目的内存中。

指针递增

在传输完成后,我们可以有选择的设置外设或内存的指针是否递增或者保证原理的位置,只需要设置 DMA_SxCR 寄存器中的 PINCMINC 位就可以设置。

如果启动了递增模式,下一次传输的地址将会在上一次传输的地址的基础上加 1 byte、2 bytes 或者是 4 bytes,这由传输的总线带宽决定。也就是由 DMA_SxCR 寄存器中的 PSIZE 和 MSIZE 控制。

为了优化包装操作,可以固定 外设地址 每次递增的偏移大小,无论在 AHB 外设端口上传输的数据的大小。DMA_SxCR 寄存器中的 PINCOS 位用于使 外设地址 每次递增的偏移大小 与外设 AHB 端口上的数据大小对齐,或者将偏移量大小与 32位 地址对齐(然后将地址加 4)。PINCOS 位只对 AHB 外设端口有影响。

如果设置了 PINCOS 位,那么下一次传输的地址将是上一次的地址加 4 bytes(自动对齐32位地址),这时候就不管 PSIZE 的值,无论单次传输多少个字节位宽的数据,都以 4 bytes 的偏移递增。但这个位(PINCOS)不会影响内存端口。

Circular Mode

这个模式主要用于环形缓存区和连续的数据流处理。通过设置 DMA_SxCR 寄存器的 CIRC 位来开启。

当启动了这个模式,传输数据的个数会被自动重置,例如:我们设置了 DMA_SxNDTR 寄存器要传输的数据的个数为 16 个,当 DMA_SxNDTR 的 NDT 位递减到零时,会重新加载初始化的值——16,然后循环再次发送。

Note:

当开启了循环模式,同时开启了内存的 burst mode(突发传输模式),必须遵守以下规则:

  1. $ DMA_SxNDTR = (MBurst) * ((Msize)/(Psize)) $

    Mburst Beat = 4,8 或 16(在 DMA_SxCR 寄存器中进行设置)

    ((MSize) / (Psize)) = 1,2 ,4, 1 2 \frac{1}{2} 21 1 4 \frac{1}{4} 41(Msize 和 Psize 表示 MSIZE 和 PSIZE)

例如:Mburst beat = 8(INCR8),MSIZE = ‘00’(byte)和 PSIZE = ‘01’(half-word)。这种情况下,DMA_SxNDTR 必须为 ( 8 ∗ 1 2 = 4 8 *\frac{1}{2} = 4 821=4

Double-buffer mode

设置 DMA_SxCR 寄存器的 DBM 位来开启 Double-buffer 模式。

一个 double buffer stream 不同于 single buffer 在于它有两个不同的 memory pointers。

当 double buffer 模式被开启,循环模式(circular mode)会被自动开启并且每一次传输结束,会交换两个 memory pointers。

这个模式下,DMA 控制器在每一次传输的结束时,从一个内存目标交换到另一个内存目标。这样的好处在于,软件能够和 DMA 并行独立的内存区域,软件读写其中一个区域,DMA 传输另一个区域。

double buffer 的 stream 可以工作在两个方向上(内存可以被配置为源或者目的)如下表所示:
STM32H7 DMA阅读笔记_第9张图片
Note:需要注意的是,如果开启了 double-buffer 模式,无法使用 memory-to-memory 模式。

突发传输

突发传输的大小可以通过软件进行配置,两个 AHB 端口可以独立进行配置。只需要设置 DMA_SxCR 寄存器中的 MBURST[1:0] 和 PBURST[1:0] 四个位就可以进行配置。

为了确保数据的连贯性,形成一次突发传输的一组数据是独立整体:AHB 在传输时会被锁住,并且 AHB 总线矩阵的仲裁者(arbiter),在突发传输的过程中不会脱离 DMA 主设备。

单一传输与突发传输的设置不同在于:

  • 当 AHB 外设端口被配置为单一传输,每一次 DMA 请求会产生一个数据传输。需要设置数据位宽 PSIZE 即可。

  • 当 AHB 外设端口被配置为突发传输,每一次 DMA 请求会产生 4、8 或 16 字节组合成的一组数据。需要设置突发传输组大小 PBURST 和数据位宽 PSIZE 两个。

    以上的考虑的点对 AHB 内存端口同理。

以下这段暂未理解:

The burst configuration has to be selected in order to respect the AHB protocol, where bursts must not cross the 1 Kbyte address boundary because the minimum address space that can be allocated to a single slave is 1 Kbyte. This means that the 1 Kbyte address boundary must not be crossed by a burst block transfer, otherwise an AHB error is generated, that is not reported by the DMA registers.

下列情况可能会发送不完整的突发传输:

  • 对于 AHB 外设端口:传输数据的总数(字节数)不等于单次突发传输的数据个数 和 数据位宽的乘积;
  • 对于 AHB 内存端口:FIFO 中存余的数据的总数(字节数)不等于单次突发传输的数据个数 和 数据位宽的乘积;

这种情况下,剩余那些不满住一次突发传输的数据会被作为 single mode 进行传输。

DMA 传输完成

不同的事件可以产生一个终止传输,通过设置 DMA_LISR 或 DMA_HISR 寄存器中的 TCIFx 位:

  • DMA 流控制模式:
    • 内存到外设传输模式时,DMA_SxNDTR 寄存器达到 0;
    • stream 在传输完成之前被关闭 和 (处于内存到内存内存到外设模式)所有 FIFO 中的数据已经被 flush 到内存中;
  • 外设流控制模式:
    • 外设产生了最后一个外部突发或者单一请求 并且 FIFO 中剩余的数据已经被传输到内存中;
    • 软件关闭了 stream 并且 FIFO 中剩余的数据已经被传输到内存中。

Note:只有 外设到内存 这传输情况下,才需要等待 FIFO 中的数据传输完毕。这个条件不应用在 内存到外设 的模式。

如果配置了 stream 处于非循环模式(noncircular mode)。在传输结束时,DMA 会被停止直到软件重新使能开启DMA,否则这期间DMA 请求将不会被服务。

Stream 配置流程

要配置一个 stream 可以参考以下步骤进行:

  1. 如果 stream 被使能了,先设置 DMA_SxCR 寄存器的 EN 位关闭使能,然后读取这个位确保当前这个 stream 没有正在处理的流操作。

    清除 EN 位并不会立马生效,还需要等待当前所有的传输完成。

    Writing this bit to 0 is not immediately effective since it is actually written to 0 once all the current transfers are finished.

    只要当 EN 位真正变为了零,才意味则 stream 可以被配置了。

    在重新启动流之前,必须先清楚 DMA_LISR 和 DMA_HISR 寄存器中的上一次传输的 DMA 传输的标志位。

  2. 设置外设地址寄存器 DMA_SxPAR 寄存器

  3. 设置内存地址寄存器 DMA_SxMA0R 寄存器(开启 double-buffer mode 时还需要开启 DMA_SxMA1R 寄存器)。The data is written to or read from this memory after the peripheral event.

  4. 配置 DMA_SxNDTR 寄存器中总的传输数据个数。After each peripheral event or each beat of the burst, this value is decremented.

  5. 使用 DMAMUX1 去规划 DMA 请求到 DMA 通道的路径;

  6. 如果外设需要作为 flow controller,设置 DMA_SxCR 寄存器中的 PFCTRL 位;

  7. 配置 stream 的优先级(DMA_SxCR 在 PL[1:0]);

  8. 配置 FIFO 的使用;(enable or disable, threshold in transmission and reception)

  9. 根据需要配置数据传输方向,外设和内存为递增或者固定模式,单一或者突发传输,外设和内存数据的位宽,是否循环模式,是否双缓存区模式 和 interrupts after half and/or full transfer,and/or errors in the DMA_SxCR register。

  10. 设置 DMA_SxCR 寄存器中的 EN 位开启 stream。

DMA 配置总结

STM32H7 DMA阅读笔记_第10张图片

你可能感兴趣的:(STM32,stm32,单片机,arm)