DMA简介
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传
输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自
于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
DMA主要特性
● 12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道
● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过
软件来配置。
● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、
中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
● ……
具体可见STM32F1参考手册第21章
DMA数据传输方向、传输数量
传输方向
外设→存储器
存储器→外设
存储器→存储器
传输数量
最多传输数据65535(由DMA_CNDTRx寄存器控制),DMA_CNDTRx寄存器31:16为保留,15:0为可编程位;所以最大值为2^16 - 1=65535。
用CubeMx新建DMA工程
三个传输方向工程都有
新建工程
File→NewProject
![]()
芯片选型
![]()
配置RCC
![]()
配置时钟树
![]()
工程配置
![]()
● 存储器到存储器
const常量存储在“内部Flash”区,全局变量存储在“SRAM”区,所以该例程定义一个const常量和一个全局变量就可以实现DMA的存储器到存储器
DMA配置
点击Add添加DMA Request即可,具体配置如下图:
![]()
生成代码
由于前边配置了RCC等,所以直接生成代码
![]()
主函数
int main(void){ uint8_t TransferStatus; HAL_StatusTypeDef DMA_status = HAL_ERROR; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); DMA_status = HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)aSRC_Const_Buffer, (uint32_t)aDST_Buffer, BUFFER_SIZE); /* 判断DMA状态 */ if (DMA_status != HAL_OK) { while (1) { LED1_ON; Delay(0xFFFFFF); LED1_TOGGLE; Delay(0xFFFFFF); } } while (__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1) == RESET) { } TransferStatus = Buffercmp(aSRC_Const_Buffer, aDST_Buffer, 32); if (TransferStatus == 0) { LED1_ON; } else { LED2_ON; } while (1) { }}
在main函数所在文件定义一个const常量数组,一个全局变量的数组
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = { 0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10, 0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20, 0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30, 0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40, 0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50, 0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60, 0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70, 0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80};/* 定义DMA传输目标存储器 */uint32_t aDST_Buffer[BUFFER_SIZE];
写一个比较数据的函数
uint8_t Buffercmp(const uint32_t *pBuffer, uint32_t *pBuffer1, uint16_t BufferLength){ /* 数据长度递减 */ while (BufferLength--) { /* 判断两个数据源是否对应相等 */ if (*pBuffer != *pBuffer1) { /* 对应数据源不相等马上退出函数,并返回0 */ return 0; } /* 递增两个数据源的地址指针 */ pBuffer++; pBuffer1++; } /* 完成判断并且对应数据相对 */ return 1;} ● 存储器到外设
将数据从SRAM区发送到串口
添加串口的配置
波特率:115200
字长:8位
停止位:1
奇偶校验:无
![]()
配置DMA
如图配置即可
![]()
现象
串口助手的现象
![]()
●外设到存储器
外设到存储器的例程可以用ADC采集来代替。