DAPLINK 源码学习(1)BL 之 main() 函数

bootloader 主函数

1)我们以 stm32f103xb_bl 为例,从 bootloader 项目的 main() 函数开始:

  • (1)sdk_init():MCU 初始化
  • (2)gpio_init():USB 相关引脚配置
  • (3)config_init():RAM 中配置初始化
  • (4)board_bootloader_init():nothing
  • (5)reset_button_pressed() 和 modify_stack_pointer_and_start_app():运行 BL or IF
  • (6)OS 和 main task 配置:
    • osKernelInitialize():初始化
    • osThreadNew(main_task):主任务回调函数 main_task()
    • osKernelStart():启动主任务

1 sdk_init()

1)sdk_init() 是 DAPLINK 提供的 厂商 sdk 初始化 接口函数。移植时可实现该函数,以进行时钟等外设上电初始化:

// 在 /source/hic_hal/sdk.h 文件中声明
void sdk_init(void);

// 在 /source/daplink/sdk_stub.c 文件中提供默认实现
__WEAK void sdk_init()
{
    // Do nothing
}

2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下:

2 gpio_init()

1)gpio_init() 是 DAPLINK 提供的 LED、按键初始化接口函数。移植时可实现该函数,用来来指示 USB 状态、等

2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下:

3 config_init()

config_init() 用来进行配置初始化。其创建 static cfg_ram_t 结构体的两个实例:config_ram 和 config_ram_copy。

可以用来对配置进行备份:比如我们在程序运行过程中(非上电)调用 config_init() 函数,则当前配置将保存到 config_ram_copy 中;此时我们可以对配置进行临时修改,修改完成后如果我们想恢复,只需要将 config_ram.key 修改一下后再次调用 config_init() 函数即可。

2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下:

4 board_bootloader_init()

board_bootloader_init() 是 DAPLINK 提供的板级 bootloader 初始化接口函数。移植时可实现该函数,用来对开发板进行初始化(DAPLINK 中,除了 nrf52820 芯片对 bootloader 所在的 flash 进行锁定外,没有其它厂商实现该函数)。

// 定义在 source/daplink/bootloader/main_bootloader.c 文件中
__WEAK void board_bootloader_init()
{
    return;
}

5 运行 IF 还是 BL?

BL 表示 bootloader,用来升级 IF;IF 则表示 interface,是 DAPLINK 实现烧录的执行代码。

该部分代码逻辑如下:

if (!reset_button_pressed()
    && g_board_info.target_cfg
    && validate_bin_nvic((uint8_t *)g_board_info.target_cfg->flash_regions[0].start)
    && !config_ram_get_initial_hold_in_bl()) {
    
    // change to the new vector table
    SCB->VTOR = g_board_info.target_cfg->flash_regions[0].start; //bootloaders should only have one flash region for interface
    
    // modify stack pointer and start app
    modify_stack_pointer_and_start_app((*(uint32_t *)(g_board_info.target_cfg->flash_regions[0].start)),
            (*(uint32_t *)(g_board_info.target_cfg->flash_regions[0].start + 4)));
}
  • 1)首先是 reset_button_pressed() 函数,该函数主要用来判断当前是否是复位状态。以 stm32f103xb_bl 为例来看,当 MCU 低电平复位时,该函数返回 1,无法进入 if 逻辑内。

  • 2)然后是 validate_bin_nvic() 函数,该函数有两个判断:

    • (1)判断 SP 指针。即 IF 在 FLASH 起始地址存储的内容是否在 RAM 的地址范围内。

      当我们没有烧录 IF 时,该地址上存储值为 0xFFFFFFFF,不在 RAM 范围内。将无法进入到该 if 判断内部执行。

    • (2)判断 Reset_Handler、NMI_Handler、HardFault_Handler 指针。即 IF 在 FLASH 起始地址偏移 4、8、12 位置存储的内容是否在超出 FLASH 区域

  • 3)最后是 config_ram_get_initial_hold_in_bl() 函数,该函数用来判断是否 hold in bootloader。
    cfg_ram_t config_ram 结构体持有的 uint8_t 类型的 hold_in_bl 变量,该变量只有在虚拟文件系统 vfs 改变时才会通过调用 config_ram_set_hold_in_bl() 函数来修改。

  • 4)modify_stack_pointer_and_start_app() 函数,从 FLASH 中 IF 所在位置开始运行。

6 main_task()

  • 1)OsKernelInitialize():初始化 OS 内核
  • 2)osThreadNew():将 main_task() 函数赋值给到 OS 的主函数回调上。
  • 3)osKernelStart():回调 main_task() 函数

7 总结

关于 main() 函数,我们来总结一下移植时需要修改的地方:

移植点 描述
sdk_init() 厂商 sdk 初始化。主要用来进行时钟 RCC 的初始化
gpio_init() led、button 初始化。USB 状态指示灯、复位按钮初始化
board_bootloader_init() 缺省。bootloader flash
board_info_t g_board_info 板子信息定义。包括 daplink 名称、mcu flash/ram 信息等
posted @ 2024-10-23 10:13  送南阳马生序  阅读(5)  评论(0编辑  收藏  举报