【STM32】 DMA模块控制器的保姆笔记总结

简介: DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。

前言

学习DMA部分的时候,我们需要学习的是什么?

  1. 掌握DMA部分的作用;
  2. 了解DMA的工作原理;
  3. 掌握DMA的编程;

DMA介绍

DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

作用:为CPU减负。

DMA工作流程

DMA是一个不需要CPU干预的独立硬件模块,可以进行外设和存储器以及存储器和存储器之间的数据传输,只需要CPU告诉它数据源在哪里,搬到哪里去,一次搬运多少字节,总共搬运多少个字节,然后启动DMA功能,那么DMA就会需要的时候自动进行数据的搬移。

STM32F4最多有2个DMA控制器,2个DMA控制器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求。每个数据流总共可以有多达8个通道(或请求),每个通道都有一个仲裁器,用于处理DMA请求间的优先级。

DMA主要特性

2345_image_file_copy_199.jpg

DMA框架图

2345_image_file_copy_200.jpg

通道选择:每个数据流都与一个DMA请求相关联,此DMA请求可以从8个可能的通道请求中选出。次选择由DMA_SxCR寄存器中的CHSEL[2:0]位控制。

2345_image_file_copy_201.jpg

DMA请求映射

2345_image_file_copy_202.jpg

DMA数据流

8个DMA控制流数据流都能够提供源和目标之间的单向传输链路。

每个数据流配置后都可以执行:

  • 常规类型事务:存储器到外设、外设到寄存器或者寄存器到寄存器的传输;
  • 双缓冲区类型事务:使用寄存器的两个寄存器指针的双缓冲区传输;

要传输的数据量多大65536,可以进行传输工作,并与连接到外设的AHB1端口进行连接

外设的源宽度有关。每个事务完成以后,包含要传输的数据项总量的寄存器都会进行递减。

2345_image_file_copy_203.jpg

外设到寄存器模式

2345_image_file_copy_204.jpg

   寄存器到外设模式

2345_image_file_copy_205.jpg

    寄存器到寄存器模式

仲裁器


仲裁器为两个AHB主端口(存储器和外设端口)提供基于请求优先级的8个DMA数据流请

求管理,并启动外设/存储器访问序列。

优先级管理分为两个阶段:

软件:每个数据流优先级都可以在DMA_ SxCR寄存器中配置。分为四个级别:

-非常高优先级

高优先级

中优先级

低优先级

硬件:如果两个请求具有相同的软件优先级,则编号低的数据流优先于编号高的数据

流。例如,数据流2的优先级高于数据流4。

位17:16 PL[1:0]: 优先级(Priority level)

2345_image_file_copy_206.jpg

DMA配置参数

1、通道

2、优先级

3、数据传输方向

4、存储器/外设 数据宽度

5、存储器/外设

6、地址是否增量

7、循环模式

8、数据传输量

DMA配置程序过程(串口发送DMA)

① 使能DMA时钟

② 初始化DMA通道参数

③使能串口DMA发送,串口DMA使能函数

④查询DMA的EN位,确保数据流就绪,可以配置

⑤设置通道当前剩余数据量

⑥使能DMA1通道,启动传输。

⑦查询DMA传输状态

⑧ 获取/设置通道当前剩余数据量

初始化函数

1、 模块初始化(不使用DMA应该怎么初始还是得写)

2、模块初始化后面添加开启模块内DMA使能位。(每个外设模块都会有一个DMA使能位)

3、USART1->CR3|=(1<<7);

4、按照DMA通道配置方法进行DMA相关寄存器初始化配置 UART1的发送函数:

5、添加DMA的UART1的发送函数

完整代码源

dma.c

#include "dma.h"
void usart3_dma_config(int n,char* sp)
{
  DMA_InitTypeDef DMA_InitStruct;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  DMA_InitStruct.DMA_BufferSize=n; 
  DMA_InitStruct.DMA_Channel=DMA_Channel_4;
  DMA_InitStruct.DMA_DIR=DMA_DIR_MemoryToPeripheral;
//  DMA_InitStruct.DMA_FIFOMode=DMA_FIFOMode_Disable;
//  DMA_InitStruct.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
  DMA_InitStruct.DMA_Memory0BaseAddr=(uint32_t)sp;
//  DMA_InitStruct.DMA_MemoryBurst=DMA_MemoryBurst_Single;//???????
  DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
  DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
  DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t) &USART3->DR;
//  DMA_InitStruct.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
  DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
  DMA_Init(DMA1_Stream3, &DMA_InitStruct);
  DMA_Cmd(DMA1_Stream3, ENABLE);
}
void usart3_dma_send()
{
  while(DMA_GetFlagStatus(DMA1_Stream3, DMA_FLAG_TCIF3)==0);
  DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3);
}
void adc1_dma_config(int n,char* sp)
{
  DMA_InitTypeDef DMA_InitStruct;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  DMA_InitStruct.DMA_BufferSize=n; 
  DMA_InitStruct.DMA_Channel=DMA_Channel_6;
  DMA_InitStruct.DMA_DIR=DMA_DIR_MemoryToPeripheral;
//  DMA_InitStruct.DMA_FIFOMode=DMA_FIFOMode_Disable;
//  DMA_InitStruct.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;
  DMA_InitStruct.DMA_Memory0BaseAddr=(uint32_t)sp;
//  DMA_InitStruct.DMA_MemoryBurst=DMA_MemoryBurst_Single;//???????
  DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
  DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;
  DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t) &ADC1->DR;
//  DMA_InitStruct.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
  DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
  DMA_Init(DMA2_Stream0, &DMA_InitStruct);
  DMA_Cmd(DMA2_Stream0, ENABLE);
}
void adc1_dma_send()
{
  while(DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF3)==0);
  DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF3);
}

dma.h

#ifndef _DMA_H_//如果没有 
#define _DMA_H_//定义
#include "stm32f4xx.h" 
void usart3_dma_config(int n,char* sp);
void usart3_dma_send(void);
void adc1_dma_config(int n,char* sp);
void adc1_dma_send(void);
#endif //结束定义
相关文章
|
5天前
【STM32】NRF24L01模块的收发调试(三)
【STM32】NRF24L01模块的收发调试
|
5天前
【STM32】NRF24L01模块的收发调试(二)
【STM32】NRF24L01模块的收发调试
|
5天前
【STM32】NRF24L01模块的收发调试(一)
【STM32】NRF24L01模块的收发调试
|
5天前
|
芯片
STM32F103标准外设库——中断应用/事件控制器(七)
STM32F103标准外设库——中断应用/事件控制器(七)
56 0
STM32F103标准外设库——中断应用/事件控制器(七)
|
5天前
毕业设计 基于stm32舞台彩灯控制器设计app控制系统
毕业设计 基于stm32舞台彩灯控制器设计app控制系统
|
5天前
|
传感器
|
5天前
|
存储 芯片
STM32 cubemx配置USART DMA传输
STM32 cubemx配置USART DMA传输
71 0
|
7月前
|
存储 物联网 芯片
STM32速成笔记(十四)—串口IAP
本文介绍了什么是IAP,IAP有什么作用,如何实现IAP。最后,给出了IAP的实现程序。
127 0
STM32速成笔记(十四)—串口IAP
|
7月前
|
芯片 内存技术
STM32速成笔记(十三)—低功耗模式
本文介绍了三种STM32低功耗模式的进入和退出方法,针对待机唤醒给出了程序设计。
147 0
STM32速成笔记(十三)—低功耗模式