加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

通用MCU Bootloader-KBOOT的配置选项

2019/11/21
187
阅读需 12 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

KBOOT 是支持配置功能的,配置功能可分为两方面:一、芯片系统的启动配置;二、KBOOT 特性配置;痞子衡在前一篇文章里介绍了 KBOOT 形态(ROM/Bootloader/Flashloader),虽然 KBOOT 有三种形态,但实际上只有 2 种类型的芯片载体,即含 ROM 空间的芯片(比如 Kinetis K80)和不含 ROM 空间的芯片(比如 Kinetis KL25),KBOOT 配置在这两种载体上是有区别的,下面痞子衡为大家详解 KBOOT 配置:

一、启动配置:FTFx_FOPT, BOOT Pin, RCM_FM

芯片系统的启动配置主要决定的是芯片上电从哪里(ROM/Flash)开始启动,所以这个启动配置对于含 ROM 空间的芯片特别重要,而不适用于不含 ROM 空间的芯片。

1.1 启动方式选择 Flash Configuration Field - FOPT

熟悉 Kinetis 芯片的朋友肯定知道,Kinetis 芯片都是含内部 Flash 的,内部 Flash 起始地址一般是 0x00000000,Flash 操作是通过 FTFx 这个 IP 模块实现的,如果你对 FTFx 模块了解的话,这个 IP 模块内部其实有一些寄存器属性是 readonly 的,并且从手册里看这些 readonly 寄存器的初值是 undefined,截取 K80 芯片 FTFA 模块中这些 readonly 寄存器如下:

  

既然这些寄存器是 readonly 属性并且初值又是 undefined 的,那么其初值到底取决于什么?这里就涉及到 Kinetis 芯片中比较特别的 FCF 加载机制,FCF 即 Flash Configuration Field,其区域地址为 Flash 偏移 0x400 - 0x40f,一共 16 个 bytes,这 16bytes 内容组织如下:

  

任何一次热启动后,芯片系统会自动从 FCF 区域加载初值进 FTFx 相应寄存器中,我们主要关注的是跟启动配置相关的 FTFx_FOPT 寄存器(特别注意,当 FCF 中对应 FOPT 的值是无效值 0x00 时,在加载过程中芯片自动会给 FOPT 赋值 0xFF),下面是 FTFx_FOPT 寄存器的 bit 定义,其中 BOOTSRC_SEL 和 BOOTPIN_OPT 位是关键(注意这两个位在不含 ROM 空间的芯片上是 reserved 的)。

  

BOOTSRC_SEL 和 BOOTPIN_OPT 的值共同决定了芯片的启动位置(ROM/Flash):

BOOTPIN_OPT = 1: 启动位置完全由 BOOTSRC_SEL 决定。

BOOTPIN_OPT = 0: 启动位置由 BOOTSRC_SEL 和 BOOTCFG0 pin 共同决定。
  

因此当在 FCF 里指定 FOPT 为 0xFF 时,芯片上电永远从 ROM 启动;当在 FCF 里指定 FOPT 为 0x3F 时,芯片上电永远从 Flash 启动。

1.2 启动位置切换 BOOT Pin

在 1.1 节的最后痞子衡提到了 BOOTCFG0 pin,其实 BOOTCFG0 pin 对于含 ROM 空间芯片而言就是 BOOT Pin,这个 BOOT Pin 是芯片系统直接指定的,与 NMI pin 复用(在上电以及 ROM 执行过程中,NMI pin 原本中断功能是被屏蔽的)。
  

你一定会疑惑 BOOT pin 有什么用?让我们再回到 1.1 节的最后,0x3F 和 0xFF 是两种比较典型的 FOPT 启动配置值,但是这种配置值指定的是固定启动位置,除非你擦除 FCF 重新烧写,不然无法轻易改变启动位置。但是有的时候我们想在不擦除 FCF 情况下自由切换启动位置 ROM/Flash,这时候就得依靠 BOOT Pin,此时我们需要在 FCF 里指定 FOPT 为 0x3D,让我们结合下面的 TWR-K80F150M 原理图来说明:

  

在上述 TWR-K80F150M 原理图中,我们可以看到两个按键开关(SW2,SW1)分别连到了 K80 芯片的 NMI_b pin 和 RESET_b pin,当我们配置 FOPT 为 0x3D 时,即启动位置由 BOOTSRC_SEL(2'b00,即从 Flash 启动)和 BOOTCFG0(NMI)共同决定,如果在 RESET_b pin(SW1)按下复位过程中,BOOTCFG0 pin(SW2)一直被按下,那么芯片会从 ROM 启动(并且超时也不会跳转到 Application);而如果 BOOTCFG0 pin(SW2)没有被按下,那么芯片会从 Flash 启动。是不是瞬间觉得这样切换启动位置很方便!
  

其实 BOOT Pin 设计不仅仅只在含 ROM 空间的芯片上存在,在不含 ROM 空间的芯片上也支持,只不过在不含 ROM 空间的芯片上,BOOT Pin 是由 Bootloader 代码指定的(需要查看芯片手册 Bootloader 章节或源代码),我们知道当芯片不含 ROM 时,上电默认从 Flash 起始地址处启动,而 Flash 起始地址已被 Flash-Resident Bootloader 占据,所以上电永远执行 Flash-Resident Bootloader,此时 BOOT Pin 的意义主要是决定是否要超时跳转到 Application,如果 BOOT Pin 在 RESET_b pin 按下复位过程中一直被按下,那么芯片将会一直停留在 Bootloader 中;如果 BOOT Pin 没有被按下,那么芯片在执行 Bootloader 超时时间到了之后会跳转到 Application。

1.3 强制从 ROM 热启动 RCM_FM

我们知道芯片复位启动分为冷启动(POR Pin)和热启动(RESET_b Pin),冷启动是最为彻底的启动(所有寄存器初值全部重置),而热启动并不是彻底启动(有些寄存器初值不会重置),RCM 模块里有 1 个寄存器(RCM_FM)就只有冷启动才能被重置,而且这个寄存器与从 ROM 启动息息相关,不得不提。下面是 RCM_FM 和 RCM_MR 寄存器的 bit 定义:

  

上述两个寄存器只在含 ROM 空间的芯片上存在,其作用是为了保证 ROM 在执行期间即使不小心发生热启动,下一次还是会强制执行 ROM 程序,而不受 FOPT, BOOT Pin 状态变化影响。ROM 程序里操作 RCM_FM/MR 寄存器使能了这一强制 ROM 启动功能,具体代码如下:

// ROM statrup 过程中调用的函数
void SystemInit (void)
{
    // ...

    // Set Force ROM bits in RCM. We only set bit 2, so the RCM_MR register doesn't
    // falsely show that the ROM was booted via boot pin assertion.
    RCM->FM = RCM_FM_FORCEROM(2);

    // ...
}

// ROM 跳转到 Application 之前调用的函数
void shutdown_cleanup(bool isShutdown)
{
    // ...

    // Disable force ROM.
    RCM->FM = RCM_FM_FORCEROM(0);

    // Clear status register (bits are w1c).
    RCM->MR = RCM_MR_BOOTROM(3);

    // ...
}
  

因为 ROM 里有了上述代码,所以只要芯片上电执行过 ROM 程序,除非是 ROM 主动跳转到了 Application 或者发生了冷启动,否则任何与 ROM 有关的配置修改操作都不会影响到下一次启动 ROM 的执行,这种机制可以确保 Application 一定会被 ROM 下载进 Flash。

二、特性配置:BCA

除了启动配置外,KBOOT 还支持特性配置,我们知道 KBOOT 提供的特性功能非常多,比如支持的外设种类丰富、超时时间可设、Application 完整性校验、USB ID 可设、运行时钟可配、加密特性支持、QSPI 启动支持,这些特性可以通过 BCA 来配置,BCA 是 Bootloader Configuration Area 的简称,KBOOT 通过从 BCA 区域加载用户配置数据完成这些特性配置。BCA 配置结构体原型如下(以 K80 芯片为例):

//! @brief Format of bootloader configuration data on Flash.
typedef struct BootloaderConfigurationData
{
    uint32_t tag;                          //!< [00:03] Tag value used to validate the BCA data. Must be set to 'kcfg'.
    uint32_t crcStartAddress;              //!< [04:07]
    uint32_t crcByteCount;                 //!< [08:0b]
    uint32_t crcExpectedValue;             //!< [0c:0f]
    uint8_t enabledPeripherals;            //!< [10:10]
    uint8_t i2cSlaveAddress;               //!< [11:11]
    uint16_t peripheralDetectionTimeoutMs; //!< [12:13] Timeout in milliseconds for peripheral detection before jumping to application code
    uint16_t usbVid;                       //!< [14:15]
    uint16_t usbPid;                       //!< [16:17]
    uint32_t usbStringsPointer;            //!< [18:1b]
    uint8_t clockFlags;                    //!< [1c:1c] High Speed and other clock options
    uint8_t clockDivider;                  //!< [1d:1d] One's complement of clock divider, zero divider is divide by 1
    uint8_t bootFlags;                     //!< [1e:1e] One's complemnt of direct boot flag, 0xFE represents direct boot
    uint8_t pad0;                          //!< [1f:1f] One's complemnt of direct boot flag, 0xFE represents direct boot
    uint32_t mmcauConfigPointer;           //!< [20:23] Holds a pointer value to the MMCAU configuration
    uint32_t keyBlobPointer;               //!< [24:27] Holds a pointer value to the key blob array used to configure OTFAD
    uint8_t reserved[8];                   //!< [28:2f] Reserved.
    uint32_t qspi_config_block_pointer;    //!< [30:33] QSPI config block pointer.
} bootloader_configuration_data_t;
  

如果你想配置 KBOOT 的特性,必须按上述结构体格式准备好配置数据,具体数据值所代表含义请查看芯片手册 Bootloader 章节,痞子衡在后续文章里也会慢慢讲到。此处假设你已经准备好了 BCA 数据,那么这个 BCA 数据应该放在哪里呢?其实 KBOOT 已经指定好了 BCA 位置,见如下代码,BCA 起始地址固定在 APP_VECTOR_TABLE 地址偏移 0x3c0 处,对于 ROM Bootloader 而言,BCA 地址就是 0x3c0,因为 APP_VECTOR_TABLE=0;而对于 Flash-Resident Bootloader 而言,BCA 地址是 Bootloader 指定的 Application 起始地址偏移 0x3c0 处。

//! @brief Flash constants.
enum _flash_constants
{
    //! @brief The bootloader configuration data location .
    //!
    //! A User Application should populate a BootloaderConfigurationData
    //! struct at 0x3c0 from the beginning of the application image which must
    //! be the User Application vector table for the flash-resident bootloader
    //! collaboration.
    kBootloaderConfigAreaAddress = (uint32_t)(APP_VECTOR_TABLE) + 0x3c0
};
  

最后再解释一下 BCA 地址为何是 APP_VECTOR_TABLE + 0x3c0,我们知道 ARM Cortex-M 系统规定 Application 前 1KB(0x0 - 0x3FF)应放中断向量表,Cortex-M 最大支持 256 个中断,其中前 16 个是系统中断,后 240 个是外设中断,而 Cortex-M 厂商生产的芯片一般用不满 240 个外设中断,所以其实中断向量表后半部分其实是 reserved 的,因此我们可以把 reserved 区域里的 0x3C0 - 0x3FF 这 64bytes 用作 BCA 配置。

相关推荐

电子产业图谱

硕士毕业于苏州大学电子信息学院,目前就职于恩智浦(NXP)半导体MCU系统部门,担任嵌入式系统应用工程师。痞子衡会定期分享嵌入式相关文章