本文主要是介绍STM32F10x IAP技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
STM32F10x IAP技术
(BOOTLOADER)
第一部分
一 计算固件占用FLASH大小
每次生成固件时,Keil 会有一个固件信息显示,如下列图
图1
固件占用FLASH大小 = Code + RO + RW + ZI,上图中的固件大小为:11,016字节,16进制为:0x2B08。
二 固件数据结构
图2
STM32F10x有一个中断向量表,这个中断向量表存放在代码开始部分的后4个字节处(即0x08000004),代码开始的4个字节存放的是堆栈栈顶的地址,当发生中断后程序通过查找该表得到相应的中断服务程序入口地址,然后再跳到相应的中断服务程序中执行。上电后从0x08000004处取出复位中断向量的地址,然后跳转到复位中断程序的入口(标号①所示),执行结束后跳转到main函数中(标号②所示)。在执行main函数的过程中发生中断,则STM32强制将PC指针指回中断向量表处(标号③所示),从中断向量表中找到相应的中断函数入口地址,跳转到相应的中断服务函数(标号④所示),执行完中断函数后再返回到main函数中来(标号⑤所示)
另:Stm32源代码中有说明。堆栈栈顶地址需为0x200的整数倍,原文为” Vector Table base offset field. This value must be a multiple of 0x200” 。即:”向量表基本偏移量字段。此值必须是0x200的倍数”。 因此,图1中,如该固件在FLASH中的起始地址为0x8000000。若想在该固件后继续放置其它固件,则最近的可用地址为 0x2C00
三 固件程序间的跳转说明
若在STM32F103x中使用IAP方案,则内置的Flash分配情况大致如下图:
图3
在内置的Flash里面添加一个BootLoader程序,BootLoader程序和 用户程序 各有一个中断向量表,假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如下图所示
图4
上电初始程序依然从0x08000004处取出复位中断向量地址,执行复位中断函数后跳转到IAP的main(标号①所示),在IAP的main函数执行完成后强制跳转到0x08000004+N+M处(标号②所示),最后跳转到新的main函数中来(标号③所示),当发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,再跳转到新的中断服务函数中执行(标号④⑤所示),执行完中断函数后再返回到main函数中来(标号⑥所示)。
以上 参考链接:https://blog.csdn.net/wzy15965343032/article/details/88545225
对于步骤④⑤,是跳转到0x8000004 还是跳转到 0x8000004+N+M,由②③来协同决定。
若想跳转到0x8000004+N+M,则:② 在跳转前要关闭所有中断外设,清除所有中断向量的使用。若是从RTOS固件跳转到其它固件,除放弃一切中断和中断服务外,还要修改CPU的模式为特权模式、关闭SysTick、激活MSP等操作;③的main中重定中断向量表地址为0x8000004+N+M。否则固件程序在④⑤的时候会跑到0x8000004的向量表中,运行结果不可预知。通常会进入 XXXX_Handler ,如 :HardFault_Handler、SysTick_Handler等。
四 不同固件在FLASH中的地址参数
前面已经提到了固件在FLASH中占用空间的算法;堆栈栈顶地址需为0x200的整数倍。下面举例说明,想将多个固件放在同一个MCU FLASH中的地址参数配置方法如下。
现有BootLoader ,APP1, APP2 三个程序要放入一片 STM32F103C8T6中。三个程序在FLASH中的存储安排如下:
BOOTLOADER | APP1 | APP2 |
BOOTLOADER 程序编译后的固件信息,算下来,约占0x2C00空间,(下一个APP的堆栈栈顶地址需为0x200的整数倍,因此取了一个你好我好大家好的占用空间0x2C00)如下图:
因此BOOTLOADER 使用的是默认地址设置,如下图:
重点是 Start : 0x8000000。(有人说Size也要设置为固件占用大小,我没有改,验证过程中也没有发现有问题)
APP1程序编译后的固件信息,算下来,约占0x2C00空间 (实际上APP1只是把BOOTLOADER的程序改了几行代码),如下图:
算上BOOTLOADER占用的空间,APP1的地址设置如下图:
重点是,Start : 0x8002C00
APP2 使用的是CMSIS RTOS2框架,实现的功能不多,占用的空间不小,约0x5C00的空间,如下图:
算上BOOTLOAD、APP1所占用的空间,APP2的起始地址要从 0x5800开始,设置如下:
为了使APP1、APP2初始化时,同步指定中断向量表,APP1要将中断向量偏移到程序所在地址(固件在FLASH中存储的起始地址),在system_stm32f10x.c中:
同理 APP2中的也要修改:
如果使用JLINK 直接烧写固件,3个固件,分3次独立烧写。无需额外设置。有朋友说也要设置地址,我验证过,没必要。但要注意不能每次烧写时把所有的FLASH清除,这样每次烧写都会把前面烧写的内容都清除掉了,这样是没有办法验证的。Jlink 烧写配置如下:
第二部分 程序跳转代码
说那么多都是云,代码才是重点,有多少朋友跨过千山万水,历经各种摩擦,总是不能正常跳转,就是跳不过去。以下代码专治各种跳转不服,从非RTOS固件到RTOS固件,再跳回非RTOS固件,随便跳!妥妥地!
/*程序中转:app_addr 程序在FLASH中的地址。不能在中断中调用*/
void Run_App(u32 app_addr)
{u32 spinitval;u32 jumpaddress;App_Function app = NULL;//确定中转的地址是否在正确的范围内if(((*(__IO u32 *)app_addr) & 0x2FFF0000) == 0x20000000) //64K 的FLASH RAM
// if(((*(__IO u32 *)app_addr) 0x2FFE0000) == 0x20000000) //128K 的FLASH RAM
// if(((*(__IO u32 *)app_addr) & 0x2FF80000) == 0x20000000) //512K 的FLASH RAM{//为了不给要跳转的程序初始化造成麻烦,初始化所有端口GPIO_DeInit(GPIOA);GPIO_DeInit(GPIOB);GPIO_DeInit(GPIOC);GPIO_DeInit(GPIOD);GPIO_DeInit(GPIOE);GPIO_DeInit(GPIOF);GPIO_DeInit(GPIOG);if(CONTROL_nPRIV_Msk & __get_CONTROL()) //RTOS{__asm("SVC #0"); //确保CPU处于特权模式}//常规RCC_DeInit(); //关闭所有外设时钟NVIC_DeInit(); //禁用NVIC中的所有已启用中断和请求 ,高版本固件库中好像没有这个函数了,可以自己写一个//RTOSSysTick->CTRL = 0 ; //关闭 RTOS 的心跳时钟SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk; //清除其异常挂起位//如果引导加载程序使用它们,则禁用各个故障处理程序SCB->SHCSR &= ~( SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk ) ;//常规spinitval = *(__IO u32 *)app_addr; // 取得栈顶地址jumpaddress = *(__IO u32 *)(app_addr + 4); //取得复位中断向量app = (App_Function)jumpaddress;//如果发现核心当前与PSP一起运行(在RTOS的线程中运行时使用的是PSP),则激活MSPif( CONTROL_SPSEL_Msk & __get_CONTROL( ) ){ /* MSP 未激活 */__set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ; //激活MSP}//将MSP设置为用户应用程序向量表中的值__set_MSP(spinitval); //如果未在中断或没有使用系统的时候,那么这个生效 //将用户应用程序的向量表地址加载到SCB-> VTOR寄存器中。确保地址符合对齐要求 0x200的倍数(这一句可能没有意义)SCB->VTOR = ( uint32_t )app_addr; // 将用户应用程序的向量表地址加载到SCB-> VTOR寄存器中app(); //中转到指定程序地址}
以上代码参考连接:https://www.keil.com/support/docs/3913.htm
第三部分 固件HEX合并烧写说明
产品出厂前,通常是两个固件要同时写入到MCU中,每一片要写两次,没效率。因此需要将多个HEX文件合并为一个文件,再一次性烧写,注:HEX文件是文本格式,可以用文本编辑器打开。操作方法如下:
- 将bootloader的最后一行(文件结束记录行)删除;
- 把APP1的HEX文件内容直接COPY在bootloader的后面,不能有空行;
- 同样把合并后的最后一行(原APP1 固件Hex文件的最后一行)删除;
- 把APP2的HEX文件内容直接COPY在合并文件的后面,不能有空行;
- 保存合并文件成为新的HEX文件,即可使用Jlink或Hex烧写工具直接烧写
以上合并文件烧写结果,验证通过。
特别说明:本说明是以STM32F103C8T6为列说明的,该MCU的FLASH扇区大小为1024。程序地址参数是否受MCU的FLASH扇区大小制约,目前并未验证。
验证工程下载地fh址:https://download.csdn.net/download/SCY820114/12915364
这篇关于STM32F10x IAP技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!