STM32学习笔记(七) —— DMA传输(MTM)

DMA,全称是Direct Memory Access(直接内存访问)。可以在存储器和存储器之间或者外设和存储器之间传输数据,而不需要CPU的干预,这样可以节省CPU的资源,提高工作效率。

1.功能框图

在这里插入图片描述

STM32F103RCT6有两个DMA控制器,需要DMA传输的时候,外设会向DMA发送请求,DMA也会进行应答,随后会进行DMA传输。

2.DMA通道

在这里插入图片描述

在这里插入图片描述

两个DMA控制器一共有12个通道(DMA1有7个,DMA2有5个),上面图中列出了每个外设的请求与DMA通道的对应关系。当有多个DMA通道请求时,由于每次只能响应一个DMA通道请求,所以DMA仲裁器会根据软件优先级以及硬件优先级来确定先响应哪个通道。

3.优先级
1° 软件优先级可以在DMA_CCRx寄存器中设置,一共有最高优先级、高优先级、中等优先级、低优先级这4个等级。
2° 硬件优先级由通道号决定,通道号小的优先级高于通道号大的,比如通道2优先级高于通道4.
DMA仲裁器会优先对比软件优先级,软件优先级相同时再对比硬件优先级。

4.DMA传输模式
DMA传输的数据量可以通过DMA_CNDTRx寄存器最大编程为65535,每次传输后会递减,在传输了一半的数据和数据传输完成后都会有相应的标志位标识,并且可以使能相应的中断。
1° 当通道配置为非循环模式时,完成数据传输后将不再产生DMA操作,如果要开始新的DMA传输,需要在关闭DMA通道的情况下,重新配置要传输的数据个数(重新配置DMA_CNDTRx寄存器);
2° 在循环模式下,最后一次传输结束时,DMA_CNDTRx寄存器会被自动重载为初始数值。
3° 存储器到存储器模式。DMA的传输方向可以是存储器到外设、外设到存储器,也可以是存储器到存储器。这种情况下需要借用外设端口,当使用外设通道代表存储器时,通道可以随意选择,注意不能与循环模式同时使用。

5.软件编程
1° 在内存中开辟两个数组空间 mData_Buffer and pData_Buffer
2° 向 mData_Buffer 中存入数据
3° 使用 DMA 将 mData_Buffer 中数据移动到 pData_Buffer 中

/* 全局变量 */
char mData_Buffer[7] = "eckard";
char pData_Buffer[7] = "before";

  /* 在while循环之前添加 */
  //开启 DMA1 时钟, 使用外设之前一定要开启时钟
  RCC->AHBENR |= (uint16_t)0x01 << 0;
  
  //清除 CCR 寄存器
  DMA1_Channel1->CCR &= (uint16_t)0xffff8000;
  //数据从存储器读, 因为我们这里是要验证存储器到存储器模式
  DMA1_Channel1->CCR |= (uint16_t)0x01 << 4;
  //不执行循环操作, 注意存储器到存储器模式不能与循环模式同时使用
  DMA1_Channel1->CCR |= (uint16_t)0x00 << 5;
  //外设地址增量操作,地址递增的意思是传输完当前地址中的数据后,地址变为下一个要传输的数据的地址
  DMA1_Channel1->CCR |= (uint16_t)0x01 << 6;
  //存储器地址增量操作
  DMA1_Channel1->CCR |= (uint16_t)0x01 << 7;
  //外设数据宽度8位
  DMA1_Channel1->CCR |= (uint16_t)0x00 << 8;
  //存储器数据宽度8位
  DMA1_Channel1->CCR |= (uint16_t)0x00 << 10;
  //通道优先级低,这里的优先级是软件设置的优先级,硬件优先级由通道号决定的
  DMA1_Channel1->CCR |= (uint16_t)0x00 << 12;
  //启动存储器到存储器模式
  DMA1_Channel1->CCR |= (uint16_t)0x01 << 14;
  
  //数据传输数量,每次传输后会递减,如果在循环模式下,最后一次传输结束时,此寄存器会被自动重载为初始数值,比如7
  DMA1_Channel1->CNDTR = (uint16_t)7;
	
  //外设地址,我们上述设置的是从存储器读,所以数据传输的方向是mData_Buffer到pData_Buffer, 此地址为目标地址
  DMA1_Channel1->CPAR  = (uint32_t)pData_Buffer;
	
  //存储器地址, 此地址是源地址
  DMA1_Channel1->CMAR  = (uint32_t)mData_Buffer;
  
  printf("transfer start.\r\n");
  printf("mData_Buffer = %s\r\n", mData_Buffer);
  printf("pData_Buffer = %s\r\n", pData_Buffer);
  printf("\r\n");
  //开启通道
  DMA1_Channel1->CCR |= (uint16_t)0x01 << 0;
	
  //等待传输完成
  while(DMA1->ISR & ((uint32_t)0x01 << 1));
  /* 清除传输完成标志 */
  DMA1->IFCR |= (uint32_t)0x01 << 1;
    
  printf("transfer completed.\r\n");
  printf("mData_Buffer = %s\r\n", mData_Buffer);
  printf("pData_Buffer = %s\r\n", pData_Buffer);

将程序下载后,打开串口调试助手,可以查看打印的信息。

在这里插入图片描述

上述使用的是寄存器编程,下面使用STM32CubeMX来初始化DMA

在这里插入图片描述

在这里插入图片描述

生成代码后,发现新增了dma.c文件,已经完成了DMA的初始化

在这里插入图片描述

在main函数中也有调用

在这里插入图片描述

STM32CubeMX只能帮助我们初始化外设的配置,应用程序需要我们自己编写,我们这里需要调用HAL_DMA_Start函数来开启DMA传输

/* 全局变量 */
char mData_Buffer[7] = "eckard";
char pData_Buffer[7] = "before";

  /* 在while循环之前添加 */
  printf("transfer start.\r\n");
  printf("mData_Buffer = %s\r\n", mData_Buffer);
  printf("pData_Buffer = %s\r\n", pData_Buffer);
  printf("\r\n");

  /* 开启DMA传输 */
  HAL_DMA_Start (&hdma_memtomem_dma1_channel1, (uint32_t)mData_Buffer, (uint32_t)pData_Buffer, 7);
  /* 等待传输完成 */
  while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_memtomem_dma1_channel1)) == RESET);
  /* 清除传输完成标志 */
  __HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma1_channel1, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_memtomem_dma1_channel1));
  
  printf("transfer completed.\r\n");
  printf("mData_Buffer = %s\r\n", mData_Buffer);
  printf("pData_Buffer = %s\r\n", pData_Buffer);

将程序下载后,打开串口调试助手,可以查看到打印的信息与上述采用寄存器编程时是一样的。

本例程代码可以在HAL库工程模板这一章节的最后,百度网盘链接分享处获取

以上是通过开发板进行实际验证的,下面使用软件仿真,

我们进入调试界面,打开串口窗口,然后点击运行( 前面章节有提到,所以本篇以及后续章节都不再重复提及 )

运行结果如下,与在开发板上验证的结果一致。

在这里插入图片描述

相关推荐

  1. <span style='color:red;'>STM</span><span style='color:red;'>32</span><span style='color:red;'>DMA</span>

    STM32DMA

    2024-02-18 15:50:03      38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-18 15:50:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-18 15:50:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-02-18 15:50:03       82 阅读
  4. Python语言-面向对象

    2024-02-18 15:50:03       91 阅读

热门阅读

  1. 39. 组合总和

    2024-02-18 15:50:03       41 阅读
  2. kvm 虚拟化

    2024-02-18 15:50:03       50 阅读
  3. Leetcode29:两数相除

    2024-02-18 15:50:03       45 阅读
  4. 华为OD机试真题- 攀登者2-2024年OD统一考试(C卷)

    2024-02-18 15:50:03       49 阅读
  5. C语言之输入字符串的字符统计

    2024-02-18 15:50:03       54 阅读
  6. css的对齐方式

    2024-02-18 15:50:03       63 阅读
  7. 汇编+C语言实现四路抢答器的分析与运行过程

    2024-02-18 15:50:03       49 阅读
  8. Rust HashMap详解及单词统计示例

    2024-02-18 15:50:03       33 阅读