IAP升级——LWIP+FreeRTOS

最近在写项目的时候学到了有关IAP这方面的知识,所以决定分享出来。
我的开发环境是STM32H743+STM32CudeIDE
网上也有很多关于IAP的知识,我也找了很多,也踩了很多的坑。

IAP是什么

我先来说说什么是IAP以及问什么要用IAP。IAP是In Application Programming的首字母缩写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。对我来说,我需要使用IAP实现无线下载程序。
IAP是怎么实现的呢?通常我们在使用IAP的时候需要准备两份代码,将它们烧写到Flash的两个不同的地址上。通常芯片上电后运行的第一份代码我们叫做boot,第二份叫做app。boot需要做两件事情:跳转到app和擦写app部分的代码。通常我们在boot中完成应用代码的更新。想要完成代码的跳转就要先知道芯片的启动流程。

STM32的正常启动流程

STM32H7 的内部闪存(FLASH)地址起始于 0X08000000, 一般情况下,程序文件就从此地址开始写入。此外 STM32H743 是基于 Cortex-M7 内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动, 而这张“中断向量表”的起始地址是 0x08000004,当中断来临, STM32H743的内部硬件机制亦会自动将 PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。在下图中, STM32H743 在复位后,先从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号①所示;在复位中断服务程序执行完之后,会跳转到我们的 main 函数,如图标号②所示;而我们的 main 函数一般都是一个死循环,在 main 函数执行过程中,如果收到中断请求(发生了中断),此时 STM32H743 强制将 PC 指针指回中断向量表处,如图标号③所示;然后,根据中断源进入相应的中断服务程序,如图标号④所示;在执行完中断服务程序以后,程序再次返回 main 函数执行,如图标号⑤所示。
在这里插入图片描述

STM32 IAP启动流程

在下图所示流程中, STM32H743 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到 IAP 的 main 函数,如图标号①所示,此部分同图 60.1.1 一样;在执行完 IAP 以后(即将新的 APP 代码写入STM32H743 的FLASH,灰底部分。新程序的复位中断向量起始地址0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数, 如图标号②和③所示,同样 main 函数为一个死循环,并且注意到此时 STM32H743 的 FLASH,在不同位置上,共有两个中断向量表。在 main 函数执行过程中,如果 CPU 得到一个中断请求, PC 指针仍然会强制跳转到地址0X08000004 中断向量表处,而不是新程序的中断向量表,如图标号④所示;程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示;在执行完中断服务程序后,程序返回 main 函数继续运行,如图标号⑥所示。
在这里插入图片描述
对比两个流程可以知道我们需要一个新中断向量表,对于STM32来说它并不知道什么boot什么app,默认情况下对于所有的代码的中断向量表都是同一个地址:0x08000004。所以这需要我们手动进行修改。在文件system_stm32h7xx.c文件中有一个宏定义

/* 修改前 */ 
#define VECT_TAB_OFFSET  0x00000000UL

/* 修改后 */
#define VECT_TAB_OFFSET  0x00040000UL

或者直接在主函数中直接修改向量表的地址:

SCB->VTOR = FLASH_BANK1_BASE |  0x00040000UL

VECT_TAB_OFFSET为偏移地址,这个地址是根据自己个人需要而定的,最小为一个Flash扇区的大小。修改了中断表的地址后就应该来修改app代码的起始地址了。对于STM32来说,一般代码都是保存在Flash中的,默认情况是从0x08000000开始的,但如果要同时存在两份代码时,app的代码就得从另一个地址开始。具体的地址与中断表的一样,也是偏移0x00040000,也就是0x08040000。因为我使用的是STM32CudeIDE,所以需要修改链接文件STM32H743IITX_FLASH.ld。
修改前:在这里插入图片描述
修改后:
在这里插入图片描述
以上修改的部分均为app的部分,boot部分无需做这些修改。
以上准备工作已经完成,接下来就该写代码了。但是在写之前我们需要捋一捋流程。
在这里插入图片描述
以上为两份代码的总方向,我们还需要对IAP升级过程进行细化。app是我们的应用代码,所以芯片一般都在运行app的代码,当我们需要更新的时候需要向app下发boot联机和boot跳转命令,这样就能转到boot代码,接着擦除app代码,然后接受app升级程序数据并写入Flash,最后跳转到app。
在这里插入图片描述
首先是boot联机,boot联机就是一个擦除固件的过程。只要擦除了固件,然后跳转到boot,这样boot就检测不到固件,就不会跳转到app了。

IAP_StatusTypeDef IAP_Clear_Flag(void)
{
	uint32_t temp = APP_CONFIG_CLEAR_VALUE;
	STMFLASH_Write(APP_CONFIG_ADDR, &temp, 8);		// 清除固件
	return IAP_OK;
}

然后是boot跳转,因为我的app代码用了比较多的外设,我用了很多方法来写这部分的代码,结果都是跳转后跑飞。因为boot有些外设没用到,当外设中断来临的时候,发现boot没有这部分的代码,所以就会跑飞。所以要关闭这些外设,但又因为外设比较多,我也不想一个个来关,并且boot代码的起始地址和向量表并没有修改,所以我直接使用系统复位来实现boot跳转。

void APP_Jump_Boot()
{
	__set_FAULTMASK(1);        // 关闭总中断
	NVIC_SystemReset();		   // 使用复位代替boot跳转
}

对于app擦除和app升级程序数据我还没有测试过,等之后测试了在贴出来。接着是app跳转,在跳转之前要关闭外设时钟,将MSP指针指向app,再将PC指针指向app。

IAP_StatusTypeDef Boot_Jump_APP(void)
{
	if(tIAP_Updata.AppClearFlag == 1 && tIAP_Updata.AppUpdataFlag != 1)
	{
		return IAP_BUSY;
	}
	if(((*(__IO uint32_t*)FLASH_APP1_ADDR)&0x2FF00000)==0x24000000)	//检查栈顶地址是否合法.0x20000000是sram的起始地址,也是程序的栈顶地址
	{
		__HAL_RCC_ETH1MAC_CLK_DISABLE();
		__HAL_RCC_ETH1TX_CLK_DISABLE();
		__HAL_RCC_ETH1RX_CLK_DISABLE();
		__set_FAULTMASK(1);     // 关闭总中断
		HAL_SuspendTick();		// 挂起滴答定时器
		jump2app=(iapfun)*(__IO uint32_t*)(FLASH_APP1_ADDR+4);		//用户代码区第二个字为程序开始地址(复位地址)
		__set_MSP(*(__IO uint32_t*)FLASH_APP1_ADDR);    //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		jump2app();									//跳转到APP.
	}
	else
	{
		return IAP_ADD_ERROR;
	}
	return IAP_OK;
}

目前已经测试的只有boot联机、boot跳转和app跳转,一切正常。对了还有app联机,增加这个接口是方便用户的,如果用户下发了boot联机指令后又不想升级了,如果没有app联机的话,在重启之后又要重新下发旧的程序代码,然后再跳转app。有了app联机就可以直接下发app联机,这样boot在运行的时候就会自动跳转到app。app联机就是一个烧写固件的过程。

IAP_StatusTypeDef IAP_Set_Flag(void)
{
	uint32_t temp = APP_CONFIG_SET_VALUE;
	STMFLASH_Write(APP_CONFIG_ADDR, &temp, 8);		// 烧写固件
	return IAP_OK;
}

由于现在的代码里有公司项目代码,等以后写个新的IAP程序再贴出来。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: IAP是In-App Purchases(应用内购买)的缩写,是一种让用户在应用内购买虚拟物品、功能或者服务的功能。通过IAP,用户可以在应用程序内直接购买并支付虚拟商品,而不需要离开应用程序去购买。 Bootloader(引导程序)是计算机系统中的一个特殊程序,它在系统启动时最先被加载执行,用于初始化硬件、引导操作系统以及其他系统初始化工作。 App是Application(应用程序)的缩写,是一种在移动设备上安装和运行的应用软件。MFC是Microsoft Foundation Classes(微软基础类库)的缩写,是一个用于开发Windows应用程序的C++类库框架。 因此,"IAP bootloader app MFC" 的意思是,在使用MFC类库框架开发的Windows应用程序中,通过IAP功能实现引导程序的更新或者应用程序的更新。 一个典型的应用场景是,如果用户在使用某个应用程序时,开发者可以使用IAP功能提供新的引导程序或者应用程序更新的提醒,并提供购买选项供用户选择。一旦用户购买了更新,应用程序会通过IAP功能将更新的引导程序或者应用程序直接下载并进行安装,而不需要用户离开应用程序或者手动进行更新的安装操作。 这种方式可以让用户方便地在应用程序内更新或购买新的功能或虚拟物品,提升用户体验,也给开发者提供了一种增加收益和提供新功能的方式。 ### 回答2: IAP(In-App Purchases)是指在移动应用程序中进行购买和付款的功能。通过IAP,用户可以使用应用内购买来解锁额外的功能、获取虚拟物品或订阅服务等。在移动设备上,IAP是一种常见的商业模式,为开发者提供了一种方式来获取收入。 Bootloader是启动引导程序的意思,它负责在计算机或移动设备启动时加载操作系统。在移动设备上,Bootloader负责验证和加载操作系统,确保设备能够正确启动。Bootloader通常由设备制造商提供,且不可修改。 App是Application的缩写,指移动设备上的应用程序。MFC(Microsoft Foundation Classes)是一种C++应用程序框架,通常用于开发Microsoft Windows操作系统上的应用程序。 综合来看,IAP bootloader app mfc可以理解为在移动设备上使用MFC框架开发的应用程序,具备IAP功能,并且由设备制造商提供的启动引导程序负责加载该应用程序。这种应用程序可以通过IAP进行付款和购买,提供额外的功能、虚拟物品或订阅服务等。这样的应用程序可以为开发者提供收入,同时由于使用了MFC框架,开发者可以更快地开发出功能丰富的应用程序。总之,IAP bootloader app mfc结合了应用内购买功能、启动引导程序和MFC框架,为用户提供更好的应用体验,同时为开发者带来商业机会。 ### 回答3: IAP(In-App Purchase)是应用内购买的简写,指的是在移动应用程序中实现购买和下载额外功能或内容的机制。通过IAP,用户可以使用应用内部的货币或在线支付购买额外的功能、解锁附加内容或去除广告等。 Bootloader(引导加载程序)是指在计算机硬件上最先运行的程序,用于启动操作系统。它位于计算机的ROM芯片中,负责调用操作系统的内核,并加载操作系统至内存中,以便开始系统的正常运行。 App(应用程序)是指在移动设备上使用的软件程序,可以用于各种不同的用途,例如社交媒体、游戏、生产力工具等。移动应用程序通常是通过应用商店(如App Store、Google Play)进行下载和安装的。 MFC(Microsoft Foundation Classes)是微软提供的一套C++类库,用于开发基于Windows平台的图形用户界面(Graphical User Interface, GUI)应用程序。通过MFC,开发人员可以使用更高层次的抽象来简化Windows编程的过程,使开发更加高效和便捷。 综上所述,IAP是一种用于在移动应用中进行购买和下载额外功能或内容的机制。Bootloader是计算机硬件上最先运行的程序,用于启动操作系统。App是移动设备上使用的各种不同用途的软件程序。而MFC是微软提供的一套用于开发Windows平台GUI应用程序的类库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值