摘要
在消费电子产品领域,开机方案通常是由用户手动按键上电,而后芯片初始化,将自身供电极拉高,完成启动。那么由此带来的一个问题就是:当硬件复位或系统复位时,同时也会复位供电极,因此芯片也会断电,无法实现再上电重启。
基于该一情况,本文提出了两种解决方案,分别为内核复位和主动跳转至bootloader复位,这两种方案不会影响外围电路,即供电极不会被复位,使得系统可以完成自动升级重启。
此外,本文同样适用的产品方案设计对象:允许复位,但对外设又有特殊要求:某一个IO状态不能因为复位而改变,某一个定时器计数值不能改变等。
一、绪论
二、MCU启动流程回顾
三、MCU复位方法概述
四、MCU重启方案实现
五、实验结果与分析
六、调试问题回顾及总结
七、参考文献
(1)概述
在消费电子产品的OTA升级过程中,产品是不插电工作的,当产品跟蓝牙完成升级文件包交互后,此时可以选择两种方式完成升级:
(2)方案优缺点比较
芯片初始上电时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存,从flash启动方式确定,arm内核将0x0800 0000地址映射到0x0000 0000中,代码区从0x0000 0000开始执行。
(1)裸机启动流程
初始化栈顶指针——从0x0800 0000读取栈顶地址,并将该地址存入MSP中;
跳转至复位中断(Reset_Handler(void))——从0x0800 0004读取中断向量表的首地址(即复位中断入口地址),跳转执行
系统时钟设置(在复位中断程序内被调用)
跳转至标准库_main()程序
数据段加载:把RW段(初始化为非0值的全局变量)从Flash搬运到SRAM中
开辟堆栈:依照启动文件所设置的堆栈大小初始化堆栈区域;
ARMCC $Sub$$main\GNUC entry(void)——操作系统在此处开始执行初始化启动
进入C文件中的main函数
(2)带操作系统启动流程
操作系统初始化所做工作如下图所示,仅作参考
系统复位
整个芯片的所有电路都会被复位,包括ARM内核、芯片外设等
内核复位
只复位内核——(CPU寄存器、特殊功能寄存器、NVIC、Systick、Debug、内存接口等),不影响外设电路变化
主动跳转复位
在app段设置MSP为bootloader段的栈顶指针,然后跳转至0x0800 0004所指向的复位中断程序入口,执行流程参考裸机启动流程。
在该复位模式下,CPU寄存器、NVIC向量中断等变量 由用户根据实际需要自行设置。
裸机环境或操作系统环境下的重启方案,并无不同。
裸机一般工作在线程模式下,全程使用主堆栈指针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)
联系客服