第2章:系统架构概览——制氧机主控芯片选型与Flash分区规划

好,咱们直接进入正题。

做Bootloader远程升级,第一步不是写代码,而是选芯片、定分区。这两件事没想清楚,后面全是坑。我见过太多团队,代码写了大半才发现Flash不够用,或者分区策略不合理导致升级失败——嗯,那种感觉,就像你装修房子才发现水管走错了。

2.1 主控芯片选型:STM32 vs ESP32

制氧机这玩意儿,说复杂也复杂,说简单也简单。核心就是控制电磁阀、读取传感器、驱动屏幕、联网升级。我个人的习惯是,先看需求再选型,别盲目追新。

咱们对比一下市面上最常见的两款芯片:

对比项 STM32(以F4/H7系列为例) ESP32
主频 168MHz ~ 480MHz 240MHz
Flash容量 512KB ~ 2MB(可外扩) 4MB ~ 16MB(内置)
SRAM 192KB ~ 1MB 520KB
WiFi/蓝牙 需外挂模块 内置双模
安全特性 硬件加密、安全启动(部分型号) Flash加密、安全启动
成本 中等偏高 较低
生态 成熟稳定,工业级 活跃,但偏消费级

你可能会问:到底选哪个?

我的建议是这样的:

  • 如果产品要求高可靠性(比如医用级制氧机),选STM32。我在项目中遇到过,某款制氧机在高温高湿环境下,ESP32偶尔会WiFi断连,而STM32稳如老狗。
  • 如果产品需要联网且成本敏感(比如家用便携制氧机),选ESP32。它内置WiFi/蓝牙,省掉一个模块的钱,而且Flash空间大,做远程升级很舒服。
  • 如果两者都要——嗯,我见过有人用STM32+ESP32双芯片方案,STM32负责控制,ESP32负责通信。但说实话,这增加了成本和复杂度,除非有特殊需求,否则不推荐。
我的小技巧: 选型时留出30%的Flash余量。你永远不知道后面会加什么功能——我曾经就因为只留了10%,结果客户要加OTA日志记录,搞得我连夜改分区表。

2.2 Flash分区规划——Bootloader的根基

芯片选好了,接下来就是分区。说白了,就是把Flash这块地皮划分好,谁住哪、谁有多大面积,都得提前规划好。

以STM32F407为例,它内置1MB Flash。我一般这样分:

Flash布局(1MB = 1024KB)
+----------------------------+ 0x08000000
| Bootloader (64KB)          | 存放启动代码
+----------------------------+ 0x08010000
| 参数区 (16KB)              | 存放设备ID、升级标志等
+----------------------------+ 0x08014000
| 应用A (448KB)              | 主程序
+----------------------------+ 0x08084000
| 应用B (448KB)              | 备份/升级用
+----------------------------+ 0x080F4000
| 升级缓存区 (48KB)          | 存放下载的固件包
+----------------------------+ 0x080FF000
| 保留区 (4KB)               | 留作他用
+----------------------------+ 0x08100000

为什么这么分?我解释一下:

  • Bootloader 64KB:够用。我见过有人只给32KB,结果代码写不下,还得压缩——何必呢?
  • 参数区 16KB:存放升级状态、版本号、校验结果。注意,这里要用双备份机制,防止写入时掉电导致数据损坏。
  • 应用A和应用B:这就是经典的A/B分区升级。说白了,就是两个区轮流当主程序。升级时写B区,写完了校验通过再切换。万一升级失败,还能回滚到A区。
  • 升级缓存区 48KB:用来存放下载的固件包。为什么不是直接写到B区?因为网络传输可能断断续续,先缓存再校验,更安全。
注意: 分区大小必须是Flash擦除块(Sector)的整数倍。STM32F407的Sector大小是16KB(前4个)和128KB(后面的)。你如果分了个32KB的区,但实际占用了两个16KB的Sector,那剩下的空间就浪费了。我刚开始做的时候踩过这个坑,后来学乖了。

2.3 分区策略的避坑指南

讲几个我实际踩过的坑:

  • 分区别太死板:我见过有人把分区大小写死在代码里,结果换了Flash容量更大的芯片,还得改代码。建议用宏定义或者链接脚本控制,方便移植。
  • 参数区要防写坏:升级过程中如果突然断电,参数区可能只写了一半。我习惯用「双缓冲」——写之前先擦除备份区,写完后校验,再更新主区。虽然多花点时间,但安全第一。
  • Bootloader别太大:Bootloader只做一件事——启动和升级。别往里面塞驱动、协议栈什么的。我见过有人把MQTT库塞进Bootloader,结果64KB不够用,还得改分区——这不是给自己找麻烦吗?

核心原则: Bootloader要小、要稳、要快。应用层可以复杂,但Bootloader必须简单。你想想看,如果Bootloader自己都跑不起来,那还升什么级?

2.4 实际项目中的分区调整

当然,上面的分区方案不是死的。我根据实际项目经验,总结了几种常见调整:

场景 调整建议
Flash只有512KB 去掉应用B,改用「压缩+差分升级」,或者只保留一个应用区,升级时覆盖写(风险较高)
需要存储大量日志 在Flash末尾划出一块日志区,用环形缓冲区方式写入
需要支持多语言字库 把字库存到外部SPI Flash,内部Flash只放程序
需要加密存储 在参数区旁边划出一块加密存储区,用硬件加密引擎保护

嗯,分区规划这块,说白了就是「提前想好,留足余量」。我见过太多项目,前期分区随便搞搞,后期升级时发现空间不够,然后各种骚操作——改链接脚本、压缩代码、甚至删功能。何必呢?

好了,这一章就到这里。下一章咱们开始讲Bootloader的启动流程,那才是真正的硬核内容。