欢迎大家留言交流~
一、因为要做模块的升级所以需要用到bootloader。先捋清楚一下各步骤:
1.划分flash区间。我的模块是stm32f103RB,flash大小是128k字节(0x2000)。我打算将flash分为三个部分:bootloader(0x8000000~0x8004000)、应用程序代码(0x8004000~0x8012000)、待升级的IAP程序(0x8012000~0x8020000)。
2.划分FRAM区间,总共0x2000字节,bootloader要记录是否需要IAP所以需要占用一些FRAM空间(0x0000~0x0100),应用程序占用(0x0100~0x2000)。
3.bootloader先实现跳转到flash应用程序app的目标位置。(IAP先不考虑)
4.跳转后成功执行app。
二、先用cubeMX生成bootloader:
1.选择芯片
2.选上需要的功能,首先是必须的RCC、SYS、IWDG。因为要用到FRAM所以需要用到I2C2。
3.对照原理图核对管脚是否正确,并且增加LED灯用来辅助调试boot
FRAM-WP、LED3、LED4、LED5都设置为output。其他默认
4.配置时钟为72M
5.详细配置,默认即可
6.工程设置
然后生成代码即可。在代码中cubeMX只是初始化了配置,但是并没有使用,比如开启了看门狗,但是并未喂狗,需要自行喂狗。因为bootloader的特殊性,并不需要喂狗,也并不需要有什么内容是放在while(1)中的,因为bootloader只运行一次,主要就是执行跳转指令。
7.生成代码后打开工程,修改工程配置
因为bootloader大小设置为0x4000大小,所以size设置一下
然后就是debug设置为J-LINK,SWD
8.代码实现
创建代码后如何验证程序可用呢?我在while(1)里加了延时和翻转小灯的状态,这样每循环两次小灯就闪烁一次。在这里我是一次成功的。当然,需要喂狗。
那么如何跳转到flash目标地址呢?
app_iap.c
app_iap.h
加上这两个文件,然后在主函数中调用IAP_ExecuteApp(USER_ADDR_APP);
为了验证这个bootloader好用,我们在这个bootloader的小灯初始化时,让LED3常亮,LED4、LED5长灭。
让应用程序初始化小灯时LED3为灭,并且LED5常量,LED4闪烁。这样如果成功的话,那么理论上LED3亮一下,随后熄灭,LED4闪烁,LED5常亮。
9.设置启动
当然,要设置一下应用程序的配置,修改起始地址和大小
之后重新编译,烧录,但是结果并不对,LED3几乎是常亮,间歇短暂熄灭的时候LED4、LED5也短暂闪烁一下,随后熄灭。
找了很久的原因,以为是触发了看门狗,或者是没有关闭中断。但其实都不是,是因为向量表没有更改
在应用程序的中的这个文件VECT_TAB_OFFSET默认是0x00000000U,但是我们应该更改为起始地址中0x08004000的0x00004000U。
编译后,就可以正常跳转了。但是根据同事的意见,还是要在跳转指令前关闭一下全局中断才好。
__disable_irq(); // 关闭总中断
__enable_irq(); // 开启总中断
于是我在跳转指令前加了关闭总中断,但又出现跳转失败的情况。通过debug发现可以跳转到应用程序成功,但是还是会在初始化的过程中死机,所以我在应用程序中的第一句加上打开总中断,这时跳转成功并且应用程序运行正常了。
搞不清楚这个原因,时间有限暂且不研究了,不过这是一个值得尝试的地方。我还是暂且不用这两句话吧。
到此,bootloader的跳转功能实现了,接下来要实现程序升级。
总结:
bootloader是常用的引导程序,可以实现诸如IAP、U盘升级、引导程序等功能。
我们在做的时候需要注意,APP的中断向量表需要修改,因为中断向量表都是默认指向0x0000000的,bootloader一个启动文件、一个中断向量表。APP一个启动文件、一个中断向量表