stm32---DMA基础

DMA,意思为直接存储器访问。
DMA 可 用于实现外设与存储器之间或者存储器与存储器之间数据高效传输。
因为 DMA 传输数据移动过程无需 CPU 直接操作,这样节省的 CPU 资 源就可供其它操作使用。
从硬件层面来理解,DMA 就好像是 RAM 与 I/O 设备间数 据传输的通路,外设与存储器之间或者存储器与存储器之间可以直接在这条通路 上进行数据传输。
这里说的外设一般指外设的数据寄存器,比如 ADC、SPI、I2C、 DCMI 等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等。


STM32F1 最多有 2 个 DMA 控制器,DMA1 有 7 个通道。 DMA2 有 5 个通道。每个通道专门用来管理来自于一个或多个外设 对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。


stm32---DMA基础_第1张图片
DMA1通道对应外设请求

stm32---DMA基础_第2张图片
DMA2通道对应外设请求

DMA就像一个中转站一样,里面有源地址和目标地址,多通道并用可以配置优先级,
只要开启DMA就可以直接实现源地址里的内容传送给目标地址,不需要CPU来管理,它就像个通道一样,开启就传输。


dma.c

#include "dma.h"


/*******************************************************************************
* 函 数 名         : DMAx_Init
* 函数功能         : DMA初始化函数
* 输    入         : 
                     DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                     par:外设地址
                     mar:存储器地址
                     buff_size:数据传输量
* 输    出         : 无
*******************************************************************************/ 
void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    //1*开启相应时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    
    //2*DMA结构体配置
    DMA_InitStructure.DMA_PeripheralBaseAddr = par;  //外设目标地址
    DMA_InitStructure.DMA_MemoryBaseAddr = mar;   //存储器源地址
    DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST ;  //方向是DMA存储器到外设寄存器。方向还有外设到存储器,存储器到存储器
    DMA_InitStructure.DMA_BufferSize = buff_size; //传输的字节数目
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设寄存器地址自递增,外设通常是一个不需要递增
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryInc_Enable;  //传输数据多字节时需要地址自增,实现开启就全部传输完
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA传输模式,单次传输
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  //优先级配置,用于多通道时
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //存储器到存储器时打开
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度为1Byte,8位
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接收数据长度为必须要存储器发送数据长度一样
    DMA_Init(DMA1_Channelx,&DMA_InitStructure);
    
}

/*******************************************************************************
* 函 数 名         : DMAx_Enable
* 函数功能         : 开启一次DMA传输
* 输    入         : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                     buff_size:数据传输量,传输时再赋值一遍防止出错
* 输    出         : 无
*******************************************************************************/ 
//3*开启DMA
void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size)
{

    DMA_Cmd(DMA1_Channelx,DISABLE);   //先关闭DMA使能来赋
    DMA_SetCurrDataCounter(DMA1_Channelx,buff_size);
    DMA_Cmd(DMA1_Channelx,ENABLE);
}

dma.h

#ifndef _dma_H
#define _dma_H

#include "system.h"


void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size);

void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size); 


#endif

main.c

#include "systick.h"
#include "led.h"
#include "system.h"
#include "key.h"
#include "usart.h"
#include "dma.h"

#define data_size 5000
u8 data[data_size];

//数组赋值专用函数
void Data_zhuang(u8 *p)
{
    u16 i;
    for(i=0;iDR,(u32)data,data_size); //DMA初始化,(u32)&USART1->DR是串口1的数据寄存器,(u32)data是我们在内存中造的数组
    
    while(1)
    { 
        key = KEY_Scan(0);
        if(key==KEY_UP)
        {
            USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //是哪个外设就开启哪个的DMA功能
            DMAx_ENABLE(DMA1_Channel4,data_size);  //使能DMA
            
            while(1)
            {
                if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==1) //判断DMA1的通道4是否传输完成
                {
                    DMA_ClearFlag(DMA1_FLAG_TC4);  //清除传输完成标志
                    break;
                }
                led2=!led2;
                delay_ms(300);
            }   
        }
    
        i++;
        if(i%20==0) //200ms变换一次
        {
            led1=!led1;
        }
    
    }
}

你可能感兴趣的:(stm32---DMA基础)