0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

利用Swap模式实现代码回滚操作

瑞萨MCU小百科 来源:瑞萨MCU小百科 作者:瑞萨MCU小百科 2024-06-19 15:45 次阅读

前面介绍了MCUboot的基础知识,您可通过上方链接回顾历史文章,上次介绍了Swap模式,本次着重介绍利用Swap模式实现代码回滚操作。在某些应用场景中,可能新版本的Firmware存在bug而需要返回至上一次的固件。

可以利用本文描述的这种方式实现以上目标。烧写在Secondary Slot中的Image有一次运行的机会,即上电后在Bootloader控制下完成一次Swap操作,Secondary Slot中的高版本代码被交换到Primary Slot中执行,在执行的过程中,根据某个函数的返回结果,在Trailer中对目标地址进行置位。

本文以RA4M2 512K Code Flash产品为例,使用Flat mode(不启用TrustZone)说明Swap模式进行升级时的注意事项。

首先回顾一下Swap模式升级的流程。

a5e3cf74-2d28-11ef-a4c8-92fbcf53809c.png

MCUboot Swap模式图解

从代码框架来看,整体划分为三部分,Bootloader,Primary Slot(保存了低版本的User Application v1.0)和Secondary Slot(保存了待更新的高版本User Application v2.0)。

初始状态下,芯片中烧录了Bootloader和Primary Slot,代码从Bootloader处启动,跳转至Primary Slot中的User Application v1.0。在User Application v1.0运行过程中,接收来自外部的更高版本Firmware v2.0,并烧写到Secondary Slot中,烧写完成后,执行软件复位Software reset,代码重新从Bootloader开始运行。此时Bootloader判断Secondary Slot中有待更新的Image,检查其完整性等,校验通过后,将Secondary Slot中的内容和Primary Slot中的内容交换(利用Scratch area作为暂存区域)。然后跳转到Primary Slot中执行。比较升级操作的初始状态和终止状态,发现Primary Slot中运行的代码从低版本的v1.0变为高版本的v2.0。

假如以当前升级操作的最后一个阶段为新的起点,下次软件复位后(以及之后的每次软件复位),Bootloader会根据Trailer中的内容判断,不需要重新执行swap操作了。

本次我们更改Bootloader的设定,如下所示,将两种Image分别烧写进Secondary Slot中,检查升级的结果。

烧写到Secondary Slot中的代码版本均为v1.1.0,但是代码有区别。

第一种代码闪烁两个LED(蓝色和红色),代码中会调用boot_set_confirmed()函数

第二种代码闪烁一个LED(蓝色),代码中并不调用boot_set_confirmed()函数

基于同样的Bootloader和Primary Slot Application v1.0.0代码,在Secondary Slot中烧写两种代码,检查升级后的状态。

1修改Bootloader MCUboot选项

基于上次Swap模式的基础工程,修改其中的关键配置Signing and Encryption Options → Custom,从--confirm更新为--pad,其他保持不变。

a612bc62-2d28-11ef-a4c8-92fbcf53809c.png

FSP中MCUboot Signing and Encryption Options属性--pad

2创建第一种Application Project

创建一个Blinky Project,命名为ra4m2_app_v1,采用默认的Blinky模板,使得EK-RA4M2上的三个LED闪烁。

依次添加Build Variables → BootloaderDataFile,Environment Variable中设定MCUBOOT_IMAGE_SIGN_KEY和MCUBOOT_IMAGE_VERSION (设定为v1.0.0)。

导入ra4m2_app_v1且重命名为ra4m2_app_v2,从默认的闪烁三个LED改为两个LED。

依次添加Build Variables → BootloaderDataFile,Environment Variable中设定MCUBOOT_IMAGE_SIGN_KEY和MCUBOOT_IMAGE_VERSION (设定为v1.1.0)。

在FSP → Stack中添加Bootloader → MCUboot Image Utilities

a64f8048-2d28-11ef-a4c8-92fbcf53809c.png

Application Project中添加MCUboot Image Utilities

根据错误提示,添加Flash driver,之后修改General属性,如下图所示,指向Bootloader所在路径。

a6783862-2d28-11ef-a4c8-92fbcf53809c.png

Application Project中添加MCUboot Image Utilities

Build Project,可以看到以“0 errors”提示编译完成。

a6a1adb4-2d28-11ef-a4c8-92fbcf53809c.png

对Application Project Build时输出的Log

3创建第二种Application Project

导入第二步创建的project,并重命名ra4m2_app_v2_confirmed,从闪烁两个LED改为一个LED。

依次添加Build Variables → BootloaderDataFile,Environment Variable中设定MCUBOOT_IMAGE_SIGN_KEY和MCUBOOT_IMAGE_VERSION (设定为v1.2.0)。

在FSP → Stack中添加Bootloader → MCUboot Image Utilities

a64f8048-2d28-11ef-a4c8-92fbcf53809c.png

Application Project中添加MCUboot Image Utilities

根据错误提示,添加Flash driver,之后修改General属性,如下图所示,指向Bootloader所在路径。

a6783862-2d28-11ef-a4c8-92fbcf53809c.png

Application Project中添加MCUboot Image Utilities

在hal_entry.c中增加调用函数boot_set_confirmed()函数。

将光标放在hal_entry()函数入口处,打开Developer Assistant,点选Confirm Primary Image,保持鼠标左键按下状态,拖拽至hal_entry()函数入口处

a707e6ce-2d28-11ef-a4c8-92fbcf53809c.png

在Developer Assistance中找到目标函数

更新后的代码如下所示。

a72bea88-2d28-11ef-a4c8-92fbcf53809c.png

Application Project调用boot_set_confirmed()函数

Build Project,可以看到以“0 errors”提示编译完成。由于添加了boot_set_confirmed()函数调用,因此text段在之前(5108)基础上有所增加。

a7573da0-2d28-11ef-a4c8-92fbcf53809c.png

对Application Project Confirmed Build时输出的Log

4调试App v1并在Secondary Slot中加载v1.1.0 Image(不调用boot_set_confirmed())

调试ra4m2_app_v1,如之前所示,在Debug Configuration做如下修改。除增加Bootloader对应的elf文件下载(Image and Symbols)之外,还需增加ra4m2_app_v2对应的Symbols only。

a7750efc-2d28-11ef-a4c8-92fbcf53809c.png

Application Project Debug Configuration Startup选项卡配置

点击Load Ancillary按钮a795d7fe-2d28-11ef-a4c8-92fbcf53809c.png,将Application Project Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Primary Slot起始地址0x18000。

a7aeb288-2d28-11ef-a4c8-92fbcf53809c.png

将1.0.0版本Image ***.bin.signed文件下载到Primary Slot的起始地址0x18000

点击Load Ancillary按钮a795d7fe-2d28-11ef-a4c8-92fbcf53809c.png,将ra4m2_app_v2 Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Secondary Slot起始地址0x48000。

a7d9d990-2d28-11ef-a4c8-92fbcf53809c.png

将1.1.0版本Image ***.bin.signed文件下载到Secondary Slot的起始地址0x48000

检查memory窗口的内容,会发现初始状态如下:

a80709f6-2d28-11ef-a4c8-92fbcf53809c.png

图 初始状态下, Primary Slot保存1.0.0,Secondary Slot保存1.1.0

点击resume,可以发现EK-RA4M2上从闪烁三个LED变为闪烁两个LED。

a825399e-2d28-11ef-a4c8-92fbcf53809c.png

首次升级完成后,Primary Slot保存1.1.0,Secondary Slot保存1.0.0

在调试界面继续按下reset,重新运行会发现EK-RA4M2又回到闪烁三个LED。如果从升级事件的起始状态和终止状态看,都是闪烁三个LED。但是Secondary Slot中的1.1.0代码得到一次运行的机会,出现过闪烁两个LED的表现,由于没有调用函数boot_set_confirmed(),因此没有对Trailer进行设定,导致下次Bootloader运行时,又执行了一次Swap,最终芯片运行的还是v1.0.0版本。

为确认这一点,在每次运行时,检查memory中两个slot代码内容即可。

a84a614c-2d28-11ef-a4c8-92fbcf53809c.png

复位完成后,Primary Slot保存1.0.0,Secondary Slot保存1.1.0

5调试App v1并在Secondary Slot中加载v1.2.0 Image(调用boot_set_confirmed())

调试ra4m2_app_v1,如之前所示,在Debug Configuration做如下修改。

a86d5170-2d28-11ef-a4c8-92fbcf53809c.png

Application Project Debug Configuration Startup选项卡配置

点击Load Ancillary按钮a795d7fe-2d28-11ef-a4c8-92fbcf53809c.png,将Application Project Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Primary Slot起始地址0x18000。

a7aeb288-2d28-11ef-a4c8-92fbcf53809c.png

将1.0.0版本Image ***.bin.signed文件下载到Primary Slot的起始地址0x18000

点击Load Ancillary按钮a795d7fe-2d28-11ef-a4c8-92fbcf53809c.png,将ra4m2_app_v2_confirmed Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Secondary Slot起始地址0x48000。

a7d9d990-2d28-11ef-a4c8-92fbcf53809c.png

将1.2.0版本Image ***.bin.signed文件下载到Secondary Slot的起始地址0x48000

下载完成后,检查memory窗口,内容如下:

a8fff6d8-2d28-11ef-a4c8-92fbcf53809c.png

初始状态下, Primary Slot保存1.0.0,Secondary Slot保存1.2.0

点击resume,可以发现EK-RA4M2上从闪烁三个LED变为闪烁一个LED。在调试界面继续按下reset,会发现EK-RA4M2依然保持闪烁一个LED。

为确认这一点,在memory窗口检查首次升级完成后,Primary Slot中保存了v1.2.0 Image,而Secondary Slot中保存了v1.0.0 Image。即使再经过升级操作,也不会重新swap。根本原因是,Secondary Slot中烧录的v1.2.0 Image在运行的时候编辑了Trailer中的相关Flag,使得Bootloader依据该Flag,判断无需进行Swap。

升级完成后,memory窗口内容如下,Primary Slot中保留v1.2.0而Secondary Slot中保留1.0.0。

a91c38e8-2d28-11ef-a4c8-92fbcf53809c.png

升级完成后, Primary Slot保存1.2.0,Secondary Slot保存1.0.0

示例代码中我们仅仅是在secondary slot调用了boot_set_confirmed()函数,实际应用中,可以给调用该函数附加一些条件,如执行某个运算后根据返回的结果决定是否调用函数,运算结果符合预期,则调用函数使得当前Image生效。

需要技术支持?

如您在使用瑞萨MCU/MPU产品中有任何问题,,进入瑞萨技术论坛寻找答案或获取在线技术支持。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    450

    文章

    48961

    浏览量

    413948
  • FlaSh
    +关注

    关注

    10

    文章

    1581

    浏览量

    147145
  • SWAP
    +关注

    关注

    0

    文章

    48

    浏览量

    12672
  • 代码
    +关注

    关注

    30

    文章

    4616

    浏览量

    67461

原文标题:MCUboot系列(4)RA Swap模式下代码回滚在FSP中的支持

文章出处:【微信号:瑞萨MCU小百科,微信公众号:瑞萨MCU小百科】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    在CCG5代码中怎么实现DR_SWAP

    请教个问题,在 CCG5代码中怎么实现DR_SWAP?我们配置了端口 0 作为源对外充电,但是我们希望 PORT0 做了 UFP。我们是这样写的代码:案例 APP_EVT_PD_合同谈
    发表于 02-26 06:27

    为什么CyInstaller时未显示正确的错误消息?

    在安装PSoC Creator、PSoC设计器或PSoC程序员时,可能会出现此问题。当CyInstaller而不显示任何错误消息时,按照以下步骤查找根本原因:1)首先,进入Windows中
    发表于 07-11 10:59

    请问有直接操作flash来实现代码的烧写吗?

    针对stm32:isp好像需要短接boot0或者boot1,而iap要有堆栈来暂存代码,所以有没有一种可以直接操作flash来实现代码的烧写的???大神come。。。求拍醒。。。
    发表于 08-26 04:37

    实现代码自动生成的步骤

    重复性的劳动,为什么不交给工具来做呢,这就产生了使用代码生成代码的想法。本文提到的实现文本内容批量替换是实现代码自动生成的一个步骤,实现了找
    发表于 08-17 09:14

    内核空间实现代码的相关资料分享

    嵌入式LINUX驱动学习之5.ioctl字符设备驱动编程(二)内核空间实现代码#include #include #include #include #include #include #include
    发表于 12-24 06:21

    OTA有哪些分类? OTA分区策略是什么?

    OTA有哪些分类?OTA分区策略是什么?
    发表于 02-10 07:26

    操作代码的原理是什么

    目录跑马灯+蜂鸣器的位操作实现代码部分Led.c部分Led.h部分Buzzer.c部分Buzzer.h部分位操作是什么?位操作代码的原理是什
    发表于 02-25 07:07

    S32 Design Studio for Power Architecture V2.1版的安装已

    S32 Design Studio for Power Architecture V2.1 版的安装已
    发表于 03-31 08:04

    什么是热交换磁盘模式(Hot swap Disk Modul

    什么是热交换磁盘模式(Hot swap Disk Module ) 热交换技术仅仅在RAID 1,3,5,10,30 和50 的配置情况下才可以工作。 热交换模式允许系统
    发表于 01-19 23:26 2353次阅读

    设计模式的原则及实现代码的复用

    for modification。 意思:软件模块应该对扩展开放,对修改关闭。 举例:在程序需要进行新增功能的时候,不能去修改原有的代码,而是新增代码实现一个热插拔的效果(热插拔:灵活的去除或添加功能,不影响到原有的
    发表于 09-26 15:12 0次下载

    Android Oreo 内置保护,禁止操作系统降级

    Google 最新释出的新版 Android Oreo 被发现加入名为“保护(Rollback Protection)”的新功能,包含了验证启动机制,它将禁止设备滚到旧版本的固件。如果尝试安装到旧版本的官方镜像将会导致设备
    发表于 04-24 14:27 802次阅读
    Android Oreo 内置<b class='flag-5'>回</b><b class='flag-5'>滚</b>保护,禁止<b class='flag-5'>操作</b>系统降级

    嵌入式linux没有swap分区,swap现象如何实现

    ,如何实现linux中支持的swap功能的呢?1,嵌入式linux随产品发布时,运行的逻辑往往是在设计之初就确定了。因而在选择内存大小时,避免了可用内存的不足的问题。因而不会出现swap现象和需求...
    发表于 11-02 11:21 12次下载
    嵌入式linux没有<b class='flag-5'>swap</b>分区,<b class='flag-5'>swap</b>现象如何<b class='flag-5'>实现</b>

    支付宝:多线程事务怎么

    可以发现子线程组执行时,有一个线程执行失败,其他线程也会抛出异常,但是主线程中执行的删除操作,没有,@Transactional注解没有生效。
    的头像 发表于 01-09 11:42 1700次阅读

    多线程事务怎么?一个简单示例演示多线程事务

    在spring中可以使用@Transactional注解去控制事务,使出现异常时会进行,在多线程中,这个注解则不会生效,如果主线程需要先执行一些修改数据库的操作,当子线程在进行处理出现异常时,主线程修改的数据则不会
    发表于 08-09 12:22 460次阅读
    多线程事务怎么<b class='flag-5'>回</b><b class='flag-5'>滚</b>?一个简单示例演示多线程事务

    MySQL数据库是如何应对故障恢复与数据恢复的问题呢?

    今天这篇文章,我想聊一聊MySQL数据库是如何应对故障恢复,与数据恢复的问题。一个最基本的数据库,应当可以做到以下几点
    的头像 发表于 11-27 10:04 708次阅读
    MySQL数据库是如何应对故障恢复与数据恢复<b class='flag-5'>回</b><b class='flag-5'>滚</b>的问题呢?