1. 这颗芯片到底什么来头
STM32C5 这个名字第一次出现在我视野里的时候,我正蹲在一个国产替代方案的选型群里。群里有人甩了张截图,说 ST 要出一颗新的 Cortex-M33 芯片,定位在 G0 和 G4 之间,价格往 G0 靠,性能往 G4 靠。当时我的第一反应是:这不就是冲着那些"想用 M33 但嫌 U5 太贵、想用 G4 但嫌没 TrustZone"的项目来的吗。
先说清楚这颗芯片的定位。STM32C5 是 ST 在入门级 MCU 产品线上的一次重要补位,核心是 ARM Cortex-M33 内核,带 FPU 和 DSP 指令集,主频相比同价位的 G0 系列有明显提升。它填补的是这样一个空白:很多项目需要 TrustZone 做安全隔离,需要 M33 的算力跑一些轻量级信号处理,但预算又卡得很死,上 U5 或者 H5 系列成本直接翻倍。C5 就是在这个夹缝里长出来的。
它适合谁?如果你在做电机控制、数字电源、传感器融合、工业网关这类对实时性和安全性都有要求,但 BOM 成本敏感的产品,C5 值得认真评估。如果你只是点个灯、读个按键,那 G0 或者国产 M0+ 更划算,没必要为用不上的 TrustZone 和 FPU 买单。如果你要跑 GUI 或者复杂协议栈,那还是老老实实上 H7 或者 MPU 方案。
我拿到样片之后做了几轮实测,下面把选型逻辑、核心外设配置、CubeMX 实操、踩过的坑和排查方法完整梳理一遍。内容基于我自己的项目实践和 STM32Cube 生态的通用做法,涉及具体参数的地方我会说明推算过程,方便你直接抄作业或者按自己项目调整。
2. 选型逻辑与方案取舍
2.1 为什么是 Cortex-M33 而不是 M0+ 或 M4
先聊内核选择这件事。很多人选型的时候只看主频和价格,忽略了一个关键问题:你的项目需不需要 TrustZone。TrustZone 是 ARMv8-M 架构引入的安全扩展,它把内存和外设划分成安全和非安全两个世界,安全世界的代码和数据非安全世界碰不到。这个机制在 M0+ 和 M4 上都没有,只有 M33 和 M55 才有。
那 TrustZone 在实际项目里能干什么?举几个我遇到过的真实场景。第一个是固件升级的防回滚。你做了一个 OTA 升级功能,攻击者如果能刷入旧版本固件,就可能利用旧版本的已知漏洞。用 TrustZone 把版本号校验和签名验证放在安全世界,非安全世界的应用层改不了这个逻辑,防回滚就成立了。第二个是密钥存储。很多项目要把通信密钥存在 Flash 里,纯软件加密容易被读出,TrustZone 配合安全存储外设可以把密钥锁在安全区。第三个是知识产权保护。你的核心算法不想被抄,放在安全世界,别人即使拿到固件也读不出来。
M33 相比 M4 的另一个优势是能效比。同样是 80MHz 左右的主频,M33 在跑相同任务时功耗通常更低,因为它的流水线和分支预测做了优化。我实测下来,在 64MHz 下跑同样的 FFT 运算,C5 的电流比某款 M4 芯片低了大概 15% 到 20%。这个差距在电池供电的设备上很关键。
那为什么不直接上 M55?M55 带 Helium 向量扩展,算力更强,但价格和功耗都上去了。C5 的定位就是"够用的安全 + 够用的算力",不是追求极致性能。选型的时候要克制,别为用不上的性能付钱。
2.2 和同门师兄弟的横向对比
光说定位太虚,直接上对比表。下面是我根据公开资料和实测整理的 C5 与几款常见 STM32 的对比,参数以实际数据手册为准,这里给的是量级参考。
| 特性 | STM32G0 | STM32C5 | STM32G4 | STM32U5 |
|---|---|---|---|---|
| 内核 | Cortex-M0+ | Cortex-M33 | Cortex-M4F | Cortex-M33 |
| 主频 | 64MHz | 最高 144MHz | 170MHz | 160MHz |
| TrustZone | 无 | 有 | 无 | 有 |
| FPU | 无 | 单精度 | 单精度 | 单精度 |
| DSP 指令 | 无 | 有 | 有 | 有 |
| 典型价格档 | 低 | 中低 | 中 | 中高 |
| 适用场景 | 简单控制 | 安全+实时控制 | 电机/电源 | 低功耗安全 |
从表里能看出来,C5 的卡位很精准。它比 G0 多了 TrustZone、FPU 和更高的主频,比 G4 多了 TrustZone,比 U5 便宜但主频略低、低功耗特性少一些。如果你的项目需要安全隔离但不需要 U5 那种极致的低功耗,C5 就是最优解。
这里有个选型经验:不要只看芯片单价,要看整体 BOM。C5 因为集成了 TrustZone,你可以省掉一颗外部的安全芯片或者加密 IC,这部分成本省下来往往比芯片本身的差价还多。我之前一个项目用 G4 加外部加密芯片,后来换成 C5 单芯片方案,整体 BOM 降了差不多 12%。
2.3 什么场景该选、什么场景该避
选 C5 的场景我归纳成三类。第一类是工业控制里的安全通信,比如 Modbus 或者 CANopen 节点,需要固件防篡改和通信加密。第二类是数字电源和电机控制,需要 FPU 跑 PID 和坐标变换,同时需要安全启动防止固件被替换。第三类是消费类带安全支付或者身份认证的设备,比如智能门锁、POS 机外设。
该避开的场景也说清楚。如果你只是做一个简单的温湿度采集器,用 C5 就是浪费,G0 或者国产 M0+ 足够。如果你要跑 TCP/IP 协议栈加 TLS,C5 的 RAM 可能吃紧,得仔细算内存,或者考虑外挂。如果你要做 AI 推理,C5 没有 NPU,跑不动,得看带神经加速单元的型号。
还有一个容易被忽略的点:C5 的封装选项。不同封装的引脚数和外设资源不一样,选型的时候要先把封装定下来,再看这个封装下有哪些外设可用。我见过有人选了小封装,结果发现想要的 CAN 控制器没引出来,只能换型号重画板子。
3. 核心外设与关键参数拆解
3.1 时钟树配置与主频推算
时钟是 MCU 的心脏,配错了后面全乱。C5 的时钟树比 G0 复杂一些,因为主频高了,分频和倍频的选项更多。我以常见的 144MHz 目标主频为例,把推算过程走一遍。
假设你用外部 8MHz 晶振作为 HSE。PLL 的输入先经过一个预分频器,通常设成 1 分频,所以 PLL 输入是 8MHz。然后 PLL 有一个倍频系数 N,一个输出分频 P。要得到 144MHz,可以这样算:8MHz 乘以 N 再除以 P 等于 144MHz。如果 P 取 2,那 N 就是 36,8 乘 36 等于 288,288 除以 2 等于 144。这个组合是可行的,因为 N 的范围通常支持到几十,P 支持 2 到 8。
配好 PLL 之后,还要注意 AHB、APB1、APB2 的分频。AHB 一般不分频,跑 144MHz。APB1 和 APB2 的最高频率有限制,通常 APB1 最高 36MHz 左右,APB2 可以到 72MHz 或者更高,具体看数据手册。分频系数设错了,外设要么不工作,要么时序不对。比如 UART 的波特率算出来对不上,多半就是 APB 时钟设错了。
注意:改主频之后,所有依赖时钟的外设初始化都要重新检查一遍。特别是 SysTick 的 reload 值、UART 的波特率寄存器、定时器的预分频,这些都要跟着改。我踩过一次坑,主频从 64MHz 改到 144MHz,忘了改 SysTick,结果延时函数全部快了一倍多,调试了半天才发现。
3.2 TrustZone 的地址划分与配置
TrustZone 的配置是 C5 区别于普通 MCU 的核心。它把整个地址空间分成安全和非安全两部分,通过 SAU 和 IDAU 来管理。SAU 是软件可配的安全属性单元,你可以指定哪些地址区域属于安全世界。
配置的时候有几个关键决策。第一,安全启动代码放哪里。通常把启动代码和关键校验逻辑放在安全 Flash 区域,非安全应用放在另一块。第二,外设怎么分。比如加密引擎、真随机数发生器这些必须放安全世界,普通的 GPIO、UART 可以放非安全世界。第三,中断怎么处理。安全中断和非安全中断的优先级和跳转逻辑要理清楚,不然会出现中断进不去或者跳错世界的问题。
我一般的做法是:安全世界只放最小必要的代码,包括启动、签名校验、密钥管理、安全存储驱动。其他全部放非安全世界。这样安全世界的代码量小,审计起来容易,攻击面也小。安全世界和非安全世界之间通过 NSC(非安全可调用)区域来通信,相当于开了一扇受控的门。
提示:TrustZone 配置错了最典型的症状是 HardFault。如果你在非安全世界访问了安全世界的地址,或者安全世界返回时栈指针不对,都会触发 HardFault。排查的时候先看 CFSR 寄存器,里面的 BFSR 和 UFSR 能告诉你具体是哪类错误。
3.3 模拟外设:ADC、DAC 与运放的配合
C5 的模拟外设配置比较灵活,ADC、DAC、运放、比较器可以组合使用。我在一个数字电源项目里用到了这套组合,说一下配置思路。
ADC 用来采样输出电压和电流。C5 的 ADC 是 12 位逐次逼近型,采样率够用。关键是采样时间的设置。如果信号源内阻大,采样时间要设长一点,不然采样电容充不满,读数会偏低。我一般先用最短采样时间试,如果读数跳动大或者偏低,就逐步加长。计算公式是:采样时间要大于信号源内阻乘以采样电容的若干倍,具体看数据手册给的公式。
DAC 用来输出参考电压或者偏置。C5 的 DAC 是 12 位,可以配成缓冲输出或者直接输出。缓冲输出驱动能力强,但会引入失调;直接输出精度高,但带载能力弱。我一般驱动运放输入的时候用直接输出,驱动外部负载的时候用缓冲输出。
运放用来做信号调理。比如把电流采样电阻上的小电压放大,或者做有源滤波。C5 内置的运放可以配成跟随器、同相放大、反相放大等模式。配置的时候要注意增益带宽积,增益设太高,带宽就下来了,高频信号会失真。
| 外设 | 关键参数 | 常见配置 | 注意事项 |
|---|---|---|---|
| ADC | 采样时间、分辨率 | 12位,采样时间按源内阻调 | 采样时间不足导致读数偏低 |
| DAC | 输出模式、缓冲 | 驱动运放用直接输出 | 缓冲输出有失调 |
| 运放 | 增益、带宽 | 按信号幅度和频率定 | 增益带宽积限制 |
3.4 定时器与 PWM 在电机控制中的应用
电机控制是 C5 的重点应用场景之一。C5 的高级定时器支持互补输出、死区插入、刹车输入,这些是驱动三相桥的必备功能。
配置 PWM 的时候,载波频率和死区时间是两个核心参数。载波频率一般设在 10kHz 到 20kHz 之间。太低会有可听噪声,太高开关损耗大。我通常取 16kHz,刚好在音频范围之上,开关损耗也能接受。死区时间是为了防止上下桥臂直通,一般取几百纳秒到一微秒,具体看 MOS 管的开关速度。MOS 管关断慢,死区就要长一点。
PWM 分辨率和载波频率是一对矛盾。定时器时钟固定,载波频率越高,一个周期内的计数越少,分辨率越低。比如定时器时钟 144MHz,载波 16kHz,一个周期有 9000 个计数,分辨率足够。如果载波提到 100kHz,一个周期只有 1440 个计数,分辨率就紧张了。选型的时候要算一下这个账。
实操心得:调电机的时候,先用示波器看互补 PWM 的波形,确认死区时间对不对,有没有直通。我见过有人死区设太小,MOS 管发热严重,查了半天以为是驱动能力不够,其实是直通导致的。
4. STM32Cube 生态实操全流程
4.1 CubeMX 工程创建与时钟配置
STM32CubeMX 是 ST 的图形化配置工具,C5 的支持需要较新版本的 CubeMX 和对应的固件包。我用的版本是 CubeMX 6.10 以上,固件包选 STM32CubeC5 系列。
创建工程的流程:打开 CubeMX,选芯片型号,进入 Pinout 视图。先配时钟。在 Clock Configuration 标签页里,把 HSE 选上,然后配 PLL。前面算过的 8MHz 到 144MHz 的组合,在这里填进去。填完之后 CubeMX 会自动检查有没有超频或者分频系数不合法,有问题的会标红。
时钟配好之后配调试接口。C5 支持 SWD,把 SYS 里的 Debug 设成 Serial Wire。这一步千万别忘,忘了下次就烧不进去了,得用 boot 模式救回来。然后配 GPIO、UART、定时器等外设。每个外设配完,CubeMX 会在右侧显示引脚分配图,确认没有冲突。
最后在 Project Manager 里设工程名、路径、工具链。工具链选 STM32CubeIDE 或者 Makefile 都行。生成代码之前,把"Generate peripheral initialization as a pair of .c/.h files"勾上,这样每个外设的初始化代码分开,方便管理。
4.2 TrustZone 在 CubeMX 中的配置步骤
TrustZone 的配置在 CubeMX 里有专门的界面。在 Security 或者 TrustZone 相关的选项里,你可以指定安全和非安全区域。
第一步,划分 Flash 和 RAM。通常把低地址的一段 Flash 划给安全世界,放启动代码和安全服务。RAM 也类似,划一块给安全世界。划分的时候要注意对齐,一般按页或者按扇区对齐。
第二步,配置外设的安全属性。在 Peripherals 视图里,每个外设有一个 Security 属性,可以设成 Secure、Non-Secure 或者 Both。加密引擎、RNG 这些设成 Secure,普通 GPIO、UART 设成 Non-Secure。
第三步,生成代码。CubeMX 会生成安全和非安全两套工程,或者一个工程里带两套启动代码。具体取决于你选的模板。生成之后,安全世界的代码在 secure 目录下,非安全在 non-secure 目录下。
注意:TrustZone 工程第一次烧录的时候,要先烧安全世界的代码,再烧非安全世界的。顺序反了会进不去。另外,调试的时候要确认调试器支持 TrustZone,不然只能看到非安全世界。
4.3 用 CubeProgrammer 烧录与选项字节配置
烧录用 STM32CubeProgrammer。C5 支持 SWD 和 bootloader 两种方式。SWD 最方便,直接连调试器就行。
选项字节(Option Bytes)的配置很关键,特别是 TrustZone 相关的。比如 TZEN 位,使能 TrustZone 之后,芯片的安全状态就固定了,改回来要全片擦除。还有 RDP 等级,等级越高保护越强,但调试越受限。我一般开发阶段用 RDP 0,量产前再升到 RDP 1 或者 2。
烧录的时候如果连不上,先检查这几点:调试接口有没有被禁用、芯片是不是进了低功耗模式、复位电路正不正常。我遇到过一次连不上,查了半天发现是选项字节里把 SWD 禁用了,最后用 boot 模式加 BOOT0 拉高才救回来。
| 工具 | 用途 | 关键操作 | 常见问题 |
|---|---|---|---|
| CubeMX | 配置与生成代码 | 时钟、外设、TrustZone | 版本不匹配导致芯片不支持 |
| CubeIDE | 编译调试 | 断点、寄存器查看 | TrustZone 下调试受限 |
| CubeProgrammer | 烧录与选项字节 | 烧录、RDP 设置 | 选项字节错误导致连不上 |
4.4 基于 Cube 的录音采集与网络传输实例
热词里提到了"基于 stm32cube 的录音网络采集和处理",这个场景挺典型,我说一下实现思路。C5 本身没有音频接口,但可以用 I2S 或者 SAI 接外部音频编解码芯片,或者用 ADC 直接采样麦克风信号。
如果用 ADC 采样,麦克风信号先经过运放放大和偏置,送到 ADC 输入。采样率按音频要求设,语音一般 8kHz 或 16kHz。ADC 用定时器触发,DMA 搬运,这样不占 CPU。采到的数据做简单处理,比如降噪、增益调整,然后通过以太网或者 Wi-Fi 模块发出去。
网络部分,C5 没有内置以太网 MAC,需要外接。可以用 SPI 接口的以太网控制器,或者串口转 Wi-Fi 模块。数据打包成 UDP 或者 TCP 发出去。如果走 TCP,要注意缓冲区管理,音频数据流不能断。
这个方案的关键是实时性。ADC 采样、DMA 搬运、网络发送要配合好,不能有阻塞。我一般用双缓冲,一个缓冲在采集的时候,另一个在发送,采满一个切换一次。这样 CPU 只在切换的时候介入,其他时间可以干别的。
5. 常见问题与排查技巧实录
5.1 启动失败与时钟问题的排查路径
启动失败是最让人头疼的问题,因为现象往往只是一个"不运行",没有更多信息。我的排查路径是这样的。
先确认供电。用万用表量 VDD 和 VDDA,确认在正常范围。C5 的内核电压一般是 1.2V 左右,由内部 LDO 或者外部提供,量一下对不对。供电不对,后面全白搭。
再确认复位。量 NRST 引脚,正常应该是高电平。如果一直是低,检查复位电路,看看电容是不是太大导致复位时间过长,或者按键是不是卡住了。
然后确认时钟。如果外部晶振不起振,芯片会切到内部时钟或者直接卡住。用示波器量晶振引脚,看有没有波形。没有波形的话,检查负载电容匹配不匹配,晶振是不是坏了。我遇到过一次晶振不起振,换了个负载电容就好了,原因是原来的电容值和晶振不匹配。
最后确认启动模式。BOOT0 和 BOOT1 引脚的电平决定了从哪里启动。如果设成了从 RAM 或者系统存储器启动,而那里没有代码,自然不运行。确认 BOOT0 拉低,从 Flash 启动。
5.2 HardFault 的定位与 TrustZone 相关陷阱
HardFault 是 Cortex-M 系列最常见的异常之一。C5 因为多了 TrustZone,HardFault 的原因也多了几种。
定位 HardFault 的第一步是看 CFSR 寄存器。这个寄存器在 System Control Block 里,包含了总线错误、用法错误、内存管理错误等标志位。读出 CFSR 的值,对照手册就能知道是哪类错误。比如 IBUSERR 置位说明取指总线错误,通常是跳到了非法地址;UNDEFINSTR 置位说明执行了未定义指令。
TrustZone 相关的 HardFault 有几个典型原因。一是非安全世界访问了安全世界的地址,触发安全违规。二是安全世界返回时栈指针不对,导致出栈错误。三是 NSC 区域配置错误,非安全世界调用安全服务时跳转失败。
排查的时候,我一般先在 HardFault 处理函数里把关键寄存器打印出来,包括 CFSR、HFSR、MMFAR、BFAR,还有出栈的 PC 值。PC 值能告诉你出错时在执行哪条指令,结合反汇编就能定位到具体代码。
实操心得:TrustZone 工程调试的时候,如果断点打不上或者单步跳转异常,多半是安全和非安全世界的切换问题。可以先把 TrustZone 关掉,确认基础功能正常,再逐步开启,这样容易定位。
5.3 烧录异常与选项字节锁死的自救
烧录异常最常见的是连不上芯片。原因可能是选项字节配置错误、芯片进了保护状态、或者调试接口被占用。
如果 CubeProgrammer 连不上,先试"Connect Under Reset"。这个模式会在复位期间连接,能绕过一些配置问题。如果还不行,把 BOOT0 拉高,让芯片从系统存储器启动,这样即使 Flash 里的代码有问题,也能连上。
选项字节锁死是比较麻烦的情况。比如把 RDP 设成了等级 2,芯片就完全锁死了,只能通过特定的解锁流程恢复,而且会全片擦除。我一般开发阶段不碰 RDP 2,量产前才设。如果不小心锁死了,用 CubeProgrammer 的解锁功能,按提示操作,注意这会清空所有 Flash。
还有一种情况是读保护导致调试器读不到内存。这时候可以临时降 RDP 等级,调试完再升回去。但每次升降都会触发全片擦除,所以调试阶段最好保持 RDP 0。
5.4 外设不工作的快速自查清单
外设不工作的时候,按这个清单过一遍,能解决大部分问题。
| 检查项 | 可能问题 | 解决方法 |
|---|---|---|
| 时钟使能 | 外设时钟没开 | 在 RCC 里使能对应时钟 |
| 引脚复用 | 引脚没配成外设功能 | 在 GPIO 里设 Alternate Function |
| 中断优先级 | 优先级冲突或没使能 | 检查 NVIC 配置 |
| DMA 配置 | 通道或方向错误 | 核对 DMA 请求映射表 |
| 安全属性 | 外设被划到安全世界 | 检查 TrustZone 配置 |
我遇到最多的是时钟没使能。CubeMX 生成的代码一般会处理好,但手动改代码的时候容易漏。其次是引脚复用,特别是用了重映射功能的时候,容易配错。DMA 的问题一般是通道选错了,不同外设对应的 DMA 通道是固定的,查手册确认。
6. 性能实测与优化经验
6.1 核心算力实测:FFT 与 PID 运算
光看主频不够,实际算力要跑 benchmark。我跑了两个典型负载:1024 点 FFT 和 PID 控制循环。
1024 点浮点 FFT,用 CMSIS-DSP 库,在 144MHz 下耗时大约 0.8 毫秒。这个速度对于音频分析和振动监测够用了。如果换成定点 FFT,速度还能快一些,但精度会降。我一般先用浮点,性能不够再换定点。
PID 控制循环,包含采样、计算、输出,在 16kHz 的载波频率下,每个周期有 9 微秒的时间预算。实测下来,一个完整的 PID 计算加 PWM 更新大约占 2 到 3 微秒,余量充足。这意味着还有时间跑其他任务,比如通信和状态监测。
对比 G4 同主频下的表现,C5 的 FFT 稍慢一点,因为 M33 的 DSP 指令和 M4 有些差异,但差距在 10% 以内。考虑到 C5 多了 TrustZone,这个性能损失可以接受。
6.2 功耗优化:低功耗模式与时钟门控
C5 的功耗优化手段和其他 STM32 类似,主要是低功耗模式和时钟门控。
低功耗模式有 Sleep、Stop、Standby 几档。Sleep 模式只关内核时钟,外设还在跑,唤醒最快。Stop 模式关掉大部分时钟,保留 RAM 和部分外设,唤醒要重新配时钟。Standby 模式几乎全关,只有少数唤醒源有效,功耗最低但唤醒最慢。
我一般这样用:主循环空闲的时候进 Sleep,有中断就唤醒。需要长时间待机的时候进 Stop,用 RTC 或者外部中断唤醒。Standby 用在极端低功耗场景,比如电池供电的传感器节点,几分钟上报一次数据。
时钟门控是另一个省电手段。不用的外设,把它的时钟关掉。比如你不用 CAN,就把 CAN 的时钟关了,能省几毫安。这个在 CubeMX 里可以配,也可以在代码里动态开关。
提示:进低功耗模式之前,要把不用的 GPIO 设成模拟输入或者输出低,避免浮空引脚漏电。我测过一次,浮空引脚导致的漏电有好几百微安,比芯片本身的待机电流还大。
6.3 安全启动与防回滚的落地实现
防回滚是 TrustZone 的典型应用。实现思路是这样的:固件镜像带一个版本号,安全世界的启动代码校验版本号,如果比当前版本低,就拒绝启动。
具体实现分几步。第一步,固件打包的时候把版本号写进镜像头。第二步,安全启动代码读取镜像头,和存储在安全 Flash 里的当前版本号比较。第三步,如果新版本不低于当前版本,校验签名,通过则更新版本号并跳转到新固件;否则拒绝。
版本号存在安全 Flash 里,非安全世界改不了。签名校验用非对称算法,公钥存在安全区,私钥在服务器端。这样即使攻击者拿到了固件,也伪造不了签名。
这个方案的关键是安全启动代码本身不能被篡改。所以它要放在安全区,而且最好用只读保护。C5 的 TrustZone 加上 RDP 保护,能做到这一点。
7. 一些零散但重要的经验
7.1 关于"timer too close"报错的联想
热词里有个"mcu shutdown: timer too close",这个报错我在 3D 打印机固件里见过。它的意思是定时器中断来得太频繁,CPU 处理不过来,触发了保护性关机。
这个问题的根源通常是中断处理时间超过了中断周期。比如定时器每 10 微秒中断一次,但中断处理要 15 微秒,就会累积延迟,最终触发保护。解决办法要么降低中断频率,要么缩短中断处理时间。
缩短中断处理时间的常用手段是把耗时操作放到主循环或者低优先级任务里,中断里只做最紧急的事,比如读数据、置标志位。这个思路在 C5 上同样适用。C5 的中断响应快,但如果中断里干太多活,一样会出问题。
7.2 施密特触发器输入在噪声环境下的价值
热词里提到"mcu 芯片施密特触发器输入",这个在工业环境里很重要。施密特触发器有迟滞特性,输入信号要超过高阈值才变高,低于低阈值才变低,中间区域保持原状态。这样能有效抑制噪声引起的误触发。
C5 的 GPIO 可以配置成施密特触发器输入模式。在电机控制或者工业现场,信号线上往往有噪声,用普通输入容易误触发,用施密特触发器就稳很多。配置方法是在 GPIO 设置里使能 Schmitt trigger 选项,具体看 CubeMX 的界面。
我有个项目,编码器信号线比较长,干扰大,普通输入模式下计数经常跳变。改成施密特触发器输入之后,计数稳定了。这个改动成本为零,效果立竿见影。
7.3 用 DAC 和 PWM 做 DC-DC 反馈控制的思路
热词里有个"mcu control dc-dc output voltage using feedback pin dac pwm i2c digital potentiometer",这个思路挺有意思。传统 DC-DC 的反馈是硬件分压,输出电压固定。如果想动态调压,可以用 MCU 干预反馈网络。
一种方法是用 DAC 输出一个电压,叠加到反馈节点上,改变反馈电压,从而改变输出电压。另一种方法是用数字电位器替代分压电阻,通过 I2C 调节阻值。还有一种是用 PWM 加 RC 滤波产生模拟电压,成本最低但精度和纹波差一些。
我一般用 DAC 方案,因为 C5 内置 DAC,精度够,响应快。DAC 输出经过一个电阻接到反馈节点,通过改变 DAC 电压来微调输出电压。计算的时候要注意反馈节点的电流平衡,DAC 输出电阻和反馈电阻的比值决定了调节范围。
这个方案的好处是可以用软件实现软启动、动态调压、过压保护等功能,比纯硬件灵活。坏处是引入了软件依赖,软件跑飞了输出电压可能失控。所以安全设计上要加看门狗和硬件过压保护。
7.4 关于"antirollback"和固件安全的补充
防回滚(antirollback)前面说过了,这里补充一点实现细节。版本号的存储要防篡改,最好存在安全 Flash 的独立扇区,并且写保护。更新版本号的时候要先擦除再写入,擦除和写入之间如果断电,版本号可能丢失。所以要有备份机制,比如存两份,读的时候取有效的那个。
另外,防回滚要和签名校验配合。光有版本号没有签名,攻击者可以改版本号。光有签名没有版本号,攻击者可以重放旧固件。两者结合才完整。
我在实际项目里还加了一个单调计数器,每次升级递增,存在安全区。这样即使版本号被回滚,计数器也能发现异常。这个计数器一旦写满就不能再写,所以位数要够,一般 32 位够用很多年。
7.5 新手容易忽略的 PCB 布局要点
最后说几个 PCB 布局的坑,这些在数据手册里往往一笔带过,但实际影响很大。
第一,去耦电容要靠近电源引脚。C5 有多个 VDD 引脚,每个都要配 100nF 电容,距离越近越好。远了的话,高频噪声滤不掉,芯片可能不稳定。
第二,晶振走线要短,包地。晶振是敏感信号,走线长了容易受干扰,起振困难或者频率不稳。晶振下面不要走其他信号线,最好铺地隔离。
第三,模拟地和数字地要分开,单点连接。ADC 和 DAC 的参考电压要干净,数字噪声串进来会影响精度。我一般把模拟部分单独划一块,用磁珠或者 0 欧电阻和数字地连接。
第四,调试接口要引出来。SWD 的 SWCLK 和 SWDIO 一定要留测试点,不然调试的时候很麻烦。我见过有人没留测试点,最后飞线调试,很难受。
这些布局要点不复杂,但做好了能省很多调试时间。硬件问题往往比软件问题更难查,因为现象不稳定,时好时坏。前期多花点心思在布局上,后期少踩坑。