把Bootloader玩出花,不走寻常路的BL

电子说

1.2w人已加入

描述

正文

3、把Bootloader玩出花

上面我所讲的都是BL最基础的一些内容,是我们实现BL所必须了解的。BL真正的亮点在于多种多样的固件数据获取方式。

3.1 BL的实现与延伸(串口传输固件)

前面我讲到过两个BL应用的实例,一个是串口传输固件文件,一个是SD卡拷贝固件文件。它们是在实际工程中经常被用到的两种BL形式。这里着重对前一个实例的实现细节进行讲解剖析,因为它非常具有典型意义,如图3.21。

bootloader

图3.21 BL(串口传输固件)的实现流程图

这个流程图提出了3个问题:

1、串口通信协议是如何实现的?

2、为什么获取到上位机传来的固件数据,不是直接写入到APP区,而是先暂存,

还要校验?

3、对固件数据是如何实现校验的?

串口通信协议以及文件传输实现的相关内容略显繁杂,在本书《大话文件传输》一章中会专门进行讲解。

第二个问题:经过串口传输最终由单片机接收到的固件数据是可能出现差错的,而有错误的固件冒然直接写入到APP区,是一定运行不起来的。所以,我们要对数据各帧进行暂存,等全部传输完成后,对其进行整体校验,以保证固件数据的绝对正确。

针对第三个问题,我们要着重探讨一下。

一个文件从发送方传输到接收方,如何确定它是否存在错误?通常的作法在文件中加入校验码,接收方对数据按照相同的校验码计算方法计算得到校验码,将之与文件中的校验码进行对比,一致则说明传输无误,如图3.22。

bootloader

图3.22 对固件文件进行补齐并追加校验码

图3.22是对固件文件的补齐以及追加校验码的示意。为什么要对文件补齐?嵌入式程序经过交叉编译生成的可烧录文件,比如BIN,多数情况下都不是128、256、512或1024的整数倍。这就会导致在传输的时候,最后一帧数据的长度不足整帧,就会产生一个数据尾巴。取整补齐是解决数据尾巴最直接的方法。这一操作是在上位机上完成的,通常是编写一个小软件来实现。这个小软件同时会将校验码追加到固件文件末尾。这个校验码可以使用校验和(Checksum)或者CRC,一般是16位或32位,如图3.23。

bootloader

图3.23 通过一个小软件实现对固件文件补齐和添加校验码

又有人会问:“要把整个固件暂存下来,再作校验,那得需要额外的存储空间吧,外扩ROM(FlashROM或EEPROM)?”是的。如果想节省成本,我们也可以不暂存,传输时直接烧写到APP区。这是有风险的,但是一般来说问题不大(STC和STM32的串口ISP其实也都是实时烧写,并不暂存)。

因为在传输的过程中,传输协议对数据的正确性是有一定保障的,它会对每一帧数据进行校验,失败的话会有重传,连续失败可能会直接终止传输。所以说,一般只要传输能够完成,基本上数据正确性不会有问题。但是仍然建议对固件进行整体校验,在成本允许的情况下适当扩大ROM容量。同时,固件暂存还有一个另外的好处,在APP区中的固件受到损坏的时候,比如固件意外丢失或IAP时不小心擦除了APP区,此时我们还可以从暂存固件恢复回来(完备的BL会包含固件恢复的功能)。

 

其实也不必非要外扩ROM,如果固件体积比较小的话,我们可以把单片机的片上ROM砍成两半来用,用后一半来作固件暂存。

bootloader

图3.24 将片上ROM划分为3部分

如图3.24,我们将片上ROM划分为3部分,分别用于存储BL、APP固件以及暂存固件。比如我们使用STM32F103RBT6,它一共有128KB的ROM,可以划分为16K/56K/56K。

有些产品对成本极为敏感。我就有过这样的开发经历,当时使用的单片机是STM32F103C8T6,片上ROM总容量为64K,固件大小为48K,BL为12K。在通过BL进行固件烧写时根本没有多余的ROM进行固件暂存。我使用了一招“狗尾续貂”,如图3.25。

bootloader

图3.25 STM32F103C8T6后64K也可用

我无意中了解到STM32F103C8T6与RBT6的晶元是同一个。只是因为有些芯片后64KB的ROM性能不佳或有瑕疵,而被限制使用了。我实际测试了一下,确实如此。但是后64K ROM的使用是有前提的,也就是需要事先对其好坏进行验证。如果是好的,则暂存校验,再写入APP区;而如果是坏的,那么就直接在固件传输时实时写入APP区(这个办法我屡试不爽,还没有发现后64K有坏的)。

以上振南所介绍的是一种“骚操作”,根本上还是有一定的风险的,ST官方有声明过,对后64K ROM的质量不作保证,所以还是要慎用。

3.2 10米之内隔空烧录

这个“隔空烧录”源于我的一个IoT项目,它是对空调的外机进行工况监测。大家知道,空调外机的安装那可不是一般人能干的,它要不就在楼顶,要不就在悬窗上。这给硬件升级嵌入式程序带来很大的困难。所以,我实现了“隔空烧录”的功能,其实它就是串口BL应用的一个延伸,如图3.26所示。

bootloader

图3.26 通过蓝牙串口模块实现“隔空烧录”

“隔空烧录确实牛,但是总要抱着一个电脑,这不太方便吧。”确实是!还记得前面我提过的AVRUBD通信协议吗?它的上位机软件是有手机版的。这样我们只要有手机,就能“隔空烧录”了,如图3.27。

bootloader

图3.27 手机连接蓝牙串口模块实现“手机隔空烧录”

“哪个APP?快告诉我名字”,别急,蓝牙串口助手安卓版,图3.28是正在传输固件的界面。

bootloader

图3.28 蓝牙串口助手传输固件文件的界面

AVRUBD其实是对Xmodem协议的改进,这个我们放在专门的章节进行详细讲解。

3.3 BL的分散烧录

我们知道BL的核心功能其实就是程序烧录。那你有没有遇到过比较复杂的情况,如图3.29所示。

bootloader

图3.29 一个系统(产品)中有多个部件需要烧录固件

这种情况是有可能遇到的。主MCU+CPLD+通信协处理器+采集协处理器就是典型的复杂系统架构。这种产品在批量生产阶段,烧录程序是非常繁琐的。首先需要维护多个固件,再就是需要一个个给每一个部件进行烧写,烧写方式可能还不尽相同。所以我引入了一个机制,叫“BL的分散烧录”。

首先我们将所有的固件拼装成一个大固件(依次数据拼接),并将这个大固件预先批量烧录到外扩ROM中,比如spiFlash;再将主MCU预先烧录好BL;然后进行SMT焊接。PCBA生产出来之后,只要一上测试工装(首次上电),BL会去外扩ROM中读取大固件,并从中分离出各个小固件,分别以相应的接口烧录到各个部件中去。配合工装的测试命令,直接进行自检。这样作,批量化生产是非常高效的。当然,这个BL开发起来也会有一定难度,最大问题可能还是各个部件烧录接口的实现(有些部件的烧录协议是比较复杂的,比如STM32的SWD或者ESP8266的SLIP)。

OK,上面振南就对一些BL实例的实现和应用场景进行了介绍。还有一些实例没有介绍,比如通过CAN总线或SPI进行文件传输,这个我们还是放到专门的章节去详细讲解。当然,各位读者可以在此基础上衍生出更多有特色而又实用的BL来。

BL没有最好的,只有最适合自己的。通常来说,我们并不会把BL设计得非常复杂,原则上它应该尽量短小精炼,以便为APP区节省出更多的ROM空间。毕竟不能喧宾夺主,APP才是产品的主角。

4、不走寻常路的BL

4.1 Bootpatcher

我来问大家一个问题:“Bootloader在ROM中的位置一定是在APP区前面吗?”很显然不是,AVR就是最好的例子。那如果我们限定是STM32呢?似乎是的。上电复位一定是从0X08000000位置开始运行的,而且BL一定是先于APP运行的。

在某些特殊的情况下,如果APP必须要放在0X08000000位置上的话,请问还有办法实现BL串口烧录吗?要知道APP在运行的时候,是不能IAP自己的程序存储器的(就是自己能自己擦出重新烧录新固件)。请看图3.30。

bootloader

图3.30 BL位于APP之后称之为Bootpatcher

APP运行时,想要重新烧录自身,它可以直接跳转到后面的BL上,BL运行起来之后开始接收固件文件,暂存校验OK之后,将固件写入到前面的APP区。然后跳转到0X08000000,或者直接重启。这样新的APP就运行起来了。这个位于APP后面的BL,我们称之为Bootpatcher(意为启动补丁)。但是这种作法是有风险的,一旦APP区烧录失败,那产品就变砖了。所以这种方法一般不用。

4.2 APP反烧BL

前面我们都是在讲BL烧录APP,那如果BL需要升级怎么办呢?用JLINK。不错,不过有更直接的方法,如图3.31所示。

bootloader

图3.31 APP烧录BL区

这是一种逆向思维,我们在APP程序中也实现接收固件文件,暂存校验,然后将其烧录到BL区。这种作法与Bootpatcher同理,也是有一定风险的,但一般都没有问题。

OK,本章对BL进行了详尽的剖析讲解,应该作到了深入浅出,包含基本的原理,以及实例的实现,还有一些知识的扩展。这其中不乏振南的一些创新思想,希望能够对大家产生启发,在实际的工作中将这些知识付诸实践。





审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分