3、MCUboot配置:从源码获取到槽位计算的实战指南
好,咱们进入第三章。这一章我打算跟你聊聊MCUboot的配置。
说实话,MCUboot的配置是整个OTA升级里最容易被忽视、但又最容易出坑的环节。我见过太多人,签名算法选错了,槽大小算错了,结果升级到一半直接变砖。嗯,咱们今天就把这些坑一个个填平。
3.1 MCUboot源码获取
先说说源码怎么拿。我个人习惯直接从官方仓库拉取,这样能保证是最新、最稳定的版本。
# 克隆MCUboot仓库
git clone https://github.com/mcu-tools/mcuboot.git
cd mcuboot
# 切换到稳定版本(我建议用v1.9.0或v1.10.0)
git checkout v1.9.0
为什么我推荐用稳定版?因为我在项目里踩过坑——用master分支,结果某个API突然变了,整个编译链全崩。你想想看,生产环境谁敢用开发分支?
3.2 单镜像槽 vs 双镜像槽
这是个大问题。说白了,单槽还是双槽,取决于你的Flash有多大、你对可靠性要求有多高。
3.2.1 单镜像槽(Single Slot)
单槽模式,就是只有一个镜像槽。升级时直接覆盖原有固件。
- 优点: 省Flash空间,适合资源受限的芯片
- 缺点: 升级失败就变砖,没有回滚能力
- 适用场景: 产品稳定后的小版本更新,或者Flash实在太小
我记得有一次做智能灯控项目,芯片只有256KB Flash。没办法,只能用单槽。每次升级前我都提心吊胆,生怕断电。后来加了个外部Flash做备份,才算安心。
3.2.2 双镜像槽(Dual Slot)
双槽模式,就是有主槽(Primary Slot)和备槽(Secondary Slot)。升级时先写到备槽,校验通过后再交换。
- 优点: 升级失败可以回滚,安全性高
- 缺点: 需要双倍Flash空间
- 适用场景: 绝大多数产品,尤其是远程升级场景
你想想看,如果升级到一半断电了,重启后MCUboot检测到备槽的镜像不完整,会自动回滚到主槽的旧版本。这就是双槽最大的价值。
3.3 签名算法选择:EC256 vs RSA
签名算法,说白了就是给你的固件加个“防伪标签”。MCUboot支持两种主流算法:EC256(ECDSA P-256)和RSA-2048。
| 特性 | EC256 (ECDSA P-256) | RSA-2048 |
|---|---|---|
| 密钥长度 | 32字节 | 256字节 |
| 签名速度 | 快 | 慢 |
| 验证速度 | 快 | 较快 |
| 安全性 | 高(等效RSA-3072) | 高 |
| Flash占用 | 小 | 大 |
我个人强烈推荐EC256。为什么?
第一,签名速度快。我在一个Cortex-M4项目上测试过,EC256签名只需要几十毫秒,RSA要几百毫秒。你想想看,如果每次OTA升级都要等签名,用户体验得多差。
第二,密钥短。32字节的私钥,存起来方便,传输也安全。
第三,安全性不输RSA。EC256的安全强度等效于RSA-3072,完全够用。
3.4 槽大小与偏移量计算
这是最烧脑的部分,但也是最关键的。槽大小和偏移量算错了,MCUboot根本跑不起来。
3.4.1 基本概念
先明确几个术语:
- 槽(Slot): 存放固件镜像的区域
- 偏移量(Offset): 槽在Flash中的起始地址
- 大小(Size): 槽的最大容量
3.4.2 计算公式
假设你的Flash起始地址是0x08000000,总大小是1MB(0x100000)。
# 单槽模式
主槽偏移量 = Flash起始地址 + MCUboot占用大小
主槽大小 = Flash总大小 - MCUboot占用大小
# 双槽模式
主槽偏移量 = Flash起始地址 + MCUboot占用大小
主槽大小 = (Flash总大小 - MCUboot占用大小) / 2
备槽偏移量 = 主槽偏移量 + 主槽大小
备槽大小 = 主槽大小
举个例子:
Flash起始地址: 0x08000000
Flash总大小: 0x100000 (1MB)
MCUboot占用: 0x10000 (64KB)
# 双槽计算
主槽偏移量 = 0x08000000 + 0x10000 = 0x08010000
主槽大小 = (0x100000 - 0x10000) / 2 = 0x78000 (480KB)
备槽偏移量 = 0x08010000 + 0x78000 = 0x08088000
备槽大小 = 0x78000 (480KB)
3.4.3 在Zephyr中的配置
在Zephyr里,这些参数通过设备树(DTS)和Kconfig配置。我一般这样写:
// 在设备树中定义Flash分区
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
boot_partition: partition@0 {
label = "mcuboot";
reg = <0x00000000 0x00010000>; // 64KB for MCUboot
};
slot0_partition: partition@10000 {
label = "image-0";
reg = <0x00010000 0x00078000>; // 480KB for primary slot
};
slot1_partition: partition@88000 {
label = "image-1";
reg = <0x00088000 0x00078000>; // 480KB for secondary slot
};
};
};
然后在Kconfig里配置:
# MCUboot配置
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="bootloader/mcuboot/root-ec-p256.pem"
CONFIG_MCUBOOT_SLOT_SIZE=0x78000
3.4.4 常见错误与排查
我总结几个常见问题:
- 槽太小: 固件编译后超过槽大小,MCUboot会拒绝写入。建议留20%余量。
- 偏移量重叠: 两个槽的地址范围重叠了,MCUboot启动时会崩溃。
- 对齐问题: 偏移量不是Flash擦除块的整数倍,写入会失败。
west build -t flash烧录后,用west debug启动GDB,查看mcuboot的日志输出。如果配置有误,MCUboot会打印详细的错误信息,比如“Image in slot 0 is not valid”。
3.5 小结
嗯,这一章内容不少。从源码获取到槽位计算,每一步都有讲究。
我个人觉得,最核心的是两点:
第一,双槽模式是标配,除非你的Flash实在太小。安全第一,别省那点空间。
第二,EC256是首选,速度快、密钥短、安全性高。除非你的芯片不支持,否则别犹豫。
下一章,咱们会深入MCUboot的启动流程,看看它到底是怎么校验和交换镜像的。到时候你会发现,今天算的这些偏移量,全都会用上。
好,今天就到这儿。有问题随时找我。