1.DMA简介
(1)DMA是英文Direct Memory Access的简称,意为直接存储器存取。
(2)DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。
(3)12独立可配置的通道:DMA1(7个通道)和DMA2(5个通道)。
(4)每个通道都支持软件触发和特定的硬件触发。
(5)STM32F103C8T6的DMA资源:DMA1(7个通道)。
注:
1.DMA外设可直接访问STM32内部存储器,包括运行内存SRAM,程序存储器Flash和寄存器等。
2.外设:一般是外设的数据寄存器DR。
3.DMA通道,即路径,从一个地方转运到另一个地方。
4.DMA触发:软件触发(一般用于存储器到存储器);特定的硬件触发(一般用于外设到存储器,因为外设触发都是有一定时机的),“特定”每个DMA通道的硬件触发源是不一样的。
2.存储器映像
类型 | 起始地址 | 存储器 | 用途 |
ROM | 0x0800 0000 | 程序存储器Flash | 存储C语言编译的程序代码 |
ROM | 0x1FFFF F000 | 系统存储器 | 存储Bootloader,用于串口下载 |
ROM | 0x1FFF F800 | 选项字节 | 存储一些独立于程序中的配置参数 |
RAM | 0x2000 0000 | 运行内存SRAM | 存储运行过程中的临时变量 |
RAM | 0x4000 0000 | 外设寄存器 | 存储各个外设的配置参数 |
RAM | 0xE000 0000 | 内核外设寄存器 | 存储内核各个外设的配置参数 |
注:
(1)外设寄存器,实际上也是存储器,前面是的外设到存储器,存储器到存储器本质上都是存储器到存储器之间的数据转运。
(2)ROM:只读存储器,是一种非易失性,不丢失的存储器。
(3)RAM:随机存储器,是一种易失性,掉电丢失的存储器。
3.DMA框图
图解:
(1)在上角Cortex-N3内核,里面包含了CPU和内核外设NVIC和SysTick等,剩下所有东西都可看作存储器。
(2)为了让CPU高效有理访问存储器,设计总线矩阵,总线矩阵左端是主动单元,拥有存储器的访问权,右边这些是被动单元,只能被左边的自动单元读写。
(3)DMA要转运数据,所有访问权,DMA1有一条总线,DMA2也有一条,DMA1有7个通道,DMA2有5个通道,可设置它们转运数据的源地址和目的地址,这样就可以开始工作了。
(4)DMA也是AHB的从设备,也就是说DMA自身的寄存器。DMA作为一个外设,有对应寄存器,这里连接到了总线右边的AHB总线上。
总结:DMA既是总线矩阵的主动单元,可以读写各种存储器,也是AHB总线上的被动单元,CPU通过下面这条线路即可对DMA进行配置。
(5)DMA请求含义:DMA请求就是DMA的硬件触发源,比如ADC转换完成,串口接收到数据,需要触发DMA转运数据的时候,就会通过DMA请求这条路线,向DMA发出硬件触发信号,之后DMA就可以执行数据转运到其他地方的工作了。
注:
1.CPU或DMA直接访问Flash的话,是只可读不可以写的
2.SRAM是运行内存,可以任意读写没有问题。
3.外设寄存器要看参考手册里的描述,有的是只读,有的是只写,不给我们只要用的是数据寄存器,数据寄存器都是可以正常读写的。
3.1DMA流程
(1)开启DMA时钟。
(2)初始化DMA
1.DMA_Mode:传输模式,可选择一次传输和循环传输,该选项决定了传输计数器是否重装
2.DMA_BufferSize:缓冲区大小,即传输计数器的值,每次传输几个数据。
3.DMA_M2M:选择软件触发还是硬件触发。
(3)开启外设的DMA(如ADC_DMACmd()),开启触发信号的输出。
(4)如需要,开启DMA的中断(DMA_ITConfig()),之前在NVIC里配置相应的通道,编写中断服务函数。
(5)DMA_Cmd:使能DMA开始运转。
(6)用DMA_GetFlagStatus判断是否传输完成,记得手动清除标志位。(但使用单词传输,如果传输结束后需要再次传输,需先失能DMA后再写传输计数器DMA_SetCurrDataCounter()再使能DMA)
4.DMA基本结构
注:
(1)DMA转运方向:1.外设到存储器
2.存储器到外设
3.存储器到存储器(Flash到SRAM;SRAM到SRAM)
补充:因为Flash是只读的,所有不可以进行SRAM到Flash和Flash到Flash。
(2)外设和存储器要配的三个参数:1.起始地址:决定了数据从哪里来到哪里去。
2.数据宽度:指定一次转运要按多大的数据宽度来进行,
可选择字节Byte,半字halfword和字word。
3.地址是否自增:指定一次转运完成后下一次转运,是不
是要把地址移到下一个位置。
(3)输出计数器:指定总只需要运行几次的,是一个自减计数器,减到0后,DMA就不会转运数据了,另外在减到0后自增的地址,也会恢复到最初的值,方便新一轮DMA转运。
(4)自动重装器:当传输计数器减到0后,是否要恢复到最初的值,即是单次模式还是循环模式。
(5)触发:M2M决定是软件触发还是硬件触发。M2M给1是软,给0是硬。(注:这里的软件触发并不是调动一次函数,触发一次,而是不断的触发DMA争取早日把计数器清0,可理解位连续触发,所有软件触发和循环模式不可同时使用)
补充:1.单次传输与循环模式的区别。单次模式:在DMA转运数据完成后,计数器不会恢复,如果要手动恢复计数器的值,需先关闭DMA。循环模式:在传输完成后自动恢复计数器并进行下一轮。2.触发选择。软件触发(连续触发):是尽快完成数据传输,适用于存储器到存储器(不可循环模式)。硬件触发适用于外设到存储器。
4.1总结:DMA转运条件
(1)开关控制:DMA_Cmd()必须使能。
(2)传输计数值必须大于零。
(2)触发源,必须有触发信号,硬件触发或软件触发。
5.DMA请求映像:不同DMA通道的触发源
图解:
(1)上图的数据选择器的EN位并不是选择哪一路数据位,而是决定这个通道(数据选择器)要不要工作,EN=0,数据选择器不工作,EN=1,数据选择器工作.
(2)软件触发:M2M给1。
(3)每个通道的硬件触发源不同,要根据对应的触发源来选择通道。
(4)DMA触发源选择是由这个外设是否开启了DMA输出来决定的,比如要使用ADCA,那会有个ADC1_DMACmd,必须使用这个库函数开启ADC这一路的输出才有效。
6.DMA相关函数
6.1 标配函数
void DMA_DeInit();
void DMA_Init();
void DMA_StructInit();
void DMA_Cmd();
6.2 void DMA_ITConfig()
作用:中断输出使能
6.3 传输器相关函数
void DMA_SetDataCounter() #DMA设置数据存储器(给传输计数器写数据)
uint16_t DMA_GetDataCounter() #DMA获取当前数据寄存器(返回传输计数器的值)
6.4 标志位标配函数
FlagStatus DMA_GetFlagStatus();
void DMA_ClearFlag();
ITStatus DMA_GetITStatus();
void DMA_ClearITPendingBit();