STM32的bootloader探究
STM32的bootloder_OTA探究
烧录方式#
-
ISP:ISP要求单片机中驻留有专门的程序,用以与上位机进行通信,接收固件数据并烧录到自身的ROM中,很显然ISP的单片机是需要可运行的,即要具备基本的最小系统电路(时钟和复位)。比如STM32的串口ISP
ICP 可以理解为MCU就是一块可供外部读写的存储电路,它不需要预置任何程序,也不需要单片机芯片处于可运行的状态
- 优点:
- 其最大的优势在于可实现在系统或在电路直接烧录程序,而无需像以前一样把单片机芯片从电路中拿出来,放到编程器上,这种烧录方式就是 ISP(In System Programming) 或 ICP(In Circuit Programming)。
- 缺点:
- 下载速度慢
- 依赖于专门的上位机或下载器硬件,不能作到统型
- 下载的时候通常需要附加额外的操作,比如STC要重新上电、STM32需要设置BOOT引脚电平等等。这些额外的操作都增加了烧录的复杂性
- 优点:
-
IAP:In-Application Programming (IAP) 是一种使微控制器(MCU)能够在系统运行时更新自身固件的技术,在程序运行过程中去烧写flash。这种技术允许设备在现场升级,而无需通过传统的编程器或调试器。IAP通常通过使用MCU的通信接口,如UART、USB或CAN等来实现。此外,还支持通过各种通信协议进行,如以太网、Wi-Fi或蜂窝网络,bootloader即是实现这种功能的代码。
- 注意这里是在程序运行时编程。
XIP:烧写到flash上,直接在flash上执行,就是我们的boot mode中从Flash启动。
-
OTA(Over-The-Air Technology,空中下载技术)是一种通过无线网络对设备进行远程升级的技术。这种技术最初在PC电脑和移动手机行业中得到应用,近年来在汽车行业中也得到了广泛的应用。
-
Z-Modem:是一个高级的文件传输协议,主要用于计算机之间的文件传输,尤其是在拨号网络和早期互联网时代非常流行。相比于X-Modem和Y-Modem协议,Z-Modem提供了更高的传输速度、错误恢复能力以及自动文件名和文件大小的协商,极大地提高了文件传输的效率和可靠性。
Z-Modem协议的几个关键特点包括:
-
自动握手与错误纠正:Z-Modem能够自动进行连接握手,无需用户干预,而且具备强大的错误检测和纠正机制,可以在嘈杂的通信线路中保证数据的完整性。
-
高速传输:通过使用更大块的数据包(可达32K字节),Z-Modem能够比X-Modem和Y-Modem更快地传输文件。
-
流控与中断恢复:Z-Modem支持双向的流控制,能够在传输过程中动态调整数据速率,以适应当前的线路条件。此外,它还支持断点续传,即使传输中断也能从中断处继续,无需重新开始。
-
自动文件名与方向检测:Z-Modem协议能够自动传输文件名和文件大小信息,接收方可以决定是否接受传输。同时,它能够自动检测文件传输的方向,无需用户指定发送或接收。
-
透明数据传输:支持二进制文件的无缝传输,无需对特殊字符进行转义,提高了文件传输的通用性。
-
bootloader的基本形态#
- 通过超级终端、SecureCRT 或 Xshell 之类的串口终端输入命令 program;
- bootloader接收到命令后,开始等待接收固件文件数据;
- 串口终端通过某种文件数据传输协议(例如 X/Y/Zmodem协议)将固件数据传给BL;
- bootloader将固件数据写入到 ROM 的 APP 区中;
- bootloader将 APP 区中的程序引导运行起来。
- 简单的bootloader:跳转到app去执行
- 复杂的bootloader:U-boot——初始化硬件,启动内核,调试作用
实现bootloader的要点#
芯片体系架构要支持:支持重定向中断向量表
ROM 要支持 IAP:在程序运行过程中,可以对自身ROM进行擦除和编程操作,即将APP搬运到某个位置
编译时需要将app链接到运行的地址
bootloader_demo#
第一个bootloader#
APP无异常向量#
-
分为两个程序,
-
一个程序是bootloader,烧写在flash开始的地方;
-
另一个为app,烧写到bootloader跳转的地方。
-
-
实现的功能:bootloader程序在上电之后初始化串口,然后跳转到app的地址去运行打印,打印出信息。Reset_Handler在bootloader中已经调用
-
程序解析:
APP有异常向量#
-
分为两个程序,
-
一个程序是bootloader,烧写在flash开始的地方;
-
另一个为app,烧写到bootloader跳转的地方。
-
-
程序解析:bootloader程序的启动文件和app的启动文件一样:都是跳转到Reset_Handler去运行,不过两个程序的Reset_Handler被链接为不同的地址。bootloader调用Reset_Handler之后跳转到app的Reset_Handler去执行。
使用汇编跳转#
-
为什么要使用汇编代码来跳转?
- cortex - m3 使用向量表机制,向量表记录了异常处理的入口。且异常发生时,会由硬件为我们从存储器的向量表中自动定位异常处理的入口。
- 处理器上电复位时,硬件会从向量表头两个字取出赋给sp 和 pc。
- 因为我们想要让我们的app程序仍然像往常一样写,则我们要软件上实现将app的向量表上的值赋值给sp,pc等寄存器。
-
程序解析:
- bootloader的main函数
重定位vector#
第二个bootloader#
- 有一种bootloader,硬件上电之后,bootloader跳转到app运行,app将自己从flash复制到RAM中去运行。
程序链接到任意处 使用绝对跳转会遇到问题#
-
程序解析:
-
app的反汇编文件:
- 联系上图查看
app将自身复制到运行的地方#
-
程序解析:
- bootloader不变,仍然重定位向量表地址,将app中的向量表第一个放到sp,跳转到向量表第二个0x08040009进行执行
- 这里app将自身的一份复制到RAM中,涉及到绝对跳转时,不会出错,但是跳转之后仍然会返回到FLASH中继续执行,也可以直接使用绝对跳转。
- app的汇编文件:
-
遇到的问题:
- 在MDK中,将链接地址设置到RAM中,无法将程序下载到ROM中。
- 没有找到烧写这段程序的算法:
- 在MDK中,将链接地址设置到RAM中,无法将程序下载到ROM中。
- 解决:需要使用别的烧写工具,比如STM32CubeProgramer
第三个bootloader#
-
复制的方式,可以用于烧写的地方不是可以执行的地方(XIP),比如我们烧写到外部SD卡,spi-flash等等大容量的设备上
-
这时要bootloader将程序复制到ROM或者RAM,然后跳到程序去运行。
-
三个要素:
- 源:SD卡,外扩的flash
- 目的:链接地址
- 固定的链接地址
- app灵活,我们可以在烧写的程序前面加上一个头部,bootloader解析这个头部,然后根据头部的信息进行复制
- 长度
-
如何生成这个头部?
-
使用U-boot的工具,mkimage.exe,可以生成带头部的image文件
-
./mkimage.exe -n "f103ZET6_app" -a(加载地址) 0x20000000 -e(入口地址) 0x20000008 -d app.bin app_with_header.bin
-
-
程序解析:
- bootloader main文件:
- bootloader的启动文件:
- 遇到的问题:
- 当把程序复制到RAM中去执行是可以的,但是复制到Flash中会出现崩溃,原因是默认Flash是上锁的,要对他进行写操作,需要先解锁擦除
- 对内部Flash不像对SRAM直接用指针操作,所以是不能用指针操作的
第四个bootloder#
修改异常向量的地址:
-
硬件支持,通过重定位向量表寄存器修改向量表地址
-
有一些硬件并不支持重定位向量表,发生异常时,仍然在bootloader中的异常向量表去寻找。
- 怎么办呢,将bootloader中的异常向量指向app的异常向量
bootloader的框架#
移植shell#
- 单片机上的shell程序上会是什么样的?
-
- 一定是死循环等待输入,输入的字符存入buffer
- 我们输入键盘,会有显示出来:输入的字符通过串口线到板子上,板子再将字符传回PC做回显
- 特殊字符处理:删除键,上下箭头显示历史命令,回车
-
命令行传参#
-
int argc, char **argv
是C语言中用于命令行参数传递的两个典型变量,通常在主函数(main function)的定义中见到。它们用于接收程序启动时从命令行传入的参数。让我们逐个解析这两个参数:-
int argc: 这个参数代表了“argument count”,即传入程序的参数个数。它是一个整数,总是大于等于1。argc至少为1,是因为程序名称自身也被视为一个参数(即argv[0])。如果用户没有提供额外的参数,argc将等于1;每增加一个额外的参数,argc的值就增加1。
-
**char argv[]: 这个参数代表了“argument vector”,即一个指向字符指针的指针,也可以理解为一个字符串数组。它包含了指向各个参数的指针。每个指针都指向一个以空字符('\0')结尾的字符串,即C语言中的字符串。argv[0]通常是程序本身的名称或路径,argv[1]开始是用户提供的第一个参数,以此类推,直到argv[argc-1]。
举例说明,假设你有一个名为
myProgram
的程序,用户在命令行中输入如下命令来运行它:myProgram -f input.txt -o output.txt 在这个例子中,
argc
将为4,因为总共有4个参数(包括程序名自身)。argv
的内容如下:argv[0]
指向"myProgram"
argv[1]
指向"-f"
argv[2]
指向"input.txt"
argv[3]
指向"-o"
argv[4]
指向"output.txt"
argv[5]
是NULL,表示参数列表的结束。
通过解析
argc
和argv
,程序可以了解用户在命令行中提供了哪些参数,以及如何根据这些参数调整行为。这是编写能够接受用户输入或配置的命令行工具的基础。 -
实现bootloader#
- flash中分为两段,第一段为bootloader,第二段为包含头信息的烧写文件。
- bootloader的功能:
- 有一个shell,可以调试,z - modem接收串口传输的文件
- 根据头信息将程序加载到某个地址去执行
- bootloader的功能:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 盘点!HelloGitHub 年度热门开源项目
· DeepSeek V3 两周使用总结
· 02现代计算机视觉入门之:什么是视频
· C#使用yield关键字提升迭代性能与效率
· 回顾我的软件开发经历(1)