【STM32】 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主要特性

【STM32】 DMA模块控制器的保姆笔记总结_第1张图片

 DMA框架图

【STM32】 DMA模块控制器的保姆笔记总结_第2张图片

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

【STM32】 DMA模块控制器的保姆笔记总结_第3张图片

 DMA请求映射

【STM32】 DMA模块控制器的保姆笔记总结_第4张图片

 DMA数据流

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

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

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

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

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

【STM32】 DMA模块控制器的保姆笔记总结_第5张图片

                                             外设到寄存器模式

 

【STM32】 DMA模块控制器的保姆笔记总结_第6张图片

                                                 寄存器到外设模式

【STM32】 DMA模块控制器的保姆笔记总结_第7张图片

                                                   寄存器到寄存器模式

仲裁器


仲裁器为两个AHB主端口(存储器和外设端口)提供基于请求优先级的8个DMA数据流请
求管理,并启动外设/存储器访问序列。
优先级管理分为两个阶段:

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

硬件:如果两个请求具有相同的软件优先级,则编号低的数据流优先于编号高的数据
流。例如,数据流2的优先级高于数据流4。
位17:16 PL[1:0]: 优先级(Priority level)
 

【STM32】 DMA模块控制器的保姆笔记总结_第8张图片

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 //结束定义

你可能感兴趣的:(嵌入式,Cortex-,STM32,stm32,单片机,嵌入式硬件)