实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

时间:2024-05-22 22:51:06

这篇文档主要讲解Cortex-M3内核的芯片怎样实现带有BOOT和APP分区程序功能,通过BOOT来给APP固件升级。

先列出主要步骤:

BOOT中:

  1. 重定位中断向量表到BOOT区首地址(必须)
  2. 在跳转之前重置所有内部外设时钟包括Systick时钟,避免跳转时产生意外中断(可选)
  3. 更改PC指针和SP堆栈指针,实现跳转(必须)

APP中:

  1. 重定位中断向量表到APP区首地址(必须)

 

         接下来详细说明,先讲解一下我们的程序为什么需要有BOOT和APP这样的程序分布,已经明白的可以跳过下面几段,直接到“分割线”下面。

         做过单片机开发的可能知道,通常做一个开发板或者普通的不需要升级固件的产品来说,是不需要BOOT的,但如果一个产品需要经常升级固件,而产品本身的电路板是不可能随意让你拆除,也不可能搞一个JTAG或者SWD烧录器进行烧写时,这时候就需要一个很方便的固件升级方式,比如通过串口升级(借助WIFI转串口、蓝牙转串口或者其它直连的方式)或者通过网口升级都行,只要能跟芯片通信就行,最简单的一般是通过串口来升级。

一般外部的升级软件通过跟芯片的BOOT通信,将APP的bin文件分块传输并写入到芯片FLASH区的APP指定的起始地址处,写入完毕之后,往往还需要对整个写入的APP固件进行校验,确保写入的APP是正确的之后,就可以更改系统的一些配置参数,这样下次程序启动的时候去读取配置参数,然后去正确的启动APP;而实际的升级比这可能还要复杂,比如程序升级到了一半突然被意外中断或干脆断电该怎么处理?产品会不会变“砖”?等问题。

        其实防砖也好处理,主要思想就是先清掉升级标志,然后等全部升级完毕,最后更改标志,BOOT启动时根据该标志决定是否跳转到APP。

在升级之前我们在“配置参数区”的某个指定位置写入特定的几个字节数据,来标记升级成功如否的标志,只有当我们把APP程序升级完毕,所有校验检查都通过之后,在复位重启之前,更改那几个特殊标记的字节,来表示升级成功,这样如果没有升级或者升级一半断电的话,该标志就不会被更改,那下次BOOT启动之后先去检查该标志,如果不满足启动APP条件,则不会进行APP跳转,程序仍然可以停留在BOOT代码中,给用户继续升级的机会,而不是跳转到APP中,而APP区又是损坏的,变成了一个“砖头”;通过这种方法我们就很好的实现了防砖设计。

实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

 

----------------------------------------------------分割线----------------------------------------------

         下面我们回到正题,在从BOOT跳转到APP这个动作以及做这个“跳转”动作之前,我们需要做的事情,这里我已经列出了主要的步骤:

  1. BOOT里面,主要是重定位中断向量表和实现跳转功能
  2. APP里面,主要是重定位中断向量表

         在BOOT代码中,main开始运行的起始,我们需要做重定位中断向量表到BOOT的起始区,中断向量表就是一系列中断的入口地址,发生中断以后,程序会跳转到中断向量表中对应的中断入口区,去寻找该中断函数真正的入口地址,然后跳到中断函数去执行中断处理,如果中断向量表的入口地址不对,那么执行的中断入口地址就不对了,你执行的甚至都不是中断函数了,所以BOOT和APP区必须都有自己的“中断向量表”,中断向量表一般位于程序的起始地址处,程序进入BOOT或者APP的main之后,第一件事情就是要重定位中断向量表地址。

STM32和LPC1768都是Cortex-M3内核的,操作中断向量表的寄存器就是VTOR寄存器

,重定位中断向量表,说白了就是向VTOR寄存器0xE000ED08地址写入BOOT区或者APP区的起始地址值。下面看下该寄存器的说明

实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

 

 

APP跳转函数,使用了C中嵌入汇编,下面是跳转代码

         __asm void f_jmp_app(U32 address)

         {

            LDR SP, [R0]                                   ;Load new stack pointer address

            LDR PC, [R0, #4]                           ;Load new program counter address

         }

 

在需要跳转的位置,执行 f_jmp_app(APP_Start);

比如STM32,我的APP起始地址为 0x0810000 地址,则写成 f_jmp_app(0x08100000)即可。

在f_jmp_app函数中,有2句汇编指令,第一句 LDR SP, [R0] ,   SP为栈顶指针, R0为函数的第一个参数,该函数只有一个就是 address ,所以R0就等于0x08100000, 而第二句就是 LDR PC, [R0, #4] ,  该指令的功能是将 address+4的新地址作为PC程序指针,原因请往下接着看,下面是Cortex-M3内核的寄存器组,SP堆栈指针就是R13, PC程序指针就是R15。

实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

         至于为什么需要上面那样操作,就需要去看Cortex-M3权威指南了,里面有关于SP和PC的详细介绍,这里我贴出主要内容

实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

实现Cortex-M3内核芯片(如STM32,LPC1768)的boot升级跳转到APP操作

 

总结:

在BOOT中,main起始处写:

SCB->VTOR = 0x0 & 0x1FFFFF80;     //重定位中断向量表

在需要跳转的位置写上:

f_jmp_app(app_start);

而f_jmp_app 的函数定义为:   

__asm void f_jmp_app(U32 address)
{

    LDR SP, [R0]          ;Load new stack pointer address

    LDR PC, [R0, #4]      ;Load new program counter address
}

APP中,main起始处写:

SCB->VTOR = app_start & 0x1FFFFF80;  //重定位中断向量表

注:app_start起始就是app程序起始地址。