# 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 负载,适用于高速数据采集、传感器融合等场景。本文提供的配置和代码可直接应用于实际项目,开发者可根据需求调整采样频率、通道数和缓冲区大小。掌握此技术,你将能构建更高效、更实时的嵌入式系统。