S32K11x 的 Bootloader 实现方法介绍 (基于 A/B 分区交换)

一、 概述

本文将基于 S32K11x 平台介绍基于 A/B 分区交换的 Bootloader 实现方法,Bootloader 程序作为引导加载程序,其最根本的目的是为了正确引导加载用户代码,即将用户代码加载到指定的位置然后跳转到该位置运行,当然,也有可能用户代码已经事先加载完成,Bootloader只需要完成跳转即可,一旦跳转到用户代码那么 Bootloader 程序的使命也就完成了。利用Bootloader,我们可以实现固件升级的功能。本文介绍的 Bootloader 基于 A/B 分区交换,即用户代码分区总共有两个分区(分区A 和分区 B),用户代码可以运行在 A 分区或者 B 分区,Bootloader 运行后会先判断新固件要加载到哪个分区,然后等待接收新固件,加载好新固件后会跳转到新固件所在的分区去执行。由于用户代码可能在 A 分区或者 B 分区执行,因此用户的代码需要使用位置无关代码,关于位置无关代码的生成在此就不细说。A/B 分区交换的运作流程大致如下图:


                                                       图 1.1 A/B 分区交换运作流程示意图



二、 Bootloader 分区

实现 Bootloader 之前我们需要规划代码的分区,即规定每个分区的位置和大小,以及分区所存放的内容,本文所讲解的 Bootloader 例程是基于 S32K116 这颗芯片,我们先了解下这颗芯片的 Flash 规格。

                                              

                                                           图 2.1 S32K1xx Flash 规格

        本文基于 S32K116 的 A/B 分区交换的 Bootloader 分区如下:

                                                     图 2.2 S32K116 的Bootloader分区

从上图可以看到 Bootloader 代码被分配到 DFlash 内存块,Bootloader 的中断向量表位于 0x0 起始地址,A 分区起始地址为 0x800,依次存放固件信息、中断向量表、应用代码,B 分区起始地址为 0x10800。

我们可以通过修改链接文件来配置代码的链接地址,链接文件存放路径为:工程所在路径/Project_Settings/Linker_Files

                                                                  图 2.3 修改链接文件

如上图所示,我们将 m_text 段的地址修改为 0x10000000,我们的 Bootloader 代码便放在该段上。



三、 程序流程

Bootloader 代码的主要流程如下图所示:

                                                          图 3.1 Bootloader 代码流程

 

  • 初始化时钟、CAN、串口、Flash 等驱动
  • 查看 A 区和 B 区 固件信息(查看固件是否有效,两个区固件都无效指定 A 区为 new 区 ;只有其中一个区固件无效直接指定此区为 new 区 ;都有效则继续查看版本号) ,从而知道当前哪一个是正在运行的应用程序(称为 old 区,即版本号大的区),哪一个是如果要更新时可擦除存放的区域(称为 new 区,即版本号小的区),然后分别获取 old 区和 new 区基地址 ,顺便获取 old 区的版本号
  • 进入一个大循环 ,查看 old 区的版本号是否有效(若为0xffffffff 则无效,反之则有效),是则表明两个区固件都无效 ,一直处于等待接收代码的状态 ,此时不设置超时 ,因为无固件跳转过去是一种错误 。如果 old 区的版本号是有效的 ,则等待接收新固件,此时需要设置超时,如果在超时之前正确接收到新固件,则跳转到 New 区执行,否则跳转到 Old 区执行。



四、 数据接收

关于 BootLoader 的数据接收部分,本文将以 CAN 作为传输方式进行介绍,实际上用户可以根据自身需求采取其他的通信方式。

如下表为 CAN 消息帧的定义

帧传输

CAN ID

载荷大小(字节)

载荷

方向

作用

起始

0x200

4

0x15151515

主机->Bootloader

说明外部要更新固件

地址

0x100

4

固件信息或固件相对地址

主机->Bootloader

接下来的数据存放的相对基地址的偏移地址

地址

0x100

4

0x53535353

主机->Bootloader

相应的数据已经传输

数据

0x300

32

固件信息或固件的内容

主机->Bootloader

固件信息或固件内容,应存放到PFlash

应答

0x400

4

0x04040404

Bootloader->主机

Bootloader已经接收处理完毕,课继续传输

应答

0x400

4

0x55555555

Bootloader->主机

Bootloader 接收错误 ,停止传输


                                                                表 4.1 CAN 消息帧定义

消息的通信流程如下图所示:

                                                  图 4.2 消息传输流程

大致的消息传输流程为:

  • 主机端发起消息传输请求
  • 主机端发送固件头的地址信息和数据
  • 主机端发送固件的逻辑地址和数据


五、 程序跳转

当 Bootloader 正确加载好应用代码后便会跳转到对应的分区去执行应用代码,下面来说下跳转代码,跳转代码的源码如下所示:

void JumpToApplication(uint32_t start_address)

{

    uint32_t __attribute__((unused)) pc;

    uint32_t __attribute__((unused)) sp;

 

    S32_SCB->VTOR=(uint32_t)(start_address);  // 更新中断向量基地址

    sp = *((volatile uint32_t*)start_address); // 获取栈顶

    __asm (" msr msp, r3");

    pc = *((volatile uint32_t *)(start_address + 4)); // 直接跳转到复位函数

    __asm("mov pc, r3");

}  

该跳转函数的输入参数为跳转的绝对地址,例如要跳转到 A 分区,则该地址便设置为0x1000,该地址必须为向量表的起始地址。跳转函数主要执行三个命令:

  • 设置向量表的偏移
  • 设置 SP 堆栈指针的值
  • 设置 PC 指针的值

 

向量表的偏移值即是要跳转的绝对地址,而 SP 堆栈指针的值则存放在向量表的第一个向量,PC 指针的值则指向复位向量的地址,即向量表中的第二个向量。只要这三个步骤正确执行,那么便可以跳转指定地址去执行代码了。

六、 参考资料

  1. NXP ,《AN12323SW》, https://www.nxp.com/docs/en/application-note/AN12323.pdf
  2. NXP ,《S32K1XXRM》,https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/s32k-automotive-mcus/s32k1-microcontrollers-for-general-purpose:S32K1?tab=Documentation_Tab

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论