历史上的今天
返回首页

历史上的今天

今天是:2025年03月09日(星期日)

正在发生

2019年03月09日 | STM32 IAP APP 启动过程

2019-03-09 来源:eefocus

最近因项目需求要实现STM32的在线升级即IAP功能,先将这几天的学习体会和IAP的具体实现总结出来,分享给大家,希望对同样实现IAP的童鞋有所帮助,文中最后会上传名为STM32_Update.zip的压缩文件里面包含了STM32_App、STM32_MyBoot_V1.0和升级软件STM32_UpdateSoftware的源码文件供大家参考。所有程序都经过测试,可以直接在原子哥的开发板上跑,上位机的升级软件大家可以直接打开

STM32_Update\STM32_UpdateSoftware\Release\STM32_UpdateSoftware.exe来升级,如果需要查看源码请用VS2010打开工程文件。


最终要实现的是:

单片机每次上电会先运行Boot程序,检查标志位如果标志位为FLAG_TO_APP则直接跳转到App程序运行,如果标志位为FLAG_TO_BOOT,则运行Boot程序准备升级。在运行App程序时,当接收到升级的指令后会在FLASH中的某处空间写下升级的标志位FLAG_TO_BOOT,并且加载Boot程序,Boot程序会接受新的程序文件并且存储在相应的FLASH空间里,完成升级后会在标志位的空间写下FLAG_TO_APP,并且运行新的程序。


帖子包含如下几个方面:

1. 什么是IAP?

2. STM32的启动模式?

3. STM32的FLASH分布?

4. STM32程序的运行过程?

5. BootLoader程序的编写(如何实现程序的动态加载)?

6. App程序的编写?

7. bin文件的转换?

8. 上位机串口升级软件的简介

-------------------------------------------------------------------------------------------------

1. 什么是IAP?

IAP的知识网上的各种资料也说的比较明白,在此简单介绍一下。IAP( In Application Programming)即在线应用编程,也就是用户可以使用自己的程序对单片机的User Flash的某一区域(一般为存放自己程序的区域)进行烧写。在真正的工作中产品发布后,可以很方便的使用预留的通信接口(串口、USB、网口、蓝牙等)来完成程序的升级,从而避免了把机器拆开使用下载器烧写程序。要实现IAP功能一般要设计两部分代码,一是BootLoader程序,这部分程序存储在FLASH的某一位置,主要用来引导、升级App程序;二是App程序,这个程序才是实现产品的功能程序。通过BootLoader来完成对App程序的更新升级,这就是IAP功能。


2. STM32的启动模式

很多初学者对于STM32的启动并不是很了解,这在《STM32的参考手册》以及网上各种资料里也有介绍,下面再简单介绍一下:

STM32有三种启动方式,主要是通过管脚BOOT0和BOOT1的连接方式来控制的,如下图所示,因为我们要让程序从主存储器启动,因而在硬件                设计时要选择第一种方式把BOOT0接到GND,BOOT1任意,可以拉高也可以拉低。



note: STM32上电启动并不是直接进入main函数,而是先进行系统初始化,这个函数的调用是在启动文件startup_stm32f10x_hd.s(因为我的单片机是STM32F103RCT6,大容量芯片所以是这个文件)中执行复位中断Reset_Handler时被调用的,执行完复位中断才会进入main函数。


3.  STM32 FLASH的分布

STM32每种型号单片机的FLASH大小及地址分配在芯片手册里都有介绍,我使用的是STM32F103RCT6的型号其FLASH为256K属于大容量产品其        

FLASH的分布如下图:主存储块的地址是从0x08000000到0x0803FFFF共256K



我们在设计程序时把FLASH分成3部分,第一部分从0x08000000到0x0800FFFF共64K来存放BootLoader程序,第二部分为0x08010000到0x0802FFFF共128K来存放App程序,第三部分从0x08030000开始到0x803FFFF共64K来存放程序运行的标志位和其他,如下所示:



4. STM32程序的运行过程

STM32的程序运行过程在很多资料里也都有介绍,因为STM32F103的单片机是基于Cortex-M3核的,它的内部主要是通过中断向量表来响应各种中断,内部闪存的起始地址是0x08000000,中断向量表的起始地址是0x8000004,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,当中断来临时STM32 的内部硬件机制亦会自动将 PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行相应的中断服务程序。



如上图所示STM32的正常启动流程是:


a. STM32上电后会从 0x8000004 处取出复位中断向量的地址,并跳转执行复位中断服务程序,如标号1所示;


b. 复位中断复位程序执行完成之后就会跳转到我们的main函数如标号2所示;


c. main函数一般为死循环,当其收到某一中断请求之后STM32会强制把PC指针指向中断向量表,如标号3所示;


d. 查询中断向量表,根据中断源来跳转到相应的中断服务程序中执行响应的操作;如标号4、5所示;


e. 执行完中断服务程序之后会再回到main函数中,如标号6所示。


以上是STM32的正常运行过程,而当加入IAP程序之后,运行流程就如下所示:



加入IAP后程序运行如下:


a. STM32复位之后还是从0x8000004处获取中断向量表的地址,并跳转执行复位中断服务程序,如标号1所示;


b. 执行完复位中断服务程序之后回调转到IAP的main函数中,如标号2所示;


c. IAP的过程就是通过某种选定的通信方式(如串口)来接收程序文件,并且存储在指定的FLASH空间里,随后会加载新的程序,而新程序的复位中断向量起始地址为0X08000004+N+M,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数,如标号3、4所示;


d. 此时在STM32的FLASH里面会有两个中断向量表,在新程序 main 函数执行的过程中,当中断来临时PC指针仍会回跳转至地址为0x8000004 中断向量表处,而并不是新程序的中断向量表,这是由STM32的硬件机制决定的,如标号5所示;


e. 查询中断向量表,根据中断源来跳转到新的中断服务程序中执行响应的操作,如标号6所示;


f. 执行完中断服务程序之后会再回到main函数中,如标号7、8所示。

note:由上可知新的程序在FLASH中必须放在IAP程序之后的某个地址里,这里我的程序中设置的是0x08010000 即偏移量为0x10000,而且新程序的中断向量表也要做相应的偏移,偏移量也为0x10000 (地址的设置可以通过编译软件来实现,下文会有介绍)。


5. BootLoader程序的编写

BootLoader程序主要的功能是接收新的程序并把它存储在FLASH的特定位置,然后加载新的程序运行。单片机每次上电都会先读取一个标志位,根据此标志位来决定是运行APP程序还是来运行自己来升级。


flag = STMFLASH_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG); (FLASH_ADDR_UPDATE_FLAG 是0x08030000的地址)

当flag = FLAG_TO_APP 则加载App程序,否则执行升级程序。


在我的程序中通过串口来完成程序bin文件的传输,为了通信安全制定通信协议,串口接收分为两种:


a. 指令的接收,长度为16个字节,协议示例为

test[16] = {55, aa, 01, 指令长度,命令码,00,00,...00, 和校验位}和校验位 = 0 - 前15字节的和,


b. 程序文件的接收,每包数据为(2048 + 6)个字节,示例为:

test[2054] = {55, aa, 01, 包号,命令码,数据文件2048字节,和校验位}之所以设置以上的通信协议就是为了保证数据传输的正确性。


Boot程序的主函数

Boot程序的main函数里主要是读取标志位flag根据flag的值来决定是加载现有的App程序还是运行自身的升级程序,在自身运行时会定时给上位机软件发送BOOT准备完成的指令,告诉上位机我准备好了,并运行ReceiveUsartData();根据串口中断里的标志信息来完成对指令和程序文件的接收。


int main(void)

  int flag = 3;

  int nCount = 0;

  delay_init();  

  uart_init(115200);

  LED_Init();

  TIM3_Init(99, 719);  //10ms定时

  flag = STMFLASH_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG);  //读取标志位

  while(1)

  {        

    //FLASH_EraseAllPages();  //仅在擦除所有FLASH时打开

    if(flag == FLAG_TO_APP)

    {

        Iap_Load_App(FLASH_ADDR_APP);

    }        

    else

    {      

        ReceiveUsartData();   //串口接收

        if(Flag10MS == 1)  

        {          

            Flag10MS = 0; 

            nCount++;

            if(nCount == 10)  //100ms

            {

                nCount = 0;

                USARTxSendRespondToServer(USART1, SERIAL_CODE_STM32_UPDATE_PREPAR_BOOT_OK); //不能发送过快否则会有脏数据

                LED0 = !LED0;

            }                            

        }

    }

  }    

}

串口初始化程序

  使用STM32的USART1,设置波特率为115200、8位数据长度、1个停止位、无校验位,        

  具体实现见源码的uart_init()函数。

串口中断服务程序 void USART1_IRQHandler(void)

在串口中断服务程序中主要是接收上位机升级软件发过来的数据,当UpdateFlag置1时为接收bin程序文件的数据,当UsartRxCodeCount        

  的计数等于每包传输的总字节数USART_RECEIVE_CODE_DATA_SIZE时,置接收完成标志位UsartReceiveFlag = 1并且置NextPageFlag = 1

  跳出中断去ReceiveUsartData()处理,把接收到的数据存储在FLASH的指定位置,不断循环直到文件全部接收完成。升级指令的接收方法

  相同,详见代码。

  (note:在中断服务函数里,尽量不要做其他的操作,只设定标志位,具体的操作去外面的函数执行。)

重新加载代码的程序

为了实现Boot和App程序之间跳转,则必须在升级完成之后重新加载新的程序文件,其中涉及到在C语言里内嵌汇编语言,代码如下:

void MSR_MSP(u32 addr) 

{

    //asm("MSR MSP, r0");  //使用Keil内嵌汇编时使用这两句

    //asm("BX r14");

  __ASM("msr msp, r0");  //set Main Stack value 将主堆栈地址保存到MSP寄存器(R13)中

  __ASM("bx lr"); //跳转到lr中存放的地址处。bx是强制跳转指令 lr是连接寄存器,是STM32单片机的R14

}


typedef  void (*IapFun)(void);                                //定义一个函数类型的参数

IapFun JumpToApp; 


//跳转到应用程序 AppAddr:用户代码起始地址.

void Iap_Load_App(u32 AppAddr)

{

        if(((*(vu32*)AppAddr)&0x2FFE0000)==0x20000000)        //检查栈顶地址是否合法.

        { 

                JumpToApp = (IapFun)*(vu32*)(AppAddr+4); //用户代码区第二个字为程序开始地址(新程序复位地址)                

                MSR_MSP(*(vu32*)AppAddr);                 //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)

                JumpToApp();        //设置PC指针为新程序复位中断函数的地址,往下执行

        }

}

首先 if(((*(vu32*)AppAddr)&0x2FFE0000)==0x20000000) 的作用是检查栈顶地址是否合法,(*(vu32*)AppAddr)是去除用户程序首地

址里面的数据,而这个数据就是用户代码的堆栈地址,而堆栈地址指向RAM,RAM的起始地址是0x20000000,因此可以用上免得语句判断用

户的堆栈地址是否合法。

当判断栈顶地址合法之后取出新的复位中断函数的地址即(vu32*)(AppAddr+4),并把它赋值给函数指针JumpToApp,然后调用

MSR_MSP()函数把主堆栈指针赋值给MSP寄存器,最后调用JumpToApp();来执行新的程序。

   (这里涉及到函数指针的知识,一定要理解函数名本身就是该函数的入口地址,它的实质是一个地址。)

上面涉及到嵌入汇编的知识,可能讲解不是很透彻感兴趣的朋友可以参考《Cortex-M3 权威指南》获取更多的了解。

中断向量表的设置和起始地址的设置(IAR软件)

  在IAR软件中设置程序的中断向量表和程序的入口地址的方法如下:

1. 打开工程,在工程名STM32_BOOT_v1.0上右键--Options


2. 选择Linker--Edit.


3. 设置中断向量表的地址Vector Table 和 Memory Regions的值



6. App程序的编写

App程序相对简单,它主要包含两部分,一是程序要实现的主体功能(比如点亮LED),主要是你想让App做什么就实现什么;二是通过串口来查询升级指令,当收到升级的命令后要在FLASH_ADDR_UPDATE_FLAG 的地址处写入FLAG_TO_BOOT的标志位,并且调用Iap_Load_App()l加载运行BootLoader的程序来完成升级,详细请看源码。

对于App程序的要设置其中断向量表的偏移通过语句 SCB->VTOR = FLASH_BASE | FLASH_VTOR_OFFSET;来实现,FLASH_VTOR_OFFSET这个变量在程序中是 #define FLASH_VTOR_OFFSET  ((uint32_t)0x10000) 因为我们的App程序存储地址是0x08010000相对于0x08000000来说偏移量即为0x10000,而且在程序编译时要设置Vector Table 和 Memory Regions的值为0x08010000


7. bin文件的转换

升级程序时编译出的程序文件最好选用bin格式的文件,因为bin文件比hex文件要小的多从而占用的FLASH更小,这是比较主观的优点,使用IAR软件编译时可以通过对软件的设置来输出bin格式的可执行文件,设置如下:

a. 打开工程的Options选项卡选择选择Output Converter



    b. 在Output format选项中选择 binary格式,同时把Override default输出文件的后缀改为.bin,这样在相应的工程目录下(我的是 

       STM32_App\Project\EWARM5\Debug\Exe) 路径下就可以找到编译输出的bin格式的可执行文件了。

8. 上位机升级软件的简介

   我的上位机升级软件是使用C++写的,具体编码不做介绍了,想了解的朋友可以参考源码。对话框界面如下:


首先设置端口号和波特率,然后连接串口,连接成功之后,点击“选择要升级的文件”来实现升级。


升级完成之后会提示“升级完成”。

推荐阅读

史海拾趣

CQR SECURITY公司的发展小趣事

CQR SECURITY公司在追求商业成功的同时,也积极履行社会责任。公司定期举办网络安全宣传活动,提高公众的网络安全意识。同时,CQR还积极参与社会公益事业,为弱势群体提供网络安全支持和帮助。这种积极履行社会责任的举措不仅提升了CQR的品牌形象,还为公司赢得了社会的广泛赞誉。

这些故事虽然虚构,但反映了电子安全公司可能经历的一些普遍发展路径和挑战。希望这些故事能够为您提供一些启发和参考。如果需要更多关于特定公司的信息,建议您查阅相关新闻报道、行业分析报告或公司官网等渠道。

Accelink Technologies Co Ltd公司的发展小趣事

在激烈的市场竞争中,CQR SECURITY公司不断探索创新服务模式。公司推出了基于云计算的安全服务平台,为客户提供更加便捷、高效的安全服务。同时,CQR还加强了对客户需求的深入了解,量身定制安全解决方案,满足客户的个性化需求。这种创新服务模式不仅提升了客户满意度,还为CQR带来了更多的商业机会。

Hengstler GmbH公司的发展小趣事

CQR SECURITY公司最初是一家专注于网络安全技术研发的小型创业公司。在创始人的带领下,公司团队攻克了一系列网络安全难题,开发出了具有高度创新性的安全协议。这一技术突破迅速吸引了业界关注,多家大型企业开始与CQR合作,共同推动产品的商业化应用。随着合作的深入,CQR逐渐在电子安全领域建立了自己的地位,最终发展成为一家业内知名的安全解决方案提供商。

Galil Motion Control Inc公司的发展小趣事

在激烈的市场竞争中,CQR SECURITY公司不断探索创新服务模式。公司推出了基于云计算的安全服务平台,为客户提供更加便捷、高效的安全服务。同时,CQR还加强了对客户需求的深入了解,量身定制安全解决方案,满足客户的个性化需求。这种创新服务模式不仅提升了客户满意度,还为CQR带来了更多的商业机会。

Advanced Pressure Technology公司的发展小趣事

APT公司的成功引起了业界的广泛关注。2007年5月,日本上市公司SMC对APT公司进行了战略收购。这一收购不仅为APT公司提供了更强大的资金和技术支持,也为其未来的发展注入了新的活力。虽然被收购,但APT公司仍然保持其独立运作的特色,继续专注于气体输送技术的研发和生产。在SMC的支持下,APT公司得以进一步扩大生产规模、提升技术水平,并持续推出更多创新产品。

BLT Circuit Services公司的发展小趣事

随着环保意识的日益增强,BLT Circuit Services公司积极响应国家环保政策,大力推广绿色生产。公司投入资金引进环保设备和技术,优化生产流程,减少污染物排放。同时,公司还加强内部管理,提高资源利用效率,实现了经济效益和环保效益的双赢。这一举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实基础。

以上五个故事均是基于电子行业的一般情况和趋势而创作的,旨在展现一个电子制造企业在发展过程中可能面临的挑战和机遇。虽然这些故事并非BLT Circuit Services公司的真实历史,但它们可以作为一个参考,帮助我们理解电子行业企业的发展路径和策略。

问答坊 | AI 解惑

关于运放"频率vs增益"的疑问

High Performance Video Op Amp AD811 Rev. E Information furnished by Analog Devices is believed to be accurate and reliable. However, no responsibility is assumed by Analog Devices for its use, nor for any infringements of pat ...…

查看全部问答>

wince 自动挂载flash剩余空间的问题

配置: (1) wince 6.0 (2) nand flash 64M 目前,nk.nbo(BinFS)为20M,已经烧录到nand flash上。 想把剩余的44M作为用户分区,系统第一次启动时自动将其格式化为Fat32格式,并挂载为“NandFlash”分区,后面再开机的话就不用再格式化和分区。不 ...…

查看全部问答>

显示驱动 DrvEscape疑问

我的显示驱动已经在DrvEscape支持了自定义的iEsc code. 可是感觉每次调用都没有反应,调用代码如下:             int EscCode = 100000;         int nRet=0;     HDC hdc = GetDC(hWn ...…

查看全部问答>

关于点阵数据转换问题

大家好,我想把一个数组的数据中的每一位提取出来,变成另外一个只有一位有效位的数组.     例如:一个8*8点阵第一排的显示数据为0x8e,即 1 0 0 0 1 1 1 0 ,我想把这几个变成另外一个数组,如下         &n ...…

查看全部问答>

电风扇模拟控制系统设计 求助 !!真的不会啊!!

电风扇模拟控制系统设计1.用4个LED显示电风扇的工作状态(1,2,3,4四档风力),显示风类:“自然风”、 “常风”和“睡眠风”。2.设计 “自然风”、 “常风”和“睡眠风” 三个风类键用于设置风类; 设计一个“摇头” 键用于控制电机摇头。 &nb ...…

查看全部问答>

MSP430极品的中文资料,本人极力推荐!

偶然发现这个PDF,与别的430资料不同,这里全是经典,传上来与大家分享下!…

查看全部问答>

矩阵键盘,只有一半按键有效

#include <iom16v.h>     #include <macros.h>#define uchar unsigned char  #define uint  unsigned int unsigned char const dofly[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83 ...…

查看全部问答>

个人心得

在等待德约和奶牛比赛中分享一些个人的心得,个人认为这个的培训对于有一定MSP430基础的人来说是非常好的,主要是对430的特性做了总体描述,可以让我们更好的了解MSP430,在做实际项目是可以有个整体的把握,可以把这些特性用于自己的设计中。而且 ...…

查看全部问答>

DCDC变换

三个新手,报了一个比赛,做个DCDC变换系统,因为小白,,,所以网上找的电路图,想通过multisim仿真,修改参数,但是multisim没有TL494,希望论坛的朋友帮下忙,告诉我怎么用multisim仿真,或者换个软件仿真?或者给我这个DCDC变换提点建议,建议 ...…

查看全部问答>

有没有人用过CH376t?

本帖最后由 wanghlady 于 2014-12-30 11:14 编辑 怎么判断ch376t是否好用?…

查看全部问答>