STM32 DMA深度解析|原理、完整工作流程、寄存器、中断联动,嵌入式面试高频考点(F1系列)

前言

在STM32嵌入式开发里,DMA是实现高速外设数据传输的核心模块,串口、I2C、SPI、ADC等外设做大批量数据传输时基本都会用到DMA。很多初学者使用DMA仅仅停留在CubeMX图形化勾选配置,只会调用HAL库函数,对底层的搬运逻辑、总线竞争、通道仲裁、中断标志、NVIC联动理解很浅,一旦面试深挖底层原理,很容易卡壳,遇到传输BUG也无从下手排查。

本文基于STM32F1系列(Cortex-M3内核)完整梳理DMA全套知识体系,从基础概念、数据搬运全过程、总线共享机制、通道仲裁,再到核心寄存器、HT/TC/TE三类中断,以及DMA和NVIC中断联动逻辑,同时整理嵌入式面试高频问题,兼顾理论学习、代码调试与面试备考。

一句话概括DMA:直接存储器访问,由独立硬件自动完成数据搬运,搬运全程不需要CPU逐字节读写,解放CPU内核去处理其他业务任务。

一、DMA是什么?为什么要有DMA?

DMA全称Direct Memory Access,直接存储器访问。DMA是MCU内部独立的硬件控制器,自带独立控制逻辑与总线接口。在CPU提前完成配置并授权之后,DMA可以直接接管系统总线控制权,不依赖CPU干预,硬件自动把数据从源地址搬运到目标地址。

通俗类比:CPU好比项目主管,DMA是专门负责搬货物的搬运工人,内存、外设寄存器就是货物存放的仓库。如果不使用DMA,每一个字节的数据都需要CPU亲自读取、再写入目标位置,大批量传输时CPU会被占用;交给DMA搬运,搬运的这段时间主管(CPU)可以并行处理别的业务。

使用DMA的核心优势:

  1. 数据搬运过程不需要CPU逐字节参与,CPU并行执行业务代码,大幅提升MCU整体运行效率。

  2. 硬件直接搬运,传输速度远高于CPU读写转发,适合高速、连续的数据传输场景。

  3. 适合大批量数据场景:串口大量收发、ADC多通道连续采样、内存之间大块数据拷贝等。

如果没有DMA,把数据从外设到内存,从内存到外设的过程,都是CPU自己做的,如下图:

以CPU独立完成串口收发图形为例:

二、DMA与CPU、MCU的关系

  1. Cortex-M3(CPU内核):内核,负责运算、业务逻辑处理、中断响应,不负责大批量数据搬运。

  2. DMA控制器:属于MCU片上外设,是独立硬件,不属于CPU内核,有自己的控制逻辑。

  3. MCU(单片机芯片):整体载体,包含Cortex-M3内核 + DMA、USART、I2C、GPIO、定时器等各类外设。

  4. 开发板:硬件载体,把MCU芯片引出引脚、搭配外围电源电路,供我们调试、烧录程序。

STM32F1系列共有2个DMA控制器:

  • DMA1:7个通道,主要服务低速外设(USART1/2/3、SPI1、I2C1、TIM、ADC1)。

  • DMA2:5个通道,主要服务高速外设(USART1、SPI1、SDIO、ADC1/2/3、TIMx)。

一句话总结:DMA是单片机芯片内部独立的搬运硬件,和CPU共用一套系统总线。

三、宏观理解DMA数据搬迁完整过程

下⾯,我们直接进⼊ STM32F103xx 内部的 DMA 部分,我先先来看 DMA 功能框图:

以最常用的内存数组 → 串口DR寄存器DMA发送场景举例:

  1. 软件提前配置DMA通道的全套寄存器:源地址(内存数组首地址)、目标地址(串口数据寄存器地址)、待传输数据长度、源/目标地址自增属性、数据位宽、传输方向,最后使能DMA通道。

  2. 串口硬件准备就绪,发送寄存器为空,向外输出DREQ外设请求信号,通知DMA可以搬运下一个字节。

  3. DMA收到DREQ请求,向总线仲裁器申请总线使用权,仲裁完成后DMA接管系统总线。

  4. DMA硬件自动执行单次搬运:从源地址读取数据,写入目标地址;按照配置,源地址自动+1,目标地址(串口寄存器固定不变,不自增)。

  5. 每成功搬运1个数据,DMA的传输计数器CNDTR自动减1。

  6. 循环重复上面的搬运动作,直到预设数量的数据全部搬运完成。

  7. 全部传输完成后,DMA硬件置TC传输完成标志,如果TC中断使能打开,就产生中断信号通知CPU;CPU进入中断服务函数,调用回调函数,我们编写自己的业务代码。

重点:整个字节搬运的循环过程,CPU不需要参与每一次读写,只需要在传输开始前做一次配置,传输完成后在中断里处理后续逻辑。

四、理解总线共享

DMA和Cortex-M3内核共享同一套系统总线。总线同一时刻只能分配给一个总线主设备使用,不能同时读写。

  1. DMA需要搬运数据时,会向总线仲裁器申请总线控制权。

  2. 总线仲裁器根据预设的通道优先级,决定当前总线交给CPU还是DMA使用。

  3. 如果CPU和DMA同时发起总线请求,高优先级设备优先获得总线使用权。

  4. DMA占用总线的时间很短,单次只搬运一个数据;DMA占用总线期间,CPU会等待总线释放,对整体程序运行影响很小。

五、理解DMA通道、DREQ信号与优先级仲裁

1)DMA通道

一个DMA控制器包含多个独立DMA通道。每一个通道都拥有一套独立的配置,可以单独完成一次传输任务,包含专属的地址寄存器、计数寄存器、中断控制位。通道相当于多条独立的搬运流水线,我们把不同外设(串口、ADC、I2C)绑定到不同DMA通道,实现多路独立传输。

2)外设请求DREQ信号

外设准备好收发数据时,会输出DREQ硬件请求信号,作为触发DMA搬运的开关。例:串口发送寄存器为空,产生DREQ信号,触发DMA把下一个字节搬运到串口DR寄存器。没有DREQ信号,DMA不会主动搬运。

3)优先级聚合与仲裁

阶段⼀,软件优先级:每个通道的优先权可以在 DMA_CCRx 寄存器中设置,有4个等级:

低: DMA_PRIORITY_LOW

中: DMA_PRIORITY_MEDIUM

⾼: DMA_PRIORITY_HIGH

最⾼: DMA_PRIORITY_VERY_HIGH

阶段⼆,硬件优先级:如果 2 个请求有相同的软件优先级,则较低编号的通道⽐较⾼编号的通道有较高的优先权

多个DMA通道同一时刻同时发出DREQ请求时,总线仲裁器做仲裁判断:

  • 通道预先配置好软件优先级,高优先级通道优先抢占总线,优先搬运数据。

  • 当两个通道优先级配置相同时,通道编号更小的通道优先执行

如下图所示,就是 DMA 模块内部,多通道和外设、多通道优先级仲裁的示意图。

每个 DMA控制器 有多个通道,未来每个通道都可以独立配置,用于处理不同外设的请求,如果需要

的话。

对于 STM32 的 DMA 使用过程都是基于 DMA通道 进行的。

很明显 USART 的收发端,被设计成对应不同的通道,就是为了支持全双工收发

六、通道核心配置寄存器

每个DMA通道都拥有一套专属寄存器,CubeMX图形化配置,底层本质就是自动填充这些寄存器。

STM32F10X 系列 MCU 内部, DMA1 内部有 7 个通道。其中每⼀个通道都能被独立设置,而每⼀个通道都有 4 个独⽴寄存器来支持该通道进行设置。

这 4 个寄存器分别是:

•DMA通道x配置寄存器(DMA_CCRx)(x = 1...7)

•DMA通道x传输数量寄存器(DMA_CNDTRx)(x = 1...7)

•DMA通道x外设地址寄存器(DMA_CPARx)(x = 1...7)

•DMA通道x存储器地址寄存器(DMA_CMARx)(x = 1...7)

  1. DMA_CPAR 外设地址寄存器:存放外设寄存器地址,例如串口USART_DR的地址。

  2. DMA_CMAR 内存地址寄存器:存放SRAM内存数组的起始地址。

  3. DMA_CNDTR 传输数量寄存器:本次需要搬运多少个数据。每搬运1个数据,硬件自动减1;计数到0,代表本次传输全部结束。

  4. DMA_CCR 通道配置寄存器(最重要)

  • 通道开关:开启/关闭DMA通道

  • 传输方向:内存→外设 / 外设→内存 / 内存到内存

  • 地址自增配置:源地址、目标地址是否开启自增

  • 数据宽度:8bit /16bit /32bit

  • 循环模式开关:单次传输结束后,是否自动重装传输计数

  • 中断使能位:HT半传输、TC传输完成、TE传输错误的中断开关

其中,每一个通道,都对应这一套4个寄存器,如下图:

再结合之前的CPU地址空间,所谓的配置DMA,本质上其实就是CPU在设置对应的寄存器,如下图:

关键点:寄存器是软件提前一次性配置,后续数据搬运全程由硬件自动执行,不需要CPU反复修改寄存器。

七、理解DMA TC、TE、HT中断(面试高频)

这三个中断标志是DMA面试必考内容,必须分清含义、触发时机:

  1. TC 传输完成中断 Transfer Complete:CNDTR计数器减到0,全部预定数据搬运完成,硬件置TC标志。如果开启TC中断使能,就向NVIC发起中断请求,通知CPU本次传输结束。

  2. HT 半传输中断 Half Transfer:数据搬运到总长度一半的时候,硬件置HT标志。常用于流式连续传输场景:搬完一半,提前通知CPU填充新数据,实现不间断数据流。

  3. TE 传输错误中断 Transfer Error:总线访问异常、地址访问非法等错误发生,硬件置TE标志,触发错误中断,通知CPU传输出现故障。

⚠️ 重要区分:标志位 和 中断使能位是两套独立寄存器。硬件事件发生后,会自动置标志位;只有打开对应中断使能位,才会向NVIC发送中断请求;仅置标志位、没开使能,不会触发中断,只能软件查询标志。

八、DMA通道与NVIC联动,彻底理解DMA

DMA产生中断信号,不会直接跳入CPU,要经过NVIC嵌套向量中断控制器,完整链路:

  1. DMA通道内部发生HT/TC/TE事件,硬件置对应的中断标志位。

  2. 如果该通道对应的中断使能位已经打开,DMA向外输出中断请求信号。

  3. 中断请求送入NVIC,NVIC根据预先配置的中断优先级,判断是否响应中断。

  4. 如果允许响应,内核暂停当前正在运行的代码,跳转到DMA对应的中断服务函数。

  5. 在中断服务函数内,HAL库读取DMA标志,判断是HT/TC/TE事件,调用对应的回调函数。

  6. 用户在回调函数里面编写自己的业务处理代码。

DMA与NVIC联动如下示意图:

核心要点:

  • 每一路DMA通道,拥有独立的中断标志、独立的中断使能控制位。

  • 多个DMA通道的中断,映射到NVIC里对应的中断向量。

  • 严格区分两套中断:DMA通道产生的搬运中断 和 串口/I2C外设自身硬件中断,互相独立,互不干扰。例如串口DMA发送完成触发的是DMA的TC中断;串口帧错误、奇偶校验错误、溢出错,属于串口外设自己的硬件中断,两套分开配置。

九、总结

一张图总结使用DMA的流程:

十、串口DMA发送完整HAL工程代码(STM32F1实战)

1)CubeMX配置(F1系列)

  • 打开USART1,异步模式,波特率115200。

  • 在DMA Settings添加通道:方向Memory To Peripheral,优先级Medium,Mode Normal。

  • 配置完成后生成代码。

2)串口DMA发送封装

3)主函数调用

十一、嵌入式面试高频DMA问题汇总

面试常问,整理成可以直接口述回答的版本

  1. DMA是什么?作用是什么?

    DMA是直接存储器访问,MCU内部独立硬件,自动搬运数据,搬运过程不需要CPU逐字节读写,减轻CPU负担,实现高速大批量数据传输。

  2. DMA和CPU的关系,总线共享的特点?

    DMA和CPU共享系统总线,总线同一时刻只能给一个主设备使用。DMA发起传输时申请总线,仲裁器根据优先级分配总线使用权。

  3. DMA通道是什么?DREQ是什么信号?

    DMA通道是独立的数据搬运流水线,每通道可以单独配置一组传输任务;DREQ是外设发给DMA的硬件请求信号,用来触发DMA开始搬运。

  4. HT、TC、TE三种中断分别在什么时候触发?

    HT半传输中断:数据搬完一半触发;TC传输完成中断:全部数据搬运完毕触发;TE传输错误中断:传输发生总线错误等异常触发。

  5. DMA中断和串口外设中断是同一个吗?

    不是。DMA中断代表数据搬运完成或者传输出错;串口中断是串口外设硬件层面的通信错误,两套独立中断,寄存器、中断服务函数都分开。

  6. DMA地址自增是什么,什么时候开启?

    每次搬运完成,源地址/目标地址自动增加对应数据宽度。内存数组传输要开启地址自增;外设寄存器地址固定不变,外设侧地址不自增。

  7. DMA循环模式是什么,适用场景?

    CNDTR计数到0之后,自动重装初始传输数量,循环往复持续搬运。适合ADC持续采样、循环缓冲区这类不间断采集场景。

  8. DMA传输时,CPU完全不工作吗?

    不是。DMA占用总线的时候CPU会短暂等待;总线空闲时CPU继续运行代码。DMA只是免去CPU逐字节读写数据的工作,不是完全冻结CPU。

结语

DMA是嵌入式开发的重难点,千万不要只会用CubeMX一键生成代码。吃透总线共享、通道原理、寄存器含义、三类中断以及DMA和NVIC的联动逻辑,不仅可以快速定位DMA传输异常的BUG,在嵌入式面试中,也能从容回答面试官的底层原理提问。

DMA的核心思想一句话总结:硬件接管数据搬运工作,CPU只在中断节点介入处理业务,以此解放内核资源。理论看懂之后,建议上手实操串口DMA收发、ADC DMA采集工程,结合代码加深理解,理论结合实践才能真正吃透DMA。

如果本文对你有帮助,欢迎点赞、收藏、关注,后续持续更新STM32嵌入式开发干货!

相关推荐
rannn_1111 小时前
【Java面试八股】Java基础篇|数据类型、面向对象、关键字、反射、注解、异常、新特性、序列化、设计模式、IO
java·后端·面试
刃神太酷啦1 小时前
Redis 核心进阶:哨兵、集群、缓存问题与分布式锁详解----《Hello Redis!》(6)
linux·c语言·数据库·c++·redis·分布式·缓存
qq_402995751 小时前
MOS管的工作原理
嵌入式硬件·mcu
新晨单片机设计1 小时前
S016A-基于STM32单片机电子秤(LCD1602显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus
程序员梅雨1 小时前
MySQL底层探索(一):什么是脏页?什么是冷热分离?
mysql·面试
luj_17682 小时前
生物体如何应对功能击穿?
c语言·开发语言·c++·经验分享·算法
wuyk5552 小时前
从零吃透 MQTT 通信|第 11 章 MQTT 项目调试验证、性能优化、常见疑难问题、OTA 升级基础
c语言·开发语言·stm32·学习·性能优化
白色的北极熊2 小时前
C 语言 保留 2 位小数并且四舍五入输出
c语言
辰域电子3 小时前
STM32项目开源:粮仓环境安防监测系统(代码 + 原理图 + 仿真)
stm32·单片机·嵌入式硬件·开源·毕业设计·proteus