bootloader的原理分析

目录

1.基础篇

1.1 bootloader实现六步曲

1.1.1 定协议

1.1.2 定分区

1.1.3 flash操作驱动实现

1.1.4 app标志位定义

1.1.5 跳转

1.1.6 app开始处理

1.2 基础篇总结


1.基础篇

1.1 bootloader实现六步曲

1.1.1 定协议

        单帧数据:帧头,帧尾,帧大小,帧校验;

        单包数据(多帧):包起始帧,包大小帧,包数据帧,包校验帧;

        整包数据(多包):起始帧,结束帧,整包校验帧;

1.1.2 定分区

        bootloader分区:boot程序存储区,通常0x8000000开始

        数据存储取:标志位等固件基本信息存储区,通常在boot分区和app分区中间;

        app分区:app程序存储区,前面两个分区留足空间后,剩下的即可定义为app区;

1.1.3 flash操作驱动实现

        flash的读,写,擦除方法实现;

        读:读取保存在flash中的一些基本信息(如标志信息,crc校验值,固件基本信息等);

        写:将接收到的bin文件数据写到app的flash分区;写固件的基本信息;

        擦除:升级起始阶段,擦除app分区数据等;

1.1.4 app标志位定义

        一、存储在flash中:该方法目前较普遍的处理逻辑是,将标志位存在bootloader分区和app分区中间的某一块可单独擦除的区域,当升级成功就把该标志位置为1。该方法优点是逻辑简单;缺点是未走升级流程时标志位不置1,当然可以通过单步调试的方法使标志位置1。

        二、存储在ram中:该方法需要在app中设置对应ram地址数值;灵活性较高,不论是烧录的程序还是升级成功的固件都能正常跳转。需要注意的是bootloader和app都要避开对该部分ram空间的操作(即用keil重设ram的起始地址)。

1.1.5 跳转

        boot跳转到app,可以说是bootloader中最核心的技能,基本功能可按如下步骤实现:

        一、关闭全部中断,__disable_irq();

        二、获取app入口函数地址(即app分区起始地址+4处保存的内容);

        三、将app入口地址赋值给函数指针*start_app;

        四、设置主栈地址(即app分区起始地址中存储的地址);

        五、调用app入口函数start_app();

注意,这几个步骤是有先后顺序的。想想为什么?

        一,在跳转前关闭全部中断是为了防止程序运行出错。因为这5个步骤没有重设中断向量表,所以当调用start_app()之后,设置中断向量表之前,用的还是bootloader的中断。

        二和三,是为了获取app入口函数地址,一定要在设置主栈地址之前获取。如果设置主栈地址后再去获取app起始地址会出错。因为start_app是在boot中声明的变量,即用boot的栈申请的内存,如果更改了主栈地址后再更改start_app的值,则会用到app中栈的地址,所以会出现内存使用错误。

        四,跳转之前准备好主栈地址,是因为在在入口函数时就可能会出现NMI或其它fault,就需要使用堆栈。

        五,主动调用进入app的函数,执行跳转到app。

void jump_to_app(void)
{
    __disable_irq();
    
    uint32_t app_addr = 0;
    app_addr = *(volatile uint32_t*)(APP_START_ADDR + 4);
    typedef void (*pfunction)(void);
    pfunction start_app;
    start_app = (pfunction)app_addr; 
    
    __set_MSP(*(volatile uint32_t*)APP_START_ADDR);
    start_app();
}

1.1.6 app开始处理

前面都是bootloader的功能,要想验证bootloader是否正常还需实际跳转一次。有bootloader的程序app需要注意两点:

一、更改中断向量表的偏移地址,NVIC_SetVectorTable();

二、开启全局中断,__enable_irq(因为bootloader跳转时关闭了全局中断);

1.2 基础篇总结

        按上面的步骤就能实现拥有基本功能的bootloader了,大多数场景都能适用。

        另外,app也要按照约定的地址在keil里面设置好。

        但是按照该方法实现的bootloader还是存在缺陷的,如下几个问题可以深思一下:

        一、当升级到一半时,中断升级会发生什么?

        答:如果有备用分区,则重启继续跑备用分区里的app;如果没有备用分区,则停留

                在bootloader模式。

        二、当升级失败时,能不能复原原来的程序?

        答:单片机的程序空间足够大的情况下,划出一个备用分区。升级成功才会跳转到新的app。

        三、当使用usb作为通信接口时,上面步骤是否还适用?

        答:目前发现usb的启动时序需要注意。因为bootloader已经初始化了usb,导致上位机认为

                usb已经连接上。所有跳转到app时要制造一个热插拔信号(通常有IO实现),然后再重

                新初始化usb。

        四、怎么避免跳转之后程序不能运行的问题?

        答:该问题还是很严重的,跳转后不能运行其实就相当于死机了。只能通过烧录来更新

                程序。所以在跳转之前要判断app程序的完整性。目前有两种方法:1.检查起始地址保存

                的值是不是栈顶地址;2.检查app程序区的crc校验值(事先将crc保存在某个地方,每次

                开机都计算对比);

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值