控制/MCU
把Bootloader玩出花
上面我所讲的都是BL最基础的一些内容,是我们实现BL所必须了解的。BL真正的亮点在于多种多样的固件数据获取方式。
BL的实现与延伸(串口传输固件)
前面我讲到过两个BL应用的实例,一个是串口传输固件文件,一个是SD卡拷贝固件文件。它们是在实际工程中经常被用到的两种BL形式。
这里着重对前一个实例的实现细节进行讲解剖析,因为它非常具有典型意义,如图
这个流程图提出了3个问题:
串口通信协议是如何实现的?
为什么获取到上位机传来的固件数据,不是直接写入到APP区,而是先暂存,还要校验?
对固件数据是如何实现校验的?
第一个问题,串口通信协议以及文件传输实现的相关内容略显繁杂,在以后的文章会专门进行讲解。
第二个问题:经过串口传输最终由单片机接收到的固件数据是可能出现差错的,而有错误的固件冒然直接写入到APP区,是一定运行不起来的。所以,我们要对数据各帧进行暂存,等全部传输完成后,对其进行整体校验,以保证固件数据的绝对正确。
针对第三个问题,我们要着重探讨一下。
一个文件从发送方传输到接收方,如何确定它是否存在错误?
通常的做法在文件中加入校验码,接收方对数据按照相同的校验码计算方法计算得到校验码,将之与文件中的校验码进行对比,一致则说明传输无误,如图。
上图是对固件文件的补齐以及追加校验码的示意。
为什么要对文件补齐?嵌入式程序经过交叉编译生成的可烧录文件,比如 BIN,多数情况下都不是128、256、512或1024的整数倍。这就会导致在传输的时候,最后一帧数据的长度不足整帧,就会产生一个数据尾巴。
取整补齐是解决数据尾巴最直接的方法。这一操作是在上位机上完成的,通常是编写一个小软件来实现。这个小软件同时会将校验码追加到固件文件末尾。这个校验码可以使用校验和(Checksum)或者 CRC,一般是 16 位或 32 位,如图,通过一个小软件实现对固件文件补齐和添加校验码。
又有人会问:“要把整个固件暂存下来,再作校验,那得需要额外的存储空间吧,外扩ROM(FlashROM或EEPROM)?”
是的。如果想节省成本,我们也可以不暂存,传输时直接烧写到APP区。这是有风险的,但是一般来说问题不大(STC和STM32的串口ISP其实也都是实时烧写,并不暂存)。
因为在传输的过程中,传输协议对数据的正确性是有一定保障的,它会对每一帧数据进行校验,失败的话会有重传,连续失败可能会直接终止传输。所以说,一般只要传输能够完成,基本上数据正确性不会有问题。
但是,仍然建议对固件进行整体校验,在成本允许的情况下适当扩大ROM容量。同时,固件暂存还有一个另外的好处,在APP区中的固件受到损坏的时候,比如固件意外丢失或IAP时不小心擦除了APP区,此时我们还可以从暂存固件恢复回来(完备的BL会包含固件恢复的功能)。
其实也不必非要外扩ROM,如果固件体积比较小的话,我们可以把单片机的片上ROM砍成两半来用,用后一半来作固件暂存。将片上ROM划分为3部分:
我们将片上ROM划分为3部分,分别用于存储 BL、APP 固件以及暂存固件。比如我们使用 STM32F103RBT6,它一共有128KB 的 ROM,可以划分为 16K/56K/56K。
有些产品对成本极为敏感。我就有过这样的开发经历,当时使用的单片机是 STM32F103C8T6,片上ROM总容量为64K,固件大小为48K,BL为12K。在通过BL进行固件烧写时根本没有多余的ROM进行固件暂存。我使用了一招“狗尾续貂”,如图
我无意中了解到 STM32F103C8T6 与 RBT6 的晶元是同一个。只是因为有些芯片后 64KB 的ROM性能不佳或有瑕疵,而被限制使用了。我实际测试了一下,确实如此。
但是后 64K ROM 的使用是有前提的,也就是需要事先对其好坏进行验证。如果是好的,则暂存校验,再写入APP区;而如果是坏的,那么就直接在固件传输时实时写入APP区(这个办法我屡试不爽,还没有发现后64K有坏的)。
以上振南所介绍的是一种“骚操作”,根本上还是有一定的风险的,ST 官方有声明过,对后 64K ROM 的质量不作保证,所以还是要慎用。
10米之内隔空烧录
这个“隔空烧录”源于我的一个 IoT 项目,它是对空调的外机进行工况监测。大家知道,空调外机的安装那可不是一般人能干的,它要不就在楼顶,要不就在悬窗上。这给硬件升级嵌入式程序带来很大的困难。
所以,我实现了“隔空烧录”的功能,其实它就是串口BL应用的一个延伸,如图所示,通过蓝牙串口模块实现“隔空烧录”。
“隔空烧录确实牛,但是总要抱着一个电脑,这不太方便吧。”确实是!还记得前面我提过的AVRUBD通信协议吗?它的上位机软件是有手机版的。这样我们只要有手机,就能“隔空烧录”了,如图,手机连接蓝牙串口模块实现“手机隔空烧录”。
“哪个APP?快告诉我名字”,别急,蓝牙串口助手安卓版,下图是正在传输固件的界面。
AVRUBD其实是对 Xmodem 协议的改进,这个我们放在专门的文章进行详细讲解。
BL的分散烧录
我们知道BL的核心功能其实就是程序烧录。那你有没有遇到过比较复杂的情况,如图所示,一个系统(产品)中有多个部件需要烧录固件。
这种情况是有可能遇到的。主 MCU+CPLD+通信协处理器+采集协处理器就是典型的复杂系统架构。这种产品在批量生产阶段,烧录程序是非常繁琐的。首先需要维护多个固件,再就是需要一个个给每一个部件进行烧写,烧写方式可能还不尽相同。所以我引入了一个机制,叫“BL的分散烧录”。
首先,我们将所有的固件拼装成一个大固件(依次数据拼接),并将这个大固件预先批量烧录到外扩 ROM 中,比如spiFlash;再将主MCU预先烧录好BL;然后进行SMT焊接。
PCBA生产出来之后,只要一上测试工装(首次上电),BL会去外扩ROM中读取大固件,并从中分离出各个小固件,分别以相应的接口烧录到各个部件中去。配合工装的测试命令,直接进行自检。
这样做,批量化生产是非常高效的。当然,这个 BL 开发起来也会有一定难度,最大问题可能还是各个部件烧录接口的实现(有些部件的烧录协议是比较复杂的,比如 STM32 的 SWD 或者 ESP8266 的 SLIP)。
BL没有最好的,只有最适合自己的。通常来说,我们并不会把BL设计得非常复杂,原则上它应该尽量短小精炼,以便为APP区节省出更多的ROM空间。毕竟不能喧宾夺主,APP才是产品的主角。
不走寻常路的BL
Bootpatcher
我来问大家一个问题:“Bootloader在 ROM 中的位置一定是在 APP 区前面吗?”很显然不是,AVR 就是最好的例子。那如果我们限定是 STM32 呢?似乎是的。上电复位一定是从0X08000000位置开始运行的,而且BL一定是先于APP运行的。
在某些特殊的情况下,如果 APP 必须要放在0X08000000位置上的话,请问还有办法实现BL串口烧录吗?要知道APP在运行的时候,是不能 IAP 自己的程序存储器的(就是自己能自己擦出重新烧录新固件)。请看图,BL位于APP之后称之为Bootpatcher。
APP运行时,想要重新烧录自身,它可以直接跳转到后面的BL上,BL运行起来之后开始接收固件文件,暂存校验OK之后,将固件写入到前面的APP区。然后跳转到 0X08000000,或者直接重启。这样新的APP就运行起来了。
这个位于 APP 后面的 BL,我们称之为 Bootpatcher(意为启动补丁)。但是这种作法是有风险的,一旦 APP 区烧录失败,那产品就变砖了。所以这种方法一般不用。
APP反烧BL
前面我们都是在讲BL烧录APP,那如果BL需要升级怎么办呢?用 JLINK。不错,不过有更直接的方法,如图,APP烧录BL区。
这是一种逆向思维,我们在 APP 程序中也实现接收固件文件,暂存校验,然后将其烧录到 BL 区。这种作法与Bootpatcher 同理,也是有一定风险的,但一般都没有问题。
最后
OK,本系列文章对BL进行了详尽的剖析讲解,应该做到了深入浅出,包含基本的原理,以及实例的实现,还有一些知识的扩展。希望能够对大家产生启发,在实际的工作中将这些知识付诸实践。
审核编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !