完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
一 STM32 IAP 原理分析
STM32 IAP的实现原理与STM8类似,只是STM32可以设置中断向量表的偏移,而STM8不能设置偏移只能通过中断向量表的重定向来实现APP程序中中断的使用。但是同样还是需要设计两个程序,在Bootloader程序通过某种通信方式,如 USB、 USART接收APP程序数据,并写入Flash中,然后跳转到APP程序的首地址,开始运行第二个程序。 首先我们来分析只有一个APP程序的时候STM32的运行流程图: 以STM32L4系列单片机为例,在官方手册中可以查到Flash的起始地址为0x0800 0000,通过上图可以看到在Flash的起始地址存放的是栈顶指针,紧接着就是中断向量表,中断向量表中的第一个中断向量就是复位中断向量。此时STM32的运行流程可以大致分为以下几步: 当加入Bootloader程序之后Flash中的内容变成了这样: 此时程序的运行流程发生了一些变化:
此时会出现一个问题:APP程序中的中断服务程序无法执行。 note:在STM8中可以通过重定向中断向量表,通过修改BootLoader的中断向量表中的内容,当PC指针指向第一个中断向量表(BootLoader的中断向量表)时,我们把中断向量表中原本应该跳转到中断服务函数的指令,修改为跳转到新的APP的中断向量表的指令,然后再跳转到APP的中断服务函数。这样就能在APP程序中使用中断了,但是这样存在的问题是,无法在BootLoader中使用中断了。显然,STM32仍然可以使用这种办法,只是对于STM32来说有更好的解决方案,STM32提供了中断向量表的偏移机制。只需要在APP程序的启动文件中设置好中断向量向量表的偏移地址,当在APP程序中产生中断请求时,PC指针会强制指向:原中断向量地址+偏移地址,这样就能在APP程序中使用中断了,而只要我们不在BootLoader中设置偏移,当BootLoader中产生中断请求时PC指针还是会指向它自己的中断向量表地址。这样无论在BootLoader中还是在APP中我们都能够使用中断了。 note:另外可以设置中断向量表的偏移还有另外一个好处,就是可以使用多个APP,因为只需要在APP程序中设置不同的中断向量表的偏移就行了,而如果用中断向量表的重定向就只能有一个APP应用程序了。二 STM32 IAP升级设计流程 有了以上对升级原理分析我们就可以来实现自己的IAP升级程序了。前面也已经说过了这里需要我们设计两个程序:
1.修改链接文件 由于BootLoader和APP程序需要烧录到不同的地址所以这里我们需要通过链接文件来对其的烧写地址进行修改。 a. 首先打开工程对应的*.icf链接文件: b. 这里我们以Flash中的程序为例,所以选择第一个icf文件,右键编辑: c.在Memory Regions栏可以看到该款芯片的ROM地址范围为0x0800 0000 - 0x0803 FFFF (256K),即Flash大小为256K。 d.对于BootLoader程序可以根据自己的需求自己设置大小,例如这里我们设置为32K。 e.APP程序直接使用剩下的空间即可(共224K)。 e.最后APP的链接文件中还需要重新设置中断向量表的起始地址。 2. 设置中断向量表的偏移地址(APP) 首先我们找到STM32的系统启动文件,这里以STM32L4为例: 在系统启动文件中找到SystemInit函数,并在最后两行可以看到如下代码: 这里可以设置SRAM和Flash中断向量表的偏移,这里以Flash为例所以需要检查VECT_TAB_SRAM是否被定义,如果定义了则需要取消,然后再设置宏VECT_TAB_OFFSET的值。在该文件中找到VECT_TAB_OFFSET宏,可以发现的初始值为0 由于我们之前设置了BootLoader的大小为32K,所以这里需要把VECT_TAB_OFFSET宏的值修改为0x8000 note:这里只需要设置APP程序的中断向量表的偏移,BootLoader不需要进行设置3. 编写Bootloader升级程序
typedef void (*PFN_Reset)(void); //定义函数指针类型 void vIapLoadApp(uint32_t xAppAddr) { uint32_t nMSP, xJumpAddr; /*栈顶指针*/ PFN_Reset vResetHandler = NULL; /*复位中断函数指针*/ /*app起始位置4个字节储存的是栈顶指针*/ nMSP = *((__IO uint32_t*)(xAppAddr)); /*取出复位中断函数的地址*/ xJumpAddr = *((__IO uint32_t*)(xAppAddr+4)); /*复位中断函数指针赋值*/ vResetHandler = (PFN_Reset)(xJumpAddr); /*检测栈顶指针是否合法*/ if((nMSP&0x2FFE0000) == 0x20000000) { /*初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)*/ __set_MSP(nMSP); /*跳转到APP(从APP复位中断向量处取指令执行)*/ vResetHandler(); } } |
|
|
|
只有小组成员才能发言,加入小组>>
3314 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9059 浏览 16 评论
4088 浏览 18 评论
1180浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 19:52 , Processed in 1.086652 second(s), Total 46, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号