初识DAM

1.DMA的简介

  • 首先先跟大家说明一下什么叫DMA,英文名称Direct Memory Access,简称DMA,翻译成中文就是直接存储器访问,是一种让硬件设备直接直接与内存直间接进行传输数据的技术,这种机制可以大大减轻CPU的负载

    那么,我们为什么要,设置DMA呢,因为我们知道CPU有转移数据、计算、控制程序转移等很多功能,而且CPU无时无刻的在处理着大量任务,但是有些事情就不那么重要,比如说数据的复制和转移,如果我们把这部分CPU资源拿出来,去处理其他更重要的任务,这样就可以提高CPU的利用率,由此DMA产生了

下面用ADC采集数据发送到SRAM中

如下图所示,当数据量过大时,会严重占用CPU资源

下面就是采用DMA则,不会占用CPU资源,当数据量过大时,也对CPU没有影响,可以大大提高CPU利用率

简单介绍一下他的工作流程

DMA传输时外设对DMA控制器发出请求。 DMA控制器收到请求,触发DMA工作。 DMA控制器从AHB外设获取ADC采集的数据,存储到DMA通道中 DMA控制器的DMA总线与总线矩阵协调,使用AHB把外设ADC采集的数据经由DMA通道存放到SRAM中,这个数据的传输过程中,完全不需要内核的参与,也就是不需要CPU的参与,

这样一来,就解决了大量数据转移过度浪费CPU资源的问题,使CPU更专注于更加实用的操作–计算、控制等。

仲裁器

仲裁器的作用是当有多个申请时,确定其优先级,

分为两个阶段

第一阶段

软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级

  • 最高优先级

  • 高优先级

  • 中等优先级

  • 低优先级;

    第二阶段

    硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。比如:如果软件优先级相同,通道2优先于通道4。

    注意: 在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。

    DMA数据流(仅存在于STM32F4 /M4 内核上)
DMA的传输方式

因为DMA就是两个区域的数据传输,所以说,DMA就有四个传输方式

  • 内 ->内

  • 内->外

  • 外->内

  • 外->外

可编程的数据传输宽度的问题

假如源端想要发送两个八个字节的数据,接收端有两个16个字节的数据,那么他会怎么接收呢

他们回传输到两个不同的位置,而不会填满一个

假如我发送端是一个16字节数据,接受端是8字节数据,那么只能接受8个字节

2 .DMA在STM32中的使用

上面用画图的方法给大家做了DMA的简介,以及他的优点,下面给大家介绍一下DMA在STM32中的使用

DMA控制器介绍

在STM32F1系列微控制器中,有两个DMA控制器:DMA1 和 DMA2。每个DMA控制器都包含若干个通道,具体如下:

  • DMA1 包含 7 个通道(DMA1_Channel1 到 DMA1_Channel7)。

  • DMA2 包含 5 个通道(DMA2_Channel1 到 DMA2_Channel5)。

因此,在STM32F1系列中,总共有 12 个DMA通道。

下图给大家介绍了DMA1和DMA2各个通道的请求,根据下图来配置不同的外设

根据上图和你想实现的功能,来配置通道,

DMA在USART1传输代码

首先呢,给大家书写了一份中文结构体注释,这样有利于大家的理解

{
  uint32_t DMA_PeripheralBaseAddr; /*!< 指定DMAy通道x的外设基地址。 */
​
  uint32_t DMA_MemoryBaseAddr;     /*!< 指定DMAy通道x的内存基地址。 */
​
  uint32_t DMA_DIR;                /*!< 指定外设是源地址还是目标地址。
                                        此参数可以是@ref DMA_data_transfer_direction 中的一个值。*/
​
  uint32_t DMA_BufferSize;         /*!< 指定指定通道的数据缓冲区大小,以数据单元为单位。
                                        数据单元等于在DMA_PeripheralDataSize或DMA_MemoryDataSize成员中设置的配置,
                                        取决于传输方向。*/
​
  uint32_t DMA_PeripheralInc;      /*!< 指定是否使能外设地址寄存器的递增功能。
                                        此参数可以是@ref DMA_peripheral_incremented_mode 中的一个值。*/
​
  uint32_t DMA_MemoryInc;          /*!< 指定是否使能内存地址寄存器的递增功能。
                                        此参数可以是@ref DMA_memory_incremented_mode 中的一个值。*/
​
  uint32_t DMA_PeripheralDataSize; /*!< 指定外设数据宽度。
                                        此参数可以是@ref DMA_peripheral_data_size 中的一个值。*/
​
  uint32_t DMA_MemoryDataSize;     /*!< 指定内存数据宽度。
                                        此参数可以是@ref DMA_memory_data_size 中的一个值。*/
​
  uint32_t DMA_Mode;               /*!< 指定DMAy通道x的操作模式。
                                        此参数可以是@ref DMA_circular_normal_mode 中的一个值。
                                        注意:如果配置了所选通道的内存到内存数据传输,则不能使用循环缓冲区模式。*/
​
  uint32_t DMA_Priority;           /*!< 指定DMAy通道x的软件优先级。
                                        此参数可以是@ref DMA_priority_level 中的一个值。*/
​
  uint32_t DMA_M2M;                /*!< 指定DMAy通道x是否用于内存到内存的传输。
                                        此参数可以是@ref DMA_memory_to_memory 中的一个值。*/
}DMA_InitTypeDef;
​

DAM初始化函数,为了加大大家对初始化函数的理解,给初始化分成了三个部分,

1.数据的输入与输出,

​
    //数据输入与输出
    //1外设地址  2内部储存器地址  3传输方向
DMA_InitStruc.DMA_PeripheralBaseAddr = (uint32_t)SRC_Buffer;  //外设地址,就是串口的DR寄存器的地址
    DMA_InitStruc.DMA_MemoryBaseAddr = (uint32_t)DST_Buffer;  //内部储存器地址
    DMA_InitStruc.DMA_DIR = DMA_DIR_PeripheralSRC;  //传输方向,外设作为传输源
​

2.数据大小以及单位

    DMA_InitStruc.DMA_BufferSize  = BUFFER_SIZE;//传输数据大小
    DMA_InitStruc.DMA_PeripheralInc = DMA_PeripheralInc_Enable;   //内存地址增量使能,因为是数组
    DMA_InitStruc.DMA_MemoryInc = DMA_MemoryInc_Enable;//外设地址增量使能,因为串口的位置是固定的
    DMA_InitStruc.DMA_PeripheralDataSize =  DMA_PeripheralDataSize_Word;   //外设数据宽度
    DMA_InitStruc.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;   //内存的数据宽度

3.传输模式选择

    DMA_InitStruc.DMA_Mode = DMA_Mode_Normal;   //选择普通股模式
    DMA_InitStruc.DMA_Priority = DMA_Priority_High;   //选择高的优先级,因为就一个,所以说选择那个都可
    DMA_InitStruc.DMA_M2M = DMA_M2M_Disable;      //内存到内存功能使能
​

根据以上整理出完整版

void USART_DMA()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    DMA_InitTypeDef DMA_InitStruc;
        //数据输入与输出
    //1外设地址  2内部储存器地址  3传输方向
    DMA_InitStruc.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADD;  //外设地址
    DMA_InitStruc.DMA_MemoryBaseAddr = (uint32_t)Send_Buff;  //内部储存器地址
    DMA_InitStruc.DMA_DIR = DMA_DIR_PeripheralDST;  //传输方向,内部作为传输源
​
    //数据的大小
    DMA_InitStruc.DMA_BufferSize  = 500;//传输数据大小
    DMA_InitStruc.DMA_PeripheralInc = DMA_PeripheralInc_Disable;      //外设地址增量
    DMA_InitStruc.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址增量
    DMA_InitStruc.DMA_PeripheralDataSize =  DMA_PeripheralDataSize_Byte;   //外设数据宽度
    DMA_InitStruc.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;   //内存的数据宽度
    DMA_InitStruc.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStruc.DMA_Priority = DMA_Priority_High;
    DMA_InitStruc.DMA_M2M = DMA_M2M_Disable;    
    
    DMA_Init(DMA1_Channel4 , &DMA_InitStruc);
    DMA_ClearFlag(DMA1_FLAG_TC4);
    DMA_Cmd(DMA1_Channel4,ENABLE);
​
}

.h文件

#ifndef __DAM_H
#define __DAM_H
#include "stm32f10x.h"
​
#define BUFFER_SIZE 16
​
#define USART_DR_ADD (USART1_BASE+0x04)  //串口DR寄存器加上便宜量
​
void DMA_Init_Srtuct();
uint8_t  Buffcrmp(const uint32_t *Buff1,uint32_t*Buff2,uint32_t size);
void USART_DMA();
​
#endif
    

main函数

#include "stm32f10x.h"
#include "main.h"
#include "LED.h"
#include "Bear.h"
#include "key.h"
#include "Realy.h"
#include "usart.h"
#include "shake.h"
#include "exti.h"
#include "time.h"
#include "pwm.h"
#include "HC-SR04.h"
#include "Systick.h"
#include "OLED.h"
#include "DHT11.h"
#include "SPI.h"
#include "NRF24L01.h"
#include "DAM.h"
​
​
    extern const uint32_t SRC_Buffer[16];
    extern uint32_t DST_Buffer[BUFFER_SIZE];
    extern uint8_t Send_Buff[500];
​
​
​
int main(void)
{
    uint32_t i = 0;
    
    for(i = 0;i<500;i++)
    {
    
    Send_Buff[i] = '0';
    
    }
    Usart_Init();
        USART_DMA();
    
        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
    while(1)
    {
    
    
    
    }
    
}
​
​
​

结果是在串口上看见500个0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值