DMA
-
DMA,全称Direct Memory Access,即直接存储器访问,可以在不需要CPU的参与下直接将数据从外设传输到内存,或是从内存传输到外设中,或从内存中的一个位置传输到另一个位置,在如今的大部分CPU中都有它的身影。
-
DMA控制器,用于设置DMA请求的各种参数,接收并处理DMA请求,当DMA传输完成,传输终止后还可能会产生中断。
-
除了需要DMA控制器,还需要开启DMA的请求,这种请求通常是由外设发起的,例如定时器溢出事件,串口接收数据寄存器非空,当使能了外设中的DMA请求之后,接收到对应事件便会自动触发一次DMA请求。
DMA 设备树描述
DMA控制器
在设备树中会有针对DMA控制器的描述,以STM32为例,下面是设备树中的DMA控制器
dma1: dma@40026000 {
compatible = "st,stm32-dma-v1";
#dma-cells = <4>;
reg = <0x40026000 0x400>;
interrupts = <11 0 12 0 13 0 14 0 15 0 16 0 17 0 47 0>;
clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x200000>;
status = "disabled";
};
- 与DMA控制器对应的绑定文件,其中 “#dma-cells” 为4代表每一个DMA通道的配置需要一个DMA控制器的 phandle 加上 四个参数
- channel 被使用的DMA通道
- DMA外设请求ID
- 32位的通道配置
- DMA的传输特性(fifo)
/* st,stm32-dma-v1.dtsi */
compatible: "st,stm32-dma-v1"
include: st,stm32-dma.yaml
properties:
"#dma-cells":
const: 4
dma-cells:
- channel
- slot
- channel-config
- features
/* st,stm32-dma.yaml */
description: |
STM32 DMA controller
The STM32 DMA is a general-purpose direct memory access controller
capable of supporting 5 or 6 or 7 or 8 independent DMA channels.
Each stm32 soc with a DMA is of a special version type, which could be
V1 like stm32F4 or stm32F2 socs, they include FIFO control registers
or V2 like stm32L4 soc or stm322WB, some also have DMAMUX controller
or V2bis like stm32F1 or stm32L1, where requests are multiplexed
compatible: "st,stm32-dma"
include: dma-controller.yaml
properties:
reg:
required: true
interrupts:
required: true
st,mem2mem:
type: boolean
description: If the DMA controller V1 supports memory to memory transfer
dma-offset:
type: int
description: |
offset in the table of channels when mapping to a DMAMUX
for 1st dma instance, offset is 0,
for 2nd dma instance, offset is the nb of dma channels of the 1st dma,
for 3rd dma instance, offset is the nb of dma channels of the 2nd dma
plus the nb of dma channels of the 1st dma instance, etc.
外设DMA请求
- 当设备需要使用DMA时,从 zephyr/include/zephyr/devicetree/dma.h 中的宏可以看出,如果想在驱动中访问设备树,必须在对应的节点中增加 dmas 和 dma-names 属性,其中 dmas 属性中保存了各个通道的配置参数,dma-names 则是每个dmas 中配置对应的名称。
dma1: dma@... { ... };
dma2: dma@... { ... };
n: node {
dmas = <&dma1 1 2 0x400 0x3>,
<&dma2 6 3 0x404 0x5>;
dma-names = "tx", "rx";
};
DT_DMAS_CTLR_BY_IDX(DT_NODELABEL(n), 0) // DT_NODELABEL(dma1)
DT_DMAS_CTLR_BY_NAME(DT_NODELABEL(n), rx) // DT_NODELABEL(dma2)
- 在Zephyr中使用DMA的外设并不多见,以STM32为例,仅在I2S,UART,SPI中使用到了DMA,如果要在其他外设中使用DMA,需要在drivers目录下对应的板载外设驱动中获取设备树相应配置,并参考其他外设实现对DMA的支持。