6

HAL 库开发笔记(五)-DMA

 2 years ago
source link: https://wiki-power.com/HAL%E5%BA%93%E5%BC%80%E5%8F%91%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%94%EF%BC%89-DMA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

HAL 库开发笔记(五)-DMA

DMA(Direct Memory Access,直接存储器访问)允许不同速度的硬件装置直接沟通,而不需要依赖于 CPU 的大量中断负载。

基本原理#

DMA 是什么#

DMA 提供外设 / 存储器或存储器 / 存储器之间的高速数据传输,其过程中无需占用 CPU 资源。

20210404153423.png

如上图所示,STM32F4 系列有两个 DMA 控制器,共 12 通道(DMA1 有 7 个,DMA2 有 5 个)。DMA 控制器与 Cortex-M3 核心共享系统的数据总线。

简单地理解,当 CPU 懒得把一大串数据转移到另一个地方,或者说它还有更重要的事情要做的时候,就可以把这个任务丢给 DMA 去干,DMA 干完 / 出问题了跟 CPU 说一声就行。

DMA 的使用场景#

  • 串口通讯:最常见的使用情况,当有大量数据从串口读入或者写入的时候,让 DMA 处理。这样可以将 CPU 解放出来,让 CPU 处理更重要的事情。
  • ADC:一般在需要 ADC 时的通道扫描模式下,可以用 DMA 处理。
  • SD 卡读写:需要往 SD 卡里面读写大量数据的时候,一般也用 DMA 来处理。

DMA 的传输方向#

  • P2P(Peripheral to Peripheral,从外设到外设)。
  • P2M(Peripheral to Memory,从外设到内存):一般用于传感器通过串口发送读数回单片机。
  • M2P(Memory to Peripheral,从内存到外设):一般用于单片机通过串口发送数据到执行器。
  • M2M(Memory to Memory,从内存到内存):MCU 内部的数据转移,常见于 Buffer 之间互相转移数据,或者从 Buffer 读写数据。只有 DMA2 能够进行 M2M 操作。

DMA 的传输模式#

  • DMA_Mode_Normal:正常模式。任务完成后就停止 DMA,如果还需使用,要再次手动启动。
  • DMA_Mode_Circular: 循环传输模式。当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。

常用的 DMA 函数参考#

串口 DMA 发送数据#

功能:串口通过 DMA 发送指定长度的数据。
参数:

  • UART_HandleTypeDef *huart:UATR 的别名(如 : UART_HandleTypeDef huart1 -> huart1)
  • *pData:需要发送的数据
  • Size:发送的字节数

串口 DMA 接收数据#

功能:串口通过 DMA 接收指定长度的数据。
参数:

  • UART_HandleTypeDef *huart:UATR 的别名(如 : UART_HandleTypeDef huart1 -> huart1)
  • *pData:需要存放接收数据的数组
  • Size:接收的字节数

串口 DMA 恢复函数#

作用:恢复 DMA 的传输
返回值:0(正在恢复);1(已经完成恢复)

DMA 串口传输实验#

在 CubeMX 内配置 DMA#

串口部分的配置请参考文章 HAL 库开发笔记(四)- 串口通信

配置完 USART 引脚和 NVIC 中断后,切换到 DMA Settings 标签页,按照下图进行配置:

20210404165541.png

  • 点击 Add 添加通道(USART1_RX 与 USART1_TX)
  • 将两个的优先级都设置为 Medium(中优先级)
  • DMA 传输模式为 Normal(正常模式)
  • DMA 内存地址自增,每次增加一个 Byte(字节)

随后,在 System Core 标签页找到 DMA,增加一个 MEMTOMEM 栏目,如图:

20210404170002.png

在代码内配置 DMA#

main.c
/* USER CODE BEGIN Init */
uint8_t Senbuff[] = "Serial Output Message by DMA \r\n"; // 自定义发送的字符串
/* USER CODE END Init */
......
/* USER CODE BEGIN 3 */
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Senbuff, sizeof(Senbuff));
HAL_Delay(1000);
/* USER CODE END 3 */

烧录程序,打开串口助手,即可看见循环发送的自定义数组。

参考与致谢#

文章作者:Power Lin
原文地址:https://wiki-power.com
版权声明:文章采用 CC BY-NC-SA 4.0 协议,转载请注明出处。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK