【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 //结束定义
相关文章
|
6月前
|
芯片
STM32F103标准外设库——中断应用/事件控制器(七)
STM32F103标准外设库——中断应用/事件控制器(七)
417 0
STM32F103标准外设库——中断应用/事件控制器(七)
|
6月前
【STM32】NRF24L01模块的收发调试(三)
【STM32】NRF24L01模块的收发调试
191 0
|
6月前
【STM32】NRF24L01模块的收发调试(二)
【STM32】NRF24L01模块的收发调试
126 0
|
6月前
【STM32】NRF24L01模块的收发调试(一)
【STM32】NRF24L01模块的收发调试
180 0
|
6月前
毕业设计 基于stm32舞台彩灯控制器设计app控制系统
毕业设计 基于stm32舞台彩灯控制器设计app控制系统
111 0
|
14天前
|
存储 数据管理 数据处理
处理STM32 DMA方式下的HAL_UART_ERROR_ORE错误
通过正确配置UART和DMA、实现有效的错误处理回调函数以及优化数据处理和缓冲区管理,可以有效处理STM32中DMA方式下的 `HAL_UART_ERROR_ORE`错误。这些方法确保了数据的高效传输和处理,避免了因数据溢出导致的通信中断和数据丢失。希望这些解决方案能够帮助您在实际应用中更好地应对和解决此类问题。
88 0
|
6月前
|
传感器
STM32标准库ADC和DMA知识点总结-1
STM32标准库ADC和DMA知识点总结
|
5月前
|
传感器 数据格式
【STM32】DHT11温湿度模块传感器详解&代码
【STM32】DHT11温湿度模块传感器详解&代码