嵌入式技术之IAP,自从有了它老板再也不担心我的代码了!(中)

news2025/1/14 18:18:09

上篇文章我们一起学习了IAP的工作原理和IAP包含的3个重要功能:数据交互、数据存储和程序跳转

这3个重要功能称为“IAP的三板斧”,接下来我们看这三板斧具体完成哪些细节工作,如何实现这三板斧。请添加图片描述

1.数据交互

数据交互的功能是IAP核心功能之一,这个功能作用是使得设备和外部完成数据交互,数据交互的主要目的是获取新版本程序固件
在这里插入图片描述
IAP数据交互通常有两种方式:读取文件方式收发数据方式
在这里插入图片描述
读取文件方式指的是设备通过接口读取存储介质,获取程序固件实现更新。在这种方式下设备可以使用USB接口读取U盘,使用读卡器接口读取SD卡。

读取文件方式需要设备拥有文件系统功能(如FatFs文件系统),在这种方式下新版本程序固件以特定名称存入存储介质,存储介质插入设备的存储接口,设备检开始查询存储介质中的文件,只有当检测到特定名称的文件后,设备才会根据这个特定名称文件中的内容更新程序固件。这种方式只需要一个存储器即可(不需要外接其他设备),非常适合小批量脱机更新固件。
在这里插入图片描述
收发数据方式指的是设备通过通讯接口与外部通讯,获取程序固件实现更新。在这种方式下设备可以使用485接口或者以太网口与外部进行数据收发。

例如设备使用网口接收云端服务器的数据,服务器将新版本固件程序文件分为n个小的数据包发送给设备,设备接收到数据后,将数据一包一包保存起来,获取完整的程序固件后执行更新操作。这种方式适合无人化升级,也非常适合大批量在线更新固件。在这里插入图片描述
IAP数据交互使用收发数据方式的较为常见,接下来将详细的讲解一下这种方式。数据发送的本质是通讯,通讯功能由底层硬件和通讯协议共同实现。底层硬件可以是485接口,以太网口,蓝牙接口等。通讯中的数据必须按照一定的格式进行打包发送和数据解析,因此需要制定通讯协议,收发数据方式的重点就是制定通讯协议和实现通讯协议功能。
制定通讯协议有两种实现方式:使用通用协议和使用自定义协议

适合IAP通用通讯协议有 XModem ,YModem等协议,这些协议比较简单,非常适合传输小体积文件。使用通用协议的最大好处是不用特定去设计上位机软件,可以直接使用现成的软件工具实现文件传输,例如软件工具SecureCRTPortable可以支持XModem ,YModem等协议。
在这里插入图片描述
自定义的通讯协议指的是公司根据需求定制一套专用的通讯协议。这种方式定制的协议会非常适合设备,对设备的固件程序软件开发比较友好,但是这种方式需要上位机工程师来实现上位机的文件发送功能。

不管是使用通用的通讯协议,还是使用自定义通讯协议,作为通讯协议它们至少要包含以下通讯指令:
1、升级请求指令。在升级前,通过发送升级请求,让双方的设备进入准备状态。
2、数据包请求指令。指的是在升级过程中一包一包的收发固件数据。
3、结束请求指令。指的是完成固件数据发送后,通知设备数据已经发生完毕,设备收到通知后自行进行固件更新。
在这里插入图片描述

2.数据存储

数据存储是IAP核心功能之一,该功能主要作用是访问(读/写)设备内部的存储器,数据存储的主要目的是将新版本的app程序固件以数据的方式写入设备内部存储器的指定位置
在这里插入图片描述
数据存储的基本操作是读/写存储器,目前嵌入式设备内部的存储器通常为NOR-FLASH(片内FLASH),设备运行的固件存储在NOR-FLASH中,嵌入式设备可以直接运行NOR-FLASH中的指令(XIP)。片内FLAHS不仅可以存储固件还可以存储其他数据。因此数据存储的基本操作就是FLASH读写操作,FLASH读写有如下特点:
1、最小擦除单位为扇区。
2、必须是先擦除一个扇区,才能写入数据。扇区擦除后数据变为全1。
3、数据写操作只能将数据从1写为0,不能将数据从0写为1,如果该扇区数据已经被写入过了,则需要先擦除再写入。
下图是STM32系列MCU内部FLASH数据表:在这里插入图片描述
对FLASH区间进行规划是数据存储的一个重要部分,通常情况会将FLASH划分为以下几个区间
1、bootloader区间,存放bootloader程序固件。
2、app区间,存放需要运行app程序固件。
3、app备份区间,存放接收到的最新版本app程序固件。
4、更新标志位区间,存放更新标志位。在这里插入图片描述
其中bootloader区间,app区间和更新标志位区间是必须的,app备份区间可以根据实际情况来选择。

数据存储重要功能是将最新的app程序固件以数据的方式写入app区,写入数据到app区有两种方式
1、单包写入。设备接收到一个数据包后,按照一包数据写入app区存储器,就是每接收到一包数据就向app区写一包数据。通常情况下每一包数据长度是固定的(末尾包可以使用0XFF填充),此时需要计算好一个扇区包含多少个包,保证写入数据前扇区已经执行了擦除操作。
2、整包写入。设备能接收到一个数据包后,先将一包数据写入app备份区存储器,所有包接收完成后,再将app备份区数据按照扇区为单位写入app区间。
在这里插入图片描述
App数据完成写入后,需要在FLASH更新标志位区间写入一个标志位,bootloader可以读取标志位,判断是否需要执行app数据更新,因此需要完成升级完成标志位和检查升级标志位功能。为了提高稳定性标志为采用一串幻数作为标志为,例如当需要更新时标志位区间的前5个数据为0x13,0x14,0x17,0x55,0x20 ,不需要更新时标志位区间的前5个数据为0xFF,0xFF, 0xFF,0xFF ,0xFF。

3.跳转

IAP功能通常需要计两个项目代码:第一个项目代码不执行产品功能操作部分代码称为bootloader,第二个项目代码执行真正的产品功能,这部分代码称为app。bootloader和app这两个代码都同时烧录在Flash中,当芯片上电后,bootloader代码首先开始运行,随后跳转并执行app代码。

程序跳转是IAP的核心功能,程序跳转主要目的就是实现从bootloader程序跳转到APP程序,让APP程序运行。程序跳转也是IAP中最难理解的部分,需要将一步一步地揭开它神秘的面纱。
在这里插入图片描述

3.1 工程启动

每次复位后MCU都可以重头开始运行写入的固件(写入MCU内部FLASH)。实现这种现象的底层的运行逻辑主要有以下两方面原因:
1、MCU复位后,PC寄存器被强制赋予了一个初始值(通常情况下为0X00000000),因此MCU从地址0X00000000获取第一条指令。
2、在编译工程的时候,通常会工程配置代码下载的起始位置(通常是0X00000000),编译好的固件会携带起始位置信息。使用FLASH烧写工具下载固件的时候,烧写软件会根据起始位置信息,将固件从指定起始位置开始烧写到FLASH。
由于代码被下载到MCU内部FLASH的起始位置是0X00000000,而MCU复位后PC值也为0X00000000,因此每次复位后都可以重头开始运行写入MCU内部FLASH固件。MCU复位后启动流程如下图:
请添加图片描述
以STM32系列MCU为例,复位后先从地址 0x00000000 处取出值强制写入 MSP (MSP初始化),然后从地址 0x00000004 处取出值强制写入 PC ,然后从地址 0x00000004中数据所对应的地址处取指运行。
在这里插入图片描述
STM32系列MCU主闪存存储器是STM32内置的Flash(芯片Flash),正常的工作模式是将主内置的Flash地址0x08000000映射到0x00000000,这样代码启动之后就相当于从0x08000000开始。下图是一个由STM32系列工程的编译出的HEX文件,由图可知此HEX文件会从FLASH地址0x08000000处(程序的起始位置)开始烧写。
在这里插入图片描述

3.2 跳转原理

复位后PC值赋值为0X00000000,FLASH中固件的起始位置是0X00000000,这样就能保证每次复位后都可以重头开始运行固件。那么我们将固件代码B下载到0X0000Y000处,然后将PC值设置为0X0000Y000,是不是就跳转到固件代码B了
在这里插入图片描述
这种想法是完全正确的,事实上这也就是IAP跳转的工作原理:bootloader固件代码被下载到了0X00000000处,app固件代码被下载到0X0000Y000处,复位后bootloader先运行,随后bootloader代码中执行将PC至设置为0X0000Y000,跳转到app固件代码。

IAP跳转工作原理有两关键点:
1、修改工程代码的下载起始位置。
2、模拟复位流程,强制修改PC值完成跳转动作。

修改工程代码起始位置
通常情况下我们可以通过配置工程参数,实现修改工程代码的下载起始位置。以STM32系列MCU,使用KEIL开发环境为例。点开工程设置,将IROM1起始值改为0x8020000,此时工程就将代码下载的起始位置修改为0x8020000(MCU会将0x08020000映射到0x00020000)。
在这里插入图片描述
配置好工程IROM1起始值后编译工程,打开HEX文件就可以发现下载的起始位置为0x0802000。
在这里插入图片描述
修改PC值完成跳转

那么应该如何模拟复位流程完成跳转动作呢?STM32系列MCU复位后先从地址 0x00000000 处取出值强制写入 MSP (MSP初始化),然后从地址 0x00000004 处取出值强制写入 PC ,然后从地址 0x00000004中数据所对应的地址处取指运行。
因此模拟复位流程首先完成MSP初始化,然后强制写入 PC 值,模拟复位流程跳转代码如下:
在这里插入图片描述
由代码可知,程序首先将将0x00020004这个地址中的值强制转换成一个函数jump_to_application,然后0x00020000这个地址中的值赋值为MSP,最后执行jump_to_application函数,执行jump_to_application函数等价于跳转到地址0x00020004中数值对应的代码处执行。
在这里插入图片描述
对工程进行反汇编,分析运行指令执行流程,代码反汇编后如下图
在这里插入图片描述
核心汇编代码分析如下:

MOV      r0,#0x20000    ; 将立即数0x20000存入r0
LDM      r0,{r0,r4}		; 将地址0x20000中的数据存入r0,地址0x20004中的数据存入r4
BLX      r4			; 跳转至r4指向的地址,即地址0x20004中的数据指向的地址

汇编中的跳转指令(分支指令)可用来改变程序的执行流程或者调用子程序。在ARM架构中有两种方法可以实现程序流程跳转:
1、使用分支指令
2、向程序计数器PC写入目标地址值。
通过向程序计数器PC写入跳转地址可以实现4G(32位系统)的地址空间任意跳转,而使用分支指令是跳转空间受到限制,ARM架构中的跳转指令如下表:
在这里插入图片描述

3.3 构建实例

结合修改代码的下载起始位置和模拟复位流程修改PC值完成跳转这两个知识点,以STM32系列MCU为例构件一个IAP项目,这个项目包含两个工程bootloader工程和app工程。

工程代码的下载起始位置设置:bootloader工程使用默认配置0x08000000 ,app工程配置0x08020000 ,两个工程的配置如下图:
在这里插入图片描述
在bootloader工程中完成必需的功能后调用iap_jump_to_app函数,实现跳转到地址0x08020000中数值指向的位置执行代码,iap_jump_to_app函数如下:在这里插入图片描述
完成bootloader工程和app工程后,编译这两个工程,并将这两个工程下载到MCU中,我们会发现MCU先运行bootloader固件,然后再运行app固件,至此完成IAP项目构建。下载固件的时候一定要把Erase Full Chip这个选项去掉,不然的话下载第二个固件的时候会将整个FLASH擦除,因此第一个下载的固件(之前的固件)会被擦除掉
在这里插入图片描述

3.4 注意事项

上节构建了一个简单的IAP项目,在bootloader中设置了MSP和PC,MCU跳转到app固件,这个跳转过程实际上是模拟了一个复位流程。使得MCU开始执行app固件,在app固件前面通常会执行一段启动代码,启动代码会对RAM等外设执行初始化。

但是真正的复位,是由硬件发起的,硬件会将所有外设进行默认设置,通常情况是默认关闭所有外设,将GPIO设置为输入状态。app固件虽然执行了启动代码,但是所有外设的设备都是保存了bootloader固件中设置的状态,这些外设(如USART,ADC,TIMER等等)如果在bootloader中被配置和开启,会对app运行产生异常影响,因此在bootloader执行跳转前,需要将bootloader中用到的外设全部关闭。
在这里插入图片描述
在bootloader执行跳转前除了关闭外设之外,还需要对MCU的中断向量进行重映射,中断向量是什么?

中断向量是指计算机系统中由硬件产生的中断入口地址。中断是指计算机在执行程序的过程中,出现特殊请求时,计算机停止当前运行的程序,跳转到这些特殊请求的处理程序,处理结束后再返回到程序的中断处继续执行。在这里插入图片描述
在ARM架构处理器中,中断向量的大小是4个字节,其中存放的不是中断程服务程序的入口地址,而是是一条跳转指令。当中断发生时,硬件自动执行相应中断向量处的跳转代码,跳转到响应的中断服务程序的入口地址。
中断向量规定了中断服务的入口地址,这个入口地址由硬件决定,bootloader工程使用了默认配置,中断向量与bootloader工程代码是匹配的。跳转到app工程后中断向量并没有改变,这样在app工程中发生中断,此时程序会跳转到bootloader工程代码中!因此我们在app工程启动后需要重新设置中断向量,否则程序将会运行异常!

如果不对外设和中断向量进行相应的操作,会这么样?接下来使用一个反例来看看结果如何。
bootloader工程核心代码如下在这里插入图片描述
由bootloader代码可知:系统开启了滴答定时器,滴答定时器中断函数中输出了打印信息,配置完成后执行了跳转函数,跳转到了app固件中。

app工程核心代码如下在这里插入图片描述
由app代码可知:系统开启了滴答定时器,滴答定时器中断函数中输出了打印信息,配置完成后进入whlie(1)流程定时输出打印信息。
运行工程的结果如下图
在这里插入图片描述
根据串口信息可知app代码运行的时候,滴答定时器产生中断后跳转到了bootloader代码中,执行了bootloader代码中的滴答定时器产生中断函数

4.总结

本文讲解了IAP的3个重要功能:数据交互、数据存储和程序跳转。并构建了一个简单的IAP项目,同时说明了在设计IAP项目中的注意事项。下篇文章将详细的介绍如何完成IAP的功能代码,并构建一个完成的IAP项目。
在这里插入图片描述
创作不易希望朋友们点赞,转发,评论,关注!
您的点赞,转发,评论,关注将是我持续更新的动力!
CSDN:https://blog.csdn.net/li_man_man_man
今日头条:https://www.toutiao.com/article/7149576260891443724

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/117647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Gson解析JSON

1.介绍 Gson是Google提供的处理JSON数据的Java类库&#xff0c;主要用于转换Java对象和JSON对象。 2.依赖 <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <dependency><groupId>com.google.code.gson</groupId><artifac…

python协程--yield和yield from

字典为动词“to yield”给出了两个释义&#xff1a;产出和让步。对于 Python 生成器中的 yield 来说&#xff0c;这两个含义都成立。yield item 这行代码会产出一个值&#xff0c;提供给 next(...) 的调用方&#xff1b;此外&#xff0c;还会作出让步&#xff0c;暂停执行生成器…

Web应用怎样获取Access Token?

1.在联盟创建服务器应用 参考文档&#xff1a;开发准备 2.获取用户级Access Token 2.1 获取code 参考文档&#xff1a;接入华为帐号获取凭证 2.1.1 先按照跳转链接进行配置url https://oauth-login.cloud.huawei.com/oauth2/v3/authorize? response_typecode& acces…

docker(七)容器监控(CAdvisor+InfluxDB+Granfana)

docker可能会运行多个容器&#xff0c;一个宿主机上有多个容器时&#xff0c;需要监控容器的&#xff1a;CPU使用率&#xff0c;内存使用率&#xff0c;网络状态&#xff0c;磁盘空间等数据。 一、docker stats docker stats命令可以监控以下数据&#xff1a; 数据是实时的&…

FFmpeg简单使用:过滤器 ---- 视频过滤2

1. 简介 FFmpeg filter提供了很多⾳视频特效处理的功能&#xff0c;⽐如视频缩放、截取、翻转、叠加等。 其中定义了很多的filter&#xff0c;例如以下常⽤的⼀些filter。 scale&#xff1a;视频/图像的缩放 overlay&#xff1a;视频/图像的叠加 crop&#xff1a;视频/图像的裁…

新建unity项目

在此处点击新项目按钮&#xff0c;建立新的项目。 选择对应的项目模板和项目名称&#xff0c;位置。 项目新建会花费几分钟到十几分钟的时间。 新建完项目打开后就可以进入到unity引擎中。 新建项目会默认创建一个场景&#xff0c;场景保存在Assets--> Scenes中&#xff0c;…

服务器,只有“鞋盒”大小

上期,我们谈到了边缘端的远中近分类法,并介绍了戴尔科技集团最新发布的“远边缘”服务器PowerEdge XR4000。今天我们来继续说说这款服务器的奥秘。      服务器,只有“鞋盒”大小      PowerEdge XR4000代表了戴尔继续致力于边缘创新的承诺,它的大小只与鞋盒差不多,是P…

Java 集合有哪些内容?

今天我们就来简单的了解下java中的集合&#xff0c;有了解过得朋友都知道&#xff0c;也都用过&#xff0c;比如说做常用的List&#xff0c;还有Set、Map&#xff0c;而且像List和Set都是用于存储单列数据的集合&#xff0c;他们的父接口都是Conllection&#xff0c;List的特点…

hyperf中的缓存之CacheEvict

在开发中难免会遇到要批量删除一些缓存&#xff0c;hyperf的注解中提供了关于缓存的几个注解如下 Cacheable 生成缓存的&#xff0c;根据你的返回值生成缓存 参数($prefix, $value, $ttl, $listener, $offset, $group, $collect) CachePut 更新缓存 参数($prefix, $value, …

MS 训练笔记【1】:nnUNet

文章目录前言1. 安装2. 训练与测试2.1. 数据处理2.1.1. 整理数据路径2.1.2. 设置 nnFormer 读取文件的路径2.1.3. 数据集预处理2.2. 训练2.2.1. 训练代码2.2. 预测总结前言 nnUNet是德国癌症研究中心的工程师编写的框架&#xff0c;迄今为止依旧在维护和更新。本文主要记载 nn…

FBX模型

概览 fbx文件&#xff0c;一般是导出给unity使用的模型文件。 如下图所示&#xff0c;建立一个models目录&#xff0c;然后右击&#xff0c;选择 imoprt new asserts 即可导入这些文件。 展示如下&#xff0c;Mesh定义了形状。 铅笔也是同理&#xff0c;只不过铅笔有自己的贴图…

尚医通-前端列表(十一)

目录&#xff1a; &#xff08;1&#xff09;搭建前端环境 &#xff08;2&#xff09;目录结构和登录改造 &#xff08;3&#xff09;医院设置前端-列表 &#xff08;1&#xff09;搭建前端环境 vue-element-admin 简介 vue-element-admin是基于element-ui 的一套后台管理系…

计算机系统基础实验 - 数的机器级表示

实验1 数的机器级表示 实验序号&#xff1a;1 实验名称&#xff1a;数的机器级表示 适用专业&#xff1a;软件工程 学时数&#xff1a;2学时 一、实验目的 1.熟练掌握无符号整数的机器级表示 2.熟练掌握有符号整数的机器级表示 3.熟练掌握浮点数的机器级表示 二、实验要求 …

WORDPRESS WOOCOMMERCE购物网站安装AB跳转支付插件接口的教程

本文介绍在Wordpress Woocommerce购物系统上安装支付插件&#xff0c;并且对接《品牌出海AB跳转收单系统》的方法&#xff0c;以下是图文教程 注意本教程是采用Wordoress中文版本后台截取的图例&#xff0c;英文版本后台文字略有不同&#xff1b; 1、首先打开支付插件压缩包&…

反编译python 生成的exe源码

反编译python 生成的exe源码记录反编译exe工具使用 工具准备 – pyinstxtractor.py – uncompyle6 – sublime Text&#xff08;或者其他的二进制编辑工具&#xff09; 一、解包&#xff08;exe&#xff09; ①&#xff1a;先把下载的pyinstxtractor.py文件和需要进行反编译的…

π120M60代替ADuM2210SRIZ 双通道数字隔离器 电路简单速度快

π120M60代替ADuM2210SRIZ 双通道数字隔离器 电路简单速度快。具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&#xff0c;可实现 5.0kV rms 隔离耐压等级和 DC 到 10Mbps 信…

下载和安装MySQL官方提供的示例数据库(Employees)

一、前言 在此之前笔者写过一篇博客《你说精通MySQL其实很菜jī&#xff08;1&#xff09;&#xff1a;你不一定会的基本技巧或知识点&#xff08;值得一看&#xff09;》&#xff0c;本文内容是从那篇博客截取出来的。我们要学习MySQL相关的技术点&#xff0c;使用官方提供的测…

构造HTTP请求

构造HTTP请求一、浏览器自己构造二、通过 form 表单构造三、通过 ajax 构造一、浏览器自己构造 1&#xff09;地址栏里写URL&#xff0c;构造出GET请求 2&#xff09;点击a标签等&#xff0c;也会构造GET请求 3&#xff09;img、link、script也会构造GET请求 二、通过 form 表…

Java中的常用队列

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;Java中的常用队列 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪…

【Django】第二课 基于Django图书借阅管理网站平台

概念 本文在上一篇文章之上完成登录&#xff0c;图书显示&#xff0c;关键字搜索以及分页功能 登录功能实现 当用户在首页进行输入学生用户信息后&#xff0c;点击登录按钮发送请求给服务器&#xff0c;地址请求为: /toLogin/ urls.py path(toLogin/,views.toLogin), 将接…