STM32:Bootloader(AB备份,自动回滚)
目录
- 1.STM32的升级方式
- 2.IAP升级
- 3.代码逻辑展示
- 3.1 划分存储区域
- 3.2 IAP的状态
- 4.源码分析
- 4.1 记录IAP的状态
- 4.2 APP代码异常判断
- 4.3 IAP状态的切换以及异常的处理逻辑
- 4.4 完整的逻辑代码
1.STM32的升级方式
1、ICP:In Circuit Programing,简单说就是在单片机开发时使用烧录器升级程序,比如使用J-Link烧录单片机程序。
2、ISP:In System Programing,在单片机内部实现了基于通信接口(如串口、I2C、SPI等等)的FLASH引导程序,配合厂家提供的烧录软件工具或自行开发的软件实现程序烧录。
3、IAP:In applicating Programing,是指单片机程序开发好之后在运行过程中由外部用户发起的在线升级,这种升级方式一般由用户自行设计升级方案,方案灵活性和自由度较高,在智能家居、汽车电子、物联网设备中常用的OTA(Over The Air)即空中下载技术原理也与之类似。
2.IAP升级
ICP和ISP需要连接才能更新固件,实际的交付客户的产品肯定不行,需要用到IAP,STM32的IAP升级,需要用到Bootloader,需要两段代码一段boot,一段app,boot区域负责更新app区域的代码,而app区域是项目的逻辑实现和功能实现。
STM32 IAP (In-Application Programming) 介绍STM32 IAP(In-Application Programming)是一种允许应用程序在运行时更新或编程内部Flash存储器的技术。通过IAP,您可以在不使用外部编程器的情况下,直接从应用程序代码中对STM32的内部Flash进行读取、写入和擦除操作。这对于实现固件升级、数据存储等功能非常有用。
- IAP 的应用场景
•固件升级:通过IAP,您可以实现OTA(Over-The-Air)固件升级,允许设备在运行时从网络或其他来源下载并安装新的固件版本。
•数据存储:IAP可以用于将用户数据、配置参数等存储到Flash中,确保数据在断电后不会丢失。
•多应用管理:某些应用可能需要在同一片Flash中存储多个应用程序,并根据需要切换运行不同的应用程序。 - IAP 的工作原理IAP的核心是通过调用STM32 HAL库或标准外设库中的Flash编程函数来操作Flash存储器。STM32的Flash存储器分为多个扇区(Sector),每个扇区可以独立进行擦除和写入操作。IAP通常包括以下几个步骤:
•解锁Flash:在对Flash进行任何操作之前,必须先解锁Flash以允许编程操作。
•擦除Flash:在写入新数据之前,必须先擦除目标扇区。注意,擦除操作是以扇区为单位的,不能只擦除单个字节或字。
•写入数据:将新数据写入指定的Flash地址。写入操作是以半字(16位)或字(32位)为单位进行的。
•锁定Flash:完成所有操作后,重新锁定Flash以防止意外修改。 - IAP 的实现方式IAP可以通过以下几种方式实现:3.1 Bootloader + Application 结构这是最常见的IAP实现方式。系统启动时,首先运行Bootloader程序,Bootloader负责检查是否有新的固件需要更新。如果有,则将新固件写入应用程序区域,然后跳转到应用程序执行。如果没有新固件,则直接跳转到应用程序。
•优点•
•Bootloader和应用程序分离,互不影响。
•可以实现安全的固件升级,避免损坏整个系统。
•支持多种升级方式(如UART、USB、SPI、Ethernet等)。
•缺点•
•需要额外的空间来存储Bootloader。
•Bootloader和应用程序之间的通信需要设计良好的协议。
3.代码逻辑展示
3.1 划分存储区域
把下载的固件存储到一个固定位置,另外还需要把原先APP区的代码进行备份,避免升级过程中出现异常导致生成砖
//1M start
#define USER_FLASH_FIRST_PAGE_ADDRESS 0x000000 //
#define USER_FLASH_LAST_PAGE_ADDRESS 0x0FFFFF //
#define USER_FLASH_END_ADDRESS 0x0FFFFF
//1M end//3M start
#define APP_FLASH_BACKUP_FIRST_PAGE_ADDRESS 0x200000 //
#define APP_FLASH_BACKUP_LAST_PAGE_ADDRESS 0x27FFFF //
#define APP_FLASH_BACKUP_END_ADDRESS 0x27FFFF//3M end
3.2 IAP的状态
//IAP STATUS
typedef enum iap_status_code{IAP_NO = 0,IAP_START = 1,IAP_COPY_APP_TO_BACKUP, //拷贝APP区域代码到备份区域IAP_COPY_APP_TO_BACKUP_SUCCESS_STATUS, //拷贝APP区域代码 成功IAP_COPY_APP_TO_BACKUP_FAIL_STATUS, //拷贝APP区域代码 失败IAP_COPY_APP_TO_BACKUP_CHECK_MD5_FAIL_STATUS, //拷贝APP区域代码 MD5校验失败IAP_COPY_NEWBIN_TO_APP, //拷贝新的固件到APP区IAP_COPY_NEWBIN_TO_APP_NO_DATA_STATUS,//新固件存储区域没有数据IAP_COPY_NEWBIN_TO_APP_SUCCESS_STATUS,//成功IAP_COPY_NEWBIN_TO_APP_FAIL_STATUS,//失败IAP_COPY_NEWBIN_TO_APP_CHECK_MD5_FAIL_STATUS,//MD5校验失败 IAP_BACK_TO_BACKUP_OLDBIN, //备份区域的旧固件恢复到APP区域IAP_BACK_TO_BACKUP_OLDBIN_NO_DATA_STATUS,//备份区域没有数据IAP_BACK_TO_BACKUP_OLDBIN_SUCCESS_STATUS,//成功IAP_BACK_TO_BACKUP_OLDBIN_FAIL_STATUS,//失败 IAP_BACK_TO_BACKUP_OLDBIN_CHECK_MD5_FAIL_STATUS,//MD5校验失败 IAP_ERROR_TO_APP, //IAP 升级失败 跳转到APP区运行IAP_END_TO_APP, //IAP 升级成功 跳转到APP区运行}IAP_STATUS;#define IAP_COPY_APP_SIZE 409600 //(400*1024) (448*1024)
为了避免升级过程中出现异常,需要对下载的文件进行MD5校验,此外未预防OTA文件有问题,添加多少次没有进入APP区域,代码自动回滚到上一个版本
4.源码分析
4.1 记录IAP的状态
记录上一次IAP的状态,避免中途断电,断网等异常导致OTA流程被打断后无法正常OTA
//读取OTA过程中上一次的iap状态BSP_W25Qx_Read(&last_iap_status_flag,IAP_STATUS_FLAG_ADDRESS,1);if(last_iap_status_flag == 0xFF || last_iap_status_flag > 20){last_iap_status_flag = 0;BSP_GD25QXX_Write(&last_iap_status_flag,IAP_STATUS_FLAG_ADDRESS,1);}
4.2 APP代码异常判断
Boot区和APP区进入次数进行比较,差异超过设定的次数,表示APP区域代码有问题,需要回滚到上一版本的代码
in_boot_times_count();get_in_app_times();if(boot_app_times_compare() != 0){iap_status = IAP_BACK_TO_BACKUP_OLDBIN; last_iap_status_flag = IAP_BACK_TO_BACKUP_OLDBIN; LOG_INFO("in_boot_times.value - in_app_times.value >30 iap_status = IAP_BACK_TO_BACKUP_OLDBIN...\r\n"); }
4.3 IAP状态的切换以及异常的处理逻辑
switch(iap_status){//不需要IAPcase IAP_NO:LOG_INFO("IAP_NO...jump to app --->\r\n"); HAL_Delay(1000);load_jump_to_app();break;//开始IAP的升级流程case IAP_START:LOG_INFO("IAP_START 1 : last_iap_status_flag = %d iap_status = %d\r\n",last_iap_status_flag,iap_status);if(last_iap_status_flag > IAP_START && last_iap_status_flag < IAP_ERROR_TO_APP){iap_status = last_iap_status_flag;}else{iap_status = IAP_COPY_APP_TO_BACKUP; }LOG_INFO("IAP_START 2 : last_iap_status_flag = %d iap_status = %d\r\n",last_iap_status_flag,iap_status);break;//拷贝app区域的内容到外部flash的备份区域case IAP_COPY_APP_TO_BACKUP:{//把外部flash的备份区域的内容清空if(Erase_back_flash_Sector_to_backup_app_area() != 0){LOG_INFO("IAP_COPY_APP_TO_BACKUP Erase_back_flash_Sector_to_backup_app_area fail......\r\n");iap_status = IAP_COPY_APP_TO_BACKUP_FAIL_STATUS;}else{LOG_INFO("IAP_COPY_APP_TO_BACKUP Erase_back_flash_Sector_to_backup_app_area success......\r\n");error_code = copy_app_to_back_area(IAP_COPY_APP_SIZE);//LOG_INFO("copy_app_to_back_area error_code = %d\r\n",error_code);if(error_code == 0){calculate_app_area_md5(now_app_md5_value,IAP_COPY_APP_SIZE);LOG_INFO("IAP_COPY_APP_TO_BACKUP now_app_md5_value MD5: ");for(uint16_t i =0;i<16;i++){LOG_INFO("%02x",now_app_md5_value[i]);}LOG_INFO("\r\n");calculate_back_area_md5(back_md5_value,IAP_COPY_APP_SIZE); LOG_INFO("IAP_COPY_APP_TO_BACKUP back_md5_value MD5: ");for(uint16_t i =0;i<16;i++){LOG_INFO("%02x",back_md5_value[i]);}LOG_INFO("\r\n");if(!compare_md5_2buff(now_app_md5_value,back_md5_value,16)){LOG_INFO("IAP_COPY_APP_TO_BACKUP_SUCCESS_STATUS......\r\n");BSP_GD25QXX_Write(back_md5_value,APP_FLASH_BACKUP_MD5_VALUE_ADDRESS,16); iap_status = IAP_COPY_APP_TO_BACKUP_SUCCESS_STATUS;//BSP_GD25QXX_Write(&iap_status,IAP_STATUS_FLAG_ADDRESS,1); }else{LOG_INFO("IAP_COPY_APP_TO_BACKUP copy_app_to_back_area check is fail ---> BSP_Reset_system\r\n");HAL_Delay(100);iap_status = IAP_COPY_APP_TO_BACKUP_CHECK_MD5_FAIL_STATUS; }}else{LOG_INFO("IAP_COPY_APP_TO_BACKUP copy_app_to_back_area copy is fail ---> BSP_Reset_system\r\n");HAL_Delay(100);iap_status = IAP_COPY_APP_TO_BACKUP_FAIL_STATUS;}} }break;case IAP_COPY_APP_TO_BACKUP_SUCCESS_STATUS:{iap_status = IAP_COPY_APP_TO_BACKUP_SUCCESS_STATUS;BSP_GD25QXX_Write(&iap_status,IAP_STATUS_FLAG_ADDRESS,1); iap_status = IAP_COPY_NEWBIN_TO_APP;} break; case IAP_COPY_APP_TO_BACKUP_FAIL_STATUS:iap_copy_app_to_backup_error_cnt++;if(iap_copy_app_to_backup_error_cnt >= 10){iap_status = IAP_COPY_APP_TO_BACKUP_FAIL_STATUS; BSP_GD25QXX_Write(&iap_status,IAP_STATUS_FLAG_ADDRESS,1); iap_status = IAP_ERROR_TO_APP; }else{iap_status = IAP_COPY_APP_TO_BACKUP; }break;case IAP_COPY_APP_TO_BACKUP_CHECK_MD5_FAIL_STATUS:iap_copy_app_to_backup_error_cnt++;if(iap_copy_app_to_backup_error_cnt >= 10){iap_status = IAP_COPY_APP_TO_BACKUP_CHECK_MD5_FAIL_STATUS; BSP_GD25QXX_Write(&iap_status,IAP_STATUS_FLAG_ADDRESS,1); iap_status = IAP_ERROR_TO_APP; <相关文章:
STM32:Bootloader(AB备份,自动回滚)
目录 1.STM32的升级方式2.IAP升级3.代码逻辑展示3.1 划分存储区域3.2 IAP的状态4.源码分析4.1 记录IAP的状态4.2 APP代码异常判断4.3 IAP状态的切换以及异常的处理逻辑4.4 完整的逻辑代码1.STM32的升级方式 1、ICP:In Circuit Programing,简单说就是在单片机开发时使用烧录器…...
数独小游戏(Matlab)
基于Matlab制作的数独小游戏 (完整源码和介绍) 感兴趣可以随时联系博主噢~常在线能秒回! “Matlab数独小游戏”程序设计的关键技术流程和核心算法如下: 1.图形用户界面(GUI):使用MATLAB的GUIDE工具创建和管理用户界面࿰…...
使用docker让项目持续开发和部署
大多人选择开发时在本地,部署时文件都在容器里,如果没有容器,那就本地开发,没有映射文件,如果部署环境到容器了,容器内部启动时设置执行命令,再将映射的文件进行编译,这就直接能实现…...
电子应用设计方案-45:智能火锅系统方案设计
智能火锅系统方案设计 一、引言 随着人们生活水平的提高和对饮食体验的追求,智能火锅系统应运而生。本方案旨在设计一款集智能化控制、高效加热、安全保障和个性化体验于一体的智能火锅系统。 二、系统概述 1. 系统目标 - 实现精准的温度控制,满足不同…...
windows在conda下安装nlpia库
最近在学习《自然语言处理实战》这本书,书中用了其自己的库nlpia,我一直装不上,网上也找不到教程遂放弃,看到现在第四章没办法了,需要用到库里的一些文本语料,又折腾了一天,终于装好了ÿ…...
分布式事务的前世今生-纯理论
一个可用的复杂的系统总是从可用的简单系统进化而来。反过来这句话也正确: 从零开始设计的复杂的系统从来都用不了,也没办法让它变的可用。 --John Gal 《系统学》 1975 1. 事务的概念 百科: 事务(Transaction),一般是…...
apache部署若依前后端分离项目(开启SSL)
网站部署之后,大多数需要配置https,所以本章教程,介绍使用apache部署若依前后端项目的时候,如何开启SSL,以及如何配置SSL证书。 一、安装ssl模块 默认情况下,ssl模块是没有安装的。需要手动安装,否则直接配置SSL模块的时候,会报错。 sudo yum install mod_ssl二、查询s…...
Elasticsearch scroll 之滚动查询
Elasticsearch scroll 之滚动查询 Elasticsearch 的 Scroll API 是一种用于处理大规模数据集的机制,特别是在需要从索引中检索大量数据时。通常情况下,Elasticsearch 的搜索请求会有一个结果集大小的限制 (fromsize 的检索数量默认是 10,000 条记录)&am…...
MySQL 内存使用率常用分析语句
最近连续遇到MySQL内存占用过高导致服务器内存不足的问题,整理下收集到的常用分析语句 一、 OS层 首先需要确认是否是MySQL占用的内存 top -p $(pidof mysqld) -n 1 或者 cat /proc/$(pidof mysqld)/status 二、 DB层 1. 全局情况 各种buffer pool大小…...
L20.【LeetCode笔记】用栈实现队列(方法2)(★详解★)
目录 1.实现方法 过程详解 1.执行push 1->push 2->push 3->push 4 2.执行第一个pop 3.执行第二个pop 4.执行push 5->push 6 编辑 5.执行pop->pop->pop 代码实现 队列创建函数myQueueCreate 入队函数myQueuePush 出队函数myQueuePop 返回队列开头…...
PR蒙太奇
简介 蒙太奇是将不同的镜头鬓角在一起,已不同的时间、地点来表现人物、环境、情节等,有时会产生意想不到的想过。广义上来说,这种剪接做法就是蒙太奇,是由镜头组合构成的隐式语言。 含义 镜头组接技巧 叙事蒙太奇:…...
高中数学:计数原理-排列组合
文章目录 一、排列排列数例题 二、组合组合数例题 三、使用方法总结 一、排列 排列数 例题 二、组合 组合数 例题 三、使用方法总结 组合:从n个元素中抽取m个元素,不排序,则用组合计算 排列:从n个元素中抽取m个元素,再…...
pytorch中有哪些归一化的方式?
在 PyTorch 中,归一化是一种重要的操作,用于调整数据分布或模型参数,以提高模型的训练效率和性能。以下是常见的归一化方式及其应用场景: 1. 数据归一化 (1)torch.nn.functional.normalize 对输入张量沿…...
Next.js系统性教学:增量静态再生成 (ISR) 完全解析
更多有关Next.js教程,请查阅: 【目录】Next.js 独立开发系列教程-CSDN博客 目录 1. 什么是增量静态再生成 (ISR)? 1.1 传统的静态生成与挑战 1.2 增量静态再生成(ISR)的出现 2. 如何使用增量静态再生成(ISR&…...
视频编辑技术的发展:AI技术在小咖视频混剪中的应用
随着数字技术的飞速发展,视频编辑领域也迎来了革命性的变化。AI技术的引入,使得视频编辑变得更加智能和高效。本文将探讨AI技术在视频混剪领域的应用,并介绍一些实用的工具,帮助用户提升视频编辑的效率和质量。 视频演示 AI技术在…...
【JVM】JVM基础教程(一)
目录 初识JVM JVM是什么? JVM的功能 解释、即时编译和运行 内存管理 常见的JVM JVM虚拟机规范 HotSpot的发展历程 JVM的组成 字节码文件详解 应用场景 以正确姿势打开字节码文件 编辑字节码文件的组成 基本信息 Magic魔数 主副版本号 常量池 接口…...
Python并发编程全解析
一、前言 在现代开发中,并发编程是提高性能、响应速度的关键技术之一。Python提供了多种实现并发的方式,如多线程、多进程和异步IO。本篇文章将逐一解析这些技术,探讨其适用场景,并通过代码示例帮助理解。 二、并发编程的核心概念 1. 并发与并行 并发:任务在时间片上交替…...
大语言模型应用Text2SQL本地部署实践初探
自从两年前OpenAI公司发布ChatGPT后,大模型(Large Language Model,简称LLM)相关技术在国内外可谓百家争鸣,遍地开花,在传统数据挖掘、机器学习和深度学习的基础上,正式宣告进入快速发展的人工智能(Artificial Intellig…...
每日十题八股-2024年12月7日
1.说说hashmap的负载因子 2.Hashmap和Hashtable有什么不一样的?Hashmap一般怎么用? 3.ConcurrentHashMap怎么实现的? 4.分段锁怎么加锁的? 5.分段锁是可重入的吗? 6.已经用了synchronized,为什么还要用CAS呢…...
VTK编程指南<三>:基于VTK入门程序解析来理解VTK基础知识
1、VTK入门程序 下面是一个完整的Vtk入门程序,我们基于这个程序来对VTK的基本知识进行一个初步了解。 #include <iostream>#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2 VTK_MODULE_INI…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
