当前位置: 首页 > news >正文

STM32 OTA应用开发——自制BootLoader

STM32 OTA应用开发——自制BootLoader

目录

  • STM32 OTA应用开发——自制BootLoader
    • 前言
    • 1 环境搭建
    • 2 BootLoader工作原理以及常见分区介绍
    • 3 BootLoader的制作
    • 4 烧录下载配置
    • 5 运行测试
    • 结束语

前言

什么是OTA?

百度百科:空中下载技术(Over-the-Air Technology; OTA),是通过移动通信的空中接口实现对移动终端设备及SIM卡数据进行远程管理的技术。经过公网多年的应用与发展,已十分成熟,网络运营商通过OTA技术实现SIM卡远程管理,还能提供移动化的新业务下载功能。

实际上,现在我们所说的OTA比百度百科的定义还要更广泛,OTA的形式已经不再局限于手机和SIM卡,只要涉及到远程下载升级程序的方式我们都可以称之为OTA。例如通过4G,5G,WiFI,蓝牙等无线通讯进行下载升级的可以称为OTA,通过U盘,RS485等串行接口进行升级的也可以称之为OTA。

OTA的作用?
OTA的意义在于它在一定程度上突破了距离的限制,在不借助烧录器的情况下完成固件的下载升级,极大的方便了产品的升级和维护,降低售后成本。

什么是BootLoader?

百度百科:在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。

实际上,BootLoader不仅仅在操作系统上使用,在一些内存小,功能应用较为简单的单片机设备上面也可以通过BootLoader来完成OTA升级。

我之前也有发过一些关于STM32远程OTA的文章,但用的是第三方BootLoader,而且是基于操作系统实现的。BootLoader占用的内存也比较大,而且不开源。
所以这一讲我就来介绍一下如何自己制作一个简单的BootLoader程序。

1 环境搭建

关于STM32以及Keil的环境这里就不具体介绍了,网上教程也很多,不懂的同学自行查阅资料。

2 BootLoader工作原理以及常见分区介绍

不管用的是什么MCU,要使用OTA都离不开BootLoader,BootLoader是一个统称,它其实只是一段引导程序,在MCU启动的时候会先运行这段代码,判断是否需要升级,如果不需要升级就跳转到APP分区运行用户代码,如果需要升级则先通过一些硬件接口接收和搬运要升级的新固件,然后再跳转到APP分区运行新固件,从而实现OTA升级。
请添加图片描述

常见分区方式介绍:
1.Application
没有加入Bootloader之前,我们单片机内部的flash就是一整块的,所有的应用代码都放在这。
请添加图片描述

2.Bootloader + Application
在原有的flash区域里面划分出两个区域,Bootloader和Application,这种分区方式的好处在于既可以OTA,Appd区又可以分到较大的空间,缺点是没有存放新固件的区域,需要从外部导入进来,而且一旦传输的过程被异常打断,那么原有的App代码也无法正常运行了,也就是传说中的“变砖”。
请添加图片描述

3.Bootloader + Application + Download
这种分区方式是比较万能的一种,优点是新固件是先存放到Download区的,哪怕搬运的过程中出现异常中断的情况,也不会“变砖”,缺点是需要单独划分一块内存跟APP区差不多的区域用来存放新固件,变相的减少了APP区的空间,对于内存较小的单片机来说压力就比较大了。
请添加图片描述

4.Bootloader + Application1 + Application2
这种方式可以同时存在两套App,优点在于升级了新固件以后,还保留了原来的旧版固件,必要的时候还可以进行版本的回退。
请添加图片描述

5.Bootloader + Setting + Application + Download
这种方式跟第3种基本一样,只是增加了一个区域用来存放升级相关的一些参数以及用户的一些配置。
请添加图片描述

3 BootLoader的制作

BootLoader的制作需要根据实际的需求来做,不同的运行方式或者升级方式在做法上都是有区别的,包括BootLoader所需要的内存空间也不尽相同。
不过不管是用什么方式,Bootloader都应该尽可能做的更小更简洁,这样的话内存的开销就更小,对于内存较小的MCU来说压力就没那么大了。

我下面要做的这个bootloader是上面讲的常见分区方式里面的第5种。
分区介绍:
我用的是STM32F103,内存是128K的(想用内存更小的MCU也是可以的,改下各个分区的内存分配就行了)。

分区表如下:

nameoffsetsize
boot0x080000000x00003000
setting0x080030000x00001000
app0x080040000x0000E000
download0x080120000x0000E000

功能描述:
运行bootloader的时候先从setting里面读一些参数,确定是否需要升级,如果需要,则把download分区的固件搬运到app分区,如果不需要升级则直接跳转到app分区.
至于新固件的下载传输过程,我放到App里面去处理了,这跟我的项目实际需求有关系,App部分这里就先不往下拓展了,后面我会专门写一篇博客来介绍。

各个功能模块的具体讲解:
1、分区定义
先把各个分区的内存地址以及大小定义好,方便后面使用。

#define FLASH_SECTOR_SIZE       1024
#define FLASH_SECTOR_NUM        128    // 128K
#define FLASH_START_ADDR        ((uint32_t)0x8000000)
#define FLASH_END_ADDR          ((uint32_t)(0x8000000 + FLASH_SECTOR_NUM * FLASH_SECTOR_SIZE))#define BOOT_SECTOR_ADDR        0x08000000     // BOOT sector start address 
#define BOOT_SECTOR_SIZE        0x3000         // BOOT sector size
#define SETTING_SECTOR_ADDR     0x08003000     // SETTING sector start address 
#define SETTING_SECTOR_SIZE     0x1000         // SETTING sector size
#define APP_SECTOR_ADDR         0x08004000     // APP sector start address  
#define APP_SECTOR_SIZE         0xE000         // APP sector size
#define DOWNLOAD_SECTOR_ADDR    0x08012000     // Download sector start address
#define DOWNLOAD_SECTOR_SIZE    0xE000         // Download sector size   

2、程序跳转
Bootloader作为引导程序,最重要的工作之一就是通过内存跳转进入用户程序,下面这段代码可以跳转到任何一个内存地址。

uint8_t jump_app(uint32_t app_addr) 
{uint32_t jump_addr;jump_callback cb;if (((*(__IO uint32_t*)app_addr) & 0x2FFE0000 ) == 0x20000000) {  jump_addr = *(__IO uint32_t*) (app_addr + 4);  cb = (jump_callback)jump_addr;  __set_MSP(*(__IO uint32_t*)app_addr);  cb();return 1;} return 0;
}

3、处理函数
从setting区里面读取process状态值,然后进行对应的处理,如果需要升级则把download区的固件搬运到app区,然后再运行新APP,如果不需要升级则直接跳转到APP。

process = get_boot_state();
switch (process) 
{case START_PROGRAM:printf("start app...\r\n");delay_ms(50);if (!jump_app(APP_SECTOR_ADDR)) {printf("no program\r\n");delay_ms(1000);}printf("start app failed\r\n");break;case UPDATE_PROGRAM:printf("update app program...\r\n");app_addr = APP_SECTOR_ADDR;down_addr = DOWNLOAD_SECTOR_ADDR;printf("app addr: 0x%08X \r\n", app_addr);printf("down addr: 0x%08X \r\n", down_addr);printf("erase mcu flash...\r\n");mcu_flash_erase(app_addr, APP_ERASE_SECTORS);  printf("mcu flash erase success\r\n");printf("write mcu flash...\r\n");// memset(down_buf, 0, sizeof(down_buf));for (i = 0; i < APP_ERASE_SECTORS * 8; i++){mcu_flash_read(down_addr, &down_buf[0], 128);delay_ms(5);mcu_flash_write(app_addr, &down_buf[0], 128);delay_ms(5);down_addr += 128;app_addr += 128;}printf("mcu flash write success\r\n");set_boot_state(UPDATE_SUCCESS);break;case UPDATE_SUCCESS:printf("update success\r\n");boot_state = UPDATE_SUCCESS_STATE;write_setting_boot_state(boot_state);set_boot_state(START_PROGRAM);break;default:break;
}

完整代码下载地址:https://download.csdn.net/download/ShenZhen_zixian/87462312

4 烧录下载配置

我们的Bootloader做好以后需要烧录到MCU里面,可以直接用Keil uVison来下载,也可以用J-Flash或者其他,这个都没关系,但是要注意内存的分配,要把固件烧到对应的内存地址上。
我这里做出来的bootloader bin只有8K,不过为了方便后续在这部分增加新功能,我实际分配了12K的空间,地址区间是0x08000000-0x08003000。

如果是用keil下载的话,需要注意flash的配置,具体如下:
请添加图片描述
请添加图片描述
如果是用J-Flash或者STlink的工具烧录的话注意烧录的起始地址是0x08000000就好了。

5 运行测试

注:这里我还没讲解App部分代码,你们只看Bootloader部分的log就好了,不影响的,也可以下载完整的代码实际去跑一下。
不需要升级时直接跳转到App区,如下图:
请添加图片描述

需要升级时先从download区搬运新固件到app区,然后再跳转到App区,如下图:
请添加图片描述

结束语

好了,关于自制BootLoader的介绍就讲到这里,本文只是提供一个思路,不是唯一的方法,关键还是看你自己实际的需求。
还有App那部分这里没详细讲,后续我会专门写一篇关于App部分的博客,到时候合并到一起就比较清晰了。或者你也可以下载完整的源码自己去跑一下,下面的源码我把BootLoader和APP都上传了。

完整代码下载地址:https://download.csdn.net/download/ShenZhen_zixian/87462312

如果你有什么问题或者有更好的方法,欢迎在评论区留言。

相关文章:

STM32 OTA应用开发——自制BootLoader

STM32 OTA应用开发——自制BootLoader 目录STM32 OTA应用开发——自制BootLoader前言1 环境搭建2 BootLoader工作原理以及常见分区介绍3 BootLoader的制作4 烧录下载配置5 运行测试结束语前言 什么是OTA&#xff1f; 百度百科&#xff1a;空中下载技术&#xff08;Over-the-Ai…...

时域和频域的简单理解

目录文章背景结论举例说明说回频域连续或离散总结文章背景 时域和频域在傅里叶变换和拉普拉斯变换&#xff0c;z变换中经常提到的高频词。本文的重点就是想说明怎么理解 “频域” 这个名词。 结论 频域就是一个信号 所有组成频率的取值范围的集合 举例说明 以大家从中小学开…...

华为OD机试 - 第 K 个最小码值的字母 | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...

离散数学笔记_第一章:逻辑和证明(1)

1.1命题逻辑1.1.1 命题 1.1.2 逻辑运算符 定义1&#xff1a; 否定联结词定义2&#xff1a; 合取联结词定义3&#xff1a; 析取联结词定义4&#xff1a; 异或联结词1.1.3 条件语句 定义5&#xff1a; 条件语句定义6&#xff1a; 双条件语句1.1.1 命题 1.命题&#xff1a;是…...

Rust FFI 与C语言互相调用

参考 https://cloud.tencent.com/developer/article/2077534 https://github.com/shepmaster/rust-ffi-omnibus cbindgen 简介 二进制方式构建 $ cargo install cbindgen //默认构建C头文件 C语言需要 --lang C $ cd /path/to/my/project && cbindgen . -o target/…...

从全局变量寻找到Tomcat回显方式

前言 对于回显的获取主要是在ApplicationFilterChain类的lastServicedRequest / lastServicedResponse两个属性&#xff0c;是使用的ThreadLocal进行修饰的&#xff0c;并且&#xff0c;在执行请求的过程中&#xff0c;通过反射修改属性值&#xff0c;能够记录下当前线程的req…...

Tapdata Connector 实用指南:数据入仓场景之数据实时同步到 BigQuery

【前言】作为中国的 “Fivetran/Airbyte”, Tapdata 是一个以低延迟数据移动为核心优势构建的现代数据平台&#xff0c;内置 60 数据连接器&#xff0c;拥有稳定的实时采集和传输能力、秒级响应的数据实时计算能力、稳定易用的数据实时服务能力&#xff0c;以及低代码可视化操作…...

关于机器人状态估计(12)-VIO/VSLAM的稀疏与稠密

VIO三相性与世界观室内ALL IN ONE 首先以此链接先对近期工作的视频做个正经的引流&#xff0c;完成得这么好的效果&#xff0c;仅仅是因为知乎限流1分钟以内的视频&#xff0c;导致整个浏览量不到300&#xff0c;让人非常不爽。 这套系统已经完成了&#xff0c;很快将正式发布…...

Python每日一练(20230220)

目录 1. 存在重复元素 II 2. 按要求实现程序功能 3. 分割链表 附录 链表 1. 存在重复元素 II 给定一个整数数组和一个整数 k&#xff0c;判断数组中是否存在两个不同的索引 i 和 j&#xff0c;使得 nums [i] nums [j]&#xff0c;并且 i 和 j 的差的 绝对值 至多为 k。 …...

技术总监的“技术提升”

技术负责人的能力要求是什么?成本中心技术负责人最重要的工作是让其他CXO理解、认可并且支持技术部的工作&#xff0c;否则作为成本部门&#xff0c;在公司的地位会很低。技术创新光是让其他部门理解还不行&#xff0c;技术还需要创造价值&#xff0c;所以需要做技术创新。上面…...

kettle安装部署_简单认识_Spoon勺子界面---大数据之kettle工作笔记002

然后我们来看一下这个kettle的安装,很简单,下载解压就可以了 上面的地址是官网很烂 下面的地址好一些 这个是官网可以看到很慢,很不友好 这个是下面那个地址,可以看到 最新的是9.0了,一般都用 一般都用8.2 这里下载这个就可以了 下载以后可以看到有个pdi...

第三章 Kafka生产问题总结及性能优化实践

第三章 Kafka生产问题总结及性能优化实践 1、线上环境规划 JVM参数设置 kafka 是 scala 语言开发&#xff0c;运行在 JVM 上&#xff0c;需要对 JVM 参数合理设置&#xff0c;参看 JVM 调优专题 修改 bin/kafka-start-server.sh 中的 JVM 设置&#xff0c;假设机器是 32G 内…...

Comparable和Comparator的区别

一、概述 Comparable和Comparator都是用来实现比较的&#xff0c;一般用于集合中元素的比较 基本包装类型&#xff0c;Integer、Long以及String都实现了Comparable接口&#xff0c;该接口的排序逻辑必须写在比较对象中&#xff0c;所以又叫自然排序 我们一般集合排序使用的Col…...

全15万字丨PyTorch 深度学习实践、基础知识体系全集;忘记时,请时常回顾。

✨ ✨我们抬头便看到星光&#xff0c;星星却穿越了万年. ✨ ✨ &#x1f3af;作者主页&#xff1a;追光者♂ &#x1f338;个人简介&#xff1a;在读计算机专业硕士研究生、CSDN-人工智能领域新星创作者&#x1f3c6;、2022年度博客之星人工智能领域TOP4&#x1f31f;、阿里云…...

简洁易用的记账小程序——微点记账

背景 由于每个月的信用卡账单太过吓人&#xff0c;记性也不是特别的好&#xff0c;加上微信支付宝账单中有些明细不是很明确。比如在京东花销的明细不会记录用户购买了什么&#xff0c;只会记录那个通道支出的。所以&#xff0c;才会有了想自己开发一款记账小程序&#xff0c;…...

Windows平台上达梦数据库的ODBC安装与配置

文章目录概述安装包准备安装ODBC驱动配置ODBC数据源概述 最近很多公司都在响应信创&#xff0c;需要切换到国产数据库&#xff0c;然而很多数据库的一些基础组件的使用都没有一个很明确的官方文档。为了避免更多的人踩坑&#xff0c;本人将踩过的坑总结成博文&#xff0c;分享…...

哈希表的介绍

1.哈希表的介绍 在哈希表中插入、删除或查找一个元素都只需要O(1)的时间&#xff0c;因此经常被用来优化时间效率。 在Java中&#xff0c;哈希表有两个对应的类型&#xff0c;即HashSet和HashMap。 2.HashSet的应用 若每个元素都只有一个值&#xff0c;则用HashSet&#xf…...

spring cloud gateway 实现redis动态路由及自动项目路由上报

前言 spring cloud gateway默认为内存存储策略&#xff0c;通过配置文件加载的方式生成路由定义信息 可以看到&#xff0c;RouteDefinitionRepository继承了两个父接口&#xff0c;分别为RouteDefinitionLocator和RouteDefinitionWriter&#xff0c;RouteDefinitionLocator定…...

c++函数对象(仿函数)、谓词、内建函数对象

1、函数对象 1.1 概念 重载函数调用操作符的类&#xff0c;这个类的对象就是函数对象&#xff0c;在使用这个函数对象对应使用重载的&#xff08;&#xff09;符号时&#xff0c;行为类似于函数调用&#xff0c;因此这个函数也叫仿函数。 注意&#xff1a;函数对象&#xff0…...

物联网对供应链管理的影响

物联网对于许多行业来说都是一项革命性技术&#xff0c;其应用领域涉及零售、交通、金融、医疗保健和能源等行业。物联网在供应链等流程中已经展示了其深度的潜力。管理、预测和监督应用程序有助于车队运输经理提高配送的运营效率&#xff0c;并增加决策的准确性。如今&#xf…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...