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 程序中,跳转用户程序前,需要先关闭全局中断。
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的大小有关系;移植和调试时需加以注意.
处理 :
处理。