DMA外设

总结stm32中的片上外设DMA

介绍

片上外设

DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用CPU,即在传输数据的时候,CPU可以干其他的事情,好像是多线程一样。

这里的存储器可以是FLASH也可以是SARM。

DMA只是一帮助cpu缓解压力的“小cpu”,其并不是存储空间,而是控制数据传输的方向。

stm32f103系列DMA有DMA1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道,不同的DMA控制器的通道对应着不同的外设请求, 这决定了我们在软件编程上该怎么设置,具体见DMA请求映像表。

DMA的组成

控制器

最主要的是有DMA控制器,其控制着整个DNA外设,并且在stm32中一般有两个DMA。一个是DMA1一个是DMA2,DMA是只有大容量、互联型的产品中才会有。

DMA具有12个独立可编程的通道,其中DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的DMA请求。 虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

DMA的映射如下:

其中ADC3、SDIO和TIM8的DMA请求只在大容量产品中存在,这个在具体项目时要注意。

仲裁器

当有多个通道同时传输信号时,我们需要仲裁先后顺序。这分为两步:

  1. 软件自定义,通过在DMA_CCRx寄存器中设置,有4个等级:非常高、高、中和低四个优先级。我们可以自己控制优先级。
  2. 硬件判断,当没有设置软件优先级或者是软件优先级是相同的,此时通过判断通道号,越小优先级越高。

在大容量产品和互联型产品中, DMA1控制器拥有高于DMA2控制器的优先级。


DMA的数据配置

DMA作为一个关于数据传输的片上外设,其最重要的六点是:

数据从哪里来、数据到哪里去、传输多少数据、分为几次传输、一次传输数据的单位是多少。传输完成了吗
下面我们来逐个解决这些问题

数据从哪里来、到哪里去

在stm32中,只有以下三种数据传输的方向:

  1. 外设到存储器:以ADC采集为例。DMA外设寄存器的地址对应的就是ADC数据寄存器的地址, DMA存储器的地址就是我们自定义的变量(用来接收存储AD采集的数据)的地址。方向我们设置外设为源地址。
  2. 存储器到外设:stm32发送数据到上位机,这个存储器就是FLASH,外设就是USART
  3. 存储器到存储器:将SARM中的数据传输到FLASH中。跟上面两个不一样的是,这里需要把DMA_CCR位14:MEM2MEM:存储器到存储器模式配置为1,启动M2M模式。

这里说的外设实际上就是通过串口来实现的,所以说是外设到存储器,实际上是从串口到存储器。

传输多少、一次传输单位是什么

要传输好数据,我们必须使双方的数据传输的单位(大小)一致。

数据宽度

当外设和存储器之间传数据时,两边的数据宽度应该设置为一致大小。

设置增量模式

在DMA控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置两边数据指针的增量模式。 外设的地址指针由DMA_CCRx的PINC配置,存储器的地址指针由MINC配置。以串口向电脑发送数据为例,要发送的数据很多,每发送完一个,那么存储器的地址指针就应该加1,而串口数据寄存器只有一个, 那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定。

一次传输还是多次传输

传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一次之后就停止,要想再传输的话, 必须关断DMA使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输, 不断的重复。具体的由DMA_CCR寄存器的CIRC 循环模式位控制。

传输完成了吗?

数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个DMA通道在DMA传输过半、 传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会产生中断。有关各个标志位的详细描述请参考DMA中断状态寄存器DMA_ISR的详细描述。


DMA编程

DMA_ InitTypeDef初始化结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; // 外设地址
uint32_t DMA_MemoryBaseAddr; // 存储器地址
uint32_t DMA_DIR; // 传输方向
uint32_t DMA_BufferSize; // 传输数目
uint32_t DMA_PeripheralInc; // 外设地址增量模式
uint32_t DMA_MemoryInc; // 存储器地址增量模式
uint32_t DMA_PeripheralDataSize; // 外设数据宽度
uint32_t DMA_MemoryDataSize; // 存储器数据宽度
uint32_t DMA_Mode; // 模式选择
uint32_t DMA_Priority; // 通道优先级
uint32_t DMA_M2M; // 存储器到存储器模式
} DMA_InitTypeDef;

DMA配置步骤

  1. 使用RCC函数打开DMA时钟
  2. 定义配置结构体,初始化配置
  3. 使用DMA_Init函数完成初始化
  4. 使用DMA_Cmd函数开启DMA

DMA外设
https://ysc2.github.io/ysc2.github.io/2023/11/26/DMA外设/
作者
Ysc
发布于
2023年11月26日
许可协议