STM32/GD32 IAP/Bootloader升级APP
STM32/GD32 IAP/Bootloader升级APP研究以及编程实现、hex文件格式一、Hex格式
【Intel英特尔Hex格式官方文档】
【什么是Hex文件格式?】
除每行开头的 ‘:’ 外,其它均是2字节表示一个十六进制数。例如02表示0x02,F2表示0xF2
行开头:每行以ASCII的 : 为开头
长度:标识数据区域的字节数
地址:相对于基地址的偏移地址
类型标识:有6种,如下表
数据区域
行校验: 冒号后、校验和前的值累加,并对和值按位取反后加1
在Keil MDK中更改程序起始地址 0x8000000 -> 0x8005000 后, hex文件的地址变化如下:
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));
} 加上以上代码以输出Flash地址的值,烧写程序之后,对比hex文件和打印结果
Flash支持16位半字写入和32位整字写入,且为小端格式。
选择半字写入时,向地址0x08000000写入0x5B88,向地址0x08000002写入0x2000,向地址0x08000004写入0x0145,…
选择整字写入时,向地址0x08000000写入0x20005B88,向地址0x08000004写入0x08000145,向地址0x08000008写入0x0800014D,… 烧写地址设置
在Keil MDK中,对Cortex-M3/4已经默认了程序烧录起始地址是0x08000000,并且可以选择在烧写程序前进行全片擦除或是按需擦除 。那么就可以划分出两块区域分别放Bootloader程序和APP程序。
例如如下划分
Bootloader在前:单片机上电时先运行Bootloader,等待升级指令。无指令时计时,超时进入APP;有升级指令,则开始升级APP即接收升级数据写入Flash,写入完成后跳转APP。
Bootloader在后:单片机上电时直接进入APP,运行过程中接收到升级指令后跳转Bootloader进行APP升级。升级完成后跳转APP。
同样的,在APP中也可升级Bootloader,但一般不需要。
Bootloader的功能尽量单一,大小尽量小,且占用的地址不能与APP的重叠。
需要特别注意的是,如果不勾选“Use Memory Layout from Target Dialog”,则上面选项卡中设置的地址是不起作用的,需要自行修改分散加载文件(未研究)。 Bootloader跳转APP
跳转前需要检查APP的栈顶指针是否合法、关闭所有中断、重设栈顶指针、偏移中断向量表(可以在APP中设置)。 定义如下数据
@ CSDN Tyrion.Mon
#define APP_LOADED_ADDR 0x5000 //APP加载地址
typedefvoid(*pAppFunction) (void);
pAppFunction application;
__IO uint32_t JumpAddress = NULL; 升级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
} 宏 APP_LOADED_ADDR 是APP的起始地址,而APP程序的起始是栈顶指针。
为什么加载地址不是0x8005000?
因为选择了从Flash启动,所以Flash被映射到了0x00000000。所以访问0x080050000和0x5000效果是一样的。 所以如果正确写入了APP,则 地址 (__IO uint32_t *)APP_LOADED_ADDR 处的栈顶指针必然在该型号单片机的SRAM大小范围内。96K Sram地址范围为0x2000 0000 - 0x2001 7FFF,64K Sram地址范围为0x2000 0000 - 0x2000 FFFF。 (0x20000000 == (((__IO uint32_t)APP_LOADED_ADDR) & 0x2FFE0000)) 表示的是从地址0x5000取出栈顶指针,通过运算检查栈顶地址是否落在0x2000 0000 - 0x2001 7FFF。64K的检查为(0x20000000 == (((__IO uint32_t)APP_LOADED_ADDR) & 0x2FFF0000))。相当于读出的值直接与Sram范围值比较。 跳转到APP不是跳转栈顶指针,而是跳转Reset_Handler,而Reset_Handler在栈顶指针后,所以需要偏移32位。 application为一个void类型的函数指针,并将其指向Reset_Handler的地址。application()表示执行指针指向的函数,即Reset_Handler函数。
页:
[1]
2