软件控制时钟调制SCCM扩展功能详解:降低EMI的核心技术
2026/9/8 14:16:00 网站建设 项目流程

1. “扩展”到底多了什么:先弄清软件控制时钟调制的基础盘

1.1 软件控制时钟调制(SCCM)是干什么用的

把标准方波时钟想象成一把聚光手电,所有能量都打在一个点上,EMI 接收机扫频时就会在那个频率以及它的奇次谐波上看到很高的尖峰。软件控制时钟调制(Software Controlled Clock Modulation,以下简称 SCCM)做的事情就是给这个“手电”加一个振动电机,让光点在墙上快速来回扫动。频率变了,能量就从原来的离散频点摊开到了一段频率范围,墙上的峰值亮度自然就降下来了。

工程上的表述是:SCCM 让 PLL 输出时钟的频率随时间周期性微调,把原本集中在基频和奇次谐波上的能量扩展到目标频段,从而降低峰值辐射。在频谱仪上你会看到原来的单根谱线变成一段类似“小土包”的包络。这个手段在MCU、FPGA、存储控制器里都很常见,目的非常直接——解决 EMI 超标问题,省下改板、加屏蔽罩的钱,也让产品更好过认证。

现在各家芯片厂手册里的章节号很像,当你看到类似 14.7.3.1 这种编号,基本可以判断它是“时钟与复位控制”大章节里面的细分条目;【五】通常表示这是同系列说明文档或者同一功能域的第五个部分。这个标题里真正要关注的是 EXTENSION,也就是“扩展”。为什么单独把“扩展”拎出来讲?因为基础版 SCCM 往往就是一个全局开关加固定档位,而扩展版意味着你可以在更细的粒度上控制它。

1.2 扩展功能在哪些维度做了升级

我拆过好几款主流 MCU 的手册,也实际调过这些寄存器,总结下来“扩展”一般体现在四个维度:

第一,从“全局开关”扩展到“多时钟域独立控制”。基础版本通常是一个总开关,打开以后整个芯片的时钟都跟着调。扩展版本会分成多个时钟域,比如 CPU 内核域、总线域、USB 域、SDIO 域,每个域可以单独决定调制深度甚至单独关闭。这个非常重要,因为不同外设对时钟抖动的容忍度差异很大。USB 和 Ethernet 对参考时钟的抖动要求非常苛刻,而 PWM、UART 这种相对宽松;一块板子上不可能用一套参数同时满足所有外设,分域控制才有实际意义。

第二,从“固定档位”扩展到“参数可动态配置”。基础版可能就是出厂写死 0.5% 向下扩频,你只能打开或关闭。扩展版通常提供调制深度、调制频率、调制波形等多个可配置项,而且支持运行期重新写入。这样你在现场调 EMI 的时候,不用反复编译烧录固件,直接在调试器里改寄存器就能看到效果,效率高一大截。

第三,从“自由运行”扩展到“带握手和状态反馈”。扩展版通常会增加调制引擎忙标志、锁定状态、启动停止控制位,甚至会在 PLL 失锁时自动暂停调制。握手机制是为了防止你在调制引擎工作的过程中强行修改参数,导致输出时钟中间出现毛刺。这看似简单,实际非常关键。

第四,从“单波形单模式”扩展到“多种调制策略可选”。包括中心扩频、向下扩频,三角波调制、正弦波调制,甚至一些自定义波形。不同策略对 EMI 的抑制效果和对系统时序的影响完全不同,有了选择才能应对不同协议的限制。

看懂了这四点,再去读 14.7.3.1 这一节就不会一脸茫然。它不是在讲一个新的外设,而是在讲如何把原有的 SCCM 功能做深做细。

2. 调制深度、调制频率与波形:参数背后的权衡逻辑

2.1 调制深度 M:一边压辐射,一边伤时序

调制深度是 SCCM 里最核心的参数,没有之一。它的含义是输出频率相对中心频率的最大偏移比例,一般用百分数表示。瞬时输出频率可以写成:

f(t) = f_base × (1 + A × m(t))

m(t) 是归一化调制波形,取值在 -1 到 1 之间;A 就是调制深度。比如中心扩频 A = 1%,f_base = 128MHz,那么输出频率会在 128MHz×(1 - 0.5%) 到 128MHz×(1 + 0.5%) 之间摆动,也就是 127.36MHz 到 128.64MHz 之间来回扫。如果是向下扩频 A = 1%,那就是从 128MHz 到 126.72MHz 之间摆动,频率上限就是标称值。

从 EMI 角度看,扩频跨的带宽越宽,峰值辐射降得越多。工程上有个粗略估算:如果频谱仪分辨率带宽是 RBW,扩频展宽是 B_mod,调制的能量近似均匀铺开以后,峰值衰减量大约在 10log10(B_mod / RBW) 这个量级。举个例子,基频 128MHz,调制深度 1%,展宽约 1.28MHz,用 120kHz 的 RBW 去测,理论上衰减大约 10 个 dB。这跟实际测试结果比较接近,当然实际情况还要看波形、谐波序号和板子走线,没法做到精确,但可以拿来做预判。

代价是什么?时序裕量。频率摆起来以后,所有由这个时钟分频出来的定时器、PWM、UART 波特率、ADC 采样周期都在跟着动。UART 最典型,一帧数据十来个 bit,如果调制深度太大,接收端采样点会逐渐偏移,等到偏移超过 0.5bit,帧就解析错误。做 UART 通信时我一般会把调制深度压在 0.5% 以内,或者干脆对 UART 所在时钟域关闭调制。

调制深度不是越大越好,这在实测里表现得很明显。0.25% 到 0.5% 往往就能拿到 3 到 6 个 dB 的改善;往上到 1% 到 1.5%,改善继续增加到 6 到 9 个 dB;再往上到 2% 甚至更多,频谱已经铺得很平,边际收益变得很小,但是时序方面的损失却非常直接。我通常建议从 0.5% 起步,跑一次预扫描,不够再加,绝对不能一开始就把参数拉满。

2.2 调制频率和调制波形:容易被忽略但很关键

调制深度决定频率摆动的范围,调制频率决定摆动得多快。常见的默认调制频率在 30kHz 到 60kHz 之间。这个区间是经过权衡的,理由有两个:

一是要避开人耳可闻范围。调制频率低于 20kHz 时,时钟频率的周期波动会通过板上的电感和陶瓷电容耦合到电源环路,产生人耳能听到的“滋滋”声。这个声音虽然不影响功能,但客户听到很难接受,尤其是静音环境下的工业设备。把调制频率提到 30kHz 以上,人耳基本就听不到了。

二是要保证下游时钟链路能跟上调制。如果调制频率太高,超过了下游 PLL 或者时钟 Buffer 的环路带宽,实际到达输出引脚的频率变化会被“平均”掉,扩频效果大打折扣。举个例子,外部设备接收你的时钟信号时,它内部通常也有一个 PLL 在跟踪输入频率,这个 PLL 的带宽往往就在几十 kHz 量级。调制频率高出带宽太多,接收端根本来不及跟踪,等于没扩。30 到 60kHz 正好处于“听得见问题已解决、跟踪也来得及”的甜点区。

再说调制波形。最常见的两种是三角波和正弦波。三角波的特点是瞬时频率在整个调制周期内线性变化,能量在展宽频带里分布均匀,频谱包络比较平,峰值抑制效果好。但它有缺点,频率在转折点会瞬间改变变化方向,相当于瞬时频率加速度很大,对下游跟随时钟的 PLL 不友好。正弦波的频率变化圆滑,对被调制端友好,但能量集中在频带两端,中间不够平,峰值抑制效果弱一些。所以内部时钟域常用三角波,外送时钟尽量用正弦波或降低深度。

2.3 中心扩频与向下扩频怎么选

先看一张对比表,后面细说:

模式频率范围核心优势主要限制
中心扩频f_base×(1±M/2)平均频率接近标称值,长期误差小瞬时频率可能超过标称上限
向下扩频f_base 到 f_base×(1-M)频率始终不超过标称值,合规性好平均频率偏低,有系统性的负偏移

中心扩频很好理解,频率围绕标称值上下摆动,长时间统计平均频率基本就是标称值。这种方式适合对时钟频率误差有要求的系统,比如某些高精度定时场景,或者外部设备对进入的时钟严格执行标称频率的场景。

向下扩频则完全牺牲“平均频率等于标称值”这个优点,换来的好处是频率永远不会超过标称上限。这个在很多协议里是硬性要求。最典型的就是 USB,USB 2.0 参考时钟就允许向下扩频,甚至有标准明确建议使用向下的扩展方式。PCIe 也有类似的限制,不允许让时钟在标称频率之上跑。所以当你做 USB 或者 PCIe 相关设计时,优先考虑向下扩频,这是行业惯例。

还有一点,扩展功能里看到的“向上扩频”实际上很少见到,因为频率只往高走既没有协议需求,还会带来更多的热和功耗问题,所以很多芯片干脆就不提供。

3. 扩展功能配置实操:从寄存器到位域

3.1 寄存器长什么样

具体型号不同,寄存器名字会有差异,但位域设计高度相似。下面这套写法是基于我见过的主流 MCU 归纳出来的通用模型,不方便直接套到某个具体芯片,但思路完全一致。

typedef struct { uint32_t MOD_EN : 1; /* 0: 调制关闭 1: 调制开启 */ uint32_t MOD_MODE : 1; /* 0: 向下扩频 1: 中心扩频 */ uint32_t MOD_DEPTH : 3; /* 调制深度档位,0~7 */ uint32_t MOD_RATE : 4; /* 调制频率档位,0~15 */ uint32_t MOD_START : 1; /* 写1启动调制引擎 */ uint32_t MOD_BUSY : 1; /* 只读,1表示调制引擎忙 */ uint32_t RESERVED : 21; } SCCM_CTRL_TypeDef;

实际使用中,调制深度和调制频率很可能被拆成独立寄存器,比如 SCCM_CFG 管深度,SCCM_RATE 管频率。但位域的设计意图就是通过软件把所有调制行为管起来,这也是“Software Controlled”这几个词的核心所在。真正的硬件调制过程由内部模拟电路自动完成,软件只需要负责配置参数、启动停止、检测状态,这正是它比纯硬件扩频方案灵活的原因。

3.2 首次使能调制的标准流程

按我调过的几款芯片经验,第一次打开 SCCM 不要直接改一堆寄存器然后一次性使能,那样出问题你很难定位是哪个参数惹的祸。稳妥的流程如下:

  1. 关闭调制引擎,把 MOD_EN 写 0;
  2. 等待 MOD_BUSY 变成 0,确保调制引擎已经完全停止;
  3. 先把时钟源切到目标频率,等 PLL 锁定;
  4. 选择扩频模式,需要合规要求的选向下扩频,否则先试中心扩频;
  5. 调制深度从最低档开始,比如 0.25% 或 0.5%;
  6. 调制频率选 30kHz 到 60kHz 之间的档位;
  7. 置位 MOD_START,启动调制;
  8. 确认 MOD_BUSY 没有再报忙,置位 MOD_EN 让调制真正生效;
  9. 先用示波器观察输出时钟,再用频谱仪做对比测试。

第 1、2 步很多人会忽略,直接改参数再开调制,结果偶尔能成偶尔不行。原因在于调制引擎内部有数字滤波器和模拟电路,如果它还在运行中就改了参考参数,输出时钟可能产生毛刺。毛刺如果被时钟监控模块捕获,轻则触发一次复位,重则导致整个时钟域切换,系统行为完全乱套。

void sccm_init(uint8_t mode, uint8_t depth, uint8_t rate) { /* 第 1 步:先关闭调制 */ SCCM->CTRL &= ~SCCM_CTRL_MOD_EN_MASK; /* 第 2 步:等待调制引擎完全停止 */ while (SCCM->CTRL & SCCM_CTRL_MOD_BUSY_MASK) ; /* 第 3~6 步:配置模式、深度、频率 */ SCCM->CFG = (SCCM->CFG & ~(SCCM_CFG_MODE_MASK | SCCM_CFG_DEPTH_MASK)) | ((uint32_t)mode << SCCM_CFG_MODE_SHIFT) | ((uint32_t)depth << SCCM_CFG_DEPTH_SHIFT); SCCM->RATE = rate; /* 第 7 步:启动调制引擎 */ SCCM->CTRL |= SCCM_CTRL_MOD_START_MASK; /* 第 8 步:使能调制 */ SCCM->CTRL |= SCCM_CTRL_MOD_EN_MASK; }

这段代码在逻辑上是完整的,但你在真机上写的时候一定要去查具体型号的头文件,把掩码和偏移量换成实际定义。不要相信任何一篇博文里的寄存器地址可以直接照搬,包括你现在看到的这一篇,真实硬件代码必须以 datasheet 为准。

3.3 运行期动态调整:扩展功能最实用的部分

扩展功能里我觉得最有价值的就是运行期动态调整。之前调一个板子的 EMI,参数不合适就得改代码、重新编译、烧录、开机、测试,一次循环 5 到 8 分钟。有了动态调整,调试器里直接改寄存器,改完立刻看频谱,几分钟就能扫出一组最优参数。

动态调整有个关键动作:先停止,再修改,再启动。直接修改正在运行的调制深度没问题,但如果你从 1% 直接调回 0.5%,中间可能经过一个未定义的状态,输出频率会出现一个突跳。这就好比开车时从 120 直接挂回 1 挡,变速箱必然顿挫。正确做法永远是先关闭调制,等 BUSY 清零,改参数,再开启。

void sccm_set_depth(uint8_t depth) { if (depth > 7) depth = 7; /* 先关 */ SCCM->CTRL &= ~SCCM_CTRL_MOD_EN_MASK; while (SCCM->CTRL & SCCM_CTRL_MOD_BUSY_MASK) ; /* 改深度 */ SCCM->CFG = (SCCM->CFG & ~SCCM_CFG_DEPTH_MASK) | ((uint32_t)depth << SCCM_CFG_DEPTH_SHIFT); /* 再开 */ SCCM->CTRL |= SCCM_CTRL_MOD_EN_MASK; }

注意:如果一个芯片支持多时钟域独立调制,每个域的使能、停止、参数配置是独立的,千万别用一个函数把所有域都关了。我之前踩过这个坑,调用了一次通用初始化函数,结果 USB 域也被关了调制,整个系统的 EMI 不降反升,排查了半天才意识到是分域配置没有做隔离。

4. 常见问题与排查技巧实录

4.1 USB 枚举不稳定,调制一开就出问题

现象非常典型:不开 SCCM,设备在电脑上识别一切正常;一开调制,USB 设备时而识别时而不识别,枚举失败率大幅上升。用 USB 分析仪看,能看到 SOF 包间隔抖动变大,眼图闭合明显。

问题基本出在调制深度上。USB 对参考时钟的抖动要求非常严格,比如 USB 2.0 高速模式对时钟误差的容忍范围很小,你如果用了 1% 甚至更高的深度,数据线上的信号直接不合格。解决办法有两条路:一是把这个时钟域的调制深度降到 0.25% 左右的低档位;二是干脆对 USB 域关闭调制,只给 CPU、存储这类不那么敏感的域开。我用后一种方法比较多,USB 的 EMI 主要靠物理层设计和屏蔽来解决,SCCM 只是辅助。

另外注意 USB PHY 通常有自己的 PLL,输入参考时钟的微小抖动会被 PHY 的 PLL 放大或者平滑,所以哪怕关闭 USB 域的调制,对整体辐射的影响通常也可控。

4.2 调制打开之后板子发出“滋滋”声

这个问题出现的时候,你先别怀疑硬件焊接和电感质量问题。拿示波器去测调制相关的时钟控制位,十有八九是调制频率设得太低,落到了 20kHz 以下。这个可闻噪声不是从喇叭发出来的,而是电流流过 MLCC 电容和功率电感时,介质和磁芯在交变电场/磁场下产生微小的机械形变,形变频率落在人耳听觉范围内就成了“吱吱”声。

解决很简单,把调制频率提到 30kHz 以上。我在一个电源项目上遇到过,默认配置是 14kHz,整个办公室都能听到,改成 32kHz 之后声音立刻消失,EMI 效果几乎不变。如果改了频率还叫,就得考虑是不是调制深度太大,导致电流纹波偏大,把深度降半档试试。

4.3 ADC 采样数据出现规律性波动

这个坑比较隐蔽。ADC 的采样时钟如果分频自被调制的系统时钟,那么每个采样点的实际时刻会有周期性的时间偏移。被采样信号如果是慢变的直流电平还好,一旦是高频信号或者边沿快速的 PWM 波形,采样时刻的抖动会直接转化为幅度误差,你会看到采样数据里面有一条明显的波浪形扰动。

排查方法很简单:把 SCCM 先关掉,看采样数据是否恢复正常。如果恢复正常,基本可以锁定是调制导致的采样时刻抖动。处理方式有三种:一是把 ADC 的时钟源切换成不受 SCCM 影响的异步时钟域;二是降低该时钟域的调制深度,把抖动压到 ADC 的量化误差以下;三是改用硬件触发采样,让采样点固定在调制周期的同一相位上,这样每次采样的时间偏移是固定的,误差就变成了系统偏差而不是随机扰动。

4.4 调试器偶发断连,烧录时尤其明显

SWD 或 JTAG 调试连接在调制开启后出现偶发断连,这个问题我碰到过两次。表面看是调试链路问题,实际根源在复位和时钟切换。调制引擎在启动和停止瞬间,如果系统时钟正好处于频率突变点,复位控制器可能产生一次毛刺,导致内核短暂复位或者调试状态丢失。尤其是你在调试器里单步执行时,寄存器写入和调制状态切换的时序容易撞到一起。

我的经验是:调试阶段就把 SCCM 关掉,等所有功能调通了,到 EMI 测试阶段再开启调制。不要一边开着扩频一边去调试时序敏感的外设,否则你会把“调制引入的问题”和“代码自身的问题”混在一起,排查效率极低。

4.5 动态调参不生效,寄存器写不进去

如果你按照前面说的“先关、再等、后改、再开”流程来做,一般不会遇到这个问题。但我见过一些同事直接往控制寄存器赋值,结果发现改了深度之后的波形和之前一模一样。原因就是忘了先关闭调制或等待 BUSY 位清除。硬件在这种情况下会直接忽略写操作,或者写入后立即被内部状态机覆盖。这不是芯片 bug,是扩展功能故意设计的保护机制,防止你在错误时序下写入参数造成时钟毛刺。遇到这种问题不要强行绕过等待机制,老老实实按要求操作。

4.6 问题排查速查表

现象首要怀疑点快速验证方法常用处理
USB 枚举失败调制深度过大关闭该域调制测试降到 0.25% 或关闭
电源吱吱声调制频率过低听声音判断频率提到 30kHz 以上
ADC 数据波浪采样时钟被调制关调制对比采样换异步时钟源
调试器断连调制启停毛刺调试阶段关 SCCM量产固件再开
参数写不进未等待 BUSY 清零读状态寄存器补全握手流程

5. 调参实测经验与最后一点补充

前面讲的是原理和流程,这里分享一段我实际调板子的过程,算是把整个思路串一遍。当时是一块带 USB 接口的采集板,主控跑 96MHz,外部 24MHz 晶振倍频出来。EMI 预扫描时在 96MHz、192MHz、288MHz 三个频点超标,基本可以确定是主控时钟的谐波。我当时的处理动作是:先把 USB 时钟域从 SCCM 里排除,因为 USB 更要紧的是协议合规,这个决定了产品能不能正常工作;然后对 CPU 和总线域开启向下扩频,深度从 0.5% 开始,调制频率设到 33kHz,三角波。预扫描看到 96MHz 那个点降了大约 6dB,其余两个谐波也降了 4 到 7dB,三个频点都落到了限值以内。整个过程前后不到半小时,没有改一行原理图,没有加任何屏蔽材料。

有几个操作细节分享一下。第一,同一块板子在调试时开和关 SCCM,分别记录一次频谱峰值列表,比对数据就能看出功能有没有真的生效,也能看出调制压掉了哪些频点。第二,调制深度每加一档,频谱峰值下降的幅度会越来越小,当你发现加一档深度只降了零点几个 dB 的时候,就说明已经接近饱和,没必要再往上加。第三,对外提供时钟信号时,比如音频 MCLK 或视频像素时钟,优先选正弦波加低深度,不要用三角波,否则对端芯片的 PLL 可能锁不住或者抖动过大。

最后还有一条经验,不要把所有 EMI 希望都寄托在 SCCM 上。它只能帮你把时钟谐波相关的峰值压下去,对电源噪声、差分信号共模辐射、走线天线效应基本无能为力。SCCM 的正确打开方式是,先做好原理图和 PCB 的基础设计,等到最后测试阶段还剩几个频点超标,用它来打补丁。这样调起来效率最高,效果也最可控。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询