注意:下列描述是在PIC单片机上启用Bootloader的一个相关知识的近似完备集。所有需要了解的,bootloader与用户态程序交互的理论知识都已给出。
1.概述
嵌入式产品化后,需要考虑现场升级,单片机如果需要添加现场升级功能,必须考虑添加bootloader,否则,现场设备一旦升级失败,返修率会大大增加。
最小的bootloader系统,至少需要包含如下功能:
- 用户程序完整性核查(如果不可以跳转,则需要停留在bootloader状态)
- 用户程序跳转。
- 用户程序下载和烧写
进阶的功能还需要考虑这些:
- 中断的处理
- 因为中断向量表是固定的,那么这个时候需要考虑怎么在中断发生时,切换中断向量表。
2.PIC官方的处理策略
2.1完整性核查
pic提供了三种方式来完成用户程序的完整性核查策略,具体位置在 MCC中:
- 检查ResetVector的方法,就是只要这个ResetVector不为0xff,或者不为0x00,类似这样,就执行跳转。
- 最严格的方法是进行checksum计算,相当于对整个用户程序区域做了校验,用户程序的长度怎么计算,这些代码都是明的,可以自行检查。
- 完整性核查也可以完全跳过,用类似看门狗,或者延时的方式实现,效果一样。ARM芯片,芯片级的Bootloader,就是在开机时等待串口的数据,如果比如100ms没有信号过来,就切至正常的启动过程。
这些方法,怎么做都可以。
2.1跳转
跳转涉及两个问题,怎么跳和跳到哪里。
跳转指令可以使用C混入asm代码来实现:
asm ("goto 0xB00");
上面的代码,可以让程序跳至指令存储器的:0xB00位置。注意:PIC18系列,指令和数据存储器是独立的(哈佛架构),指令称为Rom,数据称为Ram。
这个待跳转的地址,称为Reset Vector。芯片固有的Reset Vector地址,位于指令的ROM地址0x00:
所以,现在我们首先要对存储空间进行划分,强制指定用户态程序的基地址,假定,现在这个地址,就是0xB00。(这个地址要设置为多大,取决于:
- 你的Bootloader有多大,一般会把Bootloader放置在内存地址的最低部分
- 地址还需要考虑Rom的最小可擦除块的大小
- 那么在编译用户态的程序(就是Bootloader需要加载的那个程序),需要指定这个基地址:
原厂的Bootloader可以把自己的尺寸控制在0x500以内,就是1280字节。初次写Bootloader,由于某种原因,不能直接用原厂的Bootloader程序,可以适当加大这个空间。指令空间需要进行严格划分,数据RAM,似乎无需做这类划分。用户态程序,仅需额外处理那一处地方即可。
3.用户程序下载和烧写
这个部分,就是指令 rom的分区擦除和读写,没有什么特别要说的。芯片手册有。MCC也有写好的函数,用就是了。
3.1 两个.hex文件的merge
测试时,为了同时写入bootloader和应用程序,可以使用下面的.bat脚本把相关的两个.hex文件合并为一个大的.hex,然后再用仿真器一次写入:
"C:\Program Files\microchip\MPLABX\v6.00\mplab_platform\bin\hexmate.exe" +PicBootloader.X.production.hex MyApp.X.production.hex -ototal.hex
4.中断的处理
中断部分,我觉得pic的做法是可以的。就是不用中断,完全靠寄存器操作与硬件设备交互。这部分如果能写得简省,也无需考虑代码复用的问题。因为bootloader中可以把总中断关掉。所以,它的中断向量表可以完全不用。
既然不用,就可以把这些区域配置为指向新的中断向量的模式,这个代码,MCC的Bootloader例程里已经给出:
//intcode代表中断向量所在的内存区域
asm ("psect intcode,global,reloc=2,class=CODE,delta=1");
asm ("GOTO " str(NEW_INTERRUPT_VECTOR_HIGH));
//intcodelo代表启用两级中断向量,低优先级中断向量,所在位置
asm ("psect intcodelo,global,reloc=2,class=CODE,delta=1");
asm ("GOTO " str(NEW_INTERRUPT_VECTOR_LOW));
5.任务量评估
因为MCC已经承担了大量的工作。此项工作,包括Bootloader相关的内存分配,代码,测试。不应该超过10个小时。比较熟悉代码和编程工具的同志,应该最快在4小时内,应该就能从无到有完成具备基本的跳转功能,并理清中断的处理。实现Bootloader,而后加载用户App的工作。
后续,如果你希望自行处理升级过程,比如你们设计了自己的升级协议,比如通过类似xmodem并添加了签名或加密的协议完成升级逻辑,那么系统的代码里,与bootloader直接相关的代码,你可以完全抛开。仅使用上面提到的这些必备的代码,然后摘出其与指令rom读写的部分即可。
6.未来拓展
bootloader的编写,特别是中断的处理,稍稍扩展,就能写出支持基础服务的包含任务调度和基础外设操控功能的操作系统——用户态向内核态的迁移,可以通过软中段进行。
First Version: Jul04,2023
Last Modified: Jul04,2023 11:13 定稿