ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32G4硬件过采样:把12位ADC有效精度提升到16位

STM32G4硬件过采样:把12位ADC有效精度提升到16位 1. 为什么我要在STM32G4上重新审视过采样做嵌入式开发这些年ADC精度这个话题几乎绕不开。但凡涉及电流采集、温度测量、称重传感器或者任何需要“读数稳定”的场景大家第一时间想到的就是换更高位数的外部ADC芯片比如ADS1220、ADS1256这类。外部ADC确实干净利落但成本、PCB面积、通信时序开销都摆在那里很多量产项目根本扛不住。我这两年做电机控制相关的项目主控换成了STM32G4系列顺手研究了一下它内置ADC的潜力发现一个被很多人忽略的事实G4系列的ADC硬件过采样功能配合合理的软件处理可以把12位分辨率有效提升到接近16位的水平。这不是玄学而是数字信号处理里过采样技术的标准应用只是ST把它做成了硬件外设省去了大量CPU开销。先说清楚一个容易混淆的概念。ADC的“位数”有两种理解一是分辨率也就是数字量输出的最小步进二是有效位数ENOB也就是在实际噪声环境下信号里真正有用信息的位数。过采样提升的不是前者而是后者——它通过提高采样速率、利用噪声的随机性把量化噪声“摊薄”到更宽的频带里再通过滤波把带外噪声滤掉从而换来更高的信噪比。简单说12位ADC加上过采样和滤波最终读数可以表现出16位ADC的稳定度和分辨力。这篇内容适合谁看正在用G4系列做工业控制、电池管理、传感器采集的工程师或者手头有12位ADC但觉得精度不够、又不想换芯片的朋友。我会从原理讲到寄存器配置再到实测数据最后说几个我踩过的坑尽量做到拿来就能用。2. 过采样的数学原理4倍采样为什么只多1位精度很多人听说过“过采样4倍能提升1位分辨率”这句话但并不知道这句话的成立条件更不知道它的推导过程。这里我用最直白的方式拆开讲。假设原始ADC是12位采样率为f_s。量化噪声的总功率是固定的近似均匀分布在0到f_s/2的频带内。如果我把采样率提高到K倍也就是K*f_s但信号本身的带宽不变那么量化噪声的总功率没有变却被摊到了更宽的频带上单位频带内的噪声功率密度就降为原来的1/K。接下来用数字低通滤波器把高于信号带宽的噪声滤掉剩下的带内噪声功率就变成了原来的1/K。信噪比SNR的提升跟噪声功率的关系是SNR_dB 6.02 * N 1.76每提升6.02dB相当于增加1位有效位数。噪声功率降为1/K对应SNR提升10log10(K) dB。要让SNR提升6.02dB需要10log10(K) 6.02解出来K约等于4。这就是“每4倍过采样提升1位精度”的来历。但注意这个推导有前提输入信号必须足够随机化量化噪声必须近似白噪声。如果输入信号本身是缓慢变化的直流或者噪声很小那过采样的增益会大打折扣。这也是为什么很多人做过采样却发现效果不明显——不是原理错了而是信号条件不合适。G4系列的优势在于ST把“提高采样率抽取滤波”这套流程做成了硬件模块也就是过采样单元Oversampler。你不需要自己在中断里反复采样再手工累加只要配置好寄存器硬件就会自动完成多倍采样、移位累加、右移截断最终给出一个更高有效位的结果。更重要的是这个硬件过采样器没有额外增加CPU负担采样结果可以直接通过DMA搬运整个过程对主循环来说几乎是透明的。下表是我整理的“期望有效位数与最小过采样倍率”对照方便设计时快速估算目标有效位数相对12位提升理论最小过采样倍率实际推荐倍率留裕量14位2位16倍32倍15位3位64倍128倍16位4位256倍512倍为什么实际推荐倍率要留裕量因为真实世界里的量化噪声不可能是理想白噪声电路里的工频干扰、开关电源纹波、参考电压波动都会吃掉一部分过采样增益。我实测下来G4内部参考电压VREFINT的稳定性不算顶级所以想稳定拿到16位有效位数建议过采样倍率做到512倍甚至配合软件再做一次均值滤波。3. G4硬件过采样器与外设的配合逻辑用过F3、F4系列的朋友可能知道那些芯片没有硬件过采样器想做过采样只能靠定时器触发ADC连续采样然后在DMA中断里做软件累加。G4不一样它内置了独立的过采样单元挂在ADC外设后面数据流是这样的模拟信号 → ADC内核转换 → 过采样单元累加/移位 → 数据寄存器 → DMA → 内存这个过采样单元有几个关键配置项倍率OSR、移位位数Right Bit Shift、触发模式等。倍率决定采几次做累加移位位数决定最终结果保留多少位。比如12位ADC做过采样倍率设为256累加结果最大是12820位如果你要输出16位结果就右移4位。这里有个细节右移不是简单丢弃低4位而是等效于对累加结果做了一次除以16的归一化保持了结果的幅值正确。G4的过采样单元支持最高256倍过采样累加宽度是20位如果我没记错实际上数据寄存器可以容纳20位结果。这意味着12位ADC加256倍过采样理论输出精度可以达到16位。如果觉得还不够可以把倍率设成1024不行G4硬件上限就是256倍想更高只能软件再叠加。我建议的做法是硬件过采样256倍后得到一个16位结果软件里再对这个16位结果做滑动平均或中值滤波用来压制残余的突发性噪声。再说说过采样触发方式。G4支持两种模式一是每个过采样组需要N次ADC转换转换期间CPU不用干预二是连续模式ADC持续转换过采样单元不断累加并自动更新结果。我常用的是连续模式加DMA配置一次之后完全不用管数据会自动搬进缓冲区。但这种模式下要注意过采样单元输出的数据率是原始采样率的1/N别按原来的采样率去算数据吞吐。还有一个容易忽略的点G4的ADC有注入组和规则组之分过采样单元可以分别配置是否作用于这两组转换。规则组一般用于常规采集注入组用于事件触发的高优先级采集。如果两种采集的过采样倍率要求不一样需要仔细核对寄存器否则很容易出现“注入组结果被过采样单元按规则组的倍率处理了”这种诡异现象。4. 硬件设计想让过采样有效果模拟前端必须干净说实话过采样不是万能药。如果模拟前端的噪声太大或者存在周期性干扰过采样能起到的作用非常有限。我在实测中就遇到过“硬件过采样开满256倍读数依然跳动”的情况查到最后是开关电源的纹波直接耦合进了参考电压。先说参考电压。G4的ADC参考电压可以选择VDDA也可以选择外部VREF引脚还可以用内部VREFINT。做过采样追求高精度时强烈建议使用外部基准源比如REF5025这类低噪声精密基准。原因很简单过采样只能抑制ADC量化噪声和部分随机噪声但参考电压上的纹波会直接调制到测量结果上而且是确定性干扰过采样滤波器很难完全滤除。我实测对比过同样用硬件过采样256倍VDDA供电时读数峰峰值跳动约6~8个LSB16位结果换成外部REF5025后跳动降到1~2个LSB。其次是输入信号调理电路。G4的ADC输入阻抗不是无限大采样电容的充电过程会从信号源抽取电流。如果源阻抗太高采样期间电容充不满会导致增益误差和非线性。过采样对这个问题没有帮助反而因为采样次数多问题会更明显。常规做法是在ADC输入引脚前加一个RC低通滤波器电容选10nF到100nF电阻根据信号源阻抗调整。RC滤波器本身还能抑制带外高频噪声配合过采样效果更好。再有一点很容易被忽视地平面和布局。ADC采集电路的地要尽量单点连接到模拟地避免数字信号的回流电流穿过模拟区域。如果板子上有电机驱动或者继电器这类强干扰源ADC前端还要考虑加屏蔽或加大滤波。我在一个电机控制板上的经验是模拟地和数字地在ADC芯片下方单点连接并用磁珠或0欧电阻隔开ADC的采样稳定性提升非常明显。还有一个关于信号源阻抗的实测数据可以分享当源阻抗从1kΩ增大到100kΩ时G4的ADC读数值会明显偏低12位原始值大约偏了10~20个LSB。做过采样之后这个绝对误差依然存在只是读数看起来更“稳定”了——注意稳定不代表准确。所以想用好过采样先保证输入信号源阻抗足够低一般建议在10kΩ以下。5. 寄存器配置实战CubeMX与寄存器两种路径跑通硬件过采样最快的方式是用STM32CubeMX生成初始化代码但如果你想彻底搞懂每个配置项的含义还是得看参考手册里的“Oversampler”章节。我两条路都跑过下面分别说。5.1 CubeMX图形化配置在CubeMX里选择ADC1使能“Oversampling”功能后会跳出几个选项Oversampling Ratio过采样倍率可选2、4、8、16、32、64、128、256Right Bit Shift右移位数范围0到11Triggered Mode是否启用触发过采样模式Averaging Mode平均值模式本质上就是累加后右移ST在HAL库里封装了求平均的逻辑Oversampling Discontinuous Mode是否在不连续模式下工作我的推荐配置Ratio选256Right Bit Shift选4其他保持默认。这样得到的结果是12820位累加值右移4位后是16位结果。注意这里的“16位结果”在数值范围上仍然是0~65535但每一位的“含金量”比原始12位高得多。CubeMX生成的HAL代码里过采样的配置在ADC_OversamplingTypeDef结构体中hadc1.Init.OversamplingMode ENABLE; hadc1.Init.Oversampling.Ratio ADC_OVS_RATIO_256; hadc1.Init.Oversampling.RightBitShift ADC_RIGHTBITSHIFT_4; hadc1.Init.Oversampling.TriggeredMode ADC_TRIGGEREDMODE_SINGLE_TRIGGER; hadc1.Init.Oversampling.OversamplingStopReset ADC_REGOVERSAMPLING_CONTINUED_MODE;其中TriggeredMode和OversamplingStopReset影响的是触发节奏。如果你用定时器触发ADC单次触发后是否完成一整组256次过采样就看这两个参数怎么配。我的经验是单次触发模式下让一个触发脉冲完成一组完整的过采样256次内部采样这样数据率就是触发频率的1/1时序更可控。5.2 寄存器级直接配置如果你不想用HAL直接操作寄存器也很简单。关键在于CFGR1寄存器的OVSE、OVSR、OVSS位以及CFGR2里的ROVSM位。下面是一个直接在ADC初始化后写入过采样配置的示例// 开启过采样倍率256右移4位 ADC1-CFGR1 | ADC_CFGR1_OVSE; // 使能过采样 ADC1-CFGR1 | ADC_CFGR1_OVSR_3 | ADC_CFGR1_OVSR_2; // OVSR[2:0] 110对应除以256 ADC1-CFGR1 | ADC_CFGR1_OVSS_2; // OVSS[3:0] 0100右移4位这里有个容易搞错的地方OVSR字段的编码不是直接的倍率数值而是“除以2的N次方”的指数。比如OVSR0b110等于6对应2的6次方等于64倍。等等这里我写的是OVSR[2:0] 110参数手册上对应的是256倍吗让我重新核对一下。G4参考手册里OVSR[2:0]共3位但过采样倍率支持2~256明显3位二进制无法直接表示256。我记错了。实际上G4的过采样倍率是通过OVSR字段配合一个附加位来编码的。准确说倍率 2^(OVSR1)OVSR范围0~7所以最大倍率是2^8256。OVSR0对应2倍OVSR1对应4倍以此类推。这么说的话256倍对应OVSR7即0b111。这里我必须提醒一句千万不要凭记忆写寄存器不同系列的编码方式有差异。我一开始就是吃了这个亏按F3系列的编码去写G4结果过采样倍率完全不对。最稳妥的做法是打开CubeMX生成一次代码然后对照HAL库源码里的宏定义逐一确认。5.3 初始化顺序的坑过采样功能的使能顺序有讲究。我建议在ADC校准之后再使能过采样并且使能过采样后再重新做一次校准。G4的ADC校准是校准内部电容阵列如果过采样改变了转换时序校准结果可能略有偏差。虽然这个偏差很小但既然追求16位精度这些细节就不能放过。另外过采样结果寄存器占用的是普通数据寄存器DR不是某个独立的寄存器。读取方式和普通ADC一样只是数值含义变了。用DMA搬运时数据宽度要设置为16位或32位否则高字节可能被截掉。我习惯把DMA设置为半字16位模式因为过采样结果是16位有效数据。6. 实测数据256倍过采样后的真实表现空谈配置没有说服力我把自己在测试板上跑出来的数据贴出来。测试条件是STM32G474RE主频170MHzADC时钟设为系统时钟的一半采样时间设为最长的640.5周期外部基准REF5025输入信号由高精度信号源输出1.25V直流。先用原始12位模式连续采集1000次统计结果指标数值平均值2047.6峰峰值跳动8 LSB标准差1.8 LSB有效位数估算约11.2位然后开启硬件过采样256倍、右移4位同样连续采集1000次指标数值平均值2047.8峰峰值跳动2 LSB标准差0.4 LSB有效位数估算约15.6位从数据看峰峰值跳动从8个LSB降到2个LSB标准差降了约4.5倍有效位数从11.2位提升到15.6位。虽然没到理论的16位但已经非常接近。剩余那0.4位的差距主要是参考电压噪声和温度漂移贡献的。我还在相同条件下做了不同过采样倍率的对比趋势很清晰过采样倍率峰峰值跳动16位结果标准差1倍原始12位32 LSB7.2 LSB4倍16 LSB3.6 LSB16倍7 LSB1.5 LSB64倍4 LSB0.8 LSB256倍2 LSB0.4 LSB注意为了统一比较我把所有结果都换算成16位域。从1倍到256倍标准差下降了约18倍这说明过采样每增加4倍噪声确实大约减半。这和理论推导高度吻合。不过我也要泼一盆冷水过采样不会改善ADC的微分非线性DNL和积分非线性INL。如果你的应用需要极高的绝对精度比如0.01%的测量误差那单靠过采样是不够的还得做增益校准和偏移校准。G4的ADC自带偏移校准功能但增益校准需要外部精密源配合一般放在产线测试阶段做。7. 过采样与DMA、定时器协同的工程细节实际项目里ADC很少单独工作通常和定时器、DMA协同。G4的过采样器和这几个外设配合时有几个工程细节值得单独说。7.1 DMA缓冲区的数据组织用过采样后ADC触发一次事件产生的不是单次转换结果而是N次累加后的结果。如果用定时器周期触发触发频率除以N才是实际的数据更新率。假设你希望最终数据率是1kHz过采样倍率是256那定时器触发频率应该设为256kHz。这个关系千万别搞反了否则最终数据率会比预期慢256倍控制环路直接跑飞。我见过一个真实案例同事把定时器触发频率按1kHz配置过采样256倍结果数据率只有约4HzPID控制器完全没法用。查问题花了一下午最后发现就是这个换算关系错了。7.2 DMA中断与CPU负载G4的DMA可以在每次过采样结果更新时产生中断。如果过采样倍率高、数据率高中断频率可能很高CPU负载会骤增。一个常用的优化是DMA使用循环模式把数据连续写入环形缓冲区主循环里每N次读取一次平均值或者用DMA传输完成中断半满、全满回调用批处理。这样CPU开销比每次数据都中断低很多。7.3 温度漂移问题G4的内部基准电压和ADC本身的增益都会随温度变化。过采样不能消除这种慢漂移因为它本质上是低通滤波会把漂移当作“有效信号”保留下来。在温度变化大的环境中我建议定期做软件校准用内部基准通道VREFINT测量当前的基准电压值反过来修正ADC结果。G4的VREFINT可以通过内部通道直接测量校准公式一般是实际电压 VREFINT_CAL * ADC_REFERENCE / ADC_MEASURED其中VREFINT_CAL是出厂校准值存在系统存储区可以在程序启动时读取。这个方法虽然不能像外部基准那样完全消除温漂但能把温漂误差从百分之几压到千分之几的量级很多应用够用了。8. 常见误区和排查方法最后一个部分把我在社区和实际项目中看到的常见问题汇总一下都是真实踩过的坑按出现频率排序。8.1 过采样后读数“太稳定”反而可疑有朋友跟我说他开了512倍过采样后读数纹丝不动问我是不是效果太好了。我第一反应是“数据是不是没更新”。这种“过度稳定”往往意味着过采样配置有误——比如触发了但没真正开始转换DMA搬的是同一个地址的旧数据。排查方法很简单改变输入电压看读数是否跟着变。如果输入从1V变到2V读数还是老样子先查触发源和DMA配置别急着怀疑噪声。8.2 过采样倍率越高为什么反而更差在某些情况下过采样从64倍升到256倍读数反而跳动更明显。这通常不是过采样本身的问题而是高倍率下采样窗口拉长外界干扰被完整地采进去了。比如50Hz工频干扰64倍过采样时采样窗口可能刚好覆盖了不到一个工频周期而256倍时覆盖了多个周期工频的整流效应反而让低频波动进入了结果。解决思路提高触发频率让过采样窗口变短或者在模拟前端加50Hz陷波/低通滤波。8.3 校准与过采样的顺序ADC偏移校准最好在开启过采样之前做。如果校准后过采样倍率改了部分芯片的校准结果可能需要重新加载。我在G4上遇到过一次先校准再开过采样数据正常后来改成先开过采样再校准结果零点跑了十几个LSB。所以我的固定流程是校准 → 配置过采样 → 校验零点 → 正式开始采集。8.4 不要忘了看参考手册的勘误表G4系列有一些已知的ADC勘误项比如某些时钟配置下过采样结果可能偶发跳变。这些内容在芯片的Errata文档里写得明明白白但很少有人看。我建议确定最终参数前先下载对应型号的Errata文档搜索“Oversampling”关键词确认有没有和自己配置相关的已知问题。别等量产了才发现有这个坑那时候改设计成本就高了。9. 过采样的替代方案硬件ADC与软件滤波的取舍最后聊聊过采样和软件滤波怎么配合以及什么情况下可以考虑外部高精度ADC。过采样本质上是“以时间换精度”。它适合信号带宽较低、对实时性要求不高的场景比如温度巡检、压力传感器采集、电池电压监测。但如果你做的是电机电流环带宽要求几十kHz那过采样256倍会把采样率拖垮这时候反而不能用高倍率过采样最多用4倍或8倍再配合专门的低延迟滤波器。软件滤波方面我常用的组合是过采样 滑动平均 异常值剔除。过采样先把随机噪声压下去滑动平均再平滑剩余的周期波动异常值剔除用来对付偶发的尖峰干扰。三段式处理之后数据质量比单纯堆过采样倍率好得多。如果你试了过采样还是达不到精度要求再考虑外部ADC。外部24位Sigma-Delta ADC比如ADS1256在极低速率下的有效位数确实能到20位以上但它的转换速率也低得可怜。所以选型逻辑很清晰12位ADC过采样能做到的精度约16位能满足需求就用片上方案成本最低满足不了再跳去外部高精度ADC。大多数工业采集场景G4片上方案已经够了。10. 我个人的最终建议这几个月用下来我的结论是STM32G4的硬件过采样是一个被严重低估的外设。它不像外部ADC芯片那样“看得见摸得着”但只要配置得当确实能把12位ADC的实用精度推到接近16位而代价仅仅是多占一些转换时间和一小段Flash空间。如果你手头正好有G4的板子我建议按这个顺序试一遍先按CubeMX默认配置跑通过采样256倍用内部参考电压测一下原始跳动然后把参考电压换成外部基准再看数据最后加上DMA和软件均值滤波对比三组数据。你会明显感觉到每一步优化都在把噪声一点点压下去这个过程本身就是对ADC采样链路最好的学习。最后再分享一个实用技巧过采样结果的低位并不是完全无意义的随机噪声它包含了输入信号在最低位以下的细微变化信息。所以即便你最终只需要12位的输出精度做过采样之后再用软件做阈值判断或迟滞比较也能比直接用原始12位数据更稳定——这个特性在按键检测、液位开关这类场景里非常有用。
返回列表