函数解析:
2、
boot_ota_process(){
send_to_main_mcu(OTA_START_ACK);
flash_eara_obj(eFlashApp);
while(1){
ota_deal_sub();//处理自身逻辑
ota_deal_main(); //处理主mcu发过来要做的逻辑
}
}
这是ota部分的主要函数
包括几个环节:
①首先要定义一些信号的宏定义:
#define SUBMCU_OTA_START_ACK 0x11 //收到主mcu升级请求,回复ack
#define SUBMCU_OTA_PROCESS_ACK 0x22 //收到主mcu升级包,回复ack
#define SUBMCU_OTA_VERIFY_ACK 0x33 //收到主mcu升级包验证请求,回复ack
#define SUBMCU_OTA_FAIL 0X44 //OTA过程有任何导致ota失败的情况向主机发送
主mcu端发送过来的是相同的宏定义,知识宏定义名字会去掉ACK,也就是主MCU发送给子MCU,SUBMCU_OTA_STAR这条命令时,子MCU通过解析后得到,处理完成会给主MCU回复SUBMCU_OTA_START_ACK
②给主mcu会ACK,因为收到了主机升级准备得请求进入boot,选择进入boot成功回给主机ack告知主机准备好了,并且进行flash擦除工作
send_to_main_mcu(SUBMCU_OTA_START_ACK);
flash_eara_obj(eFlashApp);
③ota_deal_normal();
这个函数涉及主要是处理boot接收到主mcu发过来的包,解析后通过命令判断下一步需要做什么,并且给主mcu会ack的过程
打包的协议一般都是项目中定下来的,如果需要自定协议,建议可以参考成熟的协议,例如TCP/IP这类,一般来说会包含包头、地址、指令、包的大小,包数据,以及CRC校验
我们这里用的串口dma将包传到ringbuf中,这样从ringbuf里去读包
通过包头来识别一帧的包,也能防止粘包,
然后需要对地址,指令的有效性进行判断
然后根据包的大小可以找到crc校验,验证crc是否正确
验证通过此时就可以拿到包的数据,并且根据指令可以区分将解出来的包送给不同的处理函数
-------------------------------------------------------------------------------------------------------------------------
当发给主mcu ACK后,主MCU会开始给子MCU发送升级包,指令SUBMCU_OTA_PROCESS
此时子MCU开始解包,写到flash中
SUBMCU_OTA_PROCESS:
sub_mcu_write_flash_process(uint32_offset,uint32_t length,uint8_t*payload){
s_LastProcessTick=get_ms_tick();//记录本次收到包的时间,以便异常处理
//offet记录已经写了多少数据,这样才知道下次从哪个位置开始写
//length是本次要写的长度,payload是本次要写的数据的首地址
if(FLASH_COMPLETE==write_flash_data(ROM_APP_BASE+offset,length,payload)){
//写入成功要回ack
send_to_main_mcu(SUBMCU_OTA_PROCESS_ACK);
}
}
SUBMCU_OTA_VERIFY:
当主MCU将包发完后会通知子MCU,包发送完了,可以做整个代码的检查了,此时子mcu会对已经更新了的flash部分做crc计算,看看是不是与发过来的crc一致,看看是否能够通过
void whole_app_verify(){
if(true==app_crc_verify()){
send_to_main_mcu(SUBMCU_OTA_VERIFY_ACK);
//其实这里就可以重新启动程序了,但是立即重启可能会导致ACK还没发过去,所以最好在这里做个计时,过个一秒后在重启
g_StartWaitTick=get_ms_tick();
}else{
send_to_main_mcu(SUBMCU_OTA_FAIL);
}
}
④ota_deal_sub();
自身逻辑无非是升级好了重启或者是升级失败了,卡在里面了
那就是记录了两个tick
一个是上面说的升级成功后害怕重启导致ACK没发过去,可以在这里做个计时过个一两秒在启动
重启的函数:
void boot_restart(void){
__disable_irq();
stBootParam.BootFlag = BootFlagNormal;
flash_save_data(eBOOTFLAG);//这里需要把bootflag改成正常BootFlagNormal,存到flash中
NVIC_SystemReset();
}
另一种就是升级没成功,使用另一个tick,s_LastProcessTick,计时超时后发送 send_to_main_mcu(SUBMCU_OTA_FAIL)告知主机,等待下一次升级。
3、boot_normal_process();
正常启动的函数
void boot_normal_process()
{
__disable_irq();
jump2app = (void (*)())*(__IO uint32_t*) (ROM_APP_BASE + 4);
__set_MSP(*(__IO uint32_t*) ROM_APP_BASE);
jump2app();
}
①先关闭中断
②取出异常处理程序的地址(Reset_Handler),保存在向量表首地址的第二个元素
③设置MSP的初始值,保存在向量表首地址的第一个元素
④通过函数指针进行跳转