打印
[其他]

STM32/GD32 IAP/Bootloader升级APP

[复制链接]
1036|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32/GD32 IAP/Bootloader升级APP研究以及编程实现、hex文件格式
一、Hex格式

【Intel英特尔Hex格式官方文档】
【什么是Hex文件格式?】

除每行开头的 ‘:’ 外,其它均是2字节表示一个十六进制数。例如02表示0x02,F2表示0xF2



行开头:每行以ASCII的 : 为开头
长度:标识数据区域的字节数
地址:相对于基地址的偏移地址
类型标识:有6种,如下表
数据区域
行校验: 冒号后、校验和前的值累加,并对和值按位取反后加1


使用特权

评论回复
沙发
铁血丹心LLLL|  楼主 | 2022-11-23 14:49 | 只看该作者

使用特权

评论回复
板凳
铁血丹心LLLL|  楼主 | 2022-11-23 14:50 | 只看该作者
在Keil MDK中更改程序起始地址 0x8000000 -> 0x8005000 后, hex文件的地址变化如下:

使用特权

评论回复
地板
铁血丹心LLLL|  楼主 | 2022-11-23 14:52 | 只看该作者
Hex数据域

@ CSDN Tyrion.Mon
for (i = 0; i < 10; i++)
{
       printf("%x, ", *((uint32_t *)0x8000000 + i));
}
printf("\r\n");
for (i = 0; i < 20; i++)
{
        printf("%x, ", *((uint16_t *)0x8000000 + i));
}
printf("\r\n");
for (i = 0; i < 40; i++)
{
        printf("%x, ", *((uint8_t *)0x8000000 + i));
}

使用特权

评论回复
5
铁血丹心LLLL|  楼主 | 2022-11-23 14:53 | 只看该作者
加上以上代码以输出Flash地址的值,烧写程序之后,对比hex文件和打印结果


    Flash支持16位半字写入和32位整字写入,且为小端格式。
    选择半字写入时,向地址0x08000000写入0x5B88,向地址0x08000002写入0x2000,向地址0x08000004写入0x0145,…
    选择整字写入时,向地址0x08000000写入0x20005B88,向地址0x08000004写入0x08000145,向地址0x08000008写入0x0800014D,…

使用特权

评论回复
6
铁血丹心LLLL|  楼主 | 2022-11-23 14:54 | 只看该作者
烧写地址设置

在Keil MDK中,对Cortex-M3/4已经默认了程序烧录起始地址是0x08000000,并且可以选择在烧写程序前进行全片擦除或是按需擦除 。那么就可以划分出两块区域分别放Bootloader程序和APP程序。

使用特权

评论回复
7
铁血丹心LLLL|  楼主 | 2022-11-23 14:55 | 只看该作者

使用特权

评论回复
8
铁血丹心LLLL|  楼主 | 2022-11-23 15:16 | 只看该作者
例如如下划分

使用特权

评论回复
9
铁血丹心LLLL|  楼主 | 2022-11-23 15:17 | 只看该作者
Bootloader在前:单片机上电时先运行Bootloader,等待升级指令。无指令时计时,超时进入APP;有升级指令,则开始升级APP即接收升级数据写入Flash,写入完成后跳转APP。
Bootloader在后:单片机上电时直接进入APP,运行过程中接收到升级指令后跳转Bootloader进行APP升级。升级完成后跳转APP。

使用特权

评论回复
10
铁血丹心LLLL|  楼主 | 2022-11-23 15:18 | 只看该作者
同样的,在APP中也可升级Bootloader,但一般不需要。
Bootloader的功能尽量单一,大小尽量小,且占用的地址不能与APP的重叠。

需要特别注意的是,如果不勾选“Use Memory Layout from Target Dialog”,则上面选项卡中设置的地址是不起作用的,需要自行修改分散加载文件(未研究)。

使用特权

评论回复
11
铁血丹心LLLL|  楼主 | 2022-11-23 15:19 | 只看该作者

使用特权

评论回复
12
铁血丹心LLLL|  楼主 | 2022-11-23 15:20 | 只看该作者

使用特权

评论回复
13
铁血丹心LLLL|  楼主 | 2022-11-23 15:22 | 只看该作者
Bootloader跳转APP

跳转前需要检查APP的栈顶指针是否合法、关闭所有中断、重设栈顶指针、偏移中断向量表(可以在APP中设置)。

使用特权

评论回复
14
铁血丹心LLLL|  楼主 | 2022-11-23 15:23 | 只看该作者
定义如下数据

@ CSDN Tyrion.Mon
#define APP_LOADED_ADDR                                                0x5000                //APP加载地址
typedef  void  (*pAppFunction) (void);
pAppFunction application;
__IO uint32_t JumpAddress = NULL;

使用特权

评论回复
15
铁血丹心LLLL|  楼主 | 2022-11-23 15:25 | 只看该作者
升级APP完成后,调用如下代码

@ CSDN Tyrion.Mon
/* APP栈顶指针合法 */
if (0x20000000 == ((*(__IO uint32_t*)APP_LOADED_ADDR) & 0x2FFE0000))
{
        __disable_irq();        //关闭所有中断
        JumpAddress = *(__IO uint32_t*)(APP_LOADED_ADDR + 4);        //Reset_Handler 入口地址
        application = (pAppFunction) JumpAddress;
        __set_MSP(*(__IO uint32_t*) APP_LOADED_ADDR);        //APP程序堆栈指针起始
        printf("APP地址%#x, \r\n", APP_LOADED_ADDR);
        application();        //跳转到Reset_Handler即APP
}

使用特权

评论回复
16
铁血丹心LLLL|  楼主 | 2022-11-23 15:26 | 只看该作者
宏 APP_LOADED_ADDR 是APP的起始地址,而APP程序的起始是栈顶指针。
为什么加载地址不是0x8005000?
因为选择了从Flash启动,所以Flash被映射到了0x00000000。所以访问0x080050000和0x5000效果是一样的。

使用特权

评论回复
17
铁血丹心LLLL|  楼主 | 2022-11-23 15:31 | 只看该作者
所以如果正确写入了APP,则 地址 (__IO uint32_t *)APP_LOADED_ADDR 处的栈顶指针必然在该型号单片机的SRAM大小范围内。96K Sram地址范围为0x2000 0000 - 0x2001 7FFF,64K Sram地址范围为0x2000 0000 - 0x2000 FFFF。

使用特权

评论回复
18
铁血丹心LLLL|  楼主 | 2022-11-23 15:34 | 只看该作者
(0x20000000 == (((__IO uint32_t)APP_LOADED_ADDR) & 0x2FFE0000)) 表示的是从地址0x5000取出栈顶指针,通过运算检查栈顶地址是否落在0x2000 0000 - 0x2001 7FFF。64K的检查为(0x20000000 == (((__IO uint32_t)APP_LOADED_ADDR) & 0x2FFF0000))。相当于读出的值直接与Sram范围值比较。

使用特权

评论回复
19
铁血丹心LLLL|  楼主 | 2022-11-23 15:35 | 只看该作者
跳转到APP不是跳转栈顶指针,而是跳转Reset_Handler,而Reset_Handler在栈顶指针后,所以需要偏移32位。

使用特权

评论回复
20
铁血丹心LLLL|  楼主 | 2022-11-23 15:36 | 只看该作者
application为一个void类型的函数指针,并将其指向Reset_Handler的地址。application()表示执行指针指向的函数,即Reset_Handler函数。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

495

帖子

1

粉丝