一个完善的 Bootloader 不仅仅是“跳转到应用程序”那么简单,完整功能一般包括:
提供 CLI(命令行接口)供用户交互;
支持:
load
, flash
, boot
, md
, mw
等);mw 0x40021000 0x1
);md 0x08040000
);cmp 0x20000000 0x08040000 0x1000
);整体设计可以划分为以下几个模块:
Bootloader/
│
├── startup/ → 启动代码(启动文件、异常向量)
├── drivers/ → 底层驱动(UART、Flash、SD、Net)
├── hal/ → 硬件抽象层
├── protocol/ → 下载协议实现(Xmodem/TFTP等)
├── cmd/ → 命令解析器和命令注册表
├── loader/ → 镜像加载与跳转
├── flash/ → 烧写器接口
├── cli/ → 命令行接口(带历史、编辑等功能)
├── utils/ → 通用函数(CRC、字符串、打印等)
└── main.c → 主函数,初始化和主循环
系统上电或复位
↓
Bootloader 启动
↓
初始化硬件外设(串口、SD卡、以太网、Flash等)
↓
进入命令行界面 CLI(等待用户输入)
↓
┌─────────────┐
│ 用户输入命令 │
└─────────────┘
↓
执行解析的命令:
├─ boot → 启动 APP
├─ load → 下载镜像(串口/网卡/SD)
├─ flash → 烧写 APP 到 Flash
├─ erase → 擦除 APP 区域
├─ md/mw/cmp → 读/写/比较内存
└─ help → 显示帮助信息
具备编辑能力:
void cli_loop() {
while (1) {
cli_get_input(); // 获取用户输入,支持方向键等
cli_parse_command(); // 解析命令
cli_execute_command(); // 调用对应命令处理函数
}
}
采用“命令注册表 + 回调函数”机制:
typedef struct {
const char *name;
int (*handler)(int argc, char **argv);
const char *help;
} cmd_entry_t;
static const cmd_entry_t cmd_table[] = {
{ "boot", cmd_boot, "Start application" },
{ "load", cmd_load, "Load image" },
{ "flash", cmd_flash, "Write to flash" },
{ "md", cmd_md, "Memory dump" },
...
};
对 Flash 操作进行封装,支持写、擦除、保护:
int flash_write(uint32_t addr, const uint8_t *buf, size_t len);
int flash_erase(uint32_t start_addr, size_t len);
int flash_verify(uint32_t addr, const uint8_t *buf, size_t len);
以串口 YModem 为例:
int ymodem_receive(uint8_t *dst_addr, size_t max_size);
以 TFTP 为例:
int tftp_receive(uint8_t *dst_addr, size_t max_size, const char *filename);
跳转前的准备工作:
void jump_to_app(uint32_t app_base) {
typedef void (*app_entry_t)(void);
uint32_t sp = *(volatile uint32_t *)app_base;
uint32_t pc = *(volatile uint32_t *)(app_base + 4);
__set_MSP(sp);
SCB->VTOR = app_base;
((app_entry_t)pc)();
}
一个成熟的 Bootloader 是嵌入式系统中不可或缺的基础组件。它不仅负责应用程序的启动,还承担着维护、升级、安全校验、调试等诸多职责。建议在设计之初就考虑良好的模块化、可扩展性、安全性,逐步完善功能。