1 写在开始之前
今天接到一个新项目,当拿到板子和原理图,我傻了!
嗯??? 调试串口呢??? 运行指示灯呢???
什么!!! 怎么没有debug串口!!! 怎么连运行指示灯都没有啊!!!
悲催啊!!! 这让我怎么调试啊!!!
板子设计已然这样了,没办法!就这么干吧!
MCU使用的是stm32l431rc,flash尺寸256k,ram尺寸48k,没有外部flash。
既然没有串口、没有指示灯,flash又这么小,那干脆做一版极简版的bootloader试试吧!
开始动手…
2 创建极简工程
2.1 基于芯片创建工程
使用RT-Thread Studio基于芯片创建工程,配置如下:
点击完成!等待Studio生成工程…
2.2 裁剪工程到极简
在生成工程中,打开RT-Thread Settings,在Settings页面点击 更多配置 进入详细配置界面。在内核配置页面,取消所有打勾项,如下图所示:
修改 内核设备对象 项如下图所示:
切换到组件配置页面,取消shell,如下图所示:
取消设备驱动程序中的使用UART设备驱动程序项和使用设备IPC项,仅保留使用PIN设备驱动程序项,如下图所示:
保存工程,完成配置保存。
进入构建配置界面,修改优化选项为尺寸优化,点应用并关闭保存修改,如图:
编译工程,无错误,完成极简工程创建。flash使用13.15k,ram使用3.20k。
2.3 加入必备组件
加入fal组件,打开软件包中心,搜索fal,将fal组件加入工程,保存工程,完成组件下载和安装。
在工程的driver文件夹下创建文件夹ports,如图:
在ports文件夹下,加入文件fal_cfg.h,代码如下:
#ifndef FAL_CFG_H
#define FAL_CFG_H
#include <rtconfig.h>
#include <board.h>
#define RT_APP_PART_ADDR (0x08000000 + 321024)//app partition begin address
#define NOR_FLASH_DEV_NAME FAL_USING_NOR_FLASH_DEV_NAME//"norflash0"
/ ===================== Flash device Configuration ========================= /
extern const struct fal_flash_dev stm32_onchip_flash;
//extern struct fal_flash_dev nor_flash0;
/ flash device table /
#define FAL_FLASH_DEV_TABLE
{
&stm32_onchip_flash,
/&nor_flash0,/
}
/ ====================== Partition Configuration ========================== /
#ifdef FAL_PART_HAS_TABLE_CFG
/ partition table /
#define FAL_PART_TABLE
{
/{FAL_PART_MAGIC_WORD, "bl", "onchip_flash", 0, 321024, 0},/
{FAL_PART_MAGIC_WORD, "app", "onchip_flash", 321024, 1281024, 0},
/{FAL_PART_MAGIC_WORD, "factory", "onchip_flash", 1601024, 921024, 0},/
{FAL_PART_MAGIC_WORD, "download", "onchip_flash", 1601024, 921024, 0},
/{FAL_PART_MAGIC_WORD, "param", "onchip_flash", 2521024, 41024, 0},/
/{FAL_PART_MAGIC_WORD, "filesys", NOR_FLASH_DEV_NAME, 0, 810241024, 0},/
}
#endif /* FAL_PART_HAS_TABLE_CFG /
#endif / FAL_CFG_H /
在ports文件夹下,加入文件drv_fal_init.c,代码如下:
#include <rtthread.h>
#ifdef PKG_USING_FAL
#include <fal.h>
extern int fal_init(void);
INIT_COMPONENT_EXPORT(fal_init);
#endif
修改board.h,将以下代码:
#define ROM_START ((uint32_t)0x08000000)
#define ROM_SIZE (256)
#define ROM_END ((uint32_t)(ROM_START + ROM_SIZE * 1024))
#define RAM_START (0x20000000)
#define RAM_SIZE (48)
#define RAM_END (RAM_START + RAM_SIZE * 1024)
修改为
#define ROM_START ((uint32_t)0x08000000)
#define ROM_SIZE (256 * 1024)
#define ROM_END ((uint32_t)(ROM_START + ROM_SIZE))
#define RAM_START (0x20000000)
#define RAM_SIZE (48 * 1024)
#define RAM_END (RAM_START + RAM_SIZE)
去掉BSP_USING_ON_CHIP_FLASH的注释,打开芯片flash驱动
/#define BSP_USING_ON_CHIP_FLASH*/
修改为
#define BSP_USING_ON_CHIP_FLASH
修改main.c,删除main函数内的所有代码,仅保留return RT_EOK;
int main(void)
{
return RT_EOK;
}
打开构建配置,向编译配置的includes中加入目录drivers/ports
保存、编译工程,无错误,添加fal组件完成。编译生成代码,flash使用14.67k,ram使用3.25k。
3 加入QBoot组件
打开软件包中心,搜索qboot组件,添加qboot组件到工程,关闭软件包中心。
配置qboot组件,双击qboot组件,进入组件详细配置页面,取消所有打勾项,仅保留using quicklz decompress项,如图所示:
保存配置,完成qboot组件添加。
说明:因为没有debug串口、没有状态指示灯,所以shell和打印输出相关的功能都用不上,所以统统去掉了。为什么仅保留quicklz解压呢?因为AES解密功能的flash使用比较多,所以未使用;gzip解压功能使用flash软多,不适用于资源较小的MCU,所以未选用;fastlz的资源使用与quicklz差不多,但其压缩率没有quicklz好,所以最终使用了quicklz解压功能;不用解压功能岂不是更省资源吗?为什么还要用quicklz呢?因为quicklz使用flash很少,不足1k,而使用了压缩后download区就可节省出1/4的空间(因为quicklz的压缩率在70~75%左右),比如app分区是128k,那么download分区就可以减少到96k,由此可见使用压缩还是很划算的。QBoot各功能资源使用情况详见:qboot各项配置资源占用情况说明
编译工程,无错误,极简版bootloader制作完成。flash使用17.95k,ram使用12.35k。
4 测试验证
烧入刚制作完成的bootloader到0x08000000处,再烧入app到0x08000800处。重新上电,app可以运行,说明bootloader可正常跳转到app执行。
修改app版本,然后将新的app打包为rbl固件包,将生成的固件包扩展名改为.bin,使用烧写工具将扩展名为bin的固件包写入download分区地址0x08028000处。重新上电运行。
使用仿真器查看app分区程序版本号,已变成修改后的版本号,说明bootloader释放download分区固件到app分区功能正常。
5 加入未来支持
极简版bootloader虽然可用,但调试起来太不方便了;经与硬件设计人员沟通确定,下一版本将加上debug串口和运行指示灯,所以现在在极简版的基础上,加入log输出和运行指示功能。为方便调试,自己飞线引出了debug串口。
进入内核配置页,加入控制台功能,如图:
切换到组件配置页,加入UART设备驱动,如图:
进入qboot配置页,加入状态指示灯功能和syswatch组件(可能是强迫症犯了,总感觉不保险,所以加了syswatch),如图:
保存、编译,flash使用28.90k,ram使用13.09k。
下载运行,哇!终于又能看到log了…
通过ymodem下载固件包到download,bootloader可正常释放固件到app
6 6 总结:通过极简版bootloader的制作可见,基于RT-Thread V4.0通过裁剪也可以制作出尺寸较小的bootloader,最小尺寸不足20k,如果加入log输出和syswatch,尺寸不足32k,能够满足大多数小资源MCU的使用;而且通过RT-Thread V4.0制作bootloader比较简单和容易。
原作者:红枫