参考博客:STM32 BootLoader升级固件_cyang's blog-CSDN博客
STM32固件升级详解(BootLoader)_EmbeddedOsprey-CSDN博客_stm32升级bootloader
(版权声明:本文为CSDN博主「cyang812」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011303443/article/details/53378602)
完整的下载新版本固件,下载完成后将固件搬运到APP程序运行的位置。(一般来说是将APP从片外flash搬运到片内flash上)。搬运完成后校验通过后重启APP。
服务器端: 生成差分包,bsdiff算法
1.对old文件中所有子字符串形成一个字典;
2.对比old文件和new文件,产生diff string 和extra string;
3.将diff string 和extra string 以及相应的控制 字用zip压缩成一个patch包。
设备端: 生成new File,bspatch算法
1.接收patch包;
2.解压patch包;
3.还原new文件。
相比差分升级,合包的过程,直接搬运。
容错率低。
如图所示:
A/B 系统更新可带来以下好处:
几种OTA方式的对比:
优点 |
缺点 |
|
差分升级 |
1.差分包小(5%),下载更快,节省OTA流程的时间。 |
1.一个差分包只能由特定的原包升级到特定的新包。2.保证基础包的一致性。若原包数据损毁,得到差分包也无法升级。 |
全量升级 |
1.拿到新的包就能升级。不需要指定原包。2.不需保证基础包的一致性。 |
1.全量包的size更大,下载相比差分包需要更长时间。 |
AB面升级 |
1.容错率高,更能避免固件升级出错 2.OTA过程中不影响用户APP程序的运行 3.下载完成后不需要搬运,不需要差分包还原 |
1.需要最多的flash空间的OTA方式。 |
原地升级 |
1.最节省flash空间的方式,不需要合包存储,直接根据差分包搬运到APP的位置 |
2.容错率低,若搬运过程中断电,则设备变砖 |
关于差分升级的缺点,如图所示,你懂得(懒得打字了......)
1.外设驱动-----CubeMX工具生成代码:GPIO uart(debug uart) SPI flash
2.md5库添加 、w25q80驱动文件添加
3.Boot_Start()函数
bootloader.h
#ifndef BOOTLOADER_H
#define BOOTLOADER_H
#include
#include
#include "flash.h"
#define MD5_CHECK_MSG_FLAG "firmware-header"
#pragma pack(1)
typedef struct {
uint8_t project_id;
uint16_t vendor_id;
uint16_t software_version;
uint16_t hardware_version;
uint32_t buildtime;
uint32_t filesize;
uint8_t md5[16];
} mcu_update_info_t;
#pragma pack()
#define APP_START_ADDRESS (0x08008000) //APP main //map ResetHandle :0800825d //0x08008000
#define MCU_OTA_FLAG (0xA8A8A8A8)
//printf boot:
void boot_message_print();
//boot_start : main调用这个函数
void boot_start(void);
//check bin file
void check_bin_file(void);
//update bin file
uint8_t update_bin_file(uint32_t addr, HDC01_ota_info_t *params);
//go to main
void go_to_app_main(uint32_t address); //APP_START_ADDRESS 实参
//
bool firmware_verify(uint32_t start_address, uint32_t end_address);
bootloader.c
#include "bootloader.h"
#include "stm32f4xx_hal.h"
#include "flash.h"
#include "lib_md5.h"
char version[] = {"V00.00"};
typedef void (*pFunction)(void);
pFunction JumpToApplication;
void go_to_app_main(uint32_t address) //APP_START_ADDRESS 实参
{
__IO uint32_t fun;
fun = (*(__IO uint32_t *)APP_START_ADDRESS);
// check the Vactor Table Head // 检查栈顶地址是否合法
if ((fun & 0x2FFE0000) == 0x20000000)
{
fun = *(__IO uint32_t *)(APP_START_ADDRESS + 4);
JumpToApplication = (pFunction)fun;
// set Vactor Table address
__set_MSP(*(__IO uint32_t *)APP_START_ADDRESS);
printf("Set Vactor Table address ...\n");
// start Jumping and go to App_main
printf("Real Jump and go to App_main...\r\n\r\n");
//关闭 总中断
__disable_irq();
JumpToApplication();
}
else
{
// app file error
printf("App Bin file size err 0x%8X...\r\n", fun);
// go to start
HAL_NVIC_SystemReset();
}
}
//printf boot:
void boot_message_print(void )
{
printf("Start Bootloader,version = %s...\n",version);
}
//boot_start : main use
void boot_start(void)
{
boot_message_print();
check_bin_file();
go_to_app_main(APP_START_ADDRESS);
}
//check bin file / updata bin
void check_bin_file(void)
{
HDC01_ota_info_t params;
//1. read firmware upadte flag
flash_read(FLASH_TYPE_EXTERNAL,(uint8_t *)¶ms, HDC01_MCU_OTA_INFO_START_ADDR,sizeof(HDC01_ota_info_t));
//2.check the bin file exception flag
if (params.magic == MCU_OTA_FLAG)
{
// Need update
port_trace("We need update the new firmware. len:%d\n", params.firmware_len);
// update the bin file
update_bin_file(HDC01_MCU_OTA_DATA_START_ADDR, ¶ms);
//erase OTA flag
flash_erase_sector(FLASH_TYPE_EXTERNAL, HDC01_MCU_OTA_INFO_SECTOR);
}
else
{
port_trace("Normal firmware start...\n");
}
}
//update the bin file
uint8_t buff[2048];
uint8_t check[2048];
uint8_t update_bin_file(uint32_t addr, HDC01_ota_info_t *params)
{
bool ret;
uint32_t remain_length = 0, write_num;
uint32_t index = 0;
uint32_t i = 0;
uint32_t bin_length = 0;
bin_length = params->firmware_len;
if (bin_length > (224 * 1024))
{
// error of bin file length
port_trace("Read Firmware length err: 0x%8X\n", bin_length);
return 0;
}
// erase all code segment
uint16_t sector_max_num = GetMaxSectorNum(bin_length);
for (i = 2; i <= sector_max_num; i++)
{
port_trace("erase sector %d.\n", i);
flash_erase_sector(FLASH_TYPE_INTERNAL, i);
}
// copy data from the extend flash to inner flash
port_trace("Copy data Start\n");
remain_length = bin_length;
index = 0;
while (1)
{
if (remain_length > 2048)
write_num = 2048;
else
write_num = remain_length;
flash_read(FLASH_TYPE_EXTERNAL, buff, HDC01_MCU_OTA_DATA_START_ADDR + index, write_num);
flash_write(FLASH_TYPE_INTERNAL, buff, APP_START_ADDRESS + index, write_num);
// 写入后立刻读出,并与外部Flash中的数据做校验。
flash_read(FLASH_TYPE_INTERNAL, check, APP_START_ADDRESS + index, write_num);
for (i = 0; i < write_num; i++)
{
if (buff[i] != check[i])
{
// 一旦出现问题,随后再次重启。
HAL_NVIC_SystemReset();
}
}
index = index + write_num;
remain_length = remain_length - write_num;
if (remain_length == 0) break;
}
//ret = firmware_verify(APP_START_ADDRESS, APP_START_ADDRESS + params->firmware_len);
// if (ret == false)
// {
// port_trace("md5 check fail.\n");
// // 一旦出现问题,随后再次重启。
// HAL_NVIC_SystemReset();
// }
// else
// {
// port_trace("md5 check success.\n");
// }
port_trace("Copy data finish.\n");
return 1;
}
/*
check app validity
*/
static uint32_t boot_timeout_starting_time = 0;
/* ------------------------------------------------------------------------ */
/* @Description: check app validity
* @parameters:
start_address: app start addr
end_address: app end addr */
/* ------------------------------------------------------------------------ */
bool firmware_verify(uint32_t start_address, uint32_t end_address)
{
uint8_t md5_check_flag_size = sizeof(MD5_CHECK_MSG_FLAG) - 1;
if ((start_address >= end_address) || ((end_address - start_address) <= md5_check_flag_size)) {
return false;
}
end_address -= md5_check_flag_size;
for (; end_address > start_address; end_address--) {
if (memcmp(MD5_CHECK_MSG_FLAG, (uint8_t *)end_address, md5_check_flag_size) == 0) {
mcu_update_info_t *md5_and_size = (mcu_update_info_t *)(end_address + md5_check_flag_size);
if (md5_and_size->filesize == (end_address - start_address))
{
MD5_CTX md5;
uint8_t md5_value[16] = {0};
port_trace("......APP_buildtime-->%d\n", md5_and_size->buildtime);
port_trace("......firmware_size-->%d\n", md5_and_size->filesize);
port_trace("find_md5-->");
//port_dump(md5_and_size->md5, 16);
MD5Init(&md5);
MD5Update(&md5, (uint8_t *)start_address, md5_and_size->filesize);
MD5Final(md5_value, &md5);
port_trace("flash_md5-->");
//port_dump(md5_value, 16);
if (memcmp(md5_value, md5_and_size->md5, 16) == 0) {
return true;
}
}
}
}
port_trace("......No_find_APP_flag-->error\n");
return false;
}
完整工程:CSDN下载:stm32f407-BootLoader程序_stm32f407bootloader跳转-嵌入式文档类资源-CSDN下载
百度云网盘:链接:https://pan.baidu.com/s/1dwrG1nA5voIhGBAimJgKDg
提取码:yls4
复制这段内容后打开百度网盘手机App,操作更方便哦