STM32F103 双 ADC 同步采样怎么配:DUALMOD 六种模式与 32 位 DMA 搬运一次讲透

电流环调不稳,示波器一量却是两路采样差了一个 PWM 周期。结论先给:两路 ADC 分开触发就不可能同刻采样;用双 ADC 规则同步模式让 ADC2 硬件跟随 ADC1,32 位寄存器打包、DMA 一次搬走,才是对的做法。

2026-10-26
双ADCSTM32F103同步采样DMA电机控制嵌入式

关节控制器的电流环调不稳,示波器一量才发现问题不在 PID:相电流和母线电压这两路采样,时刻差了一个到两个 PWM 周期。两路 ADC 各自被软件启动,谁先谁后取决于中断里的代码路径,采样点自然对不齐。结论先给:只要两路 ADC 分开触发,就无法保证同一时刻采样;用 STM32F103 的双 ADC 模式让 ADC2 硬件跟随 ADC1 的触发,同步规则模式下一次触发完成两路转换,结果打包进同一个 32 位寄存器,再由 DMA 一次搬走。

RM0008 把双 ADC 的十种 DUALMOD 编码、交替模式的时钟错开规则、以及"从 ADC 必须设成软件触发"这类硬性约束都写清楚了,难点不在寄存器怎么写,而在选错模式之后时序上的隐性错位。

一、先把模式分清:谁跟谁、数据落在哪

双 ADC 由 ADC1_CR1 的 DUALMOD[3:0] 选择,ADC2、ADC3 中这几位是保留位。手册的表述是"6 种可能的模式",另加 3 种混合组合,落到寄存器上是下面这些编码。

DUALMOD模式适用组触发来源数据落点
0000独立模式不限各自触发各自 ADC_DR / ADC_JDRx
0101注入同步模式注入组ADC1 的注入触发 JEXTSEL各自 ADC_JDRx
0110规则同步模式规则组ADC1 的规则触发 EXTSEL32 位 ADC1_DR,高半字 ADC2、低半字 ADC1
0111快速交替模式规则组(通常单通道)ADC1 规则触发32 位 ADC1_DR + DMA
1000慢速交替模式规则组(通常单通道)ADC1 规则触发32 位 ADC1_DR + DMA
1001交替触发模式注入组ADC1 注入触发,分两次各自 ADC_JDRx

另外四种编码 0001 ~ 0100 是混合组合:同步规则 + 注入同步、同步规则 + 交替触发、同步注入 + 快速交替、同步注入 + 慢速交替。它们解决的是"规则组要同步、注入组还要另有一套节奏"的场合。对关节控制这种"相电流用注入、母线电压用规则"的结构,同步规则模式已经够用,先不要上混合模式——混合模式的时序更难在示波器上验证。

二、同步规则模式:一次触发,两路同时采样

这个模式的行为很直接:外部触发只给 ADC1,ADC2 由硬件同步启动,两边各自转换自己规则序列里配置的通道。手册有两条硬性约束,配错就会出现"偶发丢数":

第一,从 ADC 必须设成软件触发。如果 ADC2 也开了外部触发,它可能被自己的触发源提前启动一次,同步关系当场失效。同时,主从两路的外部触发又都必须处于激活状态,这是手册明确要求的,缺一个同步就不成立。

第二,两个 ADC 的规则序列长度必须一致,或者保证触发间隔大于两个序列中较长的那个。长度不一致时,短的那一路会被下一次触发提前打断,读出来的值属于上一轮。

结果打包方式是这个模式最有价值的地方:转换完成后,ADC1_DR 这个 32 位寄存器里,低半字是 ADC1 的结果,高半字是 ADC2 的结果,一次 32 位 DMA 请求就能把两路同时搬走,天然保证电流和电压是同一时刻的。注意手册的提醒:想从主数据寄存器读到从 ADC 的数据,DMA 位必须使能,哪怕你并不打算用 DMA 搬规则数据。

三、交替模式:给一路信号提速,不是给两路对齐

快速交替和慢速交替经常被误当成"两路同步采样",其实它们是用两个 ADC 轮流采同一路信号,把等效采样率翻倍。时序上:

模式启动时序采样时间约束适用判断
快速交替ADC2 立即启动,ADC1 延迟 7 个 ADCCLK采样时间必须小于 7 个 ADCCLK,否则两个采样周期重叠只有 1.5 周期这一档满足,源阻抗必须很低
慢速交替ADC2 立即启动,ADC1 延迟 14 个 ADCCLK,ADC2 再隔 14 个周期重启;28 个 ADCCLK 后自动开始新的 ADC2 转换采样时间必须小于 14 个 ADCCLK1.5 / 7.5 / 13.5 三档可用,容得下较高的源阻抗

还有两个细节容易踩。其一,ADC 时钟预分频设为 4 时,快速交替并不是均匀的 7 个周期,而是 8 个与 6 个 ADCCLK 轮替,做等间隔重采样时要按这个实际间隔补偿。其二,交替模式只能用于规则组,且不允许注入通道的外部触发同时存在;如果你的电流采样挂在注入组,就不要指望用交替模式提速。

四、注入组:规则组会被它打断

规则组最多 16 个转换,注入组最多 4 个,规则组的转换可以被注入触发打断——这正是电流采样挂在注入组的原因:PWM 中心对齐时刻的注入触发可以插到母线电压的慢速扫描中间,采样点由定时器硬件决定,不受软件路径影响。

用同步注入模式时有一条禁令:不要在两个 ADC 上转换同一个通道,因为那样无法提供重叠的采样时间。注入结果分别存在各自的 ADC_JDRx 里,只有当一个 ADC 的所有注入通道都转换完,才产生 JEOC 中断,中途读到的数据是上一轮的。

五、采样时间八档:先按源阻抗选,再按模式收窄

每个通道的采样时间由 ADC_SMPR1/SMPR2 的 SMPx[2:0] 独立选择,共八档:

SMPx采样周期典型用途
0001.5低阻抗源;快速交替模式唯一可用档
001 / 0107.5 / 13.5运放缓冲后的电流采样;慢速交替可用
011 / 10028.5 / 41.5分压后的母线电压,需配合前端 RC
101 / 11055.5 / 71.5高源阻抗、长走线
111239.5极慢变化的信号;温度传感器推荐 17.1µs 采样

采样时间定完再谈精度。ADC 供电范围 2.4V ~ 3.6V,VREF+ 必须落在 2.4V 与 VDDA 之间;上电后先做校准,顺序是置 RSTCAL 初始化校准寄存器、等硬件清零,再置 CAL 启动校准、等硬件清零。转换正在进行时置 RSTCAL,需要额外的周期才能清完。ADON 清零后 ADC 进入断电模式,手册说此时几乎不耗电,只有几个微安——多路轮流采集的系统可以按需上电。

六、DMA:只有 ADC1 和 ADC3 有

ADC2 自己不带 DMA,双 ADC 模式下它借 ADC1 的 DMA 通道。ADC1 固定映射到 DMA1 的通道 1,配置要点是:外设地址为 ADC1_DR、存储器地址自增、外设地址不变、传输宽度 32 位、循环模式。搬运宽度必须是 32 位——按 16 位读,高半字的 ADC2 数据就被丢掉了,现象是母线电压一直是 0。

/* STM32F103 双 ADC 规则同步采样(寄存器级,RM0008 命名) */
volatile u32 adc_pair[2];              /* [0] 低半字=ADC1,高半字=ADC2 */

void dual_adc_init(void)
{
    /* 1. 改任何配置前先关双模式,否则同步会丢 */
    ADC1->CR1 &= ~ADC_CR1_DUALMOD;

    /* 2. 上电并校准 */
    ADC1->CR2 |= ADC_CR2_ADON;
    ADC1->CR2 |= ADC_CR2_RSTCAL;
    while (ADC1->CR2 & ADC_CR2_RSTCAL) {}
    ADC1->CR2 |= ADC_CR2_CAL;
    while (ADC1->CR2 & ADC_CR2_CAL) {}

    /* 3. 采样时间:通道0 取 28.5 周期,通道1 取 71.5 周期 */
    ADC1->SMPR2 = (3u << 0) | (6u << 3);
    ADC2->SMPR2 = (3u << 0) | (6u << 3);

    /* 4. 两个 ADC 的规则序列都必须是一个转换,长度一致 */
    ADC1->SQR1 = (0u << 20);          /* L=0 -> 1 个转换 */
    ADC1->SQR3 = 0;                    /* 通道0:相电流 */
    ADC2->SQR1 = (0u << 20);
    ADC2->SQR3 = 1;                    /* 通道1:母线电压 */

    /* 5. DUALMOD=0110 规则同步;只让主 ADC 接外部触发 */
    ADC1->CR1 |= (6u << 16);
    ADC1->CR2 |= ADC_CR2_EXTTRIG;
    ADC2->CR2 &= ~ADC_CR2_EXTTRIG;     /* 从 ADC 走软件触发 */

    /* 6. DMA1 通道1:32 位、循环、外设不增、存储器递增 */
    DMA1_Channel1->CPAR  = (u32)&ADC1->DR;
    DMA1_Channel1->CMAR  = (u32)adc_pair;
    DMA1_Channel1->CNDTR = 1;          /* 一次搬 32 位即两路结果 */
    DMA1_Channel1->CCR   = DMA_CCR_MSIZE_1 | DMA_CCR_PSIZE_1
                         | DMA_CCR_MINC | DMA_CCR_CIRC;
    DMA1_Channel1->CCR  |= DMA_CCR_EN;

    /* 7. 使能 DMA 位后启动;量产用 TIM1_CC1 触发替代 SWSTART */
    ADC1->CR2 |= ADC_CR2_DMA | ADC_CR2_ADON;
    ADC1->CR2 |= ADC_CR2_SWSTART;
}

七、排查:按现象对号入座

现象根因处理
高半字恒为 0,母线电压读不到DMA 位未使能,或按 16 位搬运置 ADC_CR2 的 DMA 位,DMA 传输宽度改 32 位
两路仍有 1 个 PWM 周期的错位从 ADC 也被外部触发提前启动ADC2 改软件触发,只保留主 ADC 的外部触发
电流波形出现平台或台阶快速交替下采样时间超过 7 个 ADCCLK改用 1.5 周期采样,或换成慢速交替
偶发读到上一轮的值两个 ADC 序列长度不一致SQR1 的 L 位配成相同长度,或拉长触发间隔
JEOC 来得比预期晚注入序列未全部转换完检查 JSQR 的 L[1:0] 与通道顺序,中断里再读 JDR
改通道后同步彻底乱掉在双模式运行中改配置,触发重新开始按手册建议,先关双模式再改配置

一句话总结:要"两路同一时刻",用 DUALMOD=0110 让 ADC2 跟随 ADC1 的触发,靠 32 位 ADC1_DR 和 DMA1 通道 1 一次搬走;要"一路更密",才用交替模式,并且必须把采样时间压到 7 或 14 个 ADCCLK 以内。方向选错,寄存器怎么调都对不齐。

本文基于 ST RM0008《STM32F10xxx 参考手册》中文版(参照 2008 年 12 月英文第 7 版)第 9 章 DMA 与第 10 章 ADC 整理优化。

需要定制开发?

沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付

立即微信咨询

电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应