前一阵项目上要把升级方案从“必须进DFU模式用烧录器”改成“现场用串口就能刷固件”,手里正好是一颗STM32F411,板载内部Flash 512KB,单独放Bootloader和App倒是没问题,坏就坏在升级时没有足够的RAM暂存一整包固件。后来把W25Q128拉进来当片外下载缓存,配合RT-Thread Studio里的YModem软件包,总算把这条链路跑通了。这套方案改完之后体验很顺,所以这篇笔记就专门写带片外Flash的OTA(YModem)怎么搭、怎么调、以及那些光看文档绝对想不到的坑。
这篇笔记适合两类人:一类是正在用RT-Thread Studio做Bootloader和OTA,但内部Flash空间不够、想引入片外Flash的开发者;另一类是手里有STM32F411之类Cortex-M4板子,想搞清楚YModem协议、分区规划、跳转逻辑这些事到底怎么落地的朋友。内容以实际工程为主线,原理、代码、避坑都会讲到。
1. 为什么要给OTA引入片外Flash:先想清楚固件数据去哪里的问题
很多人第一次做OTA,第一反应是“Bootloader从串口收完固件,直接覆盖写进App区不就行了”。这个想法在小固件、大Flash的片子上确实能跑,但一旦固件体积超过内部Flash余量,或者你想在升级失败时保留旧版本继续运行,就必须额外找一块“中间存放区”。片内ROM不够用,RAM更不够用,唯一的出路就是片外Flash。
1.1 三种常见OTA分区方案的对比
我把做OTA时最常见的三种分区方式整理成了一张表,方便你对着自己的硬件资源选型:
| 方案 | 存储结构 | 优点 | 缺点 |
|---|---|---|---|
| 方案A:Bootloader + App | Bootloader收包后直接写App区 | 逻辑最简单,Flash占用最少 | 升级中途断电或写坏会直接变砖,无回退能力 |
| 方案B:Bootloader + App + 片内Download区 | 固件先缓存到片内Download区,校验后再搬进App区 | 双区结构,升级失败可回退 | 需要内部Flash预留Download区,小Flash芯片不够用 |
| 方案C:Bootloader + App + 片外Download区 | 固件通过YModem先写入W25Q128,校验后搬进App区 | 内部Flash只放Bootloader和App,片外空间基本不受限 | 多了一颗SPI Flash的操作逻辑,Bootloader代码量稍大 |
我这次选的是方案C。原因很直接:STM32F411的512KB Flash需要同时放Bootloader和App,如果App本身比较胖(比如把GUI资源、协议栈都编进去),再抠一块Download区出来就会把App的可用空间压得很紧张。W25Q128片外Flash有16MB,拿最前面的几MB当下载缓存绰绰有余,剩下的还可以存字库、参数、日志,一举多得。
1.2 片外Flash在OTA链路中的真实角色
很多新手会有一个误解,以为片外Download区就是“存放固件备份”的地方。实际上在方案C里,它的角色是 传输中间缓存 :YModem一包包收数据,先落到W25Q128,全部收完后做CRC或MD5校验,校验通过后再由Bootloader把整份固件从片外Flash搬进内部App区,最后跳转。
为什么要绕这么一圈?因为YModem是流式的,一个包一个包地传,如果你收一包就写一包到内部App区,一旦中途断电或串口断开,App区可能已经被写坏,旧版本也丢了,板子直接变砖。而有了片外Flash做缓存,只要在搬运前确认数据完整,就基本不会出现“升级升一半,设备废了”的尴尬。数据每一步去哪里、什么时候校验、什么时候搬运,都必须清楚,这是整个OTA设计里最重要的一张图。
2. 分区规划与链接脚本:先算账再动手
在做任何代码之前,先把地址算明白。片上资源、链接脚本、Bootloader的跳转地址、App的中断向量表偏移,这几样必须完全对得上,否则后面全是玄学问题。
2.1 我用的分区表
以手里的STM32F411CEU6为例,它内部Flash 512KB,起始地址0x08000000;RAM 128KB,起始地址0x20000000。W25Q128挂在SPI1上。分区划分如下:
| 分区 | 存储介质 | 起始地址 | 大小 | 用途 |
|---|---|---|---|---|
| Bootloader | 片内Flash | 0x08000000 | 0x20000(128KB) | YModem接收、校验、跳转 |
| App | 片内Flash | 0x08020000 | 0x |
494




被折叠的 条评论
为什么被折叠?



