分享

MCU软件重启升级实现

 logicsoft 2023-08-16 发布于浙江

摘要

在消费电子产品领域,开机方案通常是由用户手动按键上电,而后芯片初始化,将自身供电极拉高,完成启动。那么由此带来的一个问题就是:当硬件复位或系统复位时,同时也会复位供电极,因此芯片也会断电,无法实现再上电重启。

基于该一情况,本文提出了两种解决方案,分别为内核复位和主动跳转至bootloader复位,这两种方案不会影响外围电路,即供电极不会被复位,使得系统可以完成自动升级重启。

此外,本文同样适用的产品方案设计对象:允许复位,但对外设又有特殊要求:某一个IO状态不能因为复位而改变,某一个定时器计数值不能改变等。

目录

一、绪论

二、MCU启动流程回顾

三、MCU复位方法概述

四、MCU重启方案实现

五、实验结果与分析

六、调试问题回顾及总结

七、参考文献

一、绪论

(1)概述

在消费电子产品的OTA升级过程中,产品是不插电工作的,当产品跟蓝牙完成升级文件包交互后,此时可以选择两种方式完成升级:

(2)方案优缺点比较

二、MCU启动流程回顾

芯片初始上电时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存,从flash启动方式确定,arm内核将0x0800 0000地址映射到0x0000 0000中,代码区从0x0000 0000开始执行。

(1)裸机启动流程

  1. 初始化栈顶指针——从0x0800 0000读取栈顶地址,并将该地址存入MSP中;

  1. 跳转至复位中断(Reset_Handler(void))——从0x0800 0004读取中断向量表的首地址(即复位中断入口地址),跳转执行

  1. 系统时钟设置(在复位中断程序内被调用)

  1. 跳转至标准库_main()程序

  1. 数据段加载:把RW段(初始化为非0值的全局变量)从Flash搬运到SRAM中

  1. 开辟堆栈:依照启动文件所设置的堆栈大小初始化堆栈区域;

  1. ARMCC $Sub$$main\GNUC entry(void)——操作系统在此处开始执行初始化启动

  1. 进入C文件中的main函数

(2)带操作系统启动流程

操作系统初始化所做工作如下图所示,仅作参考

三、MCU复位方法概述

  1. 系统复位

整个芯片的所有电路都会被复位,包括ARM内核、芯片外设等

  1. 内核复位

只复位内核——(CPU寄存器、特殊功能寄存器、NVIC、Systick、Debug、内存接口等),不影响外设电路变化

  1. 主动跳转复位

在app段设置MSP为bootloader段的栈顶指针,然后跳转至0x0800 0004所指向的复位中断程序入口,执行流程参考裸机启动流程。

在该复位模式下,CPU寄存器、NVIC向量中断等变量 由用户根据实际需要自行设置。

四、MCU重启方案实现

裸机环境或操作系统环境下的重启方案,并无不同。

  • 裸机一般工作在线程模式下,全程使用主堆栈指针MSP

  • 操作系统在中断时使用MSP,线程状态下使用PSP

(1)当内核复位时,除了外设电路外的内核参数均被复位,此时操作系统与裸机环境一致;

(2)当跳转复位时,操作系统一般处于线程模式,使用PSP;裸机使用MSP

此前由用户手动禁用中断,当主动跳入到0x0800 0004指向的复位中断时,cortex-m内核自动使用MSP,此时操作系统与裸机环境一致。

以下代码方案,仅作参考

(1)内核复位

// 适用M3、M4内核
__asm void RESET_ASM(void)
{LDR R0, =0xE000ED0CLDR R1, =0x05FA0001     STR R1, [R0]
}// 调用该函数实现内核复位
void kernel_reset(void)
{// 设置或延长看门狗时间RESET_ASM();while(1);
}

(2)跳转复位

__asm void MSR_MSP(u32 addr)
{MSR MSP, r0             //set Main Stack valueBX r14
}void app_jump2_bootloader(void)
{//设置或延长看门狗u32 bootxaddr = 0x08000000;if(((*(vu32*)bootxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法{__disable_irq();        //关闭中断SysTick->CTRL = 0;SysTick->LOAD = 0;SysTick->VAL = 0;       //重置Systickfor (int i = 0; i < 8; i++)    //重置中断控制器{NVIC->ICER[i] = 0xFFFFFFFF;NVIC->ICPR[i] = 0xFFFFFFFF;}RCC_DeInit();                    //复位时钟SCB->VTOR  = (0x08000000);       //设置中断向量偏移//__set_CONTROL(0);//__set_PSP(*(volatile unsigned int*) bootxaddr);//代码区第二个字为程序开始地址(复位中断地址)jump2bootloader=(otafun)*(vu32*)(bootxaddr+4); //设置主堆栈MSP为boot栈顶地址MSR_MSP(*(vu32*)bootxaddr); jump2bootloader();                        //跳转到bootloader.}
}

五、实验结果与分析

(1)实验方法:

  • 使用直流电源代替锂电池

  • 实验设备:NeckD5

  • 在SecureCRT串口调试环境下使用VBScript脚本进行自动升级,循环执行以下操作

  • 系统上电工作——bootloader->app->读取flag为真->开始工作

  • random(20, 300)随机工作20-300s后发送重启命令(内核复位、跳转复位、随机内核/跳转复位),并写重启flag

  • 复位次数+1,打印至桌面

  • 系统重启

(2)实验结果

复位方法

工作环境

软件环境

复位次数/次

持续时间

最终结果

内核复位

DC供电

操作系统

1000

24h

pass

跳转复位

DC供电

操作系统

1000

pass

内核复位、跳转复位

DC供电

操作系统

1000

pass

结论:多次重复执行复位重启,系统并无卡顿、死机等不良现象发生,证明该代码方案切实可行。

六、调试问题回顾及总结

(1)对bootloader工程以及app工程的环境配置有何要求?

boot以及app的开发环境尽可能保持一致,包括using microlib、Optimization等框选项的选择应同步设置,否则有可能导致无法正常升级跳转。

以下为是否勾选using microlib执行的mcu堆栈开辟方式,设计者须充分考虑代码方案差异可能带来的后果,并进行可行性验证

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************IF      :DEF:__MICROLIBEXPORT  __initial_spEXPORT  __heap_baseEXPORT  __heap_limitELSEIMPORT  __use_two_region_memoryEXPORT  __user_initial_stackheap

(2)为什么跳转后会触发HardFault异常?

有如下原因:跳转前未关中断;中断控制器标志数据未清零;中断向量偏移值未更改为目标工程的偏移。

(3)

七、参考文献

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多