DMA传输数据

发布时间 2023-12-04 18:30:05作者: 京多安

前言

  DMA即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。本篇文章以STM32F4为例,不同型号可能略有不同。

一.DMA特性简介

  STM32F4有两个DMA控制器,一个控制器有8个数据流,一个数据流有8个通道(请求)
  值得注意的是,DMA1仅支持外设P->M,M->P,而不支持M->M,而DMA2全都支持。这是因为DMA1的存储区端口相比DMA2的要减少AHB2外设的访问权,同时DMA1外设端口是没有连接至总线矩阵的,只有连接到 APB1 外设,所以DMA1不能实现存储器到存储器传输。
image

二.代码配置

这里仅实现简单的M->M,传输一次即可,并将结果通过串口打印。代码如下
首先是初始化DMA:

//DMA_Streamx设置DMA控制器和数据流,如DMA2_Stream0
//chx设置通道
//par设置发送地址
//mar设置接收地址
//ndtr设置数据传输量
void MYDMA_Init(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{
    DMA_InitTypeDef  DMA_InitStructure;

    if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
    {
       RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 
    }else
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 
    }
      DMA_DeInit(DMA_Streamx); 
      while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待 DMA 可配置

    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel = chx;  //通道选择
    DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址,其实就是传输起始地址
    DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址,数据接收地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;//存储器到外设模式
    DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable ;//外设增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式,一次传输,存储器到存储器只能一次模式 
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不用FIFO        
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
    DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream,初始化数据流
		
    DMA_Cmd(DMA_Streamx, ENABLE); //开启 DMA 传输
	
}

主函数代码如下

uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
uint8_t DataB[] = {0, 0, 0, 0};

int main(void)
{
    uart_init(115200);
    delay_init(84);
    //delay_ms(500);
    printf("t:%d\r\n",DataB[0]);
    printf("t:%d\r\n",DataB[1]);
    printf("t:%d\r\n",DataB[2]);
    printf("t:%d\r\n",DataB[3]);
    MYDMA_Init(DMA2_Stream0,DMA_Channel_4,(uint32_t) DataA,(uint32_t) DataB,4);
    delay_ms(500);
    printf("t:%d\r\n",DataB[0]);
    printf("t:%d\r\n",DataB[1]);
    printf("t:%d\r\n",DataB[2]);
    printf("t:%d\r\n",DataB[3]);
  while(1){
	}
}

三.实验结果

通过串口查看数组B在DMA传输前后的数据,结果如下:
image
可知数据搬运成功。