首页 > 数据库 > 数据库开发技术 > 分享一个单片机的多系统引导方案
多系统引导,通常指的是在计算机中安装多个操作系统,在开机时,由开机引导程序选择默认加载的操作系统,或通过键盘选择需要加载的操作系统,然后运行相应的操作系统。
在嵌入式单片机应用中,由于受限于Flash的资源大小,通常只有bootloader和App固件保留在单片机内部Flash,但随着MCU的发展,也有更大的Flash,运行频率更快的单片机可以选择。因此也可以用来实现多系统快速引导。本文将分享一种基于STM32F407开发的多系统引导的方案。
本工程就实现引导不同的3D打印固件,分别是Marlin、RepRap、Klipper三种固件,为了节省Flash空间,默认将他们保存在SD卡,在引导时如果当前Flash中的系统与选中的系统不同,则从SD卡中搬运App覆盖Flash中运行。
为了加快启动的速度,在BootLoader需要保留当前默认的系统的信息,如存放地址偏移,固件大小,固件CRC值等信息,因此定义以下结构体标记系统和引导的信息。
typedef struct {
/* 固件类型 */
firmware_type_t type;
/* 固件的大小 */
uint32_t size;
/* 存放flash的地址 */
uint32_t offset;
/* 固件CRC值 */
uint32_t crc;
/* 固件版本 */
uint8_t version[16];
/* 升级的固件是否加密, 0:不加密, 1加密 */
uint32_t is_encryption;
}firmware_board_info_t;
/* 板载信息段 */
typedef struct _board_info_t{
/* 信息头部的魔数, 恒定为:"CRBD" */
uint32_t magic;
/* bootload版本 */
uint8_t bootload_version[32];
/* 主板的版本号 */
uint8_t hardware_version[24];
/* 当前分区的序号 */
firmware_type_t run_number;
/* 固件状态 */
firmware_board_info_t firmware[5];
/* 保留字段,保持结构体总大小为512字节 */
//uint8_t reserve[336];
/* 信息头crc */
uint32_t info_crc;
}board_info_t;
/* 板子错误状态,
0x00:正常
bit0 = 1: app1升级中
bit1 = 1: app2升级中
bit2 = 1: app3升级中
bit3 : 保留
bit4 = 1: app1破坏
bit5 = 1: app2破坏
bit6 = 1: app3破坏
bit7 :保留
uint32_t board_err;
*/
typedef struct {
/* 固件类型 */
firmware_type_t type;
/* 在文件中的偏移值 */
uint32_t start;
/* 固件的大小 */
uint32_t size;
/* 存放flash的地址 */
uint32_t offset;
/* 固件CRC值 */
uint32_t crc;
/* 固件版本 */
uint8_t version[16];
uint8_t reserve[24]; /* 保持结构体总大小64字节 */
/* 升级的固件是否加密, 0:不加密, 1加密 */
uint32_t is_encryption;
}firmware_pack_info_t;
/* 多系统包的文件信息头,也是单片机的固件信息段 */
typedef struct {
/* 魔数标志, "HYFW" */
uint32_t magic;
/* 总文件长度 */
uint32_t len;
/* 首先引导的地址 */
uint32_t runboot;
firmware_pack_info_t firmware[3];
/* 支持的硬件版本号,最多支持8种 */
uint8_t hardware_version[8][24];
/* 保留字段,保持结构体总大小为512字节 */
uint8_t reserve[112];
/* 信息头的crc */
uint32_t info_crc;
}firmware_info_t;
引导选择,通过一个upgrade.ini配置文件来决定当前需要引导哪个系统,upgrade.ini文件内容如下:
;整包的自动升级检查
[All]
auto_upgrade=false
upgrade_addr=0x8008000
file_name=default
;RepRap的自动升级检查
[RepRap]
auto_upgrade=true
upgrade_addr=0x8008000
file_name=default
;Marlin的自动升级检查
[Marlin]
auto_upgrade=false
;upgrade_addr=0x8008000
file_name=default
;Klpper的自动升级检查
[Klipper]
auto_upgrade=false
upgrade_addr=0x8008000
file_name=default
[Other]
auto_upgrade=true
upgrade_addr=0x8008000
file_name=default
[Pack]
auto_upgrade=true
upgrade_addr=0x8008000
file_name=default
;引导顺序,升级配置优先级
[boot]
boot0=RepRap
boot1=Marlin
Boot2=Klipper
Boot3=none
;配置的优先级:
;[Other] > [All] > [RepRap] > [Marlin] > [Klipper]
单片机上电时立即运行Bootloder程序,检查SD卡是否存在,如果不存在则运行默认地址的程序,否则继续检查upgrade.ini文件中的配置,然后从SD卡中读取当前需要引导的固件,计算CRC,如果与Flash中的系统的CRC一致,则直接运行Flash中的系统,否则根据配置内容搬运新的固件到Flash,达到升级的目的。然后运行新的系统。实现逻辑如下:
#include "update.h"
#include "config.h"
#include <stdint.h>
#include <stdbool.h>
#include "debug.h"
#include "uart.h"
#include "stm32f4xx_hal.h"
#include "fatfs.h"
#include "iniparser.h"
#define BOOTLOAD_VERSION 0.0.1
#define HARDWARE_VERSION HY_DB_V0.1
#define FIRMWARE_DIR 0:/system/ /* 升级文件的目录 */
#define FIRMWARE_FILE_REPRAP RepRap.bin /* RepRap升级文件 */
#define FIRMWARE_FILE_MARLIN Marlin.bin /* Marlin升级文件 */
#define FIRMWARE_FILE_KLIPPER Klipper.bin /* Klipper升级文件 */
#define FIRMWARE_FILE_ALL_FIRM firmware_All.bin /* 整包多系统升级文件 */
#define FIRMWARE_FILE_OTHER firmware.bin /* 未知的系统包 */
#define FIRMWARE_UPGRADE_LOG upgrade.log /* 升级日志文件 */
#define FIRMWARE_UPGRADE_SET upgrade.ini /* 自动升级、启动顺序配置文件 */
#define BOARD_FILE_INFO brd.dat /* 板载信息 */
#define _STR(str) #str
#define _STR_MACR(str) _STR(str)
#define _FIRMWARE_PATH(firmware) _STR_MACR(FIRMWARE_DIR)\
_STR_MACR(FIRMWARE_FILE_##firmware)
#define RepRap_upgrade_path _FIRMWARE_PATH(REPRAP)
#define Marlin_upgrade_path _FIRMWARE_PATH(MARLIN)
#define Klipper_upgrade_path _FIRMWARE_PATH(KLIPPER)
#define All_firm_upgrade_path _FIRMWARE_PATH(ALL_FIRM)
#define Other_upgrade_path _FIRMWARE_PATH(OTHER)
#define Board_file_info_path _STR_MACR(FIRMWARE_DIR)\
_STR_MACR(BOARD_FILE_INFO)
#define BOARD_UPGRADE_SET_FILE_INI _STR_MACR(FIRMWARE_DIR)\
_STR_MACR(FIRMWARE_UPGRADE_SET)
#define BOOTLOAD_FIRMWARE_VERSION _STR_MACR(BOOTLOAD_VERSION)
#define BOARD_HARDWARE_VERSION _STR_MACR(HARDWARE_VERSION)
#define BOOT_SET_ALL_PACK All
#define BOOT_SET_REPRAP RepRap
#define BOOT_SET_MARLIN Marlin
#define BOOT_SET_KLIPPER Klipper
#define BOOT_SET_OTHER Other
#define BOOT_SET_DEFAULT_ADDR 0x8008000 /* 默认bootload 的大小为48K */
#define BOOT_SET_AUTO_UPG auto_upgrade
#define BOOT_SET_ADDR upgrade_addr
#define BOOT_SET_FILE file_name
#define BOOT_SET_DEFAULT default
#define BOOT_SET_DEFAULT_STR _STR_MACR(BOOT_SET_DEFAULT)
#define BOOT_SET_ALL_PACK_STR _STR_MACR(BOOT_SET_ALL_PACK)
#define BOOT_SET_REPRAP_STR _STR_MACR(BOOT_SET_REPRAP)
#define BOOT_SET_MARLIN_STR _STR_MACR(BOOT_SET_MARLIN)
#define BOOT_SET_KLIPPER_STR _STR_MACR(BOOT_SET_KLIPPER)
#define BOOT_SET_OTHER_STR _STR_MACR(BOOT_SET_OTHER)
#define BOOT_SET_FALSE_STR "false"
#define BOOT_SET_TRUE_STR "true"
#define BOOT_SET_NONE_STR "none"
#define BOOT_SET_DEFAULT_ADDR_STR _STR_MACR(BOOT_SET_DEFAULT_ADDR)
#define BOOT_SET_KEY(sec, key) _STR_MACR(sec)":"\
_STR_MACR(key)
#define BOARD_INFO_MAGIC (0x1234)
#define BOARD_INFO_SIZE (512)
#define FIRMWARE_INFO_MAGIC (0x5678)
#define FIRMWARE_INFO_SIZE (512)
typedef enum{
UPGRADE_OK = 0, /* 升级成功 */
UPGRADE_FILE_NOT_EXIST, /* 没有查找到升级文件 */
UPGRADE_FILE_CRC_ERROR, /* 文件CRC校验错误 */
UPGRADE_FILE_OPEN_ERROR, /* 文件打开错误 */
UPGRADE_FILE_READ_ERR, /* 文件读取错误 */
UPGRADE_FILE_READ_HALT, /* 文件读取错误 */
UPGRADE_FILE_SIZE_ERR, /* 文件大小太大 */
UPGRADE_FLASH_ERASE_ERR, /* flash擦除错误 */
UPGRADE_FLASH_WRITE_ERR, /* flash写错误 */
UPGRADE_FLASH_VERIFY_ERR, /* flash校验错误 */
UPGRADE_FIRMWARE_RUN_ERR, /* 固件运行错误 */
FIRMWARE_FILE_INFO_NOT_EXIST, /* 固件信息文件读取错误 */
FIRMWARE_NONEED_UPGRADE, /* 固件相同,无需升级 */
}upgrade_result_t;
typedef enum {
Other,
AllPack = 0,
RepRap,
Marlin,
Klipper,
}firmware_type_t;
static uint32_t crc32_default(uint8_t *pszBuf,uint32_t ulLength);
static uint32_t crc32_pend(uint32_t pre, uint8_t *bytes, uint32_t len);
static uint32_t get_file_crc(const char *file_name);
static int get_file_size(const char *file_name);
static dictionary * firmware_settings_load(const char *settings_name);
bool goto_app(void)
{
uint32_t sp;
void (*app_run_fun)(void);
if(SD_PRESENT == BSP_SD_IsDetected()){
board_info_t *bd_info;
bd_info = board_info_get_from_sd(Board_file_info_path);
sp = bd_info->firmware[bd_info->run_number].offset;
}
else{
sp = BOOT_SET_DEFAULT_ADDR;
}
/* 固件第一个字为堆栈指针 */
/* 检查栈顶地址是否合法. */
if(((*(volatile uint32_t *)sp) & 0x2FFE0000) == 0x20000000){
debug("app jump(%x)...\n", sp);
app_run_fun = (void (*)(void))*(volatile uint32_t *)(sp + 4);
/* 关闭所以中断 */
__disable_irq();
/* 设置堆栈指针 */
__set_MSP(*(volatile uint32_t *)sp);
/* 进入app */
app_run_fun();
}
/* if app run success, never run to there */
return false;
}
static const board_info_t s_default_board_info = {
/* 信息头部的魔数, 恒定为:"CRBD" */
.magic = BOARD_INFO_MAGIC,
/* bootload版本 */
.bootload_version = BOOTLOAD_FIRMWARE_VERSION,
/* 主板的版本号 */
.hardware_version = BOARD_HARDWARE_VERSION,
/* 首次直接启动的地址,必须为app的地址 */
.run_number = RepRap,
/* 固件状态 */
.firmware = {
{
.type = AllPack,
.size = 0,
.offset = BOOT_SET_DEFAULT_ADDR,
.crc = 0,
.version = "V0.0.1",
.is_encryption = 0,
},
{
.type = Other,
.size = 0,
.offset = BOOT_SET_DEFAULT_ADDR,
.crc = 0,
.version = "V0.0.1",
.is_encryption = 0,
},
{
.type = Marlin,
.size = 0,
.offset = BOOT_SET_DEFAULT_ADDR,
.crc = 0,
.version = "V0.0.1",
.is_encryption = 0,
},
{
.type = Klipper,
.size = 0,
.offset = BOOT_SET_DEFAULT_ADDR,
.crc = 0,
.version = "no firmware",
.is_encryption = 0,
}
},
/* 保留字段,保持结构体总大小为512字节 */
//.reserve = {0},
/* 信息头crc */
.info_crc = 0,
};
/* 板载信息 */
static board_info_t s_board_info;
bool board_info_save_to_sd(board_info_t *board_info, const char *board_info_name)
{
FRESULT file_op_res;
FIL file;
UINT cnt;
board_info->info_crc = crc32_default((uint8_t *)board_info,
sizeof(board_info_t) - sizeof(uint32_t));
/* 创建板载文件 */
file_op_res = f_open(&file, board_info_name, FA_CREATE_ALWAYS|FA_WRITE);
if(FR_OK != file_op_res){
std_printf("fail to create file %s: result: %s\n", board_info_name,
file_op_err_to_str(file_op_res));
return false;
}
/* 重新写入默认的信息 */
file_op_res = f_write(&file, (const void *)board_info,
sizeof(board_info_t), &cnt);
if(FR_OK != file_op_res){
std_printf("fail to write file %s, result: %s\n", board_info_name,
file_op_err_to_str(file_op_res));
f_close(&file);
return false;
}
f_close(&file);
std_printf("%s crc: %x\n", board_info_name, get_file_crc(board_info_name));
return true;
}
/* 从sd卡的板载信息文件中读取板子的信息 */
board_info_t *board_info_get_from_sd(const char *board_info_name)
{
/* 获取文件属性(大小) */
FILINFO file_info;
FRESULT file_op_res;
FIL file;
UINT cnt;
do{
file_op_res = f_stat (board_info_name, &file_info);
if(file_op_res != FR_OK){
std_printf("file %s read info error: %s\n",board_info_name,
file_op_err_to_str(file_op_res));
break;
}
/* 文件大小不对,则放弃解析文件,重新生成 */
if(file_info.fsize != sizeof(board_info_t)){
std_printf("file size not match board info, whill reset it...\n");
break;
}
/* 走到这里说明文件存在,文件大小正常,读取内容 */
file_op_res = f_open(&file, board_info_name, FA_READ);
if(FR_OK != file_op_res){
std_printf("fail to open file %s: result: %s\n", board_info_name,
file_op_err_to_str(file_op_res));
break;
}
file_op_res = f_read(&file, &s_board_info, sizeof(board_info_t), &cnt);
/* 文件读取错误,读取不了指定大小的内容 */
if(sizeof(board_info_t) != cnt){
std_printf("file read error: %s", file_op_err_to_str(file_op_res));
f_close(&file);
break;
}
/* 校验CRC */
uint32_t crc;
crc = crc32_default((uint8_t *)&s_board_info, sizeof(board_info_t) - sizeof(uint32_t));
if(crc != s_board_info.info_crc){
std_printf("board info file crc err\n");
f_close(&file);
break;
}
#if 0
std_printf("magic: %x\n", s_board_info.magic);
std_printf("bootload_version: %s\n", s_board_info.bootload_version);
std_printf("runboot: %x\n", s_board_info.runboot);
std_printf("firmware.type: %x\n", s_board_info.firmware[0].type);
std_printf("crc: %x\n", s_board_info.info_crc);
std_printf("%s crc: %x\n", board_info_name, get_file_crc(board_info_name));
#endif
f_close(&file);
return &s_board_info;
}while(0);
s_board_info = s_default_board_info;
s_board_info.info_crc = crc32_default((uint8_t *)&s_board_info,
sizeof(board_info_t) - sizeof(uint32_t));
/* 创建板载文件 */
file_op_res = f_open(&file, board_info_name, FA_CREATE_ALWAYS|FA_WRITE);
if(FR_OK != file_op_res){
std_printf("fail to create file %s: result: %s\n", board_info_name,
file_op_err_to_str(file_op_res));
return &s_board_info;
}
/* 重新写入默认的信息 */
file_op_res = f_write(&file, (const void *)&s_board_info,
sizeof(board_info_t), &cnt);
if(FR_OK != file_op_res){
std_printf("fail to write file %s, result: %s\n", board_info_name,
file_op_err_to_str(file_op_res));
}
f_close(&file);
std_printf("%s crc: %x\n", board_info_name, get_file_crc(board_info_name));
return &s_board_info;
}
/* 导入固件配置检查 */
static dictionary * firmware_settings_load(const char *settings_name)
{
dictionary * ini;
//std_printf("iniparser: file%s\n", settings_name);
ini = iniparser_load(settings_name);
#if 0
std_printf("n: %d\n", ini->n);
std_printf("size:%d\n", ini->size);
std_printf("sec cnt: %d\n", iniparser_getnsec(ini));
std_printf("Reprap auto upgrade: %s\n", iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_REPRAP, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR));
std_printf("Reprap file name: %s\n", iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_REPRAP, BOOT_SET_FILE_STR),
BOOT_SET_DEFAULT_STR));
std_printf("Reprap addr name: %s\n", iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_REPRAP, BOOT_SET_ADDR),
BOOT_SET_DEFAULT_ADDR_STR));
#endif
return ini;
}
bool firmware_upgrade_check(void)
{
dictionary * ini;
uint32_t upgrade_addr;
/* 导入ini文件 */
ini = firmware_settings_load(BOARD_UPGRADE_SET_FILE_INI);
/* 配置出错 */
if(ini == NULL){
return true;
}
/* 默认包升级自动 */
if(0 == strcmp(BOOT_SET_TRUE_STR,
iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_OTHER, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR))){
upgrade_addr = iniparser_getlongint(ini,
BOOT_SET_KEY(BOOT_SET_OTHER, BOOT_SET_ADDR),
BOOT_SET_DEFAULT_ADDR);
firmware_upgrade(Other_upgrade_path, upgrade_addr, Other);
return true;
}
#if 0
/* 整包自动升级 */
if(0 == strcmp(BOOT_SET_TRUE,
iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_ALL_PACK, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR))){
upgrade_addr = iniparser_getlongint(ini,
BOOT_SET_KEY(BOOT_SET_ALL_PACK, BOOT_SET_ADDR),
BOOT_SET_DEFAULT_ADDR);
firmware_upgrade(RepRap_upgrade_path, upgrade_addr, AllPack);
return true;
}
#endif
/* RepRap自动升级 */
if(0 == strcmp(BOOT_SET_TRUE_STR,
iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_REPRAP, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR))){
upgrade_addr = iniparser_getlongint(ini,
BOOT_SET_KEY(BOOT_SET_REPRAP, BOOT_SET_ADDR),
BOOT_SET_DEFAULT_ADDR);
firmware_upgrade(RepRap_upgrade_path, upgrade_addr, RepRap);
return true;
}
/* Marlin自动升级 */
if(0 == strcmp(BOOT_SET_TRUE_STR,
iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_MARLIN, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR))){
upgrade_addr = iniparser_getlongint(ini,
BOOT_SET_KEY(BOOT_SET_MARLIN, BOOT_SET_ADDR),
BOOT_SET_DEFAULT_ADDR);
firmware_upgrade(Marlin_upgrade_path, upgrade_addr, Marlin);
return true;
}
/* Klipper自动升级 */
if(0 == strcmp(BOOT_SET_TRUE_STR,
iniparser_getstring(ini,
BOOT_SET_KEY(BOOT_SET_KLIPPER, BOOT_SET_AUTO_UPG),
BOOT_SET_FALSE_STR))){
return true;
}
return true;
}
/* 获得文件的crc */
static int get_file_size(const char *file_name)
{
/* 获取文件属性(大小) */
FILINFO file_info;
FRESULT file_op_res;
file_op_res = f_stat (file_name, &file_info);
if(file_op_res == FR_OK){
return file_info.fsize;
}
std_printf("file read error: %d", file_op_err_to_str(file_op_res));
return 0;
}
/* 计算文件的crc */
static uint32_t get_file_crc(const char *file_name)
{
FIL file;
FRESULT res;
res = f_open(&file,file_name,FA_READ);
if(FR_OK != res){
std_printf("fail to open file %s: result: %x\n", file_name, res);
}
uint8_t buff[32];
UINT cnt;
uint32_t crc;
crc = 0;
do{
/* 每次读取32个字节依次计算crc */
res = f_read(&file, buff, sizeof(buff), &cnt);
if(cnt != 0){
crc = crc32_pend(crc, buff, cnt);
}
}while(cnt);
f_close(&file);
return crc;
}
typedef struct _sector_table{
uint32_t sector_offset;
uint32_t sector_size;
}sector_table_t;
/* STM32F407的flash扇区表 */
static const sector_table_t s_sector_table[] = {
FLASH_BASE + (16 << 10)*0,(16 << 10), /*sector 0 16KB*/
FLASH_BASE + (16 << 10)*1,(16 << 10), /*sector 1 16KB*/
FLASH_BASE + (16 << 10)*2,(16 << 10), /*sector 2 16KB*/
FLASH_BASE + (16 << 10)*3,(16 << 10), /*sector 3 16KB*/
FLASH_BASE + (16 << 10)*4,(64 << 10), /*sector 4 64KB*/
FLASH_BASE + (64 << 10)*2,(128 << 10), /*sector 5 128KB*/
FLASH_BASE + (128 << 10)*2,(128 << 10), /*sector 6 128KB*/
FLASH_BASE + (128 << 10)*3,(128 << 10), /*sector 7 128KB*/
FLASH_BASE + (128 << 10)*4,(128 << 10), /*sector 8 128KB*/
FLASH_BASE + (128 << 10)*5,(128 << 10), /*sector 9 128KB*/
FLASH_BASE + (128 << 10)*6,(128 << 10), /*sector 10 128KB*/
FLASH_BASE + (128 << 10)*7,(128 << 10), /*sector 11 128KB*/
};
static uint32_t flash_addr_to_sector(uint32_t addr)
{
assert_param((addr >= FLASH_BASE) && (addr < FLASH_END));
int table_cnt;
table_cnt = sizeof(s_sector_table)/sizeof(sector_table_t);
for(int i = 0; i < table_cnt; i++){
if(addr >= s_sector_table[table_cnt - i - 1].sector_offset){
return table_cnt - i - 1;
}
}
/* make gcc happy */
return 0;
}
static uint32_t sector_count(uint32_t addr, uint32_t len)
{
uint32_t sector;
uint32_t sector_sz;
uint32_t sector_cnt;
sector_cnt = 1;
sector = flash_addr_to_sector(addr);
sector_sz += (addr - s_sector_table[sector].sector_offset);
while((sector_sz < len) &&
(sector < (sizeof(s_sector_table)/sizeof(sector_table_t)) - 1)){
sector_sz += s_sector_table[sector + 1].sector_size;
sector++;
sector_cnt++;
}
return sector_cnt;
}
upgrade_result_t firmware_upgrade(const char *file_name, uint32_t addr,
firmware_type_t firm_type)
{
/* 检查参数 */
assert_param(file_name != NULL);
assert_param((addr >= FLASH_BASE) && (addr < FLASH_END));
/* 地址必须要4字节对齐 */
assert_param((addr & 0x03) == 0);
std_printf("firmware: %s\n", file_name);
/* 检查文件是否存在 */
/* 检查文件crc */
uint32_t file_size;
uint32_t file_crc;
board_info_t *board_info;
FRESULT file_op_res;
/* 读取板载信息 */
board_info = board_info_get_from_sd(Board_file_info_path);
file_crc = get_file_crc(file_name);
file_size = get_file_size(file_name);
//std_printf("file size: %u, crc: %x\n", file_size, file_crc);
/* 当前系统没有变化,则检查文件crc是否一致 */
if(board_info->run_number == firm_type){
/* 文件相同,不需要升级 */
if(board_info->firmware[firm_type].crc == file_crc){
std_printf("firmware is new, boot...\n");
return FIRMWARE_NONEED_UPGRADE;
}
}
/* flash解锁 */
HAL_FLASH_Unlock();
/* 擦除flash */
uint32_t sector;
uint32_t sector_cnt;
sector = flash_addr_to_sector(addr);
sector_cnt = sector_count(addr, file_size);
FLASH_EraseInitTypeDef erase_info;
erase_info.Banks = FLASH_BANK_1;
erase_info.NbSectors = sector_cnt;
erase_info.Sector = sector;
erase_info.TypeErase = FLASH_TYPEERASE_SECTORS;
erase_info.VoltageRange = FLASH_VOLTAGE_RANGE_3; /* 2.7~3.6V */
uint32_t err;
HAL_StatusTypeDef erase_res;
#if 0
std_printf("need erase addr: %x~%x\n", addr, addr + file_size);
std_printf("erase sector start: %u, need erase sector cnt: %u\n", sector, sector_cnt);
#endif
std_printf("erase ...\n");
erase_res = HAL_FLASHEx_Erase(&erase_info, &err);
/* 擦除失败 */
if(erase_res != HAL_OK){
std_printf("erase result: %d\n",erase_res);
return UPGRADE_FLASH_ERASE_ERR;
}
std_printf("erase ok\n");
FIL file;
/* 打开固件文件,读取内容 */
file_op_res = f_open(&file,file_name, FA_READ);
if(FR_OK != file_op_res){
std_printf("fail to open file %s: result: %x\n", file_name, file_op_res);
return UPGRADE_FILE_OPEN_ERROR;
}
/* 读文件内容-写flash */
HAL_StatusTypeDef st;
uint32_t data;
UINT cnt;
/* 进度显示 */
uint32_t process, process_cnt;
int idx, i;
process = file_size/10;
process_cnt = 0;
for(i = 0, idx = 0; i < file_size; i += 4){
file_op_res = f_read(&file, &data, sizeof(data), &cnt);
if(cnt == 0){
std_printf("file read error: %d", file_op_res);
f_close(&file);
return UPGRADE_FILE_READ_ERR;
}
st = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, (uint64_t)data);
if(st != HAL_OK){
std_printf("write to flash fail(%d/%d) %d\n",i, file_size, st);
return UPGRADE_FLASH_WRITE_ERR;
}
if((process_cnt += 4) > process){
idx += 10;
std_printf("process: %d%%\n", i*100/file_size);
process_cnt = 0;
}
}
std_printf("process: 100%%\n");
f_close(&file);
std_printf("upgrade success!\n");
/* 更新固件标志 */
board_info->run_number = firm_type;
board_info->firmware[firm_type].crc = file_crc;
board_info->firmware[firm_type].size = file_size;
board_info->firmware[firm_type].offset = addr;
board_info->firmware[firm_type].is_encryption = 0;
board_info->firmware[firm_type].type = firm_type;
board_info_save_to_sd(board_info, Board_file_info_path);
HAL_FLASH_Lock();
return UPGRADE_OK;
}
static uint32_t Reflect(uint32_t ref, uint8_t ch)
{
uint32_t value = 0;
for(int i = 1; i < (ch + 1); i++){
if (ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
static uint32_t s_crc_table[256] = {0x123456};
static void crc_init(void)
{
uint32_t ulPolynomial = 0x04C11DB7;
for (int i = 0; i <= 0xFF; i++){
s_crc_table[i] = Reflect(i, 8) << 24;
for (int j = 0; j < 8; j++)
s_crc_table[i] = (s_crc_table[i] << 1) ^
(s_crc_table[i] & ((uint32_t)1 << 31) ? ulPolynomial : 0);
s_crc_table[i] = Reflect(s_crc_table[i], 32);
}
}
static uint32_t crc32_default(uint8_t *pszBuf, uint32_t ulLength)
{
uint32_t Result = 0xFFFFFFFF;
/* 初始化crc表 */
if(s_crc_table[0] == 0x123456){
crc_init();
}
while (ulLength--){
Result = (Result >> 8) ^ s_crc_table[(Result & 0xFF) ^ *pszBuf++];
}
Result ^= 0xFFFFFFFF;
return Result;
}
static uint32_t crc32_pend(uint32_t pre, uint8_t *bytes, uint32_t len)
{
pre ^= 0xFFFFFFFF;
/* 初始化crc表 */
if(s_crc_table[0] == 0x123456){
crc_init();
}
while(len--){
pre = (pre >> 8) ^ s_crc_table[(pre & 0xFF) ^ *bytes++];
}
pre ^= 0xFFFFFFFF;
return pre;
}
int main(void)
{
HAL_Init();
/* 时钟初始化 */
SystemClock_Config();
uart_init();
/* sdio外设初始化 */
sdio_sd_init();
/* 文件系统初始化 */
MX_FATFS_Init();
/* led 状态初始化 */
run_led_init();
#if 0
/* 延时进入app */
for(int i = 0; i < 1; i++){
HAL_Delay(1000);
run_led_trun();
std_printf("wait %d\n", i);
}
#endif
run_led_on();
/* 插卡了则检查升级配置 */
if(SD_PRESENT == BSP_SD_IsDetected()){
firmware_upgrade_check();
}
while (1){
std_printf("goto app...\n");
HAL_Delay(500);
if(goto_app() == false){
std_printf("fail to jump app\n");
}
}
}
原文作者:Rust嵌入式;如有侵权,请联系管理员删除。