当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

NDK Bootloader 开发指南

1. 背景介绍

BootLoader 是一个系统引导程序,用于引导 App 软件初始化、支持 DFU/OTA 升级等。由于实际产品中 BootLoader 是不可以或者很难更新的,因此一个稳定且易用的 BootLoader 是对整个系统的一个基本保障。

  • NDK 通用 bootloader 例程代码位于:<PAN10XX-NDK>\01_SDK\nimble\samples\bootloader\ 目录下

  • NDK 中还有一些方案 App 有自己的 Bootloader 工程,其具体存放位置请参考相关方案文档介绍

2. Bootloader Config 配置

与 App 工程类似,Bootloader 工程中也提供了一个名为 sdk_config.h 的配置文件,但其配置项与 App 中的有所差异:

image

Bootloader Config File

2.1 Bootloader Config

Bootloader Config 是与当前 Bootloader 工程相关的配置,包括 Bootloader 支持功能的选择、Flash 分区配置等项目:

  1. Enable UART DFU:使能 Bootloader UART DFU 功能

    • 此功能基于 Xmodem 协议实现

  2. Enable USB DFU:使能 Bootloader USB DFU 功能

    • 通过子配置 USB DFU Mode 可以选择当前 USB DFU 升级模式,在不同模式下,USB DFU 上位机工具会执行不同的命令交互流程,具体解释如下:

      Select USB DFU mode, which would notify DFU Host (Panchip DFU Tool) to decide what to do when new image has been successfully upgrade to SoC flash (CRC ok).
      Mode 0:
      -> [Behavior] a. Jump to App (cmd 0x04 DFU End, param 0x00); b. DFU End
      -> [Note] For this mode, bootloader itself has responsibility to provide a way for entering USB DFU flow (such as key press event).
      Mode 1:
      -> [Behavior] a. Erase DFU flag on flash (cmd 0x06 DFU Force Upgrade, param 0x01); b. Stay in bootloader unless reset; c. DFU End
      -> [Note] App should set DFU flag to indicate bootloader to enter USB DFU proc.
      Mode 2:
      -> [Behavior] a. Erase DFU flag on flash (cmd 0x06 DFU Force Upgrade, param 0x01); b. Jump to App (cmd 0x04 DFU End, param 0x00); c. DFU End
      -> [Note] App should set DFU flag to indicate bootloader to enter USB DFU proc.
      Mode 3:
      -> [Behavior] a. Jump to App (cmd 0x04 DFU End, param 0x00); b. Wait for App USB enum OK; c. App Erase DFU flag on flash (cmd 0x06 DFU Force Upgrade, param 0x01); c. DFU End
      -> [Note] App should support USB HID, and support the DFU cmd 0x06 (DFU Force Upgrade) to set/erase DFU flag.
      
    • 默认的 Mode0 支持通过 EVB 按键 KEY2 进入 Bootloader USB DFU 流程

  3. Enable Private 2.4G OTA:使能 Bootloader 私有 2.4G OTA 功能

    • 此功能基于 Panchip 私有 2.4G OTA 升级协议实现

  4. Flash Partition Config:配置与 Bootloader 相关的 Flash 分区起始地址和大小(注意此处 Flash 分区配置需与 App 工程中的 sdk config 配置保持一致!

    • Chip Flash Size:指定当前芯片的 Flash 大小,需与实际使用的芯片 Flash 大小保持一致

      • 目前 PAN107x 芯片的 Flash 大小均为 512KB(其中尾部 4KB 为保留区域,存放芯片出厂校准信息,因此用户可用的实际空间为 508KB)

      • 目前 PAN101x 芯片的 Flash 大小均为 256KB(其中尾部 4KB 为保留区域,存放芯片出厂校准信息,因此用户可用的实际空间为 252KB)

    • Bootloader Flash Partition Size:设置 Bootloader Flash 分区大小(KB)

      • 将此项修改为非 0 值,表示为 Bootloader Image 预留的 Flash 空间大小

    • App Flash Partition Size:设置当前 App Flash 分区大小(KB)

      • 将此项修改为非 0 值,表示为 App Image 预留的 Flash 空间大小

    • App Backup Flash Partition Size:设置 App Backup Flash 分区大小(KB)

      • 根据当前项目需要,若需使用 App 备份区(如蓝牙 OTA 场景),则将此项修改为非 0 值

    • KVStore Flash Partition Size:设置 KVStore Flash 分区大小(KB)

      • 根据当前项目需要,若需使用 KVStore 分区,则将此项修改为非 0 值

    • User Custom Flash Partition Size:设置 User Custom Flash 分区大小(KB)

      • 根据当前项目需要,若需使用 User Custom 分区,则将此项修改为非 0 值

    • App Has Image Header:表示 App Image 具有 Image Header

      • 当前 SDK 框架下,若使用 Bootloader,则 App 必须同时使能 App Image Header,所以此选项必须勾上(且应与 App Config 中的对应选项保持一致)

2.2 SoC Platform

SoC Platform 是与芯片平台相关的配置,包括时钟、电源、平台相关的特殊 Feature 等项目。

Bootloader 中的此项菜单实际上是 App Config 中对应项菜单的子集,详情参考 NDK Configuration 指南

2.3 Log & Debug Config

Log & Debug Config 是与芯片 Log 功能和调试相关的配置。

Bootloader 中的此项菜单实际上与 App Config 中对应项菜单相同,详情参考 NDK Configuration 指南

3 BootLoader 升级流程和策略

BootLoader 启动的时候,会等待很多个信号,然后依次 trigger 信号的操作。

// signals:
bool sig_key1_push_down(void);
bool sig_key2_push_down(void);
bool sig_ota_start_received(void);
bool sig_back_up_is_completed_image(void);
void sig_hardware_recovery(void);
bool sig_usb_dfu_enter_check(void);

// slots:
void on_usb_dfu_enter(void);
void on_prf_ota_enter(void);
void on_uart_dfu_enter(void);
void on_image_load_enter(void);

连接信号和槽

typedef void (slot_handler_t)(void);
typedef void (signal_handler_t)(void);

void connect(uint8_t priority, signal_handler_t signal, slot_handler_t slot);

事件检测流程

    /* If backup image is valid, the on_image_load_enter function will be handled */
    ss_connect(0, sig_back_up_is_completed_image, on_image_load_enter);

#if BOOT_ENABLE_UART_DFU
    /* when detecting key1 down, the on_uart_dfu_enter function will be handled */
    ss_connect(1, sig_key1_push_down, on_uart_dfu_enter);
#endif

#if BOOT_ENABLE_USB_DFU
#if BOOT_USB_DFU_MODE == 0x00 // Use a GPIO Key to trigger entering USB DFU Mode
    /* If key2 is pressed down, the on_usb_dfu_enter function will be handled */
    ss_connect(2, sig_key2_push_down, on_usb_dfu_enter);
#endif // BOOT_USB_DFU_MODE == 0x00
    /* If the DFU flag on flash is detected, the on_usb_dfu_enter function will be handled */
    ss_connect(3, sig_usb_dfu_enter_check, on_usb_dfu_enter);
#endif // BOOT_ENABLE_USB_DFU

#if BOOT_ENABLE_PRF_OTA
    /* If a 2.4G ota start packet is received, the on_prf_ota_enter function will be handled */
    ss_connect(4, sig_ota_start_received, on_prf_ota_enter);
#endif

    /* Start to handle all of events related signal functions */
    ss_events_handle();

3.1 USB DFU 模式

void on_usb_dfu_enter(void);

进入 DFU 流程,插上 USB 后会将其枚举为 Panchip 自定义的 USB-HID 设备,并准备接收 Panchip USB DFU 上位机工具的交互指令。

3.2 UART DFU 模式

void on_uart_dfu_enter(void);

进入 DFU 流程后,会采用 xmodem 协议进行OTA升级。

3.3 PRF OTA 模式

void on_prf_ota_enter(void);

待升级设备复位进入 PRF OTA 状态,新 App 固件可通过 2.4G Dongle 发送给待升级设备。

3.4 Backup DFU 模式

尝试校验 Flash App Backup 分区中的固件, 以决定是否要将其搬移至 Flash App 分区。

4. UART DFU 升级详解

待升级的固件需要签名校验,默认 keil 编译的时候,在工程的同级 Images 目录下会自动生成带有 .signed 后缀的签名固件:

image

生成可用于 DFU/OTA 的签名 App 固件

4.1 检测并进入 UART DFU 升级模式

  1. 在 Bootloader Config 配置中使能 UART DFU 功能

  2. 编写 UART DFU 进入的 Signal 函数,并将信号和槽连接,槽属于升级流程 BootLoader 已经支持,用户不需要修改。用户可以修改 signal 函数。默认如下:

    #if BOOT_ENABLE_UART_DFU
        /* when detecting key1 down, the on_uart_dfu_enter function will be handled */
        ss_connect(1, sig_key1_push_down, on_uart_dfu_enter);
    #endif
    
    /* user can implement a custom signal fucntion */
    bool sig_key1_push_down(void)
    {
        GPIO_SetMode(P0, BIT6, GPIO_MODE_INPUT);
        GPIO_EnablePullupPath(P0, BIT6);
        SYS_delay_10nop(10000);
    
        for (uint16_t i = 0; i < 1000; i++) {
            if (P06 == 1) {
                return false;
            }
        }
        return true;
    }
    
  3. 下载 BootLoader 和 App 程序,App 程序配置为带 Bootloader 的方式

4.2 操作流程

  1. 准备好 Bootloader Image

  2. 准备好待升级的 App Image(例如 ble_periph_hr_ota.signed.bin

  3. 使用工具SecureCRT进行升级

  4. 打开工具SecureCRT连接设备串口,串口波特率 921600

  5. 按住 EVB 底板的 KEY1 按键不松开,然后再按一下 EVB 底板或核心板的 Reset 按钮复位芯片,查看工具 SecureCRT 上 log 打印,一直输出 CCCCCCCCCC:

    img

    PAN107x UART DFU进入升级模式

  6. 在工具 SecureCRT 的”传输”界面选择”发送Xmodem(N)”,选择待升级固件,位于 App 工程 Images 路径下: ble_periph_hr_ota.signed.bin,文件开始传输:

    img

    PAN107x UART DFU传输文件

  7. 再次复位芯片,观察串口 log,确认已经打印升级后的程序 log

5 USB DFU 升级详解

升级的固件需要签名校验,SDK 中 Keil 工程编译的时候,在工程的同级目录 Images 目录下会自动生成带有 .signed 后缀的签名固件:

image

生成可用于 DFU/OTA 的签名 App 固件

5.1 检测并进入 USB DFU 升级模式

  1. 在 Bootloader Config 配置中使能 USB DFU 功能

  2. 编写 USB DFU 进入的 signal 函数,并将信号和槽连接,槽属于升级流程 BootLoader 已经支持,用户不需要修改。用户可以修改 signal 函数。默认如下:

    #if BOOT_ENABLE_USB_DFU
    #if BOOT_USB_DFU_MODE == 0x00 // Use a GPIO Key to trigger entering USB DFU Mode
        /* If key2 is pressed down, the on_usb_dfu_enter function will be handled */
        ss_connect(2, sig_key2_push_down, on_usb_dfu_enter);
    #endif // BOOT_USB_DFU_MODE == 0x00
        /* If the DFU flag on flash is detected, the on_usb_dfu_enter function will be handled */
        ss_connect(3, sig_usb_dfu_enter_check, on_usb_dfu_enter);
    #endif // BOOT_ENABLE_USB_DFU
    
    /* user can implement a custom signal fucntion */
    bool sig_key2_push_down(void)
    {
        GPIO_SetMode(P1, BIT2, GPIO_MODE_INPUT);
        GPIO_EnablePullupPath(P1, BIT2);
        SYS_delay_10nop(10000);
    
        for (uint16_t i = 0; i < 1000; i++) {
            if (P12 == 1) {
                 return false;
            }
        }
    
       return true;
    }
    
    bool sig_usb_dfu_enter_check(void)
    {
        return is_dfu_flag_valid();
    }
    
    /* user can implement a custom dfu flag checking flow */
    bool is_dfu_flag_valid(void)
    {
    	const uint32_t flash_sector_start_addr = CONFIG_FLASH_PARTITION_USER_CUSTOM_ADDR + CONFIG_FLASH_PARTITION_USER_CUSTOM_SIZE - 0x1000; // last user custom sector
    	uint8_t dfu_flag;
    
    	dfu_flag = FMC_ReadByte(FLCTL, flash_sector_start_addr, CMD_DREAD);
    
    	if (dfu_flag == USB_DFU_ENTER_FLAG) {
    		return true;
    	} else {
    		return false;
    	}
    }
    
  3. 下载 BootLoader 和 App 程序,App 程序配置为带 Bootloader 的方式

5.2 操作流程

  1. 准备好 Bootloader Image

  2. 准备好待升级的 App Image(例如 ble_periph_hr_ota.signed.bin

  3. 将 EVB 底板的 USB 口连接到 PC

  4. 按住 EVB 底板的 KEY2 按键不松开,然后再按一下 EVB 底板或核心板的 Reset 按钮复位芯片,可从 Log 中观察到成功进入了 Bootloader USB DFU 流程:

    Try to load HW calibration data.. DONE.
    - Chip Info         : 0x61
    - Chip CP Version   : 255
    - Chip FT Version   : 7
    - Chip MAC Address  : E11000014DE5
    - Chip UID          : B90801465454455354
    - Chip Flash UID    : 4250315A3538380B01FD8B435603EF78
    - Chip Flash Size   : 512 KB (Inc. 4KB Panchip Info Area)
    
    Bootloader in..
    
    [I] Check valid image in App Backup Partition..
    [I] Entering USB DFU flow..
    [I] Found an App Image, version: 0.0.1.0
    [I] USB init done, INT_USBE: 0x1c
    [I] Wait for DFU Comm..
    [I] ---USB plug in---
    [I] USB isr in: Reset evt
    [I] USB isr in: Reset evt
    
  5. 打开 NDK 中 05_TOOLS/量产烧录工具/Panhcip DFU Tool 目录下的 PanchipDFUTool Vx.x.xxx.exe,界面右上角的芯片平台选择 PAN10xx NDK

    • 注意:需确保工具版本为v0.1.015或更高版本

  6. 直接点击功能列表中的读取设备版本信息按钮,工具会立刻扫描查找支持 Panchip USB DFU 的 USB-HID 设备,成功后会获取到芯片当前 App 固件版本等信息

    img

    识别 USB 设备并获取芯片当前固件版本信息

  7. 在工具程序设置那里选择加载程序,选择待升级工程的文件,位于 Images 路径下: ble_periph_hr_ota.signed.bin

    img

    上位机工具成功载入待升级的新固件

  8. 程序加载成功后,点击开始升级按钮,稍等片刻即可升级完成

    img

    Bootloader USB DFU 升级成功

  9. 升级成功后芯片程序会立刻从 Bootloader 跳转到 App 区域执行升级后的新固件

6 PRF OTA 升级详解

  1. 打开工具 NDK 中 05_TOOLS/OTA工具/Panhcip 2.4G OTA 目录下的 Panchip 2.4G OTA Vx.x.xxx.exe,选择 2.4G Dongle 对应的串口,具体设置如下图所示:

    image

    PRF OTA 上位机工具界面

  2. 2.4G Dongle 硬件需向 Panchip 申请或购买

  3. 上位机工具的使用说明请参考其自带的帮助文档

注意:2.4G 多设备升级不会进行校验,因此不能确保每个设备都能升级成功,有些设备如果升级不成功需要重新升级。

7 在 App 工程中使能 Bootloader

在本文档前面演示 DFU/OTA 升级流程的介绍中,都是以 ble_periph_hr_ota 例程做演示的,原因该例程默认使能了 Bootloader 支持,因此可以直接进行 DFU/OTA 升级演示。

实际上,NDK 中的所有 App 工程均可以通过修改 SDK Config 配置的方式来使能 Bootloader 支持,这里我们以 ble_periph_enc 例程为例:

  1. 打开 nimble/samples/bluetooth/ble_periph_enc 工程,直接编译,此工程默认未使能 Bootloader 支持,可以看到工程 Images 目录下生成了 3 个文件:

    image

    例程 Images 输出目录(未使能 Bootloader)

  2. 在 Keil 中打开当前例程的 SDK Config 配置文件(sdk_config.h),并切换到 Configuration Wizard 界面,修改如下几个配置:

    image

    在例程 App SDK Config 中使能 Bootloader 支持

    1. 勾选 Flash/Image Config : Flash Partition Config : Enable Bootloader 配置以使能 Bootloader 支持

    2. 勾选 Flash/Image Config : Flash Partition Config : Enable Bootloader : Forcibly Build Bootloader Project 配置,在当前 App 工程编译完成后强制编译一次 Bootloader 工程

    3. 修改 Flash/Image Config : Flash Partition Config : App Flash Partition Size 配置,由 480 (KB) 改为 220 (KB)

    4. 修改 Flash/Image Config : Flash Partition Config : App Backup Flash Partition Size 配置,由 0 (KB) 改为 220 (KB)

    • 使能 Forcibly Build Bootloader Project 配置原因是为了方便演示,实际也可以提前打开并手动编译 Bootloader 工程,这样 App 工程配置中就不需要勾选此选项了

    • Bootloader Flash Partition 分区默认占用了 40 KB Flash 空间,因此使能 Bootloader 后需重新规划各个 Flash 分区大小,这里我们直接保持其与 Bootloader 工程默认分区配置一致

    • 关于 Flash Partition Config 和 Bootloader Config 配置的详细介绍请参考 NDK Configuration 配置指南 文档中的相关章节

  3. 重新编译 App 例程,稍等片刻后即可编译成功(由于前面 SDK Config 配置中使能了 Forcibly Build Bootloader Project 配置,因此在编译 App 工程完成后,还会自动编译一次 Bootloader 工程,所以编译耗时会更久一些),此时可以看到工程 Images 目录下生成了更多文件:

    image

    例程 Images 输出目录(使能 Bootloader)

    • ble_periph_enc.bin:二进制格式的 App Image

    • ble_periph_enc.disasm:App 反汇编文件

    • ble_periph_enc.hex:十六进制文本格式的 App Image

    • ble_periph_enc.signed.bin:签名后的二进制格式的 App Image,可用于 DFU/OTA

    • ble_periph_enc.signed.hex:签名后的十六进制文本格式的 App Image

    • bootloader.bin:编译输出的二进制格式 Bootloader Image

    • bootloader.hex:编译输出的十六进制文本格式 Bootloader Image

    • nImageMerged.bin:合并了 Bootloader 和 签名后 App Image 的二进制格式 Image

    • nImageMerged.hex:合并了 Bootloader 和 签名后 App Image 的十六进制文本格式 Image

    重要

    注意:App 工程在使能 Bootloader 后,若点击 App 工程的 Keil Download 烧录按钮,烧录的仍然是当前 App 固件,而不会烧录 Bootloader 固件或合并后的固件。Bootloader 固件仍需手动打开 Bootloader 工程进行烧录;或者也可使用 PANLink/JFlash 工具直接烧录合并后的固件。

  4. 打开 Bootloader 和当前 App 工程,分别点击 Download 按钮,将 Bootloader 和 App 烧录到芯片中,从运行 Log 可以看出系统先执行了 Bootloader 代码,然后跳转到 App 继续运行:

    Try to load HW calibration data.. DONE.
    - Chip Info         : 0x61
    - Chip CP Version   : 3
    - Chip FT Version   : 9
    - Chip MAC Address  : E1A000095833
    - Chip UID          : A56407455338323633
    - Chip Flash UID    : 425032323033371410EE02464702B378
    - Chip Flash Size   : 512 KB (Inc. 4KB Panchip Info Area)
    
    
    Bootloader in..
    
    [I] Check valid image in App Backup Partition..
    [I] Clean up and try to jump into app image..
    [I] - app partition start addr: 0xA000
    [I] - app partition size      : 220 KB
    [I] - app image header size   : 512 B
    
    Application in..
    
    Try to load HW calibration data.. DONE.
    - Chip Info         : 0x61
    - Chip CP Version   : 3
    - Chip FT Version   : 9
    - Chip MAC Address  : E1A000095833
    - Chip UID          : A56407455338323633
    - Chip Flash UID    : 425032323033371410EE02464702B378
    - Chip Flash Size   : 512 KB (Inc. 4KB Panchip Info Area)
    
    - Current Flash Map :
      +-------------------------+ <- Addr: 0x00000
      |  Bootloader Partition   |
      |        ( 40 KB)         |
      +-------------------------+ <- Addr: 0x0A000
      |      App Partition      |
      |        (220 KB)         |
      +-------------------------+ <- Addr: 0x41000
      |  App Backup Partition   |
      |        (220 KB)         |
      +-------------------------+ <- Addr: 0x78000
      |    KVStore Partition    |
      |        ( 16 KB)         |
      +-------------------------+ <- Addr: 0x7C000
      |  User Custom Partition  |
      |        ( 12 KB)         |
      +-------------------------+ <- Addr: 0x7F000
      |    Panchip Info Area    |
      |     (4 KB, Hidden)      |
      +-------------------------+ <- End : 0x80000 (512 KB)
    
    The RCL clock frequency (after calibrate) is 32000 Hz
    APP image header check passed, image version: 0.0.1.0
    
    [I] app started
    [INF] ble stack init start..
    [INF] Spark Controller Init Start
    [INF] BLE Heap size:5636 B, remain:64 B
    [INF] ble controller version: 0.9.0.03699dd0
    [INF] Spark Controller Init OK
    [INF] ble host init ok -> ble thread start..
    
    [I] registered service 0x1800 with handle=1
    [I]   -registering characteristic 0x2a00 with def_handle=2 val_handle=3
    [I]   -registering characteristic 0x2a01 with def_handle=4 val_handle=5
    [I] registered service 0x1801 with handle=6
    [I]   -registering characteristic 0x2a05 with def_handle=7 val_handle=8
    [I]   -registering characteristic 0x2b29 with def_handle=10 val_handle=11
    [I]   -registering characteristic 0x2b2a with def_handle=12 val_handle=13
    [I] registered service 0x1811 with handle=14
    [I]   -registering characteristic 0x2a47 with def_handle=15 val_handle=16
    [I]   -registering characteristic 0x2a46 with def_handle=17 val_handle=18
    [I]   -registering characteristic 0x2a48 with def_handle=20 val_handle=21
    [I]   -registering characteristic 0x2a45 with def_handle=22 val_handle=23
    [I]   -registering characteristic 0x2a44 with def_handle=25 val_handle=26
    [I] registered service 59462f12-9543-9999-12c8-58b459a2712d with handle=27
    [I]   -registering characteristic 33333333-2222-2222-1111-111100000000 with def_handle=28 val_handle=29
    [I]     *registering descriptor 34343434-2323-2323-1212-121201010101 with handle=31
    [W] Device Id Address: 33:58:09:00:A0:E1
    [INF] GAP procedure initiated: advertise;
    [INF] disc_mode=2
    [INF]  adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
    [I] adv starting