目录 1)我们以 stm32f103xb_bl 为例,从 bootloader 项目的 main() 函数开始: 1)sdk_init() 是 DAPLINK 提供的 厂商 sdk 初始化 接口函数。移植时可实现该函数,以进行时钟等外设上电初始化: 2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下: 1)gpio_init() 是 DAPLINK 提供的 LED、按键初始化接口函数。移植时可实现该函数,用来来指示 USB 状态、等 2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下: config_init() 用来进行配置初始化。其创建 static cfg_ram_t 结构体的两个实例:config_ram 和 config_ram_copy。 可以用来对配置进行备份:比如我们在程序运行过程中(非上电)调用 config_init() 函数,则当前配置将保存到 config_ram_copy 中;此时我们可以对配置进行临时修改,修改完成后如果我们想恢复,只需要将 config_ram.key 修改一下后再次调用 config_init() 函数即可。 2)在 stm32f103xb_bl 项目中,该函数的调用逻辑如下: board_bootloader_init() 是 DAPLINK 提供的板级 bootloader 初始化接口函数。移植时可实现该函数,用来对开发板进行初始化(DAPLINK 中,除了 nrf52820 芯片对 bootloader 所在的 flash 进行锁定外,没有其它厂商实现该函数)。 BL 表示 bootloader,用来升级 IF;IF 则表示 interface,是 DAPLINK 实现烧录的执行代码。 该部分代码逻辑如下: 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。 4)modify_stack_pointer_and_start_app() 函数,从 FLASH 中 IF 所在位置开始运行。 关于 main() 函数,我们来总结一下移植时需要修改的地方:bootloader 主函数
1 sdk_init()
// 在 /source/hic_hal/sdk.h 文件中声明
void sdk_init(void);
// 在 /source/daplink/sdk_stub.c 文件中提供默认实现
__WEAK void sdk_init()
{
// Do nothing
}
2 gpio_init()
3 config_init()
4 board_bootloader_init()
// 定义在 source/daplink/bootloader/main_bootloader.c 文件中
__WEAK void board_bootloader_init()
{
return;
}
5 运行 IF 还是 BL?
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)));
}
cfg_ram_t config_ram 结构体持有的 uint8_t 类型的 hold_in_bl 变量,该变量只有在虚拟文件系统 vfs 改变时才会通过调用 config_ram_set_hold_in_bl() 函数来修改。6 main_task()
7 总结
移植点
描述
sdk_init()
厂商 sdk 初始化。主要用来进行时钟 RCC 的初始化
gpio_init()
led、button 初始化。USB 状态指示灯、复位按钮初始化
board_bootloader_init()
缺省。bootloader flash
board_info_t g_board_info
板子信息定义。包括 daplink 名称、mcu flash/ram 信息等