这次来记录下DMA实现的过程
DMA(Direct Memory Access,直接存储区访问)为实现数据高速在外设寄存器与存储器之
间或者存储器与存储器之间传输提供了高效的方法。
DMA 支持外设到存储器传输、存储器到外设传输和存储器到存储器传
输三种传输模式。这里的外设一般指外设的数据寄存器,比如 ADC、 SPI、 I2C、 DCMI 等
等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等等。
F1,F4系列是常规的DMA,H7则加入了DMAMUX这个机制。
来看F4的DMA,先来看系统框图
可知有几个部分组成,第一部分是外设通道的选择,第二部分是数据流仲裁器,第三部分是FIFO。
1.外设通道的选择
需要查看芯片手册,
例如 SPI1的RX,则可以选择通道3的数据流0,或者通道3的数据流2
2.数据流仲裁器
看框图我们可以知道同一时刻只能选择同一个数据流。比如通道2和通道3的SPI5_TX和SPI1_TX。2者都选用了数据流3,同一时刻只能用一个。
一个 DMA 控制器对应 8 个数据流,数据流包含要传输数据的源地址、目标地址、数
据等等信息。如果我们需要同时使用同一个 DMA 控制器(DMA1 或 DMA2)多个外设请求
时,那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就
需要仲裁器来管理判断了。
仲裁器管理数据流方法分为两个阶段。第一阶段属于软件阶段,我们在配置数据流时
可以通过寄存器设定它的优先级别,具体配置 DMA_SxCR 寄存器 PL[1:0]位,可以设置为
非常高、高、中和低四个级别。第二阶段属于硬件阶段,如果两个或以上数据流软件设置
优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权,比如数据流 2 优
先级高于数据流 3。
DMA可以选择单次模式或者循环模式。单次模式就是只是用一次,一旦传输完成后就停止。而循环模式在传输一次后会自动按照相同配置重新传输,周而复始直至被控制停止或传输发生错误。
DMA还可以是用双缓存模式。比如外设到存储器,使用时会开辟2快存储器内存,由自己制定地址。当传输完成的时候,会自动切换内存地址,就是乒乓buffer。
DMA也有自己的中断,一般用的比较多的是传输完成中断,表示此次DMA搬运完成。
typedef struct {
uint32_t Channel; //通道选择
uint32_t Direction; //传输方向
uint32_t DMA_BufferSize; //数据数目
uint32_t PeriphInc; //外设递增
uint32_t MemInc; //存储器递增
uint32_t PeriphDataAlignment; //外设数据宽度
uint32_t MemDataAlignment; //存储器数据宽度
uint32_t Mode; //模式选择
uint32_t Priority; //优先级
uint32_t FIFOMode; //FIFO 模式
uint32_t FIFOThreshold; //FIFO 阈值
uint32_t MemBurst; //存储器突发传输
uint32_t PeriphBurst; //外设突发传输
} DMA_InitTypeDef;
DMA的外设初始化的结构体,按照要求配置就行。
DMA的模式有正常模式和循环模式。
正常模式是指一次DMA传输完成后,将不会再次进行DMA。必须要以手动的方式来启动下一次DMA
循环模式是指一次DMA传输完成后,会再次自动进行DMA传输。
也可以和定时器结合起来,当定时器事件更新时,触发相应的DMA