stm32专题十三:DMA(一)结构框图
DMA(data memory access)直接存储器访问,和串口USART、GPIO一样,也是一个外设。
把数据从一个地方搬到另一个地方,而不占用CPU。像串口发送数据,数据是一个一个的发。CPU首先把数据从内存(数组)拿到CPU内部的寄存器(CPU内部有一组暂存数据寄存器R1、R2、R3等),然后再发到串口的数据寄存器USART_DR,这些过程一直需要占用CPU。而当我们使用DMA时,如果CPU给DMA一个命令(把数据从内存发到串口),这时DMA就会实现这个功能,整个过程CPU是空闲的,可以去做其他事。比如,点亮一个LED,显示液晶屏LCD等。
DMA支持3种模式:
- Memory to Memory (这里的Memory可以是Flash或内部SRAM);
- Memory to Peripheral,这个最典型的应用是串口发送;
- Peripheral to Memory,这个最典型的应用就是ADC。ADC采集的数据是保存在数据寄存器DR,然后要读到内存;
DMA1有7个通道,DMA2有5个通道。
开始DMA时,以内存—串口为例。首先串口向CPU发送请求,告诉DMA,把数据从内存搬到发送数据寄存器中。这个请求由其中的一方来产生(发送方),通道为传输数据的管道,
有一个比较有意思的问题,就是数据对齐。我们通常要求发送方和接收方的数据长度要一致(数据对齐),但有些时候我们又会使用到不一致的情况(比如8位数据发送到定时器16位CCR寄存器),这时候该怎么办?我看到基本上很少有这种问题的详细解释与实验验证,但其实在中文参考手册中是有相关描述的。可以看到,对于DMA对齐的数据,直接操作没有问题。而当DMA数据不对其,比如8位传到16位时,如 DMA读到的8位数据为B0,实际写入的会是00B0,高8位用0补齐。当16位转8位数据时,如DMA读到B1B0,在写入时会把高8位丢弃,只写入B0位。这跟C语言的强制类型转换一致。
为了验证这个DMA数据不对齐配置是否正确,使用stm32CubeMX进行了一次测试(8位数据从内存传到16位CCR寄存器),配置如下,实验结果正确。
DMA每个通道具体对应的外设,可以看到,连接在同一通道上的外设,DMA请求同时只能有有一个生效。同理,DMA发送数据时,每个通道只能用作其中的一种。例如:DMA1通道1,任何时刻,只能作为ADC1 TIM2_CH3 TIM4_CH1中的一个数据管道。这里说的只是M-P和P-M,当使用M-M时,所有的通道都可以随意使用。
当有多个DMA请求一起来,就需要仲裁器来仲裁,到底哪个DMA请求先执行,这个在中文参考手册中有很详细的说明,具体如下:
那么我们就知道了,当多个DMA请求一起来时,先比较软件阶段,这里由DMA_CCRx寄存器的PL位分成4个等级,根据软件等级可以确定发送顺序。如果情况更加复杂,如有7路DMA请求,此时4个等级明显不够用,一定会出现等级相同的情况。此时,则比较硬件通道编号,编号越小等级越高。