Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Bootloader
qboot
使用qboot通过U盘或SD卡下载程序
发布于 2024-05-24 14:49:15 浏览:284
订阅该版
[tocm] 由于我的设备不能联网, 又想把最新的固件下载到客户已经买的设备上, 加上客户啥也不懂, 我又不想为了更新一个程序这种小事跑一趟, 只能把固件发给客户让他保存到U盘或SD上去更新程序. 首先这是一个简要的教程, 程序我已经完成有一段时间了, 具体细节已经忘记了, 等再有机会写一个更详细的开发配置流程, 这次只把核心写出来. 单片机: STM32F407 系统: RTThread4.1.1 (bootloader和app相同) ## 基础操作 参数配置杂项代码 ```C #ifndef APPLICATIONS_APP_CONFIG_H_ #define APPLICATIONS_APP_CONFIG_H_ /** flash **/ #define DRV_FLASH #ifdef DRV_FLASH #define SPI_FLASH_BUS "spi3" #define SPI_FLASH_ATTACH "spi30" #define SPI_FLASH_DEVICE FAL_USING_NOR_FLASH_DEV_NAME #define FILE_SYS_PARTITION "filesys" #define SPI_FLASH_PATH "/" #define SPI_FLASH_CS_GPIO A #define SPI_FLASH_CS_PIN 15 #endif #include "gpio_define.h" #endif /* APPLICATIONS_APP_CONFIG_H_ */ #ifndef APPLICATIONS_COMMON_GPIO_DEFINE_H_ #define APPLICATIONS_COMMON_GPIO_DEFINE_H_ #define XXX_GPIOx(x) GPIO##x #define XXX_PINx(x) GPIO_PIN_##x #define GPIOx(x) XXX_GPIOx(x) #define PINx(x) XXX_PINx(x) #endif /* APPLICATIONS_COMMON_GPIO_DEFINE_H_ */ ``` 挂载SPI Flash ```C /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-01-15 admin the first version */ #include
#include
#include "dfs_fs.h" #include "sfud.h" #include "drv_spi.h" #include "spi_flash_sfud.h" #include
#include "rtconfig.h" #include "app_config.h" #ifdef DRV_FLASH /** * attach flash device in spi1 bus * @return */ static int rt_hw_spi_flash_init() { rt_hw_spi_device_attach(SPI_FLASH_BUS, SPI_FLASH_ATTACH, GPIOx(SPI_FLASH_CS_GPIO), PINx(SPI_FLASH_CS_PIN)); if (rt_sfud_flash_probe(SPI_FLASH_DEVICE, SPI_FLASH_ATTACH) == RT_NULL) { rt_kprintf("spi flash probe failed!\n"); } return 0; } INIT_DEVICE_EXPORT(rt_hw_spi_flash_init); //INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init); static int usr_fal_init(){ fal_init(); return 0; } INIT_COMPONENT_EXPORT(usr_fal_init); extern int access(const char *path, int amode); /** * mount flash block device * @return */ static int mnt_init() { #ifdef FILE_SYS_PARTITION struct rt_device *flash_dev = fal_blk_device_create(FILE_SYS_PARTITION); #else struct rt_device *flash_dev = rt_device_find(SPI_FLASH_DEVICE); #endif if(flash_dev == RT_NULL){ rt_kprintf("not found block device\n"); return -1; } if (dfs_mount(flash_dev->parent.name, SPI_FLASH_PATH, "elm", 0, 0) == 0) { // rt_kprintf("dfs mount ok\n"); #ifdef UDISK_MOUNTPOINT if(access(UDISK_MOUNTPOINT, 0) != 0){ mkdir(UDISK_MOUNTPOINT, 0); } #endif #ifdef SDIO_MOUNT_PATH if(access(SDIO_MOUNT_PATH, 0) != 0){ mkdir(SDIO_MOUNT_PATH, 0); } #endif } else { rt_kprintf("dfs mount failed\n"); dfs_mkfs("elm", flash_dev->parent.name); rt_kprintf("tried format flash device\n"); rt_kprintf("reset device!\n"); rt_thread_mdelay(10000); rt_hw_cpu_reset(); } return 0; } INIT_ENV_EXPORT(mnt_init); #endif ``` fal分区 ```C /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-01-31 admin the first version */ #ifndef _FAL_CFG_H_ #define _FAL_CFG_H_ #include
#include
#define FLASH_SIZE_GRANULARITY_16K (16*16*1024) #define FLASH_SIZE_GRANULARITY_64K (2*64*1024) #define FLASH_SIZE_GRANULARITY_128K (5*128*1024) #define STM32_FLASH_START_ADRESS_16K ROM_START #define STM32_FLASH_START_ADRESS_64K (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K) #define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K) #define RT_APP_PART_ADDR STM32_FLASH_START_ADRESS_128K #define NOR_FLASH_DEV_NAME FAL_USING_NOR_FLASH_DEV_NAME /* ===================== Flash device Configuration ========================= */ //extern const struct fal_flash_dev stm32_onchip_flash; extern const struct fal_flash_dev stm32_onchip_flash_16k; extern const struct fal_flash_dev stm32_onchip_flash_64k; extern const struct fal_flash_dev stm32_onchip_flash_128k; extern struct fal_flash_dev nor_flash0; /* flash device table */ #define FAL_FLASH_DEV_TABLE \ { \ &stm32_onchip_flash_16k, \ &stm32_onchip_flash_64k, \ &stm32_onchip_flash_128k, \ &nor_flash0 \ } /* ====================== Partition Configuration ========================== */ #ifdef FAL_PART_HAS_TABLE_CFG /* partition table */ #define FAL_PART_TABLE \ { \ {FAL_PART_MAGIC_WORD, "bl", "onchip_flash_16k", 0, FLASH_SIZE_GRANULARITY_16K, 0}, \ {FAL_PART_MAGIC_WORD, "prm", "onchip_flash_64k", 0, FLASH_SIZE_GRANULARITY_64K, 0}, \ {FAL_PART_MAGIC_WORD, "app", "onchip_flash_128k", 0, FLASH_SIZE_GRANULARITY_128K, 0}, \ {FAL_PART_MAGIC_WORD, "ef", NOR_FLASH_DEV_NAME, 0, 128*1024, 0}, \ {FAL_PART_MAGIC_WORD, "factory", NOR_FLASH_DEV_NAME, 128*1024, 512*1024, 0}, \ {FAL_PART_MAGIC_WORD, "download", NOR_FLASH_DEV_NAME, (128+512)*1024, 512*1024, 0}, \ {FAL_PART_MAGIC_WORD, "filesys", NOR_FLASH_DEV_NAME, (128+1024)*1024, ((8*1024)-(128+1024))*1024, 0}, \ } #endif /* FAL_PART_HAS_TABLE_CFG */ #endif /* _FAL_CFG_H_ */ ``` ## 核心代码 ```C /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-02-01 admin the first version */ #include
#include "rtconfig.h" #include
#include
#include
#include
#define DBG_TAG "FW" #define DBG_LVL DBG_LOG #include
#define DOWNLOAD_PART QBOOT_DOWNLOAD_PART_NAME #define FILE_BUFF_SIZE (4*1024) static char file_buf[FILE_BUFF_SIZE] = {0}; static const struct fal_partition * dl_part = RT_NULL; typedef struct cpu_info { union { u8 byte[12]; u32 id[3]; } v; } cpu_t; #define CPU_ID_BASE_ADDR (u32*)(0x1FFF7A10) static cpu_t cpu_id; int __cpu_id_init() { rt_memcpy(&cpu_id, CPU_ID_BASE_ADDR, sizeof(cpu_t)); return 0; } INIT_BOARD_EXPORT(__cpu_id_init); u32 GET_CPU_ID(u8 index) { return index < 3 ? cpu_id.v.id[index] : 0; } u32 get_id_code(){ return GET_CPU_ID(0)^GET_CPU_ID(1)^GET_CPU_ID(2); } static rt_err_t check_mount(){ rt_device_t ret; ret = rt_device_find("udisk0"); if(ret != RT_NULL){ return RT_EOK; } ret = rt_device_find("ud0-0"); if(ret != RT_NULL){ return RT_EOK; } return RT_ERROR; } static size_t get_file_size(FILE *f){ fseek(f, 0, SEEK_END); size_t ret = ftell(f); rewind(f); return ret; } rt_err_t fw_load(const char* fw_path){ rt_err_t ret = RT_EOK; char* recv_partition = DOWNLOAD_PART; FILE *f = fopen(fw_path, "rd"); if(f == NULL){ LOG_E("Open file error!"); ret = RT_ERROR; goto _exit; } size_t fw_file_size = get_file_size(f); LOG_I("Firmware file size:%d byte", fw_file_size); if ((dl_part = fal_partition_find(recv_partition)) == RT_NULL) { LOG_E("Partition (%s) find error!\n", recv_partition); ret = RT_ERROR; goto _exit; } if(fw_file_size > dl_part->len){ LOG_E("Firmware is too large! File size (%d), '%s' partition size (%d)", fw_file_size, dl_part->name, dl_part->len);; ret = RT_ERROR; goto _exit; } if (fal_partition_erase(dl_part, 0, fw_file_size) < 0) { LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name); ret = RT_ERROR; goto _exit; } int buff_block_len = fw_file_size / FILE_BUFF_SIZE; int buff_block_count = 0; size_t update_file_cur_size = 0; do{ int read_size = fw_file_size > FILE_BUFF_SIZE? FILE_BUFF_SIZE:fw_file_size; fread(file_buf, 1, read_size, f); if (fal_partition_write(dl_part, update_file_cur_size, (uint8_t*)file_buf, read_size) < 0) { LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name); ret = RT_ERROR; goto _exit; } update_file_cur_size += read_size; fw_file_size -= read_size; rt_kprintf("\r[%d/%d] %s=>download, replicating firmware file...", buff_block_count, buff_block_len, fw_path); buff_block_count ++; }while(fw_file_size != 0); _exit: if(f != NULL) fclose(f); return ret; } rt_err_t src_load(const char* src_path){ rt_err_t ret = RT_EOK; DIR *dir = opendir(src_path); struct dirent *ent; if(dir == NULL){ LOG_E("Not found dir: %s", src_path); ret = RT_ERROR; goto _exit; } while((ent = readdir(dir)) != NULL){ if(strcmp(ent->d_name, "System Volume Information") == 0) continue; rt_kprintf("copy %s ", ent->d_name); FILE *f_in; { char path_buff[64] = {0}; strcat(path_buff,src_path); strcat(path_buff,"/"); strcat(path_buff,ent->d_name); f_in = fopen(path_buff, "rb"); } FILE *f_out; { char path_buff[32] = {0}; strcat(path_buff,"/"); strcat(path_buff,ent->d_name); f_out = fopen(path_buff, "wb"); } size_t file_size = get_file_size(f_in); rt_kprintf("size: %d byte\n", file_size); do{ int read_size = file_size > FILE_BUFF_SIZE? FILE_BUFF_SIZE:file_size; fread(file_buf, 1, read_size, f_in); fwrite(file_buf, 1, read_size, f_out); if(file_size > FILE_BUFF_SIZE) fseek(f_out, read_size, SEEK_CUR); file_size -= read_size; }while(fseek(f_in, FILE_BUFF_SIZE, SEEK_CUR) == 0 && file_size != 0); fclose(f_in); fclose(f_out); } _exit: if(dir != NULL) closedir(dir); return ret; } extern int access(const char *path, int amode); int fw_from_udisk(){ if(check_mount() != RT_EOK){ return 0; } const char* fw_path = UDISK_MOUNTPOINT"/new.fw"; // const char* fw_path_old = UDISK_MOUNTPOINT"/old.fw"; const char* src_path = UDISK_MOUNTPOINT"/new_i18n"; // const char* src_path_old = UDISK_MOUNTPOINT"/old_i18n"; LOG_I("Check the firmware in the Udisk"); if(access(fw_path, 4)!= 0){ LOG_E("not found %s", fw_path); } else{ if(fw_load(fw_path) == RT_EOK){ // rename(fw_path, fw_path_old); // remove(fw_path); // LOG_I("success: %s -> %s", fw_path, fw_path_old); LOG_I("success: %s", fw_path); } else{ LOG_E("load fw failed!"); } } if(access(src_path, 4)!= 0){ LOG_E("not found %s", src_path); } else{ if(src_load(src_path) == RT_EOK){ // rename(src_path, src_path_old); // remove(src_path); LOG_I("success: %s", src_path); } else{ LOG_E("load src failed!"); } } return 0; } int fw_copy_init(){ qbt_hook_register(fw_from_udisk); return 0; } INIT_ENV_EXPORT(fw_copy_init); int copy_fw(int argc, char **argv){ if(strcmp(argv[1], "src") == 0){ src_load(argv[2]); } else if(strcmp(argv[1], "fw") == 0) { fw_load(argv[2]); } else{ rt_kprintf("src [dir_path]\n"); rt_kprintf("fw [fw_path]\n"); } return 0; } MSH_CMD_EXPORT(copy_fw, download firmware from disk); ``` 其中 `fw_load` 函数是下载固件的流程, `src_load` 是复制一些资源文件的流程 其中 `qbt_hook_register` 函数是我自己加的, 为了让把下载流程加到qboot启动流程中 在 `qboot.c` 文件里 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/c890c619d13189f7d9da19f61bcef280.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/d9545d56e930dfdcdb1ab6d904ce628c.png) 这里注意一下, 由于U盘挂载需要时间, 所以, 启动延时不能设置太低 好这就改完了, 在app固件里设置偏移地址 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240524/1bcf0a4816ded82078958c9ea60a5304.png) 再设置中断向量表地址对齐就可以启动app了 ```C #if 0 #include
#include
#define RT_APP_PART_ADDR 0x08060000 static int app_vtor_reconfig(){ #define NVIC_VTOR_MASK 0xFFFFFF80 SCB->VTOR = RT_APP_PART_ADDR & NVIC_VTOR_MASK; return 0; } INIT_BOARD_EXPORT(app_vtor_reconfig); #endif ```
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
ThinkCode
这家伙很懒,什么也没写!
文章
4
回答
16
被采纳
0
关注TA
发私信
相关文章
1
Linux下通过USBTinyISP为Arduino开发板烧?写Bootloader
2
请教修改NVIC后RTT调度函数失效的问题[已解决 bootloader中打开了不必要的中断]
3
进入bootloader的方式探讨
4
求助:IAP里的APP使用的RTT,跳转后出错。[已解决]
5
有没有人在STM32F103上用UART IAP跑过RT-Thread?
6
想做网口的IAP远程升级,不知可不可行
7
IAP问题
8
[已解决]请教基于RTT的IAP程序切换到应用程序不成功的问题(基于STM32F4)?
9
stm32f4xx-----IAP移植APP程序需要注意的地方
10
在调试IAP网络升级遇到跳转之后bootloader程序网络不通
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部