参考资料:RT-T官网资料如下链接所示
STM32通用Bootloader (rt-thread.org)
1.app程序env配置过程
参考上述资料中"制作 app 固件"章节,分区大小根据自己设备而定,以下是我以407VET6为例设置的fal分区
notes:上述分区是由片内flash(on-chip)和外部flash(W25Q64)两部分分区构成,关于外部flash的配置和使用参考文章"RT-T下使用easyflash的配置过程_rtthread easyflash-CSDN博客"
我使用的工程逻辑是先把升级文件通过HTTP下载到外部flash"download"分区中,然后跳转到bootloat里面进行升级;
2.制作bootload bsp工程
在env中进行配置和裁剪功能,主要包括FAL相关配置、on-chip、spi、agile_upgrade相关配置,尽量裁剪到最简:
2.1 关于FAL相关配置、on-chip、spi等相关配置参考文章 RT-T下使用easyflash的配置过程_rtthread easyflash-CSDN博客
2.2 agile_upgrade配置
2.3 修改main函数
下边是部分参考代码
#include "main.h"
#include "fal.h"
#include <agile_upgrade.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
//app启动地址
#define BOOT_APP_ADDR 0x08010000
extern const struct agile_upgrade_ops agile_upgrade_fal_ops;
static uint32_t _written_len = 0;
static uint32_t _total_len = 0;
static void step_hook(int step) { LOG_D("step: %d\r\n", step); }
static void error_hook(int step, int code) { LOG_E("step: %d, err: %d\r\n", step, code); }
static void progress_hook(uint32_t cur_size, uint32_t total_size) {
_written_len = cur_size;
_total_len = total_size;
}
void qbt_jump_to_app(void)
{
typedef void (*app_func_t)(void);
u32 app_addr = BOOT_APP_ADDR;
u32 stk_addr = *((__IO uint32_t *)app_addr);
app_func_t app_func = (app_func_t)(*((__IO uint32_t *)(app_addr + 4)));
if ((((u32)app_func & 0xff000000) != 0x08000000) || ((stk_addr & 0x2ff00000) != 0x20000000))
{
LOG_E("No legitimate application.");
return;
}
LOG_I("Jump to application running ... \n");
rt_thread_mdelay(200);
__disable_irq();
for(int i=0; i<128; i++)
{
__NVIC_DisableIRQ((IRQn_Type)i);
__NVIC_ClearPendingIRQ((IRQn_Type)i);
}
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
__set_CONTROL(0);
__set_MSP(stk_addr);
app_func();//Jump to application running
LOG_E("Qboot jump to application fail.");
}
int main(void)
{
agile_upgrade_set_step_hook(step_hook);
agile_upgrade_set_error_hook(error_hook);
agile_upgrade_set_progress_hook(progress_hook);
agile_upgrade_t src_agu = {0};
src_agu.name = "download";
src_agu.user_data = "download";
src_agu.ops = &agile_upgrade_fal_ops;
agile_upgrade_t dst_agu = {0};
dst_agu.name = "app";
dst_agu.user_data = "app";
dst_agu.ops = &agile_upgrade_fal_ops;
agile_upgrade_release(&src_agu, &dst_agu, 1);
LOG_D("Written len: %u, total len: %u\r\n", _written_len, _total_len);
qbt_jump_to_app();
return 0;
}
3.实现http远程升级
参考上述资料中"更多固件下载方式"章节,以下是配置
3.1 在控制台执行命令"http_ota http://xxx/xxx/rtthreadf.rbl “,url更换成自己的
4.遇到的问题
4.1bootload程序编译报错
原因:link.sct文件中设置的内存大小为64k,但是编译后生成的code代码大小已经68k左右
解决:1.设置优化等级;2.对冗余函数的优化
优化后code代码在40k左右
参考资料:关于ARM Keil5 Optimization level 优化等级的一些分析_keil optimization_夜星辰2023的博客-CSDN博客
MDK中One ELF Section per Function选项功能探究_iceiilin的博客-CSDN博客
4.2 bootload程序进入死循环,没有跳转到app分区
原因:
4.2.1 程序中通过万能驱动,spi通讯查找外部flash(W25Q16设备失败);
4.2.2 只在"stm32f4xx_hal_msp.c“中修改spi1相关引脚配置,其他地方可能没有进行配置;
解决:通过STM32CubeMX配置spi1并生成工程
4.3 跳转到app分区后程序不能正常运行
原因:app分区地址设置错误导致修改中断向量表的跳转基地址错误
解决:#define RT_APP_PART_ADDR 0x08010000 0x10000:64k
AT32开发板中直接修改中断向量表 改为 0x10000
#define VECT_TAB_OFFSET 0x10000
STM32中通过函数实现:
/**
* Function ota_app_vtor_reconfig
* Description Set Vector Table base location to the start addr of app(RT_APP_PART_ADDR).
*/
static int ota_app_vtor_reconfig(void)
{
#define NVIC_VTOR_MASK 0x3FFFFF80
/* Set the Vector Table base location by user application firmware definition */
SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK;
//此处代码的作用是修改中断向量表的跳转基地址
return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);
4.4在控制台通过"http_ota http://xxx/xxx/rtthreadf.rbl “升级失败问题
解决:修改webclient.c文件两个地方
4.4.1 添加"rt_thread_mdelay(10);"
4.4.2 在1160行添加else
4.5 http升级后在bootload中写往"app"分区写程序失败
现象分析:从http服务器上获取后,开始升级,跳转到bootload中后,从"download"分区往"app"分区搬运程序,写入失败,从新用jlink烧录程序卡死到这一步,如下图所示:
原因:雅特力单片机不同型号,FLAH大小不同,扇区大小也不同,如下图所示为flash大小为4032K和1024K大小的扇区大小
解决:修改board.h文件中FLASH_PAGE_SIZE大小