二十四、STM32的DMA

前言:现代 MCU 经常需要处理大量外设数据(ADC、UART、SPI、I²C 等),如果把这些数据搬运完全交给 CPU,会占用大量 CPU 周期,降低系统响应能力。**DMA(Direct Memory Access,直接内存访问)**就是解决这个问题的利器:它可以在不占用 CPU 的情况下,把外设数据自动搬运到内存(或把内存数据搬到外设),显著降低 CPU 负担、提升实时性与吞吐量。

目录

[一、DMA 是什么?为什么要用?](#一、DMA 是什么?为什么要用?)

[二、DMA 的总体架构](#二、DMA 的总体架构)

[三、DMA 的典型传输方向与使用场景](#三、DMA 的典型传输方向与使用场景)

[四、DMA 的关键配置项与概念](#四、DMA 的关键配置项与概念)

[五、DMA 的工作时序与中断](#五、DMA 的工作时序与中断)

六、常见误区与调试要点

七、性能注意事项与优化建议

八、ADC+DMA


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

DMA 的本质:一个硬件控制器,负责在外设寄存器、内存和外设之间直接搬运数据,搬运过程中 CPU 不参与数据逐字节拷贝(但仍需做配置和处理完成后的逻辑)。

主要优点

  • 降低 CPU 占用:尤其适合大量或高速数据采集(如音频、传感器阵列、图像流等)。

  • 更稳定的实时性:减少中断频率或避免中断上下文开销。

  • 更高吞吐量:硬件搬运比软件循环拷贝更快、更节省总线带宽。

适用场景举例:ADC 多通道高速采样、UART 大量数据接收、SPI 快速数据传输、内存到内存的批量拷贝、PWM 波形输出缓冲等。

二、DMA 的总体架构

  • STM32F1 系列通常有 DMA1(个别器件还有 DMA2)。

  • DMA 被划分为 通道(Channel),每个通道映射到一个或多个外设事件(例如 ADC、USART、SPI 等)。通道数量有限(例如 DMA1 通常有 7 个通道)。

  • 每个通道有自己的配置寄存器,控制源/目的地址、方向、数据宽度、优先级、传输长度、模式(循环/普通)等。

  • DMA 与外设通过**请求映射(request mapping)**关联:某个外设触发数据准备(如 ADC EOC),会产生 DMA 请求到对应通道。

三、DMA 的典型传输方向与使用场景

  • 外围设备 → 内存(Peripheral-to-Memory)

    场景:ADC 将转换结果推送到内存、USART RX 接收数据写内存。是最常见的用于数据采集的方向。

  • 内存 → 外围设备(Memory-to-Peripheral)

    场景:从一个内存缓冲区把数据写到 DAC、UART TX、SPI TX(比如发送音频或图像数据)。

  • 内存 → 内存(Memory-to-Memory)

    场景:大块内存数据搬运(在 F1 上支持有限,注意映射与配置)。用于缓冲区复制、DMA 驱动的块传输等。

  • 双向 / 循环模式 (实际是模式选择)

    循环(Circular)适合连续流数据采集;普通(Normal)适合一次性传输。

四、DMA 的关键配置项与概念

  • 源地址(Peripheral address)与目的地址(Memory address)

    DMA 在搬运时会从源地址读取数据并写到目的地址;比如 ADC->内存: 源=ADC_data_register,目的=缓冲区首地址。

  • 传输方向(Direction):见上一节。

  • 传输长度(Number of Data):要搬运的数据项个数(不是字节数,依赖数据宽度)。

  • 数据宽度(Peripheral & Memory Data Size):常见为 8-bit、16-bit、32-bit。ADC(12-bit)一般使用 16-bit 宽度(half-word),UART 通常用 8-bit。数据宽度必须匹配硬件与缓冲格式。

  • 地址递增(Peripheral increment / Memory increment):是否在每次传输后自动增加地址。外设寄存器通常禁用地址递增(固定地址),内存缓冲通常启用递增。

  • 传输模式(Normal / Circular)

    • Normal:完成指定数量传输后停止并触发完成中断。

    • Circular:完成后自动重新开始(围绕缓冲区),适合连续采样。

  • 优先级(Priority):在多通道竞争 DMA 总线时决定抢占顺序(高优先级通道更早获得总线)。

  • 中断/标志:半传中断(Half Transfer)、传输完成中断(Transfer Complete)、传输错误中断。半传在循环模式下非常有用------可以实现"前半缓冲处理同时后半缓冲接收"的方案。

五、DMA 的工作时序与中断

  • 启动步骤(概念层面):

    1. 配置 DMA(源/目地址、长度、宽度、递增、模式、优先级)。

    2. 配置外设(使能外设 DMA 请求,比如 ADC_DMACmd)。

    3. 使能 DMA 通道与相关中断(如果需要)。

    4. 启动外设触发(ADC 软件触发或定时器触发),数据开始流入缓冲区。

  • 半传中断(HT)与传输完成中断(TC)

    在循环模式下,半传中断可以触发处理已填满的缓冲区一半数据,而 DMA 继续写入另一半;传输完成中断则表示一轮缓冲写满。利用这两个事件可以实现无缝"生产者-消费者"模式。

  • 错误处理:DMA 也可能产生传输错误(比如总线错误),要有相应的检测与恢复策略(重启 DMA、报警等)。

六、常见误区与调试要点

  • 误区:DMA 一开就万事大吉

    DMA 确实减轻 CPU,但错误配置(地址错误、长度错误、宽度不匹配)会导致数据错位、溢出或硬件挂起。调试时重点检查外设数据寄存器地址、数据宽度和内存缓冲区大小。

  • 误区:半传中断和全传中断二者可互相替代

    半传中断用于"流式处理"更低延迟;若只用全传中断,会在缓冲写满后才处理,可能加大延迟。

  • 调试技巧

    • 先用短缓冲进行功能验证(例如 4 个采样点);

    • 打开半传/全传中断并在 ISR 中简单翻转 IO(示波器观察)确认触发节奏;

    • 检查 DMA 优先级与竞争关系;

    • 确认内存对齐(16-bit/32-bit)与 CPU 访问不会引起未对齐故障。

  • 跨域缓存问题(高级):F1 的 Cortex-M3 没有数据缓存问题,然而在更高端系列(如 Cortex-M7)需要考虑 D-cache 与 DMA 的一致性:使用缓存刷新/失效或使用不可缓存内存区。

七、性能注意事项与优化建议

  • 选择合适的数据宽度:尽量让外设与内存宽度匹配,减少额外的对齐/移动操作(例如 ADC 用 16-bit 存储)。

  • 优先级与通道分配:把关键通道设高优先级;避免多个高频外设共享同一 DMA 通道。

  • 中断开销最小化:把处理尽量放到任务或主循环,不在 ISR 中做大量计算;使用半传中断只做标记并在主循环处理。

  • 使用循环模式处理持续数据流:比如 ADC 连续采样或串口持续接收,循环模式可以避免频繁重启 DMA。

  • 考虑缓冲大小权衡:小缓冲降低延迟但增加中断频率;大缓冲降低中断负担但增加响应延迟。

八、ADC+DMA

  • 当需要实时采集多通道数据(如传感器阵列、音频采样、振动分析等)时,CPU 去轮询或处理中断会消耗大量计算资源,甚至跟不上数据速率。

  • ADC + DMA 可以实现:ADC 将转换结果自动写入内存缓冲区,CPU 仅在缓冲半满或满时处理数据,极大提高效率与实时性。

配置流程:

  • 设计缓冲区 :为采样结果准备好连续的内存数组(例如 uint16_t buffer[NUM_SAMPLES];)。通常选择 16-bit 单元来保持 ADC 的 12-bit 数据。

  • 配置 ADC

    • 打开 ADC 时钟,设置采样时间、分辨率(12-bit)、触发模式(软件或定时器触发)、扫描模式(若为多通道自动扫描)。

    • 对于多通道自动采样,启用扫描模式并在序列寄存器中设置通道顺序。

  • 配置 DMA(外设 → 内存):

    • 源地址:ADC 数据寄存器地址(固定);目的地址:缓冲区首地址;

    • 数据宽度:一般选择 16-bit(half-word);

    • 内存地址递增:启用;外设地址递增:禁用;

    • 模式:如果是持续采样(例如定时器触发连续采样),选择 Circular(循环) 模式;若是一次性采集选择 Normal

    • 启用半传/全传中断(根据需要)。

  • 把 ADC 的 DMA 请求打开(告诉 ADC 在 EOC 时发出 DMA 请求,让 DMA 自动搬运数据)。

  • 启动 ADC(与触发器)与 DMA 通道:在正确的时序下启动 DMA,然后启动 ADC & 触发(如果用定时器触发,启动定时器)。

  • 在中断/任务中处理数据

    • 如果使用循环模式并启用了半传/全传中断:在半传中断中处理缓冲区前半,在全传中断中处理后半;处理完后继续让 DMA 循环写入。

    • 如果使用普通模式:在传输完成中断中处理整个缓冲区并可重新配置/重启 DMA。

下一章节将详细讲解代码部分。

相关推荐
辛河5 小时前
单片机.RS485
单片机·嵌入式硬件
SKYDROID云卓小助手5 小时前
无人设备遥控器之数字图传技术
运维·服务器·单片机·嵌入式硬件·fpga开发
Brianna Home5 小时前
边缘智能革命:TinyML赋能微控制器
单片机·嵌入式硬件·物联网·嵌入式实时数据库
芯联智造5 小时前
【stm32协议外设篇】- SU03T 智能语音模块
c语言·开发语言·stm32·单片机·嵌入式硬件
申克Lab6 小时前
STM32 串口线A-B
stm32·单片机·嵌入式硬件
芯联智造7 小时前
【stm32简单外设篇】- HC-SR501 / 人体红外被动红外传感器
c语言·stm32·单片机·嵌入式硬件
_infinite_7 小时前
STM32串口配置
stm32·单片机·嵌入式硬件
XINVRY-FPGA7 小时前
XC7Z020-1CLG484I Xilinx AMD FPGA Zynq-7000 SoC
arm开发·嵌入式硬件·网络协议·fpga开发·硬件工程·信号处理·fpga
电子硬件笔记8 小时前
嵌入式硬件:如何理解高频电子线路,从入门开始
嵌入式硬件·硬件架构·硬件工程·嵌入式实时数据库