基于STM32_HAL库的DMA应用

STM32 HAL库DMA实战指南:从原理到串口、ADC、内存搬运应用 直接存储器访问(DMA)是现代微控制器中提升系统性能的关键技术,其核心原理是允许数据在外设与存储器之间直接传输,无需CPU介入。这项技术通过硬件控制器管理数据传输,解放了CPU的计算资源,使其能够专注于核心算法与任务调度。在嵌入式开发领域,DMA对于实现高效数据流处理、降低系统延迟具有重要价值,广泛应用于高速数据采集、通信协议处理和图形显示等场景。本文以STM32 HAL库为实践框架,深入解析DMA的配置逻辑与工作机制,并结合串口通信、ADC多通道采集和内存间搬运等典型应用,探讨如何规避常见开发陷阱,例如数 阅读详情

基于STM32_HAL库的DMA应用

文章目录

一、DMA介绍

STM32 的 DMA(Direct Memory Access,直接存储器访问)是一种硬件模块,用于在 外设(如ADC、USART、SPI、I2C等)与 内存(RAM) 之间,或在 内存与内存之间,实现 无需CPU干预 的数据传输。

1.1 DMA的核心作用

不通过CPU,自动搬运数据,减少CPU负担,提高效率。例如:

  • 从ADC采集数据直接写入内存
  • 接收串口数据后直接存入缓冲区
  • 内存中大块数据搬运

1.2 DMA数据传输方向

在STM32F103C8T6的DMA控制器中,三种数据传输方向决定了数据流动的路径,是DMA配置的核心要素之一。以下是清晰的分类和说明:

1. 外设到内存(Peripheral-to-Memory)

特点

  • 数据源:外设寄存器(如ADC、USART的DR寄存器)。
  • 数据目标:内存(如数组、变量)。
  • 典型应用:
    • ADC采集数据存入内存数组。
    • 串口接收数据到缓冲区。

2. 内存到外设(Memory-to-Peripheral)

特点

  • 数据源:内存(如待发送的数据数组)。
  • 数据目标:外设寄存器(如SPI/I2C的数据寄存器)。
  • 典型应用:
    • 通过USART发送字符串。
    • SPI驱动显示屏批量写入数据。

3. 内存到内存(Memory-to-Memory)

特点

  • 数据源和目标:均为内存地址(如数组间复制)。
  • 仅DMA1支持:需手动触发,无硬件外设请求。
  • 典型应用:
    • 快速初始化大块内存(如清零RAM)。
    • 数据备份或格式转换。

1.3 DMA数据传输方式

在STM32F103C8T6的DMA控制器中,数据搬运模式主要分为两种核心模式,它们决定了DMA传输的连续性和工作方式。以下是详细的介绍:

1. 正常模式(Normal Mode)

特点

  • 单次触发,单次传输:
    每次使能DMA后,仅完成一次设定的数据传输(DMA_BufferSize),之后自动关闭DMA通道。
  • 需手动重启:
    传输完成后需重新配置并启动DMA(或由外设再次触发),适合非连续数据场景。
  • 中断标志:
    传输完成会置位TC(Transfer Complete)标志,可触发中断。

典型应用

  • 单次ADC采样数据搬运。
  • 非周期性的串口数据发送(如按键触发发送)。

2. 循环模式(Circular Mode)

特点

  • 自动循环,无需干预:
    传输完成后自动重置地址和计数器,无限循环传输数据,形成闭环。
  • 双缓冲技巧:
    结合传输完成(TC)和半传输完成(HT)中断,可实现双缓冲(Ping-Pong Buffer),提升实时性。
  • 外设持续触发:
    适合外设连续产生数据(如ADC连续采样、串口接收数据流)。

典型应用

  • 实时音频信号采集(ADC+DMA循环模式)。
  • 高速传感器数据流(如陀螺仪SPI通信)。
  • 串口接收不定长数据(配合IDLE中断)。

1.4 DMA控制器通道

STM32F103 有 2 个 DMA 控制器,DMA1 有 7 个通道,DMA 2 有 5 个通道。一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。STM32F103C8T6 只有 DMA1 !

  • DMA1有7个通道

    在这里插入图片描述

  • DMA2有5个通道

    在这里插入图片描述


1.5 DMA控制器的优先级

在STM32F103系列单片机中,DMA控制器的优先级管理是一个关键功能,它决定了当多个DMA请求同时发生时,哪个请求会被优先处理。以下是关于DMA优先级的详细介绍:

1. 优先级分类

STM32F103的DMA控制器支持两种优先级管理机制:

(1) 软件可编程优先级

每个DMA通道可以独立配置以下4个优先级等级(通过DMA_InitStruct.DMA_Priority设置):

  • 最高优先级(DMA_Priority_VeryHigh)
  • 高优先级(DMA_Priority_High)
  • 中优先级(DMA_Priority_Medium)
  • 低优先级(DMA_Priority_Low)

(2) 硬件固定优先级(自然优先级)

当多个通道的软件优先级相同时,硬件根据通道编号自动仲裁:

  • 通道编号越小,优先级越高(通道1 > 通道2 > … > 通道7)。

2. 优先级仲裁规则
  1. 软件优先级优先:
    不同优先级的请求中,更高软件优先级的通道总是先被处理。
    例如:通道3(高优先级)会抢占通道1(低优先级),即使通道1编号更小。
  2. 硬件优先级补充:
    若多个通道的软件优先级相同,则按通道编号决定顺序。
    例如:通道2和通道4均为中优先级时,通道2优先。
  3. 传输中的抢占:
    • 低优先级传输可被高优先级请求打断(当前传输完成后切换)。
    • 同优先级请求需等待当前传输完成。

二、DMA控制器相关API函数

2.1 初始化指定的 DMA 通道函数HAL_DMA_Init()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);

✅ 参数:

参数 类型 说明
hdma DMA_HandleTypeDef * 指向 DMA 通道句柄的指针,包含初始化结构体配置

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

初始化指定的 DMA 通道,并配置:

  • 数据方向
  • 数据宽度
  • 地址增量
  • 优先级
  • 模式(普通、循环)

2.2 停止|重置DMA通道函数HAL_DMA_DeInit()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *hdma);

✅ 参数:

参数 类型 说明
hdma DMA_HandleTypeDef * 指定要释放的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 停止 DMA 通道
  • 重置为默认状态
  • 清除中断标志

2.3 启动 DMA 传输(非中断方式)函数HAL_DMA_Start()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

✅ 参数:

参数 含义
hdma DMA 通道句柄
SrcAddress 源地址
DstAddress 目的地址
DataLength 数据项数量(以数据宽度计)

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 启动 DMA 传输(非中断方式)
  • 手动启动一次传输

2.4 启动 DMA 并启用中断函数HAL_DMA_Start_IT()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

✅ 参数:

参数 含义
hdma DMA 通道句柄
SrcAddress 源地址
DstAddress 目的地址
DataLength 数据项数量(以数据宽度计)

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 启动 DMA 并启用中断
  • 完成时调用中断回调(非阻塞)

2.5 立即中止正在进行的 DMA 传输函数HAL_DMA_Abort()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);

✅ 参数:

参数 类型 说明
hdma DMA_HandleTypeDef * 指定要中止的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功中止
  • HAL_ERROR: 中止失败

🎯 功能:

  • 立即中止正在进行的 DMA 传输
  • 清除使能位

2.6 以中断方式中止 DMA函数HAL_DMA_Abort_IT()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma);

✅ 参数:

参数 类型 说明
hdma DMA_HandleTypeDef * 指定要中止的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功中止
  • HAL_ERROR: 中止失败

🎯 功能:

  • 以中断方式中止 DMA
  • 中止后触发 HAL_DMA_AbortCpltCallback

2.7 阻塞式等待 DMA 传输完成函数HAL_DMA_PollForTransfer()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, HAL_DMA_LevelTypeDef CompleteLevel, uint32_t Timeout);

✅ 参数:

参数 含义
hdma DMA 句柄
CompleteLevel HAL_DMA_FULL_TRANSFER 或 HAL_DMA_HALF_TRANSFER
Timeout 等待超时(ms)

🔁 返回值:

  • HAL_OK, HAL_TIMEOUT

🎯 功能:

  • 阻塞式等待 DMA 传输完成
  • 适合不使用中断场景

2.8 判断 DMA 中断标志是否被置位宏函数__HAL_DMA_GET_FLAG()原型及功能

✅ 1. 宏原型:

#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)  (((__HANDLE__)->Instance->ISR & (__FLAG__)) != 0U)

💡 这是一个 宏定义(不是函数),用于读取 DMA 状态寄存器中的某个标志位是否被置位。

✅ 2. 参数说明:

参数 类型 说明
__HANDLE__ DMA_HandleTypeDef * 指向 DMA 通道的句柄(通常是 &hdma_xxx)
__FLAG__ uint32_t 要检查的标志位宏定义(如下表)

常见标志位如下(适用于 DMA1 的各个通道):

宏定义 含义
DMA_FLAG_TCx 通道 x 的传输完成标志(Transfer Complete)
DMA_FLAG_HTx 通道 x 的半传输完成标志(Half Transfer)
DMA_FLAG_TEx 通道 x 的传输错误标志(Transfer Error)
DMA_FLAG_GIx 通道 x 的全局中断标志(全局中断 = TC + HT + TE) 例如 DMA_FLAG_TC1、DMA_FLAG_HT3、DMA_FLAG_TE2

💡 其中 x 是通道号(17,F1 系列为 DMA1_Channel17)

🔁 3. 返回值:

返回类型 说明
uint32_t(0 或 1) 如果指定标志位被置位 → 返回 1,否则返回 0

🎯 4. 功能说明:

  • 用于判断 DMA 中断标志是否被置位。
  • 可在中断服务函数或轮询中使用。
  • 一般配合 __HAL_DMA_CLEAR_FLAG() 使用来手动清除中断标志位(如果 HAL 没有自动清除)。

🧪 示例用法:

if (__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1))
{
   
   
    // 通道1的传输完成
    __HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1);
    // 执行接下来的操作...
}

2.9 DMA方式串口发送数据函数HAL_UART_Transmit_DMA()原型及功能

📌 1. 函数原型:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

✅ 2. 参数说明:

参数名 类型 说明
huart UART_HandleTypeDef * 指向 UART 句柄的指针(例如:&huart1)
pData uint8_t * 指向要发送的数据缓冲区
Size uint16_t 要发送的数据长度(单位:字节)

🔁 3. 返回值:

返回值 含义
HAL_OK 操作成功
HAL_BUSY UART 当前正在忙于另一项传输
HAL_ERROR 参数错误或初始化失败
HAL_TIMEOUT (不适用于本函数,一般不会返回)

🎯 4. 功能说明:

  • 启动一个 UART 数据发送过程,由 DMA 自动完成传输。
  • 使用 DMA 可以大幅减轻 CPU 负担,适用于高速或大批量数据发送。
  • 在传输完成后,HAL 会调用回调函数 HAL_UART_TxCpltCallback()(需要用户自己实现)。
  • 非阻塞方式,函数调用后立即返回,不等待传输完成。

🧪 5. 使用示例:

示例 1:简单发送字符串

uint8_t message[] = "Hello DMA UART!\r\n";

HAL_UART_Transmit_DMA(&huart1, message, sizeof(message) - 1);

💡 提示:

  • 如果串口未配置 DMA,函数会失败。
  • 如果正在发送其他数据,函数会返回 HAL_BUSY。

🔁 6. 配合中断回调使用(推荐):

你可以定义 HAL_UART_TxCpltCallback() 来处理传输完成后的任务:

void HAL_UART_TxCpltCallback
【RoboMaster】一次搞定最难理解的DMA机制!【STM32】 同步博客地址:从STM32开始的RoboMaster生活:进阶篇 IV [DMA] 项目&教程仓库:-STM32-RoboMaster- 1.0 什么是DMA 1.1 DMA的定义 Direct Memory Access:直接存储器访问 是所有现代计算设备的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器... 阅读详情

相关推荐

STM32CubeMX串口+DMA接收不定长数据

STM32CubeMX串口+DMA接收不定长数据 1.修改CubeMX生成的串口初始化函数 void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 19200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits...

yu_weiguo的博客 3645

STM32F103用hal库使用DMA+串口空闲中断接收数据

简介: 出现空闲标志时,认为一帧报文发送完毕,进行报文分析,比普通的串口中断效率高很多! 用到的工具:CubeMX,Keil5 芯片:STM32F103VET6 步骤: 一、配置串口 二、使能串口NVIC中断 三、配置DMA 四、配置为MDK5,并生成代码工程 五、打开工程,添加部分代码 uint8_t receive_buff[255]; //定义接收数组 int main(void) { /* USER CODE BEGIN 1 */

Lainien的博客 7774

STM32 HAL库ADC连续转换模式配置与DMA应用详解

模数转换器(ADC)是嵌入式系统中连接模拟与数字世界的关键接口,其核心原理是将连续变化的模拟信号转换为离散的数字量。在实时数据采集场景中,传统单次转换模式因频繁CPU干预而难以满足高速、连续采样需求。连续转换模式通过硬件自动循环采样,结合直接内存访问(DMA)技术,实现了数据从外设到内存的无CPU干预自动搬运,极大降低了处理器负载。这种组合尤其适用于音频处理、振动监测、闭环控制等需要高采样率与确定时序的应用。本文以STM32的HAL库为例,深入解析连续转换模式与DMA的协同工作机制,涵盖从CubeMX基础配

weixin_42623010的博客 377

【STM32】RTT-Studio中HAL库开发教程五:UART的DMA应用

【STM32】RTT-Studio中HAL库开发教程五:UART的DMA应用

Hei_se_meng_yan的博客 2427

STM32CubeIDE与HAL库实战:串口通信从阻塞到DMA的进阶应用

本文详细介绍了STM32CubeIDE与HAL库在串口通信中的应用,从基础的阻塞模式到高效的DMA模式进阶。通过实战案例和性能对比,帮助开发者理解不同通信模式的适用场景,提升嵌入式系统开发效率。特别推荐使用DMA模式处理高速数据流,实现接近零CPU占用的高效通信。

weixin_29170327的博客 362

STM32 HAL库DMA中断配置详解:从原理到实战应用

DMA(直接存储器访问)是嵌入式系统中用于实现高效数据搬运的核心技术,它允许数据在外设与内存间直接传输,无需CPU持续参与,从而显著提升系统效率。其工作原理是通过独立的DMA控制器接管总线,实现数据的批量、自动搬运。这项技术的核心价值在于解放CPU算力,使其能够专注于复杂任务处理,而非陷入低效的轮询等待。在数据采集、通信协议处理、图形显示等需要高吞吐量的应用场景中,DMA是构建高性能嵌入式系统的基石。为了进一步提升响应实时性,DMA中断机制应运而生,它能在传输完成、半传输或发生错误时及时通知CPU。本文聚焦

weixin_28292761的博客 355

STM32串口通信实战:从HAL库配置到DMA+空闲中断应用

串口通信是嵌入式系统中设备与外界进行数据交换的基础接口,其原理基于异步串行通信协议,通过TX(发送)和RX(接收)线实现全双工数据传输。在微控制器领域,高效稳定的串口驱动对系统性能至关重要,尤其适用于传感器数据采集、设备调试和上下位机通信等场景。STM32的HAL库通过抽象化硬件寄存器操作,提供了轮询、中断和DMA三种编程模式,显著提升了开发效率与代码可移植性。其中,中断模式平衡了实时性与资源占用,而DMA模式结合空闲中断,能够实现大数据量的高效、低功耗传输,有效减轻CPU负担,是处理高速数据流(如音频、图

weixin_29192141的博客 258

实测对比:DECIMER、Img2Mol、MolScribe,哪个化学结构识别工具更靠谱?

化学结构识别(CSR)工具的核心任务是将分子结构图像转换为SMILES(Simplified Molecular Input Line Entry System)表示。这一过程需要克服图像质量差异、绘制风格变化以及特殊基团识别等挑战。三款工具采用不同的技术路线:DECIMER:基于EfficientNetV2+Transformer架构,优势在于处理标准期刊文献中的分子图示Img2Mol。

weixin_32576389的博客 333

从零理解Brep:用Python玩转3D建模的边界表示法(附OpenCASCADE示例)

本文深入解析了边界表示法(Brep)在3D建模中的应用,通过Python和OpenCASCADE的实战示例,详细介绍了Brep的核心数据结构、布尔运算、网格转换及3D打印优化技巧。适合CAD设计、3D打印和计算机图形学领域的开发者学习与实践。

n4o5p6q7r的博客 413

五、2K0300 久久派开发板的GPIO控制与Shell脚本自动化实战

本文详细介绍了基于龙芯2K0300处理器的久久派开发板的GPIO控制方法,通过sysfs文件系统实现LED控制和传感器读取。重点讲解了Shell脚本自动化实战,包括LED闪烁、流水灯效果和传感器数据采集,为物联网项目开发提供完整解决方案。

silver的专栏 680

显著性算法 + 伪彩变换

利用opencv得到显著图和伪彩图

正在挣扎中的人 2294

QProgressBar:常用接口、样式表及自定义进度条实现

在Qt开发中,QProgressBar 是一个非常常用的控件,用于显示任务的进度。无论是文件下载、数据处理还是其他耗时操作,QProgressBar 都能直观地展示当前进度。本文将详细介绍QProgressBar 的使用方法,包括常用接口、样式表设置,并额外补充一个自定义进度条的C++实现。

u011186532的专栏 1009

FastAPI基础项目:仿头条新闻的web项目,实现基本的新闻列表页和详情页查看功能

该项目是一个基于FastAPI和MySQL的新闻应用入门项目。主要包含新闻列表页和详情页两个功能页面。项目结构清晰,包含主应用文件、数据库脚本和HTML模板。使用SQLAlchemy进行数据库操作,通过脚本可自动生成50条示例新闻数据。环境配置简单,仅需安装FastAPI、MySQL驱动等基础依赖,通过.env文件管理数据库连接。该项目适合作为FastAPI+MySQL的入门学习案例,展示了基本的CRUD操作、分页查询和模板渲染功能。

数据知道的博客 4416

YOLOv5/v7/v8/v9/v10/v11/v12/13目标检测结果解析,超w字精读,IoU、GIoU、DIoU、CIoU、EIoU详细解释,精确率、召回率、AP、mAP与P-R 曲线图深度解析

YOLOv5/v7/v8/v9/v10/v11/v12/13目标检测结果解析,超w字精读,IoU、GIoU、DIoU、CIoU、EIoU详细解释,精确率、召回率、AP、mAP与P-R 曲线图深度解析

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1397

【重温童年】基于tkinter模块设计的Q宠大乐斗武器升星模拟器:重温经典,畅享休闲时光

与传统的Q宠大乐斗不同,这款模拟器还加入了一个创新的功能——自定义升星概率。玩家可以根据自己的喜好和策略,为不同的武器设置不同的成功率和降级率。比如,你可以将“嗜血”这把武器的升星难度设置得极高,以体现其稀有性和强大威力;也可以将“平底锅”这样的普通武器设置得相对容易升星,让玩家在升级过程中感受到更多的成就感。这种自定义的概率设置,不仅增加了游戏的趣味性和挑战性,还让玩家在升级过程中有了更多的策略和选择。你可以根据自己的武器库和卷轴数量,制定出最合适的升级计划,从而在游戏中占据先机。

nmdbbzcl的博客 1227

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: 基于STM32_HAL库的SPI通信并驱动W25Q64存储模块
下一篇: 基于STM32_HAL库的ADC应用
大专生学编程
博客等级 码龄6年 743粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值