STM32-DMA

简介

DMA(Direct Memory Access)—直接存储器存取, 是单片机的一个外设,它的主要功能
是用来搬数据,但是不需要占用 CPU, 即在传输数据的时候, CPU 可以干其他的事情,好
像是多线程一样。 数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以
是 SRAM 或者是 FLASH。 DMA 控制器包含了 DMA1 和 DMA2, 其中 DMA1 有 7 个通道,
DMA2 有 5 个通道, 这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存
在于大容量的单片机中

DMA 有 DMA1 和 DMA2 两个控制器, DMA1 有 7 个通道, DMA2 有 5 个通道,不同
的 DMA 控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,
具体见 DMA 请求映像表
    

 

        每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
 

DMA 数据配置
 使用 DMA,最核心就是配置要传输的数据,包括

数据从哪里来?要到哪里去?

传输的数据的单位是什么?

要传多少数据?

是一次传输还是循环传输?

等等。

1. 从哪里来到哪里去
我们知道 DMA 传输数据的方向有三个:从外设到存储器,从存储器到外设,从存储
器到存储器。 具体的方向 DMA_CCR 位 4 DIR 配置: 0 表示从外设到存储器, 1 表示从存储
器到外设。 这里面涉及到的外设地址由 DMA_CPAR 配置,存储器地址由 DMA_CMAR 配
置。
外设到存储器
当我们使用从外设到存储器传输时,以 ADC 采集为例。 DMA 外设寄存器的地址对应
的就是 ADC 数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(用来接收存
储 AD 采集的数据) 的地址。 方向我们设置外设为源地址。
存储器到外设
当我们使用从存储器到外设传输时,以串口向电脑端发送数据为例。 DMA 外设寄存器
的地址对应的就是串口数据寄存器的地址, DMA 存储器的地址就是我们自定义的变量(相
当于一个缓冲区,用来存储通过串口发送到电脑的数据) 的地址。方向我们设置外设为目
标地址
存储器到存储器
当我们使用从存储器到存储器传输时,以内部 FLASH 向内部 SRAM 复制数据为例。
DMA 外设寄存器的地址对应的就是内部 FLASH(我们这里把内部 FALSH 当作一个外设来
看) 的地址, DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储来
自内部 FLASH 的数据)的地址。方向我们设置外设(即内部 FLASH) 为源地址。 跟上面
两个不一样的是,这里需要把 DMA_CCR 位 14: MEM2MEM:存储器到存储器模式配置
为 1,启动 M2M 模式。
 

配置如下:

1 void USARTx_DMA_Config(void)
2 {
3 DMA_InitTypeDef DMA_InitStructure;
4
5 // 开启 DMA 时钟
6 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

7 // 外设地址 设置 DMA 源地址:串口数据寄存器地址*/
8 DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
9 // 内存地址 (要传输的变量的指针)
10 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
11 // 方向:从内存到外设
12 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

13 // 传输大小
14 DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
15 // 外设地址不增
16 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
17 // 内存地址自增
18 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
19 // 外设数据单位
20 DMA_InitStructure.DMA_PeripheralDataSize =
21 DMA_PeripheralDataSize_Byte;
22 // 内存数据单位
23 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
24 // DMA 模式,一次或者循环模式
25 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
26 //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
27 // 优先级:中
28 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
29 // 禁止内存到内存的传输
30 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
31 // 配置 DMA 通道
32 DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
33 // 使能 DMA
34 DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
35 }

1 int main(void)
2 {
3     uint16_t i;

4     /* 初始化 USART */
5     USART_Config();
6
7     /* 配置使用 DMA 模式 */
8     USARTx_DMA_Config();
9
15     /*填充将要发送的数据*/
16     for (i=0; i<SENDBUFF_SIZE; i++)
17     {
18         SendBuff[i] = 'P';
20     }
21
22 /*为演示 DMA 持续运行而 CPU 还能处理其它事情,持续使用 DMA 发送数据,量非常大,
23 *长时间运行可能会导致电脑端串口调试助手会卡死,鼠标乱飞的情况,
24 *或把 DMA 配置中的循环模式改为单次模式*/
25
26 /* USART1 向 DMA 发出 TX 请求 */
27 USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE);
28
29 /* 此时 CPU 是空闲的,可以干其他的事情 */
30 //例如同时控制 LED
31 while (1)
32 {
33     LED1_TOGGLE
34     Delay(0xFFFFF);
35 }
36 }
USART_DMACmd 函数用于控制 USART 的 DMA 请求的启动和关闭。它接收三个参
数,第一个参数用于设置串口外设, 可以是 USART1/2/3 和 UART4/5 这 5 个参数可选, 第
二个参数设置串口的具体 DMA 请求,有串口发送请求 USART_DMAReq_Tx 和接收请求
USART_DMAReq_Rx 可选,第三个参数用于设置启动请求 ENABLE 或者关闭请求
DISABLE。运行该函数后 USART的 DMA发送传输就开始了,根据配置存储器的数据会发
送到串口。
DMA 传输过程是不占用 CPU 资源的,可以一边传输一次运行其他任务。






猜你喜欢

转载自blog.csdn.net/sinat_26528193/article/details/104678806
今日推荐