【IAP】STM32和GD32的IAP原理分析、教程、资料整理


前言

这是我使用CSDN四年以来的第一篇贴子,也是第一次将自己所学的的内容整理发帖。此贴只写了我的个人见解,算是抛砖引玉,如果这篇帖子有谬误和讲解不清楚之处,请各位大神多多赐教,那么闲话少说,下面开始正文内容。

如果想弄明白IAP原理的请从第一章开始,如果只想知道ST官方例程如何使用的请从第三章直接开始。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是IAP?

IAP即为in-application programming,应用程序内编程。对于大多数基于闪存的系统,一个重要的要求是能够在最终产品中安装固件时进行更新。STM32微控制器可以运行用户特定的固件来对微控制器中嵌入的闪存执行IAP。
由于不限制通信接口协议等,只要能通过任意通信接口拿到新版固件包数据(bin文件),就能自己升级固件。
问题:个人感觉IAP的贴子略少,是因为在IOT工程中更常用OTA升级吗?但是对于没有联网的产品怎么办?

二、IAP执行原理(以STM32F10X为例)

2.1 STM32F10X的储存器映像

在了解IAP的真正执行原理之前,我们可以来看看STM32F10X的储存器映像,这更有利于我们了解单片机的内部,尤其是flash。
请添加图片描述

上图的最左侧就是STM32的整个储存,这个储存区的大小由STM32F10X系列芯片的内存大小而定,对于用户来说,可以操作的存储区包括Flash、SRAM和操作字。
因此从上图我们可以看出几点:
1.内部Flash是从0x800 0000开始,到0x801 FFFF结束,一共128kB
2.SRAM的开始地址为0x2000 0000(后文会讲为何关注这个)

2.2 正常上电的运行流程

在正常的程序结构下,STM32F10X Flash中存储的内如图:
请添加图片描述

可以看到分成栈顶地址、中断向量表、中断服务函数和主程序四个部分。
栈顶地址占4字节,即从0x0800 0000 到0x0800 0003 其中存储了栈顶地址的值,也就是SRAM的地址。
中断向量表起始字节为0x0800 0004。

正常上电后,若Boot引脚设置为从Flash读取程序,则程序执行顺序如下:
请添加图片描述

①、从Flash相对0地址(即STM32的0x0800 0000)开始执行,存储的是栈顶地址。再偏移4个字节找到中断向量表起始地址,即复位中断向量,存储着复位中断程序入口,跳转到复位中断程序入口执行复位中断服务函数Reset_Handle(void)。
②、复位中断服务函数Reset_Handle(void)执行完会跳转到main函数,main函数循环运行。
③、main函数死循环时,发生中断请求,然后PC指针会跳转到中断向量表的开头,即复位中断向量寻找对应的中断向量。
④、找到对应的中断向量后执行对应的中断服务函数xxx_Handler(void).
⑤、执行中断服务函数完成后,返回main函数循环运行。

我们可以在startup.s中找到使用汇编语言编写的相应中断向量表
在这里插入图片描述
从第61行开始,第一个是__initial_sp,初始化了栈堆;第二个就是Reset_Handler,执行了复位句柄。

复位句柄同样在startup.s中,Reset_Handler首先把systeminit函数放入R0中,随后执行Systeminit,初始化后就跳转main函数,开始执行主函数。:
在这里插入图片描述

Systeminit主要就是初始化各种时钟,包括内置RC外置晶振主PLL外设时钟等等杂七杂八的一些,比较重要的是最后几行:
在这里插入图片描述
第235行代码直接将中断向量表基址定位在了FLASH中(也就是之前我们提到的0x0800 0000,这里可以goto看看,在STM32F10X.h中给了宏定义),同时设置了中断向量表的偏移量。

2.3 加入IAP后的Bootloader运行流程

加入IAP后,Flash内部的分配情况如下:
在这里插入图片描述
可以看到,flash中存储了两块程序,同时存在了两个中断向量表。

上电后,程序执行顺序如下:

①、和无IAP一样,从Flash相对0地址即STM32的0x0800 0000地址开始执行,跳转到复位中断程序入口执行复位中断服务函数Reset_Handle(void),执行完毕后执行IAP的主程序。
②、执行完IAP主程序后,一般flash中会被写入新的APP程序,地址为0x0800 00004+N+M,然后IAP程序进行跳转(有要点),跳转至APP的中断向量表起始地址
③、APP的中断向量表程序执行,跳转至新的main函数循环执行。
思、当main函数执行过程中发生中断请求时,PC指针仍然会返回最初始的中断向量表0x800 0004处。
⑤、由于中断向量表地址强制偏移,PC指针跳转至新中断向量表的中断程序入口。
⑥、中断服务执行完毕后,返回main函数。

注:3、4、5其实不完全正确,在APP的Reset_Handle中(system_stm32f10x.c 235行)使用VECT_TAB_OFFSET重设了中断向量表的地址,也可以使用NVIC_SetVectorTable重设中断向量表地址,所以在APP的main函数中发生的中断其实并没有返回起始地址,而是返回了最新的中断向量表地址。

2.4 IAP过程的跳转(有要点)

通过上图的相关分析,我们就能够知道,IAP的跳转过程无非是将PC指针跳转至用户APP中断向量表的开头,但在这个过程中,必须要关闭所有中断,否则会让程序直接跑飞。

具体代码如下(示例):

    /* 检测用户代码是否已从"ApplicationAddress"写入 */
    if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)
    { 
      	__set_PRIMASK(1);											//屏蔽所有中断
			
		JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);	//设置跳转指针
			
		__disable_irq(); 											//关闭中断(空函数,自己写)
     
      	Jump_To_Application = (pFunction) JumpAddress; 				//设置跳转函数
      
      	__set_MSP(*(__IO uint32_t*) ApplicationAddress);			//初始化用户程序系统栈堆
      	
		NVIC_ClearPendingIRQ(USART2_IRQn)							//清除所有挂起中断(自己写)
			
		__set_PRIMASK(0);											//取消中断屏蔽
			
		Jump_To_Application();										//跳转至APP
    }

第一句:
我们判断中断向量表的首字节,也就是系统栈堆顶部的值是否在0x20000000-0x20002000之间。因为APP的启动文件最开始就是初始化栈堆空间,如果这个里的栈顶值正确,那么就说明应用程序已经下载,并且已经初始化完成了。

第二句:
由于在整个跳转过程中不允许中断发送,因此这里先屏蔽所有中断。

第三句:
在common.c文件的第34行定义了pFunction Jump_To_Application;
(ApplicationAddress + 4)即为0x0800 3004也就是中断向量表中的复位句柄。

第四句:
__disable_irq()在官方文件中是一个空函数,作用是关闭用到的中断,需要用户自己编写函数,用到什么中断就关闭什么。

第五句:
查看pFunction的定义,我们可以在common.h文件中找到
typedef void (pFunction)(void);
该函数声明了一个函数指针,加上typedef之后,pFunciton也只是类型void (
)(void)的一个别名。
所以Jump_To_Application = (pFunction) JumpAddress; 此时Jump_To_Application指向了复位函数所在的地址;

第六句:
设置了主函数的栈指针

第七、八句:
清除所有挂起的中断,同时取消屏蔽总中断

第九句:
跳转至用户程序,也就是将PC指针跳转至了APP中断向量表中的复位句柄处。

2.5 IAP过程的总结

根据上文的相关分析,其实IAP过程很简单。
对于我们编写IAP程序,或者说Bootloader来说,除了将APP下载入Flash中,最重要的就是关闭所有中断,通过函数指针的形式将PC指针跳转至APP的复位句柄处,那么就能够执行我们的APP程序。
对于APP程序来说,一方面其存储地址必须在IAP程序后,另一方面在程序开始时必须重定位中断向量表位置,不然进入任何中断都会使程序跑飞(亲测)


三、YModem协议

3.1 介绍

YModem协议是由XModem协议演变而来的,每包数据可以达到1024字节,支持128字节传输、1024字节传输和128、1024混合字节传输模式,是一个非常高效的文件传输协议。

3.2 握手过程

ST官方IAP例程中ymodem.h中的宏的定义如下:
在这里插入图片描述

根据YModem官方说明文档,其128字节数据传输模式传输1个文件的的完整握手过程如下:

在这里插入图片描述

(1)起始帧格式:

先由接收方发送一个字符‘C’
发送方接收到‘C’后,发送第一帧的数据包,内容为:

SOH 00 FF foo.c 3232 NULL[118] CRCH CRCL

	第一字节SOH:表示本数据包大小为128字节,如果为STX表示为1024字节
	第二字节00:数据包编号,第一包为00,第二包为01,依次累加,到FF后继续从00循环递增
	第三字节FF:编号的反码,编号00对应FF,01对应FE
	第四字节到最后两字节:若第1字节为SOH时有128字节,为STX时有1024字节,这部分为数据区。“foo.c”文件名,超级终端下,在文件名后
还有文件大小。官方dome也是因为使用了这个文件大小进行比对。在文件名和文件大小之后,如果不满128字节,以0补满,如图中NULL[118]。
	最后两字节:这里需要注意,只有数据部分参与了效CRC验,不包括头和编码部分。16位CRC效验,高字节在前,低字节在后。
	接收方收到第一帧数据包后,发送ACK正确应答。

(2)数据帧格式:

先由接收方发送一个字符‘C’
发送方接收到‘C’后,发送第二帧的数据包,内容为第二帧中的数据存放的是第一包文件名下的数据。

SOH 01 FE data[128] CRCH CRCL

如果数据不足128位,则剩余空间全部用0x1A填充

SOH 02 FC data[100] CPMEOF[28] CRCH CRCL

接收方收到数据后,发送一个ACK然后等待下一包数据传送完毕,继续ACK应答。直到所有数据传输完毕。

数据传输完毕后,发送方发EOT,第一次接收方以NAK应答,进行二次确认。
发送方收到NAK后,重发EOT,接收方第二次收到结束符,就以ACK应答。

(3)结束帧格式:

最后接收方再发送一个’C’,发送方在没有第二个文件要传输的情况下,需要发送结束帧:

SOH 3A C5 NUL[128] CRCH CRCL

YModem的结束帧与起始帧的数据格式相同,数据块大小为128字节,但是结束帧的数据块要全用空字符填充。

四、教程(以STM32F10X的官方IAP例程为例)

这里就直接以ST的官方例程为例,至于代码的相关分析请各位读者自己去做,否则只是C+V很难学到东西

4.1 Bootloader的写入

首先前往STM32的官网,下载STM32F10X的官方IAP Bootloader源码:

STM32F10x_AN2557_FW_V3.3.0。

下载后解压,打开:

STM32F10x_AN2557_FW_V3.3.0\Project\IAP\MDK-ARM\IAP

第一步:keil设置MCU内存大小

由于我使用的是STM32F103C8T6,为64K Flash的中内存版本,所以需要修改Flash宏。
点击魔术棒,切换到C/C++选项卡,将Preprocessor Symbols下的Define栏中改成STM32F10X_MD。
在这里插入图片描述
可以看到,在common.h中对不同规格的Flash做了处理。
在这里插入图片描述

第二步:限制Bootloader位置、程序的大小

限制Keil在烧写Bootloader时的Flash大小,这里限制为0x2FFF,12kB,所以APP层的代码应该在0x0800 3000的位置。
在这里插入图片描述

如上,我们便完成了对官方Bootloader的设置,在清空MCU以后,就可以正常地将Bootloader烧写入芯片了。

4.2 APP程序的烧写

我们已经把Bootloader烧写入了芯片当中,现在应该将APP烧写入Flash当中,随便选择自己的一个程序或者例程作为APP。

第一步:keil设置APP的烧录位置

设置Keil在烧写APP时的起始位置,一定不能覆盖掉Bootloader程序。故写入位置应该从0x0800 3000开始。
在这里插入图片描述

第二步:APP程序中重设中断向量表地址

重设中断向量表有两种方式。

一种是在APP的Reset_Handle中(system_stm32f10x.c 235行)给VECT_TAB_OFFSET赋值,重设中断向量表的地址
另一种是,在主函数开头使用NVIC_SetVectorTable重设中断向量表地址

在这里插入图片描述
然后就可以生成bin文件,通过ymodem的方式进行烧写。
官方的Bootloader中采用的协议为YModem,仅用于数据传输和校验,如果读者有更好的协议,也可以替换,相关内容下章会讲一点。

4.3 使用Secure CRT查看(YModem协议)

如图,建立好SecureCRT的通道,选择串口,波特率要和Bootloader中设置的一致。
在这里插入图片描述

连接完成后给单片机上电,芯片自动读取Bootloader程序,显示出简单的交互菜单

在这里插入图片描述
对应分别为:烧写程序至单片机flash,从单片机flash中读出程序,执行程序。
按下1,出现如下提示:
在这里插入图片描述

然后选择以Ymodem发送文件。
在这里插入图片描述

选择APP编译完成后留下的bin文件,点击ok进行烧录
在这里插入图片描述

显示正在烧录

在这里插入图片描述

烧录完成,按下3,程序开始执行
在这里插入图片描述

问题:不知为何,有时候选择2上传MCU内Flash代码会连接不上单片机,换了新版本的SecureCRT还是没用,使用超级终端能够进入接收,但完成不了,估计是官方例程里YModem发送代码有问题,不过我们暂时只用来更新APP,以后再来解决也没关系。

五、实战(GD32F303CCT6)

基本原理已经搞懂了,那么下面我们来进行实操,我使用了GD32F303CCT6作为主控,这是兆易电子的一款基于Cortex m4的MCU,同样支持IAP功能,但在官方库函数以及单片机底层寄存器设置上与STM32F103稍微有些区别,下文我们将从datasheet开始分析。

根据GD32F303XX_Datasheet,我们可以看到GD32的内存分布
在这里插入图片描述
可以看到,GD32的主Flash地址仍然是从0x0800 0000开始,并且其SRAM也是从0x2000 0000开始,这与stm32一致。
再打开GD32的启动文件startup_gd32f30x_hd.s,可以确认,中断向量表的第二位是复位句柄:
在这里插入图片描述

此外,兆易官方实际上提供了IAP的相关跳转程序的说明,这份文档我也一并放在了文件里

在这里插入图片描述

因为flash的地址与STM32相同,并且都是基于ARM内核,CortexM3、M4的底层汇编代码几乎一致,所以我就放心大胆地把STM32的IAP程序移植到GD32上。具体的做法就只是程序的拷贝和修改,和上文第三章提到的基本相同,只不过因为GD32的官方库中函数的命名还有对寄存器的相关设置与STM32有些出入,稍微做了点修改。总而言之,哪里报错哪里改就好了。
我的程序直接移植了STM官方的IAP例程,并且还在其中加入了RS485通信的使能和失能,如果读者只需要进行串口通信,请注意将这部分代码删除或修改。

六、总结

以上就是我个人对IAP的一点总结和经验,参考了CSDN上不少大佬的贴子,连接我都放在参考资料中了。整个文章写到最后也只是列出了些知识点,提供了一份比较全的资料,算是对现有资源的一个整理归纳,因此可能会存在一些讲解不明晰或者有错误的地方,希望各位读者能够及时给我指出!

参考资料

STM32

https://blog.csdn.net/qq_33559992/article/details/103027196
——STM32 IAP Ymodem——暖暖的纠结

https://blog.csdn.net/gin_love/article/details/82020348
——STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现——Tweedle Dee

https://blog.csdn.net/yx_l128125/article/details/12992773
——STM32 IAP 在线升级详解——yx_l128125

https://blog.csdn.net/Eric__zh/article/details/108705571
——关于STM32的IAP超详细图文解说——Eric__zh

https://blog.csdn.net/CSDN1344789841/article/details/114902609
——ARM cortex-m IAP升级小记——csdn1344789841

GD32

https://blog.csdn.net/freemote/article/details/122220121
——【开源】串口YMODEM实现IAP程序升级(附工程源码)——freemote

资源连接

度盘链接:/s/1ljT18rI4tmrUEW0cA-eWmQ
提取码:uda9
密码:aletheia

  • 36
    点赞
  • 174
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: IAP是指In-Application Programming,是一种在嵌入式系统中通过软件更新固件的方法。STM32是意法半导体公司推出的一系列32位微控制器产品,具有高性能和低功耗的特点。GPRS是无线通信中的一种技术,全称为General Packet Radio Service,可以实现移动网络数据的传输。 当我们说到IAP STM32 GPRS时,一般指的是在STM32嵌入式系统中通过GPRS技术进行在线固件更新。通过IAP技术,我们可以通过GPRS无线通信方式将新的固件包传输到STM32芯片中,实现系统的在线更新。 利用GPRS技术进行在线固件更新具有以下优势:首先,GPRS网络广泛覆盖,可以在全球范围内进行数据传输;其次,使用GPRS无线通信可以避免物理连接的限制,方便快捷;此外,通过在线更新可以及时修复系统中的漏洞或添加新功能,提升系统的灵活性和可用性。 然而,在进行IAP STM32 GPRS时也需要注意一些问题:首先,固件更新的过程中需要保证数据的安全性,防止传输过程中出现数据丢失或篡改;同时,还需要考虑数据传输的稳定性,确保在网络环境不稳定的情况下也能成功地进行固件更新。 总之,基于IAP STM32 GPRS的在线固件更新技术在嵌入式系统中具有广泛的应用前景,可以为系统提供更好的可维护性和可升级性,同时也需要注意数据的安全与稳定性。 ### 回答2: IAP(In Application Programming)是一种能够在嵌入式设备中进行应用程序更新的技术。通常,当使用IAP进行固件升级时,固件可以通过gprs(General Packet Radio Service)进行远程更新。 STM32是意法半导体的一系列微控制器产品系列,具有高性能和低功耗的特点。作为一种强大的嵌入式设备,STM32具备了丰富的外设接口,如CAN(Controller Area Network)、SPI(Serial Peripheral Interface)、I2C(Inter-Integrated Circuit)以及UART(Universal Asynchronous Receiver/Transmitter)等。 GPRS是一种移动通信技术,它允许智能设备通过无线网络连接到互联网。GPRS通过使用IP协议在无线网络中传输数据,为嵌入式设备提供了连接互联网的能力。在使用GPRS进行远程固件更新过程中,STM32可以通过GPRS将新的固件从服务器下载到设备中,并进行更新。 通过IAP和GPRS技术的结合,嵌入式设备可以实现无线远程固件更新,从而可以及时修复漏洞、添加新功能或进行性能优化。这对于智能设备制造商和开发人员来说是非常重要和有益的,因为他们可以通过这种方式在设备部署后仍然可以对其进行管理和升级,而不需要额外的物理访问。 因此,IAP和GPRS的结合为嵌入式设备的固件更新提供了一种便利、高效和实时的方式,使设备能够在不受限于物理位置的情况下始终保持最新的固件状态。 ### 回答3: IAP是"固件升级"的缩写,STM32是一种基于ARM Cortex-M内核的32位单片机,而GPRS则是一种全球通用的无线通信技术,可以实现数据传输和连接互联网。那么iap stm32 gprs的含义是指在STM32单片机上通过GPRS进行固件升级。 在嵌入式系统中,固件升级是非常重要的。它可以通过修改或更新设备的内部软件来修复错误、改进功能、增强性能等。而对于移动设备或无线设备来说,GPRS通信方式可以实现在任何地方对设备进行远程访问和控制。 在使用iap stm32 gprs进行固件升级时,首先需要将新的固件文件传输到设备上。这可以通过GPRS网络将固件文件从远程服务器发送到设备来完成。然后,设备会接收固件文件并将其保存在存储介质中。 接下来,设备会在固件升级期间进入引导模式,并通过iap(固件库提供的In-Application Programming API)来执行更新操作。iap是一种软件库,它允许设备在运行时对自身的固件进行编程。通过iap库,设备可以从存储介质中读取新的固件文件,并将其加载到设备的闪存中。 在固件加载完成后,设备会重启并从新的固件开始运行。通过iap stm32 gprs进行固件升级,可以实现无需物理接触设备即可完成固件更新的便利性,节省了时间和资源。 总的来说,iap stm32 gprs是一种使用GPRS网络进行固件升级的方法,可以使得STM32单片机设备可以在任何地方通过远程访问和控制进行固件更新,方便了软件维护和性能改进。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值