STM32 DMA直接存储器存取原理及DMA转运模板代码

发布于:2024-12-06 ⋅ 阅读:(99) ⋅ 点赞:(0)

DMA简介: 

 存储器映像:

注意:FLASH是只读的,DMA不能写入,但是可以读取写到其他存储器里

变量是存在运行内存SRAM里的,常量(const)是放在程序存储器FLASH里的

 DMA框图:

 简图:

创输计数器是DMA转运的次数,会自减,减到0就不再转运,自增的地址也恢复到起始地址

由硬件还是软件触发由M2M这个决定

 DMA请求映像:

 数据宽度与对齐:

 例1:

源地址填DataA,目的地址填DataB,源和目的端都自增地址,传输计数器给7,自动重装不需要,采用软件触发

例2:

 源地址写ADC_DR的地址,不自增,目的地址写ADValue,自增,数据宽带选择半字(16位,因为ADC_DR是16位的)传输计数器写7,连续扫描自动重装写7,单次可以不用自动重装,选择ADC硬件触发。

 ——————————————————————————————————————————

 存储器之间转运代码:

#include "stm32f10x.h"
uint16_t MyDMA_Size;//用来记录传输计数器的值
//三个参数,第一个参数是源地址,第二个参数是目的地址,第三个参数是传输计数器的值
//STM32中地址都是32位的,每个地址代表一个字节
void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
    DMA_InitTypeDef DMA_InitStructure;//DMA初始化结构体
    MyDMA_Size = Size;//记录传输计数器的值
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//打开DMA的时钟
    DMA_InitStructure.DMA_BufferSize = Size;//传输计数器的值
    //方向是从外设存储器到存储器(其实这里的外设并不一定是外设寄存器,只是这么叫而已)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//由软件触发
    DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;//存储器地址设为AddrB
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//宽度设为字节
    //设为地址自增(自增大小是宽带的字节数,因为一个字节对应一个地址)
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    //设置DMA工作模式为普通模式,即不采用重装载
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    //外设存储器地址(同理的,这个外设存储器也不一定是外设存储器)设为AddrA
    DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//宽度设为字节
    //设为地址自增(自增大小是宽带的字节数,因为一个字节对应一个地址)
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    //优先级设为中等优先级
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_Init(DMA1_Channel1,&DMA_InitStructure);//传参,配置DMA1的1通道
    打开DMA1的1通道
    DMA_Cmd(DMA1_Channel1,DISABLE);
}
void MyDMA_Transfer(void)
{
    DMA_Cmd(DMA1_Channel1,DISABLE);//失能DMA1通道1,因为改变传输计数器的值要关闭DMA
    DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);//重新写入传输计数器的值
    DMA_Cmd(DMA1_Channel1,ENABLE);//使能
    while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);//判断是否传输完成
    DMA_ClearFlag(DMA1_FLAG_TC1);//清空标志位
}