STM32实战之IAP代码升级

目录

1 IAP介绍  

2 内存分区

3 整体设计流程图

4 Boot Loader的代码编写

5 APP1代码编写

6 APP2代码编写

stm32内部flash操作相关函数


1 IAP介绍  

IAP(In Application Programming)即在应用编程, IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信接口对产品中的固件程序进行更新升级。通常实现 IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如 USB、 USART,蓝牙)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在 User Flash 中,当芯片上电后,首先是第一个项目代码开始运行,它作如下操作:

  1. 检查是否需要对第二部分代码进行更新;
  2. 如果不需要更新则转到第二部分代码执行;
  3. 如果需要更新则执行更新操作;
  4. 跳转到第二部分代码执行;

第一部分代码的烧入必须通过其它手段,如 JTAG 或 ISP;第二部分代码可以使用第一部分代码 IAP 功能烧入,也可以和第一部分代码一起烧入,以后需要程序更新时再通过第一部分 IAP代码更新。

我们将第一个项目代码称之为 Bootloader 程序,第二个项目代码称之为 APP(功能代码) 程序,他们存放在 STM32 FLASH 的不同地址范围,一般从最低地址区开始存放 Bootloader,紧跟其后的就是 APP 程序。这样我们就是要实现 3 个程序:Bootloader 和 APP1和APP2。

       我们先来看看 STM32 正常的程序运行流程:

       STM32 的内部闪存(FLASH)地址起始于 0x08000000,一般情况下,程序文件就从此地址开始写入。此外 STM32 是基于 Cortex-M3 内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是 0x08000004,当中断来临,STM32 的内部硬件机制会自动将 PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。

STM32 在复位后,先从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号①所示;在复位中断服务程序执行完之后,会跳转到我们的main 函数,如图标号②所示;而我们的 main 函数一般都是一个死循环,在 main 函数执行过程中,如果收到中断请求,此时 STM32 强制将 PC 指针指回中断向量表处,如图标号③所示;然后,根据中断源进入相应的中断服务程序,如图标号④所示;在执行完中断服务程序以后,程序再次返回 main 函数执行,如图标号⑤所示。

当加入 IAP 程序之后,程序运行流程如图:

加入 IAP 之后程序运行流程图中,STM32 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到 IAP 的 main 函数,如图标号①所示,在执行完 IAP 以后(即将新的 APP 代码写入 STM32的 FLASH,灰底部分。新程序的复位中断向量起始地址为 0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数,如图标号②和③所示,同样 main 函数为一个死循环,并且注意到此时 STM32 的 FLASH,在不同位置上,共有两个中断向量表。

在 main 函数执行过程中,如果 CPU 得到一个中断请求,PC 指针仍强制跳转到地址0X08000004 中断向量表处,而不是新程序的中断向量表,如图标号④所示;程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示;在执行完中断服务程序后,程序返回 main 函数继续运行,如图标号⑥所示。

通过以上两个过程的分析,我们知道 IAP 程序必须满足两个要求:

  1.  新程序必须在 IAP 程序之后的某个偏移量为 x 的地址开始;
  2. 必须将新程序的中断向量表相应的移动,移动的偏移量为 x;

2 内存分区

       我们写的代码最终都会被编译成二进制文件并保存在Flash中,那么我们就可以进一步对我们程序进行分区。STM32的闪存模块由:主存储器、信息块和闪存存储器接口寄存器等 3 部分组成。

1)主存储器,该部分用来存放代码和数据常数(如 const 类型的数据)。对于大容量产品,其被划分为 256 页,每页 2K 字节。注意,小容量和中容量产品则每页只有 1K 字节。从上图可以看出主存储器的起始地址就是0X08000000, B0、B1 都接 GND 的时候,就是从 0X08000000开始运行代码的。

2)信息块,该部分分为 2 个小部分,其中启动程序代码,是用来存储 ST 自带的启动程序,用于串口下载代码,当 B0 接 V3.3,B1 接 GND 的时候,运行的就是这部分代码。

3)闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。对主存储器和信息块的写入由内嵌的闪存编程/擦除控制器(FPEC)管理;编程与擦除的高电压由内部产生。

       那么我们分区就是主要对FLASH的主存储器进行分区,STM32F103ZE共512K的Flash大小,我们将它分成三个区,BootLoader区、App1区、App2区(备份区)具体划分如下表:

BootLoader区存放启动代码

App1区存放应用代码

App2区存放暂存的升级代码   0x08000000---0x08007FFFF  

区域

大小

地址范围

BootLoader

12K    0x3000

0x08000000-0x08002FFF

APP1

250K    0x3E800

0x08003000-0x080417FF

APP2(备份区域)

250K    0x3E800

0x08041800-0x0807FFFF

3 整体设计流程图

先执行BootLoader程序, 先去检查APP2区有没有程序,如果有程序就将App2区(备份区)的程序拷贝到App1区, 然后再跳转去执行App1的程序。

然后执行App1程序, 因为BootLoader和App1这两个程序的向量表不一样, 所以跳转到App1之后第一步是先去更改程序的向量表,然后再去执行其他的应用程序。

在应用程序里面会加入程序升级的部分,这部分主要工作是拿到升级程序,然后将他们放到App2区(备份区),以便下次启动的时候通过BootLoader更新App1的程序。流程图如下图所示:

4 Boot Loader的代码编写

       在BootLoader程序中,我们主要实现对APP2区域的中的标志检查,读取APP2内部的程序,写入APP1地址程序,代码执行跳转程序。

       具体的代码执行过程,我们参考示例代码来掌握,整个执行流程如下图所示:

5 APP1代码编写

       在整个APP代码的编写上,我们首先修改向量表, 因为本程序是由BootLoader跳转过来的, 不修改向量表后面会出现问题;需要在APP的基本功能上加入串口接收数据并保存到APP2(备份区)的功能代码。

       具体的代码执行过程,我们参考示例代码来掌握,整个执行流程如下图所示:

       在APP程序的编译时,我们需要修改地址属性,具体如下图所示:

  

6 APP2代码编写

       APP2的代码,理论上来说和APP1的代码除了基本功能不同外,在代码上级上的功能一样。只是APP2的代码,我们可以直接将编译后的二进制文件使用串口等方式发送(也可以无线远程发送,SD卡等方式存储)到芯片内部,并存储在APP2的地址区域内。事实上接收和存储的过程是运行的APP1的程序,然后将接收到的数据存放到APP2的地址区域内。

       APP2的编译地址和APP1保持一致,但是我们发送的文件并不是hex文件,而是编译后的bin文件,那如何生成bin文件呢?需要修改配置属性:

D:\Keil_v5\Arm\ARMCC\bin\fromelf.exe --bin -o .\Objects\weather.bin .\Objects\weather.axf

E:\keil\ARM\ARMCC\bin\fromelf.exe--bin -o .\Objects\test.bin .\Objects\test.axf

其中:D:\Keil_v5\Arm\ARMCC\bin\fromelf.exe 是一个keil自带的生成bin文件的工具绝对路径。

通过这一步设置,我们就可以在 MDK 编译成功之后,调用 fromelf.exe(注意,我的 MDK 是安装在 D盘文件夹下,如果你是安装在其他目录,请根据你自己的目录修改fromelf.exe 的路径),根据当前工程的 weather.axf(如果是其他的名字,请记住修改,这个文件存放在 Objects 目录下面,格式为 xxx.axf),生成一个 RTC.bin 的文件。并存放在 axf 文件相同的目录下,即工程的 Objects 文件夹里面。在得到.bin 文件之后,我们只需要将这个 bin 文件传送给单片机,即可执行 IAP 升级。(我们也可以将bin文件无线发送,存放在SD卡内,存放在外部FLASH内等等方式进行代码升级,其中无线发送的形式叫OTA)。

       我们把APP2生成的bin文件,通过串口,发送到APP1的运行设备上,就会自动的保存APP2的代码数据到对应的Flash地址下,那么按下复位按键后(也可以软件复位),再次运行bootloader代码,就会加载APP2的数据到APP1的地址下,并运行新的程序。

stm32内部flash操作相关函数

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{return *(vu16*)faddr; 
}//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void STMFLASH_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)   
{ 			 		 u16 i;for(i=0; i<NumToWrite; i++){FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);WriteAddr += 2;//地址增加2.}  
} //从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)   	
{u16 i;for(i=0; i<NumToRead; i++){pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.ReadAddr += 2;//偏移2个字节.	}
}//startAddr地址必须是2K的整数倍
//numToErase 要擦除的内存大小,必须是2K的整数倍
uint8_t STMFLASH_Erase(u32 startAddr, u32 eraseSize) 
{uint16_t i=0;uint16_t len = eraseSize/STM_SECTOR_SIZE;if(startAddr<STM32_FLASH_BASE||(startAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return -1;//非法地址if((startAddr % STM_SECTOR_SIZE))return -2;//非法地址FLASH_Unlock();//解锁for(i=0; i<len; i++) {FLASH_ErasePage(startAddr+i*STM_SECTOR_SIZE);//擦除这个扇区}FLASH_Lock();//上锁	return 0;
}//半字数据写入
void STMFLASH_WriteHalfWord(u32 startAddr, u16 data)
{FLASH_Unlock();						//解锁FLASH_ProgramHalfWord(startAddr, data);FLASH_Lock();//上锁
}

这段代码是针对STM32单片机的FLASH操作的函数实现。主要包括读取指定地址的半字数据、不检查的写入数据、从指定地址开始读出指定长度的数据、擦除指定地址范围内的FLASH数据以及半字数据的写入。

具体分析如下:

  1. ​STMFLASH_ReadHalfWord​​函数用于读取指定地址的半字(16位数据),通过将地址转换为指针,然后读取指针对应的数据。
  2. ​STMFLASH_Write_NoCheck​​函数用于不进行检查的写入数据,通过循环将数据逐个写入指定地址,并递增地址。
  3. ​STMFLASH_Read​​函数用于从指定地址开始读出指定长度的数据,通过循环将每个地址对应的半字数据读取到指定的数据缓冲区中。
  4. ​STMFLASH_Erase​​函数用于擦除指定地址范围内的FLASH数据,先判断地址的合法性,然后对每个扇区进行擦除操作。
  5. ​STMFLASH_WriteHalfWord​​函数用于将半字数据写入指定地址,先解锁FLASH,然后进行半字数据的写入,最后上锁FLASH。

这段代码主要实现了对STM32单片机的FLASH进行读取、写入和擦除操作的功能。可以通过调用这些函数来实现对FLASH的数据存储和擦除操作。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决IDEA 不能正确识别系统环境变量的问题

问题描述 本人laptop 上的是设置了GOOGLE_APPLICATION_CREDENTIALS 这个环境变量的&#xff0c; 正常java or python 的程序能基于这个环境变量使用 某个gcp service account 去访问GCP的资源 [gatemanmanjaro-x13 ~]$ env | grep -i google GOOGLE_APPLICATION_CREDENTIALS/…

vue实现H5拖拽可视化编辑器

一款专注可视化平台工具&#xff0c;功能强大&#xff0c;高可扩展的HTML5可视化编辑器&#xff0c;致力于提供一套简单易用、高效创新、无限可能的解决方案。技术栈采用vue和typescript开发, 专注研发创新工具。 <template><div:style"style":class"…

云原生机器学习平台cube-studio开源项目及代码简要介绍

1. cube-studio介绍 云原生机器学习平台cube-studio介绍&#xff1a;https://juejin.cn/column/7084516480871563272 cube-studio是开源的云原生机器学习平台&#xff0c;目前包含特征平台&#xff0c;支持在/离线特征&#xff1b;数据源管理&#xff0c;支持结构数据和媒体标…

我在 VSCode 插件里接入了 ChatGPT,解决了Bug无法定位的难题

作为一名软件开发者&#xff0c;我时常面临着代码中Bug的定位和解决问题。这个过程往往既费时又充满挑战。然而&#xff0c;最近我在我的VSCode插件中接入了ChatGPT&#xff0c;这个决定彻底改变了我处理Bug的方式。 Bug&#xff1a;开发者的噩梦 在开发过程中&#xff0c;遇…

抖音详情API:从零开始构建抖音应用

随着短视频的兴起&#xff0c;抖音已经成为了一个全球范围内的热门平台。对于开发人员而言&#xff0c;利用抖音详情API从零开始构建抖音应用具有巨大的潜力和机会。本文将为你提供从零开始构建抖音应用的指南&#xff0c;包括开发环境搭建、API请求格式、用户认证等关键环节&a…

Stable Diffusion WebUI制作光影文字效果

在huggingface上下载control_v1p_sd15_brightness模型。 将模型放在stable-diffusion-webui\extensions\sd-webui-controlnet\models目录下。 SD参数配置 正向提示词&#xff1a; city,Building,tall building,Neon Light, gentle light shines through, anime style, paint…

图像处理-周期噪声

周期噪声 对于具有周期性的噪声被称为周期噪声&#xff0c;其中周期噪声在频率域会出现关于中心对称的性质&#xff0c;如下图所示 带阻滤波器 为了消除周期性噪声&#xff0c;由此设计了几种常见的滤波器&#xff0c;其中 W W W表示带阻滤波器的带宽 理想带阻滤波器 H ( u …

Linux中安装了openjdk后jps command not found

一、问题场景 在Linux中用yum安装了openjdk-17&#xff0c;也在.bashrc中配置了环境变量JAVA_HOME以及bin目录的PATH。 但是在运行jps命令时依然报错找不到命令 二、原因分析 进入到$JAVA_HOME/bin目录查看&#xff0c;发现只有寥寥几个命令&#xff0c;压根没有jps命令&…

深入解析 Flink CDC 增量快照读取机制

一、Flink-CDC 1.x 痛点 Flink CDC 1.x 使用 Debezium 引擎集成来实现数据采集&#xff0c;支持全量加增量模式&#xff0c;确保数据的一致性。然而&#xff0c;这种集成存在一些痛点需要注意&#xff1a; 一致性通过加锁保证&#xff1a;在保证数据一致性时&#xff0c;Debez…

【日志系列】什么是分布式日志系统?

✔️什么是分布式日志系统&#xff1f; 现在&#xff0c;很多应用都是集群部署的&#xff0c;一次请求会因为负载均衡而被路由到不同的服务器上面&#xff0c;这就导致一个应用的日志会分散在不同的服务器上面。 当我们要向通过日志做数据分析&#xff0c;问题排查的时候&#…

再见2023,你好2024

再见2023&#xff0c;你好2024 生活1月 悲伤与治愈2~4月 运动与偏爱5月 体验与美食6月 婚礼与热爱7~8月 就医与别离9~11月 陪伴与暖房12月 体验&新生 运动追剧读书总结 生活 生活是一个修罗场&#xff0c;来世间一场&#xff0c;要经历丰腴有趣的人生。去体验各种滋味&…

【c++】

1.定义自己的命名空间myspace&#xff0c;并在myspace中定义一个字符 #include <iostream> #include <cstring> //<><string.h> #include <cstdio> using namespace std; //3.定义自己的命名空间myspace&#xff0c;并在myspace中定义一个字符…

【LeetCode每日一题】1154. 一年中的第几天(直接计算+调用库函数)

2023-12-31 文章目录 [1154. 一年中的第几天](https://leetcode.cn/problems/day-of-the-year/)方法一&#xff1a;直接计算思路&#xff1a; 方法二&#xff1a;调用库函数思路 1154. 一年中的第几天 方法一&#xff1a;直接计算 思路&#xff1a; 1.根据所给的字符串&#…

HTML的学习记录

<br /> 标签在 HTML 页面中创换行符。 <hr /> 标签在 HTML 页面中创建水平线。 段落是通过 <p> 标签定义的。 浏览器会自动地在段落的前后添加空行。&#xff08;<p> 是块级元素&#xff09; 文本格式 <b>This text is bold</b>字体加粗 …

win11出现安全中心空白和IT管理员已限制对某些区域的访问(不一样的解决方式),真实的个人经历,并且解决经过

1、个人的产生问题的经历 2023年12月22日&#xff0c;由于我买了一块电脑的固态硬盘1T&#xff0c;想要扩容&#xff0c;原来电脑自带512G(由于个人是一个程序员&#xff0c;导致512G实在太古鸡肋)装好以后&#xff0c;想要重装一下系统&#xff0c;来个大清理。结果不出意料&…

【ARMv8M Cortex-M33 系列 2.1 -- Cortex-M33 使用 .hex /.srec 文件介绍】

请阅读【嵌入式开发学习必备专栏 之Cortex-M33 专栏】 文章目录 HEX 文件介绍英特尔十六进制文件格式记录类型hex 示例Cortex-M 系列hex 文件的使用 hex 文件和srec 文件生成Motorola S-Record (srec) 格式 HEX 文件介绍 .hex 文件通常用于微控制器编程&#xff0c;包括 ARM C…

3DV 2024 Oral | SlimmeRF:可动态压缩辐射场,实现模型大小和建模精度的灵活权衡

目前大多数NeRF模型要么通过使用大型模型来实现高精度&#xff0c;要么通过牺牲精度来节省内存资源。这使得任何单一模型的适用范围受到局限&#xff0c;因为高精度模型可能无法适应低内存设备&#xff0c;而内存高效模型可能无法满足高质量要求。为此&#xff0c;本文研究者提…

SpringBoot发布项目到docker

Dockerfile FROM openjdk:11 # 作者 MAINTAINER chenxiaodong<2774398338qq.com># 安装 vim # RUN yum -y install vim# 环境变量 # 进入容器后的默认工作目录 ENV WORKPATH /usr/local/webapp ENV EXECFILE Docker2Application-0.0.1-SNAPSHOT.jarRUN mkdir -p $WORKPA…

【Java开发岗面试】八股文—数据库MySQLRedis

声明&#xff1a; 背景&#xff1a;本人为24届双非硕校招生&#xff0c;已经完整经历了一次秋招&#xff0c;拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验&#xff08;主要是校招&#xff09;&#xff0c;包括我自己总结的八股文、算法、项目介绍、HR面和面试…