单片机bootloader(APP的自我复制)
文章目录
- Bootloader 中 APP 的自我复制与启动机制解析
- 一、为什么要进行自我复制?
- 二、程序整体结构概述
- 三、汇编启动代码分析
- 重点解释:
- 四、C 语言部分分析
- 核心功能:
- 五、start\_app 函数:手动启动指定 APP
- 六、总结
- 七、适用场景
Bootloader 中 APP 的自我复制与启动机制解析
在嵌入式系统中,我们常常会使用 Bootloader 作为程序的引导入口,它负责初始化系统资源、判断是否需要升级程序,并最终跳转至应用程序(APP)运行。本文将讲解一种特殊但实用的技巧:Bootloader 在启动后将自身复制到 RAM 中运行,并在复制完成后,从 RAM 重新启动整个程序。
一、为什么要进行自我复制?
Flash 中执行程序是常规做法,那为何还需要将程序复制到 RAM 呢?主要原因有以下几点:
-
加快执行速度
Flash 的访问速度相较 RAM 要慢,而将代码复制到 RAM 后运行,能显著提升程序执行效率。 -
实现代码完整重定位(Position-independent)
某些平台在运行时对代码地址有特殊要求,比如要求代码在 RAM 的某一位置执行。 -
为程序热升级或 OTA 预留空间
通过 RAM 运行,可以在 Flash 中擦除/替换当前正在执行的程序,为系统升级打下基础。
二、程序整体结构概述
这段代码主要由两部分构成:
- 启动入口(Reset Handler)
- 自我复制函数与主函数(mymain)
三、汇编启动代码分析
__Vectors DCD 0x20010000 ; 启动时设置的初始栈地址DCD 0x08040009 ; Reset_Handler 的地址(带 Thumb 标志)Reset_Handler PROCEXPORT Reset_HandlerIMPORT mymainIMPORT copy_myselfIMPORT |Image$$ER_IROM1$$Length|adr r0, Reset_Handler ; 获取 Reset_Handler 当前地址bic r0, r0, #0xFF ; 取整对齐到 Flash 起始地址ldr r1, =__Vectors ; RAM 中目标地址(0x20010000)ldr r2, =|Image$$ER_IROM1$$Length| ; 段长度(从链接脚本中获取)BL copy_myself ; 执行复制操作ldr pc, =mymain ; 跳转到 RAM 中的主函数执行ENDP
重点解释:
adr r0, Reset_Handler
:获取当前代码的实际地址(此时仍在 Flash)。bic r0, r0, #0xFF
:对地址按 256 字节对齐,作为复制源起始地址。ldr r1, =__Vectors
:复制目标是 RAM 的某段地址,比如 0x20010000。copy_myself
:这是用户编写的复制函数,将当前程序代码整体复制到 RAM。ldr pc, =mymain
:复制完成后,直接跳转至 RAM 中的入口函数。
四、C 语言部分分析
void copy_myself(int *from, int *to, int len)
{for (int i = 0; i < len / 4 + 1; i++){to[i] = from[i];}
}int mymain()
{char c = 'A';int (*fp)(char) = putchar;putstr("www.100ask.net");while (1){fp(c++);putchar(c++);delay(1000000);if (c == 'Z') c = 'A';}
}
核心功能:
copy_myself
:按字节复制程序代码到 RAM。mymain
:RAM 中的入口函数,简单测试输出字符,验证程序是否正常工作。
五、start_app 函数:手动启动指定 APP
在另一个文件中,还定义了如下函数,用于启动任意地址的应用程序:
start_app PROCEXPORT start_appldr r3, =0xE000ED08 ; VTOR 寄存器地址str r0, [r3] ; 设置中断向量基地址(如 0x08040000)ldr sp, [r0] ; 初始化栈指针ldr r1, [r0, #4] ; 获取复位向量地址BX r1 ; 跳转到 APP 启动ENDP
这个函数常用于从 Bootloader 跳转到真正的应用程序。
六、总结
整个流程可总结如下:
- MCU 上电后执行 Bootloader。
- Bootloader 将自身从 Flash 复制到 RAM。
- 跳转到 RAM 中的主函数运行,实现从 RAM 启动。
- (可选)通过
start_app
跳转到其他 APP 地址运行,实现多段代码管理。
七、适用场景
- RAM 空间充足,希望提升执行速度;
- 程序需动态更新或热加载;
- Flash 中只保留一段主程序,但需要运行时自迁移机制。