"Swap模式高效回滚代码,保障项目稳定性,轻松应对变更"

2024-06-19

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

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

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

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

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,其他保持不变。

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

Application Project中添加MCUboot Image Utilities

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

Application Project中添加MCUboot Image Utilities

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

对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

Application Project中添加MCUboot Image Utilities

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

Application Project中添加MCUboot Image Utilities

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

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

在Developer Assistance中找到目标函数

更新后的代码如下所示。

Application Project调用boot_set_confirmed()函数

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

对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。

Application Project Debug Configuration Startup选项卡配置

点击Load Ancillary按钮

,将Application Project Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Primary Slot起始地址0x18000。

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

点击Load Ancillary按钮

,将ra4m2_app_v2 Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Secondary Slot起始地址0x48000。

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

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

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

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

首次升级完成后,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代码内容即可。

复位完成后,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做如下修改。

Application Project Debug Configuration Startup选项卡配置

点击Load Ancillary按钮

,将Application Project Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Primary Slot起始地址0x18000。

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

点击Load Ancillary按钮

,将ra4m2_app_v2_confirmed Debug文件夹下的***.bin.signed下载到芯片上,注意选择地址为Secondary Slot起始地址0x48000。

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

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

初始状态下, 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。

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

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

需要技术支持?

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

文章推荐

相关推荐