2026/10/30 3:58:46

STM32C5深度解析:Cortex-M33内核与TrustZone安全实战

STM32C5深度解析:Cortex-M33内核与TrustZone安全实战 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%。这个差距在电池供电的设备上很关键。那为什么不直接上 M55M55 带 Helium 向量扩展算力更强但价格和功耗都上去了。C5 的定位就是够用的安全 够用的算力不是追求极致性能。选型的时候要克制别为用不上的性能付钱。2.2 和同门师兄弟的横向对比光说定位太虚直接上对比表。下面是我根据公开资料和实测整理的 C5 与几款常见 STM32 的对比参数以实际数据手册为准这里给的是量级参考。特性STM32G0STM32C5STM32G4STM32U5内核Cortex-M0Cortex-M33Cortex-M4FCortex-M33主频64MHz最高 144MHz170MHz160MHzTrustZone无有无有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 协议栈加 TLSC5 的 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 就是 368 乘 36 等于 288288 除以 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 因为多了 TrustZoneHardFault 的原因也多了几种。定位 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 一定要留测试点不然调试的时候很麻烦。我见过有人没留测试点最后飞线调试很难受。这些布局要点不复杂但做好了能省很多调试时间。硬件问题往往比软件问题更难查因为现象不稳定时好时坏。前期多花点心思在布局上后期少踩坑。