一般设计来说,bootloader作为引导程序和升级APP,改动并不大而且也相对稳定。但是如果项目中遇到非得更新bootloader的,比如协议的更新替换,这时候就有设计此方案的必要性了。   

flash分区图和程序图如下,接下来的描述都是基于这图来进行分析
bootloader和APP两重升级(STM32为例)
      大概说下思路:简单的说就是设计三段程序,bootloader0、bootloader1、APP。
      这里假设使用的是ST的STM32F103C8T6,该款单片机有64K flash,每个扇区为1K,一共64个扇区。在这些扇区的分配中,bootloader0占用1K,也就是一个扇区空间(0x08000000~0x080003FF);bootloader1占用22K,也就是22个扇区空间(0x08000400~0x08005BFF);标志区占用1K,也同样为一个扇区空间(0x08005C00~0x08006000);APP部分包括APP和DATA,还有40K空间可利用。这个就flash的分区思路。
      此次再来说下1K标志区的存储,在这里我只用了10个字节存储,当然如果有一些必要的标志数据啥的,也可以存储在此空间,在这里我用结构体表示这些变量成员,并把标志区的flash地址转换成此结构体指针。
bootloader和APP两重升级(STM32为例)
    此次再来说明程序流程图。正常模式下,系统开始运行是从bootloader0开始的,然后跳转到bootloader1,再者跳转到APP,这就是一个流程。bootloader0的程序也很简单,无非就是判断标志区的标志变量是否改变,从而选择跳转到Bootloader1或者APP区域。bootloader0的main函数如下,按照上述的流程图可以明白,只要是标志区的跳转标记是正常模式或者bootloader_flag未被置位,说明是没有升级过bootloader1或者已经升级成功的,进而就跳转到bootloader1。否则都直接进入APP,这样可以防止APP里面升级bootloader失败了而且不小心断电了,不用经过Bootloader1进入APP再次升级bootloader1。
bootloader和APP两重升级(STM32为例)
      当然在启动文件里面,不需要进入系统时钟初始化直接进去main,所以我们同样也要修改下启动文件。
bootloader和APP两重升级(STM32为例)
      最后生成的bootloader0空间比较小,如果觉得这1K扇区用的比较浪费,也同样可以存储一些你觉得必要的数据。
bootloader和APP两重升级(STM32为例)
     那么接下来先说明下16个字节升级参数,这16个字节是每次制作升级bin包的时候插入到此Bin包的头16个字节。说明如下:
bootloader和APP两重升级(STM32为例)
     bin包的发送上,我的上位机是这样处理的,先每次间隔两秒发送16个字节参数,后续的bin包拆分512个字节依次200ms发送。(下面会简单介绍下上位机的思路。)
     接下来再看Bootloader1,此段代码作为引导进入APP以及升级APP的代码,其作用也不言而喻。回到原来那个流程图,当APP收到APP升级的16个字节升级参数(下面会说明)的时候,APP会把标志区的跳转标志设置为升级模式并且把bootloader1置位并且复位,这时候程序重新运行的时候就一直在bootloader1中运行,一直等待升级APP,当再次收到16个字节升级参数的时候,记录升级参数的CRC,bin包的总长度、根据升级包的总数量擦出APP区域的对应空间。后续在接受512个字节的时候依次写入flash,到最后一包的时候,check下CRC是否对应上,对的上就更新标志区的标志变量并且复位,check不对就上报信息给上位机并且重发。截图中的是明文协议。因为之前用的是明文协议(方便但是弊端比较多,所以才会要更新为暗文协议。)
      bootloader和APP两重升级(STM32为例)
     再者说明APP部分,APP部分主要是一者升级APP,设置标志区的标志变量并且复位跳转至Bootloader1进行APP升;二者是升级Bootloader1。区分是升级APP还是Bootloader主要在于区分16个字节升级参数,16个字节升级参数里面带有一个字节判断APP还是bootloader,以此来决定哪个类型升级。
bootloader和APP两重升级(STM32为例)
     底层上已经大概说明完毕,不管是用xyzmodemx协议、modbus协议、自定义协议也好,只要能考虑好升级的安全性和全面性,还有代码逻辑思路清晰,其实都可以。
     接下来说下上位机。我用的是QT,升级使用定时器来做非阻塞式单线程,当然使用多线程升级更加方便。一部分截图如下。对于生产员工来说,只需要点击两个空间,等待进度条100%即可。
bootloader和APP两重升级(STM32为例)
      在控件逻辑上,打开升级文件,使用QFileDialog类并把bin包信息通过全局变量记录下来。
bootloader和APP两重升级(STM32为例)
    再点击发送升级文件控件,逻辑上是开启两个定时器,一个2s定时,一个200ms定时,当然两个定时都可以根据情况修改;这两个定时的作用是,2s定时的是发送两次16个升级参数,后面的200ms定时是依次发送512包的bin包数据。
bootloader和APP两重升级(STM32为例)
     在2s定时的槽函数里面进行发送16个升级参数,发送完关闭2s定时并且开始200ms定时。
bootloader和APP两重升级(STM32为例)
     发送bin包里面的头16个字节,可以带参多次发送。(这个是对应2S定时槽函数。)
bootloader和APP两重升级(STM32为例)
      在发送bin包的每次512个字节的时候,先记录总的512个字节总段数,每次发送完一包,依次使用seek函数来设置当前文件的位置,并且使用read设置要读的字节长度,直到发送至总段数到了。(这个是对应200ms定时槽函数)代码如下:
bootloader和APP两重升级(STM32为例)

 

另外:可以使用“相对地址链接到绝对地址的时候得根据flash实际划分调整”,根据升级文件大小重新调整flash实际划分和中断向量偏移地址。

相关文章:

  • 2021-08-09
  • 2021-09-29
  • 2022-01-04
  • 2021-07-16
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-12
猜你喜欢
  • 2022-01-11
  • 2021-12-05
  • 2021-05-07
  • 2022-12-23
  • 2022-12-23
  • 2021-10-06
  • 2021-06-22
相关资源
相似解决方案