工程项目上有时候需要为设备更新应用程序,如果不预留接口升级的话就需要拆除外壳,太麻烦了。一般会留下升级程序的接口,在需要升级设备的时候,给一个信号使程序进入BOOT区运行,然后进行在线升级。

我们一般把单片机flash空间划分为3块。
1、BOOT: 储存进行在线升级的驱动程序
2、APP : 储存应用程序
3、配置信息 : 储存需要保存的应用数据

以下是BOOT区以及APP区的配置方法。

1、设置BOOT程序的代码占用空间

根据BOOT功能来划分,这里我举个例子分配0x2000的空间给BOOT

单片机如何修改bios_单片机如何修改bios

2、BOOT区启动后要对APP区的代码进行校验
根据校验的结果来决定是停留在BOOT区等待,还是跳转APP程序运行。
可以把APP程序的校验和存在APP程序区的末尾,在烧录程序的时候烧录进去。在BOOT刚启动的时候,计算APP区代码的校验和进行对比。如果相同,就跳转到APP区,如果不同,就执行BOOT区接下来的程序进行远程升级。

3、APP区如何进入BOOT区
1、更改APP区校验信息
上面我们说到BOOT区启动的时候会校验APP区的代码来决定是否运行APP,所以APP区进入BOOT区之前,要破坏APP区的校验信息。在APP区进行操作,把校验信息改写,取反或者加1都是不错的选择。在BOOT区无法进行远程升级的时候,可以更改校验位回到APP区运行。

2、重启进入BOOT区
在更改APP区校验信息之后,需要重启单片机运行。
STM32的重启代码是:

NVIC_SystemReset();

4、BOOT区在线升级

在确定了需要在线升级之后,就可以用预留的接口,来接收数据进行在线升级了。
我们将接收到的数据,写到APP的flash区内(不要覆盖了BOOT区和配置信息区),数据接收完后,还需要计算APP区内的校验信息并写入。然后重启BOOT区,这时校验信息正确,进入APP区。

5、BOOT区跳转到APP区流程
1、关闭一些可能会干扰到跳转的功能
STM32可以用这个来实现

EXTI_DeInit();
SYSCFG_DeInit();
RCC_DeInit();

2、检查栈顶地址是否合法.
APP_ROM_ADDR 为APP区的起始位置,比如0x08002000

if (((*(uint32_t*)APP_ROM_ADDR) & 0x2FFE0000 ) == 0x20000000)

计算如果不为0x20000000,那就不进行跳转

3、初始化用户程序的堆栈指针

__set_MSP(*(__IO uint32_t*) APP_ROM_BASE_ADDR);

4、执行跳转
首先要获取跳转地址。
APP区的地址存在 APP_ROM_ADDR+4 (例如0x08002004)的位置,且有4个字节,
我们可以这样获取跳转地址以及执行跳转。

typedef void (*pFunction)(void);//定义了一个新类型,该类型是一个函数指针,
pFunction Jump_To_Application;  //定义程序地址指针
JumpAddress = *(__IO uint32_t*) (APP_ROM_ADDR + 4); 
Jump_To_Application = (pFunction)JumpAddress;
Jump_To_Application();

6、写APP程序所需注意的几个地方

程序并不是进入APP区就可以直接运行了,APP程序需要做一些处理才可以运行。

1、要划分好APP区的存放地址

比如我们设定BOOT区程序大小为0x2000,那么APP区程序就要从0X2000

单片机如何修改bios_BOOT_02


2、需要重映射中断向量

__IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));
void iRemapIrqVector(void)
{
    uint8_t i = 0;
    for(i = 0; i < 48; i++)
        VectorTable[i] = *(__IO uint32_t*)(APP_ROM_ADDR + (i<<2)); //中断向量是一个指针,每个占4个字节
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //这个一定要有
    SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM); //设置为RAM启动模式
}

要分配RAM

单片机如何修改bios_单片机如何修改bios_03