STM32H7 零 CPU 干预多通道 ADC 采样:MDMA 与 LPTIM 联动实战
👁 2 阅读 · 2026-08-27 · 嵌入式
在高速数据采集系统中,CPU 常被 ADC 中断频繁打扰,导致实时性下降。本文深入讲解如何利用 STM32H7 的 MDMA(存储器直接内存访问)与 LPTIM(低功耗定时器)联动,实现多通道 ADC 的定时触发采样,数据自动搬运至内存,全程无需 CPU 干预。文章涵盖原理剖析、CubeMX 配置步骤、完整代码示例及关键注意事项,助你打造高效低功耗的数据采集系统。
# STM32H7 零 CPU 干预多通道 ADC 采样:MDMA 与 LPTIM 联动实战
## 为什么需要 MDMA + LPTIM 联动?
传统 ADC 采样通常依赖 CPU 处理中断或 DMA 传输完成回调,但高频采样时中断频繁,CPU 占用率飙升,影响系统实时性。STM32H7 系列内置 MDMA(Master DMA)和 LPTIM(低功耗定时器),可构建一条完全自主的数据通路:
- **LPTIM** 产生精确的定时触发信号,启动 ADC 转换,无需 CPU 参与。
- **ADC** 按序列自动扫描多个通道,并将结果存入数据寄存器。
- **MDMA** 在 ADC 转换完成后自动将数据搬运至内存缓冲区,支持双缓冲或环形缓冲,搬运完成后可触发中断(可选)。
整个流程 CPU 零干预,仅在需要时处理数据,极大提升系统效率。
## 硬件与软件准备
- **硬件**:STM32H743 开发板(或任意 H7 系列)、信号源(如电位器或函数发生器)。
- **软件**:STM32CubeIDE(或 Keil MDK)、STM32CubeMX(用于初始化配置)。
- **知识基础**:熟悉 STM32 基础外设(ADC、DMA、定时器)及中断概念。
## 工作原理详解
### 1. LPTIM 触发 ADC
LPTIM 可配置为 PWM 输出模式,产生周期性脉冲,连接到 ADC 的触发源(如 `ADCx_EXTTRIG`)。每个脉冲启动一次 ADC 转换,转换频率由 LPTIM 的时钟和预分频决定。
### 2. ADC 多通道扫描
ADC 配置为扫描模式,序列包含多个通道(如 IN0、IN1、IN2)。每次触发后,ADC 按序列顺序转换所有通道,并将结果依次存入数据寄存器(或 DMA 请求)。
### 3. MDMA 搬运数据
MDMA 支持内存到内存、外设到内存的传输,且具有更高的带宽和更灵活的描述符配置。此处将 ADC 的数据寄存器(外设地址)作为源,内存缓冲区作为目标,每次 ADC 转换完成后产生 DMA 请求,MDMA 自动搬运。
### 4. 零 CPU 干预的实现
通过配置 MDMA 的循环模式,数据持续填充缓冲区,当缓冲区满时可产生中断(可选),CPU 仅在需要时处理数据,其余时间可进入低功耗模式或执行其他任务。
## 配置步骤(基于 STM32CubeMX)
### 1. 时钟配置
- 将系统时钟配置为 400MHz(H7 最高主频)。
- 确保 LPTIM 时钟源选择(如 LSI 或 APB 时钟),并计算所需触发频率。
### 2. LPTIM 配置
- 选择 LPTIM1,时钟源设为 LSI(典型 32kHz)或 APB 时钟。
- 配置为 PWM 模式,设置周期和脉冲宽度,例如周期 1ms(1kHz 触发频率)。
- 使能输出引脚(如 PB5),并连接到 ADC 的外部触发引脚(需硬件连接)。
### 3. ADC 配置
- 选择 ADC1,启用扫描模式,添加多个通道(如 IN0、IN1、IN2)。
- 设置采样时间(如 32.5 周期),确保转换精度。
- 触发源选择外部触发,触发边沿选择上升沿(对应 LPTIM 脉冲)。
- 使能 DMA 请求(但使用 MDMA 时,需将 DMA 请求映射到 MDMA)。
### 4. MDMA 配置
- 在 MDMA 配置界面,添加一个通道,源地址设为 ADC1 的数据寄存器地址(如 `ADC1->DR`),目标地址设为内存缓冲区。
- 设置传输方向为外设到内存,数据宽度为半字(16 位,ADC 结果)。
- 启用循环模式,缓冲区大小设为通道数 × 采样次数(例如 3 通道 × 100 次 = 300 半字)。
- 使能传输完成中断(可选),用于通知 CPU 处理数据。
### 5. 生成代码并整合
生成初始化代码后,在 `main.c` 中启动 LPTIM、ADC 和 MDMA,并实现中断回调(如有)。
## 完整代码示例(核心部分)
```c
// main.c 中初始化后启动
// 定义 ADC 缓冲区(3 通道,100 次采样)
#define ADC_CHANNELS 3
#define SAMPLE_COUNT 100
uint16_t adc_buffer[ADC_CHANNELS * SAMPLE_COUNT];
// 启动 LPTIM、ADC 和 MDMA
void start_acquisition(void) {
// 启动 LPTIM PWM 输出
HAL_LPTIM_PWM_Start(&hlptim1, LPTIM_PERIOD, LPTIM_PULSE);
// 启动 ADC 的 DMA 请求(实际由 MDMA 处理)
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buffer, ADC_CHANNELS * SAMPLE_COUNT);
// 启动 MDMA 传输(源为 ADC 数据寄存器,目标为缓冲区)
HAL_MDMA_Start_IT(&hmdma_mdma_ch0, (uint32_t)&hadc1.Instance->DR, (uint32_t)adc_buffer, ADC_CHANNELS * SAMPLE_COUNT, 0);
}
// MDMA 传输完成回调(可选)
void HAL_MDMA_IRQHandler(void) {
HAL_MDMA_IRQHandler(&hmdma_mdma_ch0);
}
void HAL_MDMA_TransferCompleteCallback(MDMA_HandleTypeDef *hmdma) {
// 数据已就绪,可处理 adc_buffer
process_adc_data(adc_buffer, ADC_CHANNELS * SAMPLE_COUNT);
}
```
## 注意事项
- **硬件连接**:LPTIM 输出引脚必须与 ADC 的外部触发引脚相连(如通过跳线或 PCB 走线),否则无法触发。
- **时钟同步**:确保 LPTIM 和 ADC 的时钟域匹配,避免触发抖动。
- **缓冲区大小**:MDMA 循环模式下,缓冲区大小需为通道数的整数倍,否则数据错位。
- **中断优先级**:若启用 MDMA 中断,建议设置较高优先级,避免数据覆盖。
- **功耗优化**:在无采样需求时,可停止 LPTIM 和 ADC,进入低功耗模式,进一步节能。
- **调试技巧**:使用逻辑分析仪观察 LPTIM 输出和 ADC 触发信号,验证时序正确性。
## 总结
通过 MDMA 与 LPTIM 联动,STM32H7 实现了真正的零 CPU 干预多通道 ADC 采样,大幅降低 CPU 负载,适用于高速数据采集、传感器融合等场景。本文提供的配置和代码可直接应用于实际项目,开发者可根据需求调整采样频率、通道数和缓冲区大小。掌握此技术,你将能构建更高效、更实时的嵌入式系统。