STM32 MCU IAP例程跳转到APP代码简要分析
- 格式:pdf
- 大小:38.67 KB
- 文档页数:2
我用CAN接口做了IAP两个程序区8000000-8002000是BOOT区,写入的启动代码,引导应用程序写入的。
8002000-结尾是应用区,APP程序区现在的问题是进行APP程序后,不响应中断如果不用中断程序,在APP工作一切正常,用中断程序的话就不正常说一下我的设置:在应用程序区APP区,IROM设置8002000-801E000共56K为应用程序区。
在LINKer中设置R/O base为8002000在NVIC初始化时设置:NVIC_SetV ectorTable(NVIC_V ectTab_FLASH, 0x2000);其它地方没有动过。
答案:问题是在这里产生的,当从CAN接受中断中跳转到应用区时,整个应用区程序都是Boot 程序中CAN接收中断的ISR,于是在应用区中任何优先级低于CAN接受中断的中断程序都是得不到执行的。
问题2:IAP跳转到App中会死在下面这个函数里?void Delay(u32 nCount){TimingDelay = nCount;/* Enable the SysTick Counter */SysTick_CounterCmd(SysTick_Counter_Enable);while(TimingDelay != 0){}/* Disable the SysTick Counter */SysTick_CounterCmd(SysTick_Counter_Disable);/* Clear the SysTick Counter */SysTick_CounterCmd(SysTick_Counter_Clear);}在stm32f10x_nvic.h中,找到#define NVIC_V ectTab_FLASH ((u32)0x08000000) 这一行,改为#define NVIC_V ectTab_FLASH ((u32)0x08002000) IAP下载和APP 应用程序运行正常。
STM32 IAP 设计实例(一)项目需要,需要开发一款手持设备,对产品进行软件升级。
现在的产品都是使用STM32,所以可以很方便的应用STM32 的IAP 功能对软件进行在线升级。
总体需求就是,主机Master 通过CAN 接口,发送数据给从机Slave。
从机在接收到应用程序APP 后,把接收的数据覆盖掉原来的应用程序区。
从而实现Master 对Slave 的在线升级。
这里先介绍IAP,对IAP 的整体实现有个了解,方便后续开发。
参考了原子STM32 开发板,对IAP 功能的介绍。
要实现IAP,需要有两个项目代码。
第一个称之为Bootloader 程序,第二个称之为APP 程序。
Bootloader 负责引导APP 程序启动,以及需要在线更新APP 时,接收主机发送的APP 文件,将接收的APP 覆盖掉原来的APP。
关于IAP 的具体内容,可以参考原子STM32 开发板的开发指南的五十三章。
下面是自己对IAP 有大概了解之后,进行的实验。
1,编写bootloader 程序测试程序,用来引导指定位置的APP。
2,修改原来的一个应用程序,使之可以用该bootloader 引导。
3,通过jlink 下载器,分别下载bootloader 和APP。
一,bootloader 程序。
主要代码如下,流水灯之后,执行跳转到APP 区域的命令[cpp]viewplaincopyintmain(void){delay_init();LED_Init();LED1=0;delay_ms(200);//延时LED2=0;delay_ms(200);//延时LED3=0;delay_ms(200);//延时LED4=0;delay_ms(200);//延时LED1=1;delay_ms(200);//延时LED2=1;delay_ms(200);//延时LED3=1;delay_ms(200);//延时。
STM32 IAP 调试经验一、基本方法描述:将flash划分成3个扇区(可以单存用单片机内部flash,对于中大型容量MCU,且用户较小的案例,可以外挂片外flash应用于程序较大的工程),引导区、用户app区和程序存储备份区。
程序启动时先从引导区启动,查询备份区是否有升级程序标志,如果有,则将备份区的程序填充到用户app区,覆盖掉原先的程序,然后跳转到app区执行应用程序;如果没有升级标志,则直接跳转到用户app区地址,执行应用程序。
二、从引导区跳转到app区的函数定义需要添加以下两个函数1、void JumpToSpecifiedAddress(u32 EntranceAddress){u32 JumpAddress;pFunction Jump_To_Application;JumpAddress = *(vu32*) (EntranceAddress + 4);Jump_To_Application = (pFunction) JumpAddress;__set_MSP(*(vu32*) EntranceAddress); //Initialize Stack PointerJump_To_Application();}入口参数即是用户划分的app区地址,调用该函数后便可跳转执行app程序,例如分配app 区地址从0x8002000(引导区从0x8000000开始,8k空间)则,入口参数即0x8002000 2、void NVIC_Configuration(void){#ifdef VECT_TAB_RAMNVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);#elseNVIC_SetVectorTable(NVIC_VectTab_FLASH,0x2000);#endif}此处使用NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x2000);重新定义程序的中断向量链表,因为引导区8k,所以长度0x2000,从起始地址开始外呼0x2000地址的就是用户app 的中断向量链表,这里需根据实际分配的引导区长度填充,本例用用8k,填入0x2000. 注:#define NVIC_VectTab_FLASH ((uint32_t)0x08000000)三、引导区-用户应用区启动跳转简易实例引导区程序:int main(void){RCC_Configuration(); //系统时钟配置NVIC_Configuration(); //中断向量映射配置JumpToSpecifiedAddress(0x8002000)//跳转至用户app区}用户应用程序:int main(){//根据用户需要编写自己的程序}编译器设置:1、引导区程序工程设置其实地址0x8000000 长度8k(0x2000)2、用户应用程序其实地址0x8002000 长度60K(0x1E000)程序下载过程:需要烧写两个程序,才能运行,下载时先烧写引导程序,然后烧写应用程序。
STM32学习:IAP简单的IAP例⼦章节概述:以⼀个最简单的例⼦⽰范IAP程序(没有⽂件通讯,没有跳转判断),需要借助IDE进⾏分区数据的划分以及下载。
准备IDE:keil-MDK 5MCU:STM32F103ZET6为例(Flash地址为0x08000000—0x0807ffff,共512KB)。
BSP:STM32-HAL启动⽅式:FLASH启动前32KB存放BootLoader程序(0x08000000 ~ 0x08007fff)剩余的空间存放APP程序(0x08008000 ~ 0x0807ffff)假定跳转的APP程序的实际物理地址为:0x08008000分别新建2个⼯程,名字可以为:bootLoader与app。
从Bootloader跳转到APPBootloader为了区分执⾏分区的不同,添加串⼝打印功能。
(略)例如:printf("Hello Bootloader\r\n");添加下⾯的代码以实现跳转功能:节选⾃CubeMX的例程:STM32Cube\Repository\xxx\Projects\Applications\IAP#define NVIC_VectTab_RAM ((u32)0x20000000)#define NVIC_VectTab_FLASH ((u32)0x08000000)#define PHYSICAL_ADDRESS_Flash (0x08000000) // 程序烧写的物理地址#define APPLICATION_POSADDR (0x0000C000) // APP 偏移量#define APPLICATION_ADDRESS ((PHYSICAL_ADDRESS_Flash) | (APPLICATION_POSADDR)) // 最终跳转的地址,实际上就是0x08008000typedef void (*pFunction)(void);pFunction JumpToApplication;uint32_t JumpAddress;void NVIC_SetVectorTable(uint32_t base, uint32_t offset){/* close interruption*/__set_FAULTMASK(1);/* set vector table*///NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0xffset);SCB->VTOR = base | offset;/* open interruption*/__set_FAULTMASK(0);}int main(void){// 在BootLoader程序的中断向量表指向设置中应有这么⼀句:NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //设置中断向量表指向/* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) //①{/* Jump to user application */JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);// ②JumpToApplication = (pFunction) JumpAddress;//③/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); // ④JumpToApplication(); // ⑤}while (1){}}解析:①因为⽤户程序开始位置(0x08008000处)的前4个字节存放的是堆栈的地址,堆栈地址必定是指向RAM空间的,⽽STM32的RAM空间起始地址为0x20000000,所以要进⾏判断。
关于STM32的IAP与APP互相跳转常见问题分析关于STM32 的IAP 与APP 互相跳转之前做了一个不带系统的IAP 与APP 互相跳转,在网上找了资料后,很顺畅就完成了,后来在IAR 集成开发环境下,IAP 无系统,APP 用UCOS 系统做互相跳转出现了很多问题。
现将IAP 学习过程和实际遇到问题总结一下。
首先说一下什么是IAP。
IAP(In Application Programming)即在应用编程,IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。
通常实现IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。
以上内容摘自原子的开发指南。
说的通俗一点,要做IAP 功能(也可以说成是远程升级功能),需要有两段程序一个是IAP 程序(也可以称为BootLoader),另一个是APP 程序(主应用程序)。
通过USB、串口、CAN 等通讯方式向STM32 发送要升级的程序文件数据(按自定的协议),IAP 程序中将接收到的数据写到APP 程序的地址实现将APP 程序的升级。
这是大致的流程。
此文档只做互相跳转的总结不包含接收数据、FLASH 写入等操作。
说到IAP 升级不得不说两个图(图片引自原子的开发指南)第一个是正常运行时的流程图STM32 的FLASH 地址起始于0x08000000,程序文件就从此地址开始写入。
此外STM32 内部通过“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而“中断向量表”的起始。
STM32 IAP实验小结首先假设bootloader程序的大小限定为64k。
编译器使用MDK518。
MCU是STM32F103ZET6(512kFLASK+64kRAM)▲Bootloader的程序跟一般的程序设置都是一样的,唯独要注意的是它编译后得到的rom不能超过64k▲FLASH中的app程序:MDK默认的FLASH起始地址是0x8000000,大小是0x80000,先把FLASH 的起始地址和大小设置好,这里起始地址是0x8010000,大小为0x70000,因为bootloader占64k=0x10000,所以app程序的起始地址加0x10000,大小自然是0x80000-0x10000=0x70000了;RAM不用动,因为bootloader 跳转到app后,app可以占用整个RAM使用。
首先app程序中main函数一开始加上这句:这句是用来设置中断向量表偏移量的,大小等于bootloader的限制大小:64k然后设置一下代码存放位置▲RAM中的app:设置跟FLASH app差不多RAM app配套的bootloader程序跟FLASH的是一样的,这里限制bootloader 的RAM占用为4k(0x1000),所以bin文件从RAM的0x20001000开始存储(RAM app的bin文件不能从RAM的开头存储,必须给bootloader留一片RAM),大小为0xC000(48k),剩下的RAM从0x20001000+0xC000=0x2000D00开始,大小为64k-4k-48k=12k=0x3000▲最后,不管是FLASH app还是RAM app都要在MDK中加入一个脚本命令脚本为:找到你的MDK中fromelf.exe的路径,还有.axf文件的路径,设置好你想要的.bin文件的名字和存放路径,按照上图顺序填上去即可▲注意:●无论是FLASH app还是RAM app,bin文件的偏移量都必须是0x200的倍数!●如果要调试一个app文件,有两种办法,一种是把所有app设置都改为正常设置,即:以下这些设置恢复为系统默认设置另一种是在这个地方导入一个ini文件,使得MDK debug时一开始就直接跳转到app程序运行,但我没试过。
关于STM32的IAP与APP互相跳转常见问题分析关于STM32 的IAP 与APP 互相跳转之前做了一个不带系统的IAP 与APP 互相跳转,在网上找了资料后,很顺畅就完成了,后来在IAR 集成开发环境下,IAP 无系统,APP 用UCOS 系统做互相跳转出现了很多问题。
现将IAP 学习过程和实际遇到问题总结一下。
首先说一下什么是IAP。
IAP(In Application Programming)即在应用编程,IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。
通常实现IAP 功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。
以上内容摘自原子的开发指南。
说的通俗一点,要做IAP 功能(也可以说成是远程升级功能),需要有两段程序一个是IAP 程序(也可以称为BootLoader),另一个是APP 程序(主应用程序)。
通过USB、串口、CAN 等通讯方式向STM32 发送要升级的程序文件数据(按自定的协议),IAP 程序中将接收到的数据写到APP 程序的地址实现将APP 程序的升级。
这是大致的流程。
此文档只做互相跳转的总结不包含接收数据、FLASH 写入等操作。
说到IAP 升级不得不说两个图(图片引自原子的开发指南)第一个是正常运行时的流程图STM32 的FLASH 地址起始于0x08000000,程序文件就从此地址开始写入。
此外STM32 内部通过“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而“中断向量表”的起始地址是0x08000004,当中断来临,STM32 的内部硬件机制亦会自动将PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。
STM32 IAP 无法运行用户程序的解决方法IAP 程序:主要是设置用户程序的起始地址APPLICATION_ADDRESS,如0x08004000,通过外设把用户代码写入FLASH 的用户区。
满足条件后,跳转至用户区起始地址。
解释一下跳转部分代码:/* Test if user code is programmed starting from address “APPLICATION_ADDRESS”*/if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)// 判断栈顶地址是否在0x2000 0000 - 0x2000 2000 之间// 通过判断栈顶地址值是否正确来判断是否已经下载用户应用程序。
因为用户程序的启动文件开始会初始化栈空间,如果栈顶地址正确,说明用户程序已经下载。
{__set_PRIMASK(1);// 关闭全局中断。
注意,在跳转前,必须先关闭全局中断,进入用户程序后,在中断向量表地址设置完成后再开中断。
printf(“Jump to the new program.\r\n”);/* Jump to user application */JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);// 前4 字节为中断向量表Jump_To_Application = (pFunction) JumpAddress;// 指向用户程序复位函数所在的地址/* Initialize user applications Stack Pointer */__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);// 设置用户程序的栈指针Jump_To_Application();// 执行用户程序}需要注意的是,在IAP 程序中,跳转用户程序前,需要先关闭全局中断。
STM32F4系列的app和boot相互跳转首先要明确的是ISP和IAP两个概念。
ISP 即(In-System Programming)在系统可编程,指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路板上取下器件,已经编程的器件也可以用ISP 方式擦除或再编程。
IAP:In Application Programming 是指在应用编程,即在程序运行中编程,就是片子提供一系列的机制(硬件/软件上的)当片子在运行程序的时候可以提供一种改变flash数据的方法。
STM32F4芯片自带ISP程序,在系统存储区内,通过开机的时检测BOOT0和BOOT1的引脚电平来判断从什么地方启动,如下图当BOOT1处于低电平,同时BOOT0是高电平时,系统从System memory启动,这里保存着stm32出厂时内置的ISP程序,可以通过串口或者usb口等来进行内置flash的编程,这部分原理数据手册里写的很清楚。
ISP这部分由官方实现,是一段固化的程序,使用isp软件进行升级即可,下面我们来看一下IAP 的问题。
IAP:IAP的好处就是不用进行跳线改变boot引脚的电平,就可以进行在线编程,在产品化以后使用的比较多,通常用一个boot程序来引导,选择是进行升级还是进入app应用中。
这一部分,st 官方也有示例代码(多么贴心)。
官方给出的IAP的核心代码:[cpp] view plain copy1. #define __IO volatile2. typedef void (*pFunction)(void);3. #define APPLICATION_ADDRESS (uint32_t)0x080000004. pFunction Jump_To_Application;5. uint32_t JumpAddress;[cpp] view plain copy1. /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */2. if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)3. {4. /* Jump to user application */5. JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);6. Jump_To_Application = (pFunction) JumpAddress;7. /* Initialize user application's Stack Pointer */8. __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);9. Jump_To_Application();10. }1.if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) 这句旨在判定 APPLICATION_ADDRESS这个地址保存的是否是SP堆栈指针,下面是stm32的矢量表:从这个表中能看出来,用户应用的首4个字节应该放的是栈顶的值,启动采样完boot引脚后,CPU 将从地址 0x0000 0000 获取栈顶值,然后从始于 0x0000 0004 的自举存储器开始执行代码。
探究STM32H7芯片IAP跳转失败案例
有STM32用户反馈,他在使用STM32H750VB编写用户引导程序【BOOT CODE】和应用程序【APP CODE】。
根据数据手册描述,STM32H750有128K Bytes的片内flash,地址是从0x0800 0000~~0x0801 FFFF。
他将用户bootloader放在0x0800 0000~0x0800 2FFF,应用程序放在0x08003000~0x0801 FFFF。
但当他按照这样的存储分配设计时,发现总是没法实现从BOOT区到APP区的跳转。
基于该用户的反馈信息,给他做了些提醒,比如中断矢量表定位问题,客户都说已经注意到了,代码应该没有问题。
我这边就客户反馈的问题找了块STM32H743的板做了验证测试。
发现从BOOT区到APP区的跳转并没有异常,那幺客户怎幺又有问题呢?
再次查看了客户邮件的反馈信息。
他用的默认内部SRAM区为AXI SRAM,地址区间在0x24000000 --0x2407FFFF,即下面表格中的A区,而我使用的默认内部SRAM区是DTCM SRAM,地址区间在0x20000000 -0x2001FFFF,即下面表格中的B区。
难道是这个差别导致跳转的不同结果?当然,这两个SRAM区在使用上还是有差异的。
STM32F0芯片内不同程序区的跳转问题交流与介绍STM32F0芯片内不同程序区的跳转问题交流与介绍对于STM32用户,经常会涉及到通过用户启动程序实现对用户应用程序的更新升级。
一般来讲,用户启动程序主要用来跟外界通信,获取新的用户程序代码并实现对用户代码区的应用程序升级。
用户应用程序是指实现各种用户功能的代码。
在这个过程中,往往需要做从用户引导程序区到用户应用程序区的跳转,有时可能还需实现从用户应用程序区跳回到用户启动程序区,或者不同用户程序区的互相跳转等操作。
在这些跳转过程中,往往有人在此遇到阻碍,破费周折,尤其是在使用基于cortex M0内核的STM32F0做IAP 应用时,这个过程跟其它基于CORTEX M3/M4/M7内核的STM32系列相比,操作上不太一样,实现起来稍微复杂些。
这里就STM32F0芯片内不同程序区的跳转问题做些交流与介绍,限于篇幅,仅直接介绍具体操作和注意事项,不做过多拓展。
相关知识点可阅读STM32芯片参考手册、STM32相关ARM内核编程手册。
下面介绍中提及的集成编译环境是指ARM MDK,硬件基于STM32F072RB Nucleo开发板。
后面我将逐一介绍从BOOT区【用户启动程序区】跳转到APP区【用户应用程序区】,从APP区跳转到另外新APP区以及从APP区跳回BOOT区的基本流程及注意事项。
一般来讲,不同区段的执行代码我们通过建立不同的工程项目来实现,最终将不同区段执行代码写入芯片。
这里假定用户BOOT区对应的内部FLASH地址段为0x8000000—0x8004000, 用户APP1区对应的内部FLASH地址段为0x8004000—0x8008000, APP2区对应的内部FLASH地址段为0x8008000—0x800C000.一、从用户启动程序区【BOOT区】到用户应用程序区【APP区】的跳转先说从BOOT区跳转到APP区。
跳转代码比较简洁、简单,注意跳转前要关闭刚才程序区开启过的所有中断使能,保证所有中断请求位都被清除,不要只是简单的关闭总中断,否则往往隐患多多。
关于IAP与APP互相跳转的实现首先,在您动手做这个实验之前,先要弄清除咱俩的软硬件有什么不同:1.我的CPU是STM32F103ZET6,里面有512K的FLASH,您的CPU如果是其它类型,也不要紧,只是在程序里面,地址上限可能不一样。
但是,个人觉得,最好能用256K以下的FLASH。
2.我的外部存储介质是U盘,如果您的外部存储介质是SD卡,那也应该一样用,只是它们必须是FAT16,FAT32文件系统。
如果您的板上没有外部存储介质,那也能做跳转实验,只是不能做加载APP实验。
3.我的仿真器是JLINK7,如果您的仿真器是其它的,估计也没多大问题,只要您会用它就行了。
什么?没有仿真器,那还是别做这个实验吧,出错了没法调试。
4.我的开发环境是RVMDK3。
7,STM库是V2。
03。
使用其它开发环境的话,您要是能找到MDK中的设置对应到您那里怎么设置,估计也没问题。
至于库嘛,您现在是用哪个就哪个吧,全部包在您的工程里,没问题的。
好了,开始啦。
先找个你以前调好的工程,当然,最好是非常可靠的,内容很精彩的,带液晶显示的,这样比较容易知道你后面有没有调好。
这个工程还最好是在FLASH里面运行的,如果不是,要将它改回来。
至于什么开发文档,太麻烦了,不用看。
我之前看了STM的IAP应用笔记AN2557,就觉得一个字“乱”,特别是心里还没谱的时候,更是越看越糊涂,这么大个工程,到最后对我有帮助的,就是一小段,就是如何擦除,如何编程那小段。
当然,STM32的库还是非常有用的,如果不用库的话,学习、工作进度会慢很多。
说多啦,找好工程没有?找好工程咱就开工了。
将这个工程复制两份,一份命名为IAP,一份命名为APP。
第一步:规划好你两个程序的存放位置。
IAP程序肯定是从0X08000000开始的,因为它是引导程序。
将IAP程序放在0X08000000-0X0800FFFF的位置,给它64K空间,足够了。
APP程序从0X08010000-0X0807FFFF,给它448K空间。
STM32F030之IAP代码编写
程序收尾总想着以后更新的方便性,采用在应用编程(In ApplicaTIon Programming),通过Bootload引导单片机自己往程序存储器里写数据或修改程序。
下面简介STM32F030的IAP方法。
不同于STM32F1系列,F0没有中断向量偏移寄存器。
所以在APP程序的开头要添加以下代码。
为什么这样做??
可以看到函数用了for循环将矢量表拷贝到0 x20000000 SRAM的基地址,即将矢量表由Flash映射到了SRAM。
所以在MDK里面设置Flash偏移地址的时候,同时要设置SRAM 偏移地址。
如下截图
//APP程序开头加入IAP_Set(void)函数
有Target对话框可以看出APP程序有Flash地址0x8001400开始执行。
Sram数据则有0x20000c0出开始存储。
说完APP代码要处理事项,下面说一下IAP代码编写
程序更新完以后执行以上跳转函数即可执行更新的APP代码。
关于如何通过IAP将代码将APP代码(bin文件)传到单片机Flash,可以通过串口分包传输。
因为F0Flash是1K 为一页所以这里我用的是1K缓存,即接收串口1K的数据量就执行一次Flash写操作,传输到最后不满1K,填写0XFF按照1K数据写。
写Flash代码如下
关于IAP如何接收串口的数据,我用的是正点原子的XCOM V2.0串口调试助手通过协议传输每次传输128字节数据,执行的IAP串口数据接收。
stm32f030IAPIAR环境stm32f030 IAP升级:IAP核⼼代码:#if(FLASH_PAGE_SIZE == 0X400U)#define FLASH_SIZE (256 * FLASH_PAGE_SIZE)#define BOOT_AREA_SIZE (12 * FLASH_PAGE_SIZE)#define TAG_AREA_SIZE (2 * FLASH_PAGE_SIZE)#define APP1_AREA_SIZE ((FLASH_SIZE -BOOT_AREA_SIZE-TAG_AREA_SIZE)/2) // must mod == 0#define APP2_AREA_SIZE APP1_AREA_SIZE#endif#if(FLASH_PAGE_SIZE == 0x800U)#define FLASH_SIZE (128 * FLASH_PAGE_SIZE)#define BOOT_AREA_SIZE (7 * FLASH_PAGE_SIZE)#define TAG_AREA_SIZE (1 * FLASH_PAGE_SIZE)#define APP1_AREA_SIZE ((FLASH_SIZE -BOOT_AREA_SIZE-TAG_AREA_SIZE)/2) // must mod == 0#define APP2_AREA_SIZE APP1_AREA_SIZE#endif#define BASE_ADDRESS 0x08000000#define TAG_ADDRESS (BOOT_AREA_SIZE + APP1_AREA_SIZE + APP2_AREA_SIZE + BASE_ADDRESS) #define APP1_IMG_BEG_ADDRESS (BOOT_AREA_SIZE + BASE_ADDRESS)#define APP2_IMG_BEG_ADDRESS (BOOT_AREA_SIZE + APP1_AREA_SIZE + BASE_ADDRESS)typedef void ( *jump ) ( void );void Restart ( void ){jump reboot;__set_MSP ( * ( volatile uint32_t * ) 0x08000000 );reboot = ( jump ) * ( volatile uint32_t * ) 0x08000004;reboot();}void AppJump ( void ){jump appjump;__set_MSP ( * ( volatile uint32_t* ) APP1_IMG_BEG_ADDRESS );appjump = ( jump ) * ( volatile uint32_t * ) ( APP1_IMG_BEG_ADDRESS + 4 );appjump();} ⼯程配置按照正常⼯程配置即可;APP端核⼼代码:#if(FLASH_PAGE_SIZE == 0X400U)#define FLASH_SIZE (256 * FLASH_PAGE_SIZE) // only support even page#define BOOT_AREA_SIZE (12 * FLASH_PAGE_SIZE) // only support even page#define TAG_AREA_SIZE (2 * FLASH_PAGE_SIZE) // only support even page#define APP1_AREA_SIZE ((FLASH_SIZE -BOOT_AREA_SIZE-TAG_AREA_SIZE)/2) // must mod == 0#define APP2_AREA_SIZE APP1_AREA_SIZE#endif#if(FLASH_PAGE_SIZE == 0x800U)#define FLASH_SIZE (128 * FLASH_PAGE_SIZE)#define BOOT_AREA_SIZE (7 * FLASH_PAGE_SIZE)#define TAG_AREA_SIZE (1 * FLASH_PAGE_SIZE)#define APP1_AREA_SIZE ((FLASH_SIZE -BOOT_AREA_SIZE-TAG_AREA_SIZE)/2) // must mod == 0#define APP2_AREA_SIZE APP1_AREA_SIZE#endif#define BASE_ADDRESS 0x08000000#define TAG_ADDRESS (BOOT_AREA_SIZE + APP1_AREA_SIZE + APP2_AREA_SIZE + BASE_ADDRESS) #define APP1_IMG_BEG_ADDRESS (BOOT_AREA_SIZE + BASE_ADDRESS)#define APP2_IMG_BEG_ADDRESS (BOOT_AREA_SIZE + APP1_AREA_SIZE + BASE_ADDRESS)#if (defined ( __CC_ARM ))volatile uint32_t VectorTable[48] __attribute__ ( ( at ( 0x20000000 ) ) );#elif (defined (__ICCARM__))#pragma location = 0x20000000__no_init volatile uint32_t VectorTable[48];#elif defined ( __GNUC__ )volatile uint32_t VectorTable[48] __attribute__ ( ( section ( ".RAMVectorTable" ) ) );#elif defined ( __TASKING__ )volatile uint32_t VectorTable[48] __at ( 0x20000000 );#endifvoid VectorTableRemap ( void ){uint32_t i = 0;/* Relocate by software the vector table to the internal SRAM at 0x20000000 ***//* Copy the vector table from the Flash (mapped at the base of the applicationload address APP_IMAG_LOCATION) to the base address of the SRAM at 0x20000000. */for ( i = 0; i < 48; i++ ){VectorTable[i] = * ( volatile uint32_t* ) ( APP1_IMG_BEG_ADDRESS + ( i << 2 ) );// VectorTable[i] = * ( volatile uint32_t* ) ( 0x08000000 + ( i << 2 ) );}/* Enable the SYSCFG peripheral clock*/__HAL_RCC_SYSCFG_CLK_ENABLE();/* Remap SRAM at 0x00000000 */__HAL_SYSCFG_REMAPMEMORY_SRAM();} 将此函数放到main函数最开头即可,然后将中断向量表起始地址改为APP1_IMG_BEG_ADDRESS ,ram起始地址改为0x200000C0,如下图所⽰:⾄此,IAP功能便配置成功,详细原理可以参考如下链接:。
(扩展-IAP主要用于产品出厂后应用程序的更新作用,上一篇博文详细的对IAP 升级程序做了详细的分析/yx_l128125/article/details/12992773,考虑到出厂时要先烧写IAP 再烧写APP应用程序要烧写2次增加工人劳动力基础上写了“STM32IAP+APP ==>双剑合一”链接稍后发,希望通过IAP程序的hex 文件和 APP的hex文件合成一个hex 或者把合成的hex文件转成.bin 文件减少“体力”)一、简单框架介绍(简单回顾上篇博文《IAP在线升级详解》/yx_l128125/article/details/12992773的几个重要知识点:1、stm32内部flash起始地址:0x0800 0000 -- 0x0802 0000 ,其中从 0x0800 0000开始位置存放IAP 升级程序,从0x 0800 3000开始的位置存放APP应用程序[ 而APP中的中断向量表放在0x0800 3000地方,更重要的是中断向量表的第1项存放的是栈顶地址,第二项放的是”复位中断“ ]二、IAP +APP 结合的方法IAP 和APP 的hex 文件合成1个hex 文件的方法有2种:(1) "简单1+1"(2) IAP 先烧写进flash 的 0x0800 0000 开始位置, APP烧写到 flash 的0x 0800 3000开始的地方;之后通过我上一篇博文的 IAP程序的文件读出功能读取flash 上的数据读到一个.bin文件上;我们先来详细分析“方法一”的操作:1.我们设置编译IAP程序的编译器(如图),这个设置意思是把IAP程序下载到flash的 0x0800 0000开头的位置,然后编译程序第一个字节表示本行数据的长度;第二、三字节表示本行数据的起始地址;第四字节表示数据类型,数据类型有:0x00、0x01、0x02、0x03、0x04、0x05。
STM32 MCU IAP 例程跳转到APP 代码简要分析
问题问题::
有客户在初次使用STM32 MCU IAP 的例程的,可能会对跳转到APP 部分的函数的实现产生疑问 :
问题1:JumpAddress 地址为什么指向APPLICATION_ADDRESS + 4 ;
MSP 主堆栈指针为什么指向APPLICATION_ADDRESS ;
问题2:为什么需要做以下判断 :
if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
{
}
此Tips 对于这两个个问题做简要分析.进行所以说主要代码如下 :
/* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
{
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
Jump_To_Application();
}
调研调研::
问题1分析 :
从startup_stm32f4xx.s 中的启动代码可以看出:程序开始第一条指令地址为CSTACK ,第二条指令地址为复位指令 ,参考代码中的红色部分(蓝色为注释);
EXTERN __iar_program_start
EXTERN SystemInit
PUBLIC __vector_table
DATA
__vector_table
DCD sfe(CSTACK) ; APPLICATION_ADDRESS
DCD Reset_Handler ; Reset Handler ; APPLICATION_ADDRESS + 4
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
当程序启动时首先要执行复位程序,因此JumpAddress地址指向复位指令地址(即
APPLICATION_ADDRESS + 4) ;
MSP对应的是主堆栈指针,指向CSTACK地址(即APPLICATION_ADDRESS).
问题2分析 :
ApplicationAddress存放的是程序的主堆栈地址,CSTACK堆栈地址指向RAM,而RAM的起始地址是0x20000000;
因此上面的判断语句执行:判断用户代码的堆栈地址是否落在:0x20000000~0x2001ffff区间
中,这个区间的大小为128K.
例程中使用芯片RAM=128K,因此做上面的判断;如果芯片RAM比128K大的话,可以在
此判断语句做调整.
结论 :
结论
以上分析可以看出,程序跳转部分的设计与APP启动代码和芯片RAM的大小有关系;移植和调试时需加以注意.
处理 :
处理。