本帖最后由 cruelfox 于 2019-12-28 17:58 编辑
学习资料:STM32不同系列产品的参考手册(Reference Manual)
我最早使用STM32 MCU的DMA是在 STM32F072 这个产品上,读过手册明白后用它并不复杂。再后来,用到 STM32F446 的时候,忽然发现以前写的 DMA 操作代码不能直接移植过去,才明白不同 STM32 的DMA控制器设计是不完全一样的。此后,用一款没用过的型号时我就要留意一下。在这里写个我遇到过的DMA控制器的(不同版本)相互差异比较。
1. F0x 系列里面大部分MCU, 以及 F10x, F3xx 的 DMA,最简单的那种。
一个DMA控制器有几个通道(Channel),最多支持7个通道。F0x大多数只有一个DMA控制器,少数如F072则有DMA1和DMA2两个控制器,各自的通道是独立的。每个通道各自的配置有:
CCR, CNDTR, CPAR, CMAR 这四个寄存器。其中 CCR 是控制寄存器,配置这个通道的传输方式,CNDTR 决定传输数量,CPAR 和 CMAR 分别是作为传输源或目标的设备、内存的地址。
每个通道的优先级有四级可选。
每个通道可以有三种类型事件引发中断:TE(传输错误)、TC(传输完成)、HT(传输一半完成),在CCR寄存器中设置相应的中断允许位。
每个DMA控制器还有一个公用的中断状态寄存器 ISR, 和一个公用的中断标志清除寄存器 IFCR.
那么,一个片上设备要使用DMA传输,除了在设备中配置DMA请求使能之外,该如何配置DMA控制器呢? 首先是确定用哪个DMA通道——根据参考手册中的表,例如下面这个
这些DMA请求是分配到几个DMA通道上的,另外根据系统SYSCFG的寄存器设置,可以有两个映射模式,对某些DMA请求的分配进行了调整。总的来说,设备的DMA请求类型个数是远多于DMA通道数的,而每个DMA通道在一个应用场景下只能为一个设备服务(因为传输方式、地址只有一个设置),所以如果有两个设备的DMA请求分配到同一个DMA通道的话,就会冲突,也就是只能允许其中一个使用DMA功能。尽管使用SYSCFG改变映射模式可以稍微协调一下DMA冲突问题,还是很有限。一定无法避免DMA冲突的时候,就要另选型号了。
2. F09x, L4xx 等当中的 DMA 控制器,上一种的增强
与上一种相比较,在 DMA 请求的分配上有所功能增强。上一种当中,每个DMA通道对应的所有来自设备的DMA请求是被"OR"起来的,所以不能同时使能,否则冲突。在 F09x以及 L4x系列当中,增加了多路选择器来避免这个问题。例如下面的图和表:
每个通道有一个Request Number可以配置,这样就只能选择一个DMA请求了,避免了冲突。在这样的机制下,一个设备的DMA请求可以连接到多个通道上,以及不同DMA控制器上,配置起来灵活性就比上一种明显好了。
在 DMA 控制器寄存器中,增加了一个公用的 CSELR 寄存器用于选择各个通道的请求。
当然,引入选择器以后,也不可能满足任意设备的同时使用DMA的需求,毕竟通道就那么多个,僧多粥少嘛。
3. F20x, F4xx, F7xx 中的第二代 DMA 控制器
姑且叫做“第二代”吧,相比上面所说的简单,这一种要复杂不少。首先是“通道”(Channel)的概念不一样了,不要和上一种控制器混淆,在这一种DMA控制器上面,负责一个设备和内存之间传输的硬件单元叫做 Stream——“流”,而 Channel 变成了每个DMA Stream请求来源的概念。
结构上,最重大的变化是每个DMA控制器从一个AHB master接口变成了两个AHB master接口,并且增加了FIFO功能,使得吞吐性能提高。
每个DMA流(一个控制器最多8个流)的寄存器表:
一共是 CR, NDTR, PAR, M0AR, M1AR, FCR 六个寄存器,和第一代的控制器比较除了名称改变之外,因为多了内存双缓冲模式所以增加一个内存地址寄存器,另外增加一个用于FIFO的寄存器。
因为有FIFO,可以支持数据打包、突发传输这两个新功能;另外还支持设备流控制功能(似乎只有SDIO一个设备可以用)。
从编程的角度来看,只要用不到新的特性的话其实和上一代的DMA控制器编程操作方式差不多,只是寄存器内容变了一些而已。
至于DMA stream与设备请求的分配,由每个CR寄存器中CHSEL[2..0]位选择,一共有8种选择(通道),例如下表:
因此DMA控制器也不再有公用的 CSELR 了,此外因为中断标志增多,ISR和IFCR分别升级为 LISR, HISR 和 LIFCR, HIFCR.
4. DMAMUX 的出现
我见到 DMAMUX 最早是在 STM32L4+ 上。虽然 L4R5 的 DMA 控制器是第一代的,但没有了 CSELR, 取代它的功能的是一个新的单独硬件——DMAMUX.
单说DMA请求分配功能的话,DMAMUX可以把任意一个来自设备的DMA请求分配给任何一个DMA通道。于是彻底解决了DMA请求冲突的问题——只要使用DMA请求总数不超过总的通道数量。
DMAMUX还有附加的功能,可以对DMA请求进行干预。
在最新的 STM32 产品例如 H7xx, G0xx, G4xx 上,大概都可以见到 DMAMUX.
5. STM32H7 中的 MDMA, BDMA
在 H7 系列里面,情况就变得很复杂,除了DMA1, DMA2 (这两个和F4xx, F7xx中的DMA基本一样),又多出来一个 MDMA 和一个 BDMA.
不过,如果根据 H7 Dx domain 的划分来看就好理解了。这三组DMA的用途不一样:MDMA属于D1 Domain, 是在64-bit AXI总线上的,主要用于Flash、AXI SRAM、FMC等内存设备;DMA1, DMA2是传统DMA, 在D2 Domain 32-bit AHB总线上,主要用于SRAM1, SRAM2, SRAM3;BDMA属于D3 Domain, 主要用于SRAM4.
另外,比较寄存器表可以发现 BDMA 和第一代的 DMA 很像,区别在于增加了双缓冲功能。但MDMA则是全新的一个设备,寄存器多了很多,差别明显。
总结:
除了 H7 以外的 STM32 MCU, DMA控制器大概有两种版本。后一种版本有FIFO,功能多一些。在硬件设备的DMA请求分配上,不同型号MCU的设计往往是不一样的,在系统设计时要注意。最新的几个系列额外有DMAMUX硬件,用起来就灵活了很多。
H7系列是一个复杂的系统,DMA控制器有三类,应当根据需求选择合适的DMA控制器。
|