又到年末,事情总是格外的多,12月竟然没有一点产出是不行的,今天就来分析一下DMA的作用【下附DMA映射表,可用于开发者自查】
-
简介
DMA 即 Direct Memory Access,直接内存访问
这次分析的是STM32F4xx系列的DMA,需要注意的是F4系列的DMA和F1系列的DMA在结构上有所不同!
DMA用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。
可以在无需任何CPU操作的情况下通过DMA快速移动数据。这样节省的CPU资源可供其它操作使用。
我常用的几种使用DMA来控制的功能有USART,FSMC,ADC/DAC以及SPI,这些功能我会在之后的博文中带着实际工程做一些讲解。
-
结构
F4系列的单片机有两个DMA控制器:DMA1 和 DMA2 ;
每一个控制器有8个数据流(0~7);(注意,数据流这个结构概念是F1系列单片机没有的)
每个数据流有8个通道(0~7);
每个通道都有一个仲裁器(用于处理DMA请求间的优先级)
-
映射表
下面是两个DMA控制器的请求映射表:
【DMA1的映射表】
【DMA2的映射表】
-
初始化配置代码
以下是笔者配置遥控接收代码的部分节选,大家可以看到在下面的代码中开启了DMA2的Stream5的Channel4,查上面的表可知开启的是串口1的接收DMA,这样我在触发接收中断时就不需要花时间搬运接收数据了,收到的数据已经被DMA自动搬运到rec_sbus_data数组中,可以直接操作了。
// 1 启动DMA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);//DMA通道配置
// 2 DMA通道配置
DMA_DeInit(DMA2_Stream5);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);//外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rec_sbus_data;//内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA传输方向
DMA_InitStructure.DMA_BufferSize = SBUS_DATA_LEN;//设置DMA在传输时缓冲区的长度
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据字长
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存数据字长
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//设置DMA的传输模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//设置DMA的优先级别
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
// 3 配置DMA2的通道
DMA_Init(DMA2_Stream5, &DMA_InitStructure);
// 4 使能通道
DMA_Cmd(DMA2_Stream5,ENABLE);