MCU远程升级方案,可解决升级错误死机问题

项目场景:

很多有关MCU的项目应用,都需要具备远程升级程序的功能。功能实现起来容易,但是会遇到例如程序文件传输失败,bin文件原本就有BUG,中途掉电等原因导致产品死机。这时就只能由维护人员到现场重新烧程序解决,增加一大笔的维护费用。


方案概述:

由于MCU本身的资源限制,要么跑裸核,要么就是跑FreeRTOS一类的微内核操作系统,无法像linux一样能做到内核态和用户态分离。一旦运行的程序有问题就死机,死得很彻底,无法恢复,以下介绍一种程序设计方法来解决这个问题。


硬件支持:

1.外部看门狗

作用程序死机时复位。

2.外部Flash

常见的MCU程序执行方式有两种:一种是具有片内Flash的直接执行(STM32),另一种是程序存储在片外Flash用XIP的模式执行代码(NXP的i.mxRT系列)。在正常运行时,均无法直接擦出程序空间,所以这里单独加一片Flash,用于存储需要更新的程序文件和备份文件


软件方案:

1.外部Flash驱动及分区

(1)常用的Flash都是SPI接口,根据手册实现其驱动,用于存储APP文件。

(2)根据具体的APP文件大小划定三个分区,分别是:程序区、备份程序区、程序更新信息区。

注:备份程序是产品出厂时需要写入的一个包含主要功能的有效程序。

2.APP文件传输方式

根据具体产品应用,有线可用485、SPI、CAN网传输;无线可通过蓝牙、WIFI传输之后,存储到外部Flash。至于传输协议,可自行设计,或采用例如xyzmodem等标准协议。

3.程序更新信息结构

这个结构很重要,用于区分在程序升级时发生各种异常情况之后进行程序引导,结构如下:

typedef struct TProgramFile
{
    uint32_t magic;              //魔术数            0x9f5abeef
    uint32_t appLen;
    uint32_t backupsLen;
    uint32_t appCrc;
    uint32_t backupsCrc;
    uint8_t updateFlag;        //1--新的APP程序写入外部flash,0--写入失败
    uint8_t startFlag;            //1--成功启动,0--启动失败
}TProgramFile;

4.BootLoader

裸核编程,实现最基本的外设,主要用于引导程序启动。

引导程序:将已经存储在外部Flash中的程序读取出来写入程序Flash区。程序空间如下:

软件流程:

updateFlag与startFlag的更新机制是实现该方案的重点,流程如下:

 当更新的程序有bug,或者引导时遇到中途掉电的情况,均会导致跳转失败。此时,updateFlag == 0 && startFlag == 0,重新引导备份程序。成功跳转APP启动之后,置位startFlag = 1。之后再次上电就可以直接跳转APP,不再执行引导。


BootLoader主要代码:

 TProgramFile fileHead;
 uint32_t readFlashAddr = 0,crc = 0,i = 0;
 uint32_t programSize = 0,programCrc = 0,offset = 0,writeCnt = 0;
    
//硬件初始化

.....


    spiDevice_read(g_flashFlagtAddr,(uint8_t*)&fileHead,sizeof(TProgramFile));

    if(fileHead.magic != BOOT_MAGIC)
    {
        JumpApplication();
    }

    if(fileHead.updateFlag == 0 && fileHead.startFlag == 1)
    {
        JumpApplication();
    }
    if(fileHead.updateFlag == 0 && fileHead.startFlag == 0)
    {
        readFlashAddr = g_flashBackAppAddr;
        programSize = fileHead.backupsLen;
        programCrc = fileHead.backupsCrc;
    }
    if(fileHead.updateFlag == 1 && fileHead.startFlag == 0)
    {
        readFlashAddr = g_flashAppAddr;
        programSize = fileHead.appLen;
        programCrc = fileHead.appCrc;
    }

//擦除程序空间
    if(EraseSectionAPP(FLASH_APP_OFFSET) != status_success)
    {
        printf("EraseSectionAPP error !\n");
        return 0;
    }

    while(programSize)
    {
        writeCnt = (programSize > 1024) ? 1024 : programSize;
        spiDevice_read(readFlashAddr + offset,fileBuf,writeCnt);


        //写入程序空间

        ...............
        crc += SumCheck(fileBuf,writeCnt);
        programSize -= writeCnt;
        offset += writeCnt;
    }
    
    if(crc != programCrc)
    {
        return 0;
    }

    fileHead.updateFlag = 0;
    spi_flash_sector_erase(g_flashFlagtAddr);
    spiDevice_write(g_flashFlagtAddr,(uint8_t *)&fileHead,sizeof(TProgramFile));

    JumpApplication();

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值