学习DMA部分的时候,我们需要学习的是什么?
DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
作用:为CPU减负。
DMA是一个不需要CPU干预的独立硬件模块,可以进行外设和存储器以及存储器和存储器之间的数据传输,只需要CPU告诉它数据源在哪里,搬到哪里去,一次搬运多少字节,总共搬运多少个字节,然后启动DMA功能,那么DMA就会需要的时候自动进行数据的搬移。
STM32F4最多有2个DMA控制器,2个DMA控制器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求。每个数据流总共可以有多达8个通道(或请求),每个通道都有一个仲裁器,用于处理DMA请求间的优先级。
通道选择:每个数据流都与一个DMA请求相关联,此DMA请求可以从8个可能的通道请求中选出。次选择由DMA_SxCR寄存器中的CHSEL[2:0]位控制。
DMA数据流
8个DMA控制流数据流都能够提供源和目标之间的单向传输链路。
每个数据流配置后都可以执行:
要传输的数据量多大65536,可以进行传输工作,并与连接到外设的AHB1端口进行连接
外设的源宽度有关。每个事务完成以后,包含要传输的数据项总量的寄存器都会进行递减。
外设到寄存器模式
寄存器到外设模式
寄存器到寄存器模式
仲裁器为两个AHB主端口(存储器和外设端口)提供基于请求优先级的8个DMA数据流请
求管理,并启动外设/存储器访问序列。
优先级管理分为两个阶段:
●
软件:每个数据流优先级都可以在DMA_ SxCR寄存器中配置。分为四个级别:
-非常高优先级
高优先级
中优先级
低优先级
●
硬件:如果两个请求具有相同的软件优先级,则编号低的数据流优先于编号高的数据
流。例如,数据流2的优先级高于数据流4。
位17:16 PL[1:0]: 优先级(Priority level)
1、通道
2、优先级
3、数据传输方向
4、存储器/外设 数据宽度
5、存储器/外设
6、地址是否增量
7、循环模式
8、数据传输量
① 使能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 //结束定义