MCU bootload IAP程序是如何跳转的?需要注意哪些事项呢?
2021-11-29 09:06:51
这里是引用
https://www.jianshu.com/p/2eef44b1cfd3 <
>
https://blog.csdn.net/tq384998430/article/details/81010002<<设计一款STM32的BootLoader>>
https://blog.csdn.net/baideweidao/article/details/82774808<>
http://news.eeworld.com.cn/mcu/2018/ic-news081940854.html<>
https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/<>
https://blog.csdn.net/yangzhao0001/article/details/73293379<>
...
由于我写的GD的32E230 ARM® Cortex®-M23核,与STM32有些库不太一样,根据参考文献自己写了段代码测试发现可以跳转,单独使用boot和app都没有问题,但一组合app就频繁重启,经过同事帮助下才找到问题根本.
MCU启动是从FLASH起始地址开始的;ARM® Cortex®-Mxx常见的FALSH起始地址0x08000000.
我们现在把bootload代码区放在0x08000000,根据需要划分4K~16K的空间,空间必须FLASH最小块的整倍数;剩下的用来放应用程序(APP)代码.
代码划分参考"百度"<<分散加载>>.
bootload跳转代码及注意:
#define APP_ADDRESS (uint32_t)0x08004000
/* Private typedef -----------------------------------------------------------*/
typedef void (*pFunction)(void); /*!< Function pointer definition */
void vJumpToApplication(void)
{
uint32_t JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
pFunction Jump_To_Application;
if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000) //ApplicationAddress为新程序的起始地址,检查栈顶地址是否合法,即栈顶地址是否为0x2000xxxx(内置SRAM)
{
usart_disable(USART0); //这里是在跳转前关闭已经初始化的外设
usart_disable(USART1);
rcu_deinit();
__set_MSP(*(__IO uint32_t*) APP_ADDRESS); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
SCB->VTOR = APP_ADDRESS; //重定向中断向量表
JumpAddress = *(__IO uint32_t*) (APP_ADDRESS + 4); //用户代码区第二个字存储为新程序起始地址(新程序复位向量指针)
Jump_To_Application = (pFunction) JumpAddress;
Jump_To_Application(); //设置PC指针为新程序复位中断函数的地址
}
else
{
printf("!!!!!!ERROR:APP_ADDRESS ERR!!!!!!!!!n");
}
}
注意:无意中参考到部分资料中说跳转前要屏蔽中断调用__set_PRIMASK(1),我就在这句话中上当.
在跳转前调用用屏蔽了中断,跳转后如果不及时恢复(正常情况不会有人去恢复)那么代码就会进不了中断造成异常.
正常情况下在跳转前需要关闭在bootload中打开的外设,初始化APP堆栈指针;中断向量表可选择是否重定向.
用户程序(APP)需要修改内容:
在main()第一行加入以下代码
SCB->VTOR = 0x08004000;
如果boolload和APP是分开烧写,就参考普通<<分散加载>>处理就可以了;现在我希望把bootload的代码以库或者镜像的方式直接加载在APP程序中,这样就不用合并两份代码:
链接文件
APP 0x08004000 0x0000C000 { ; load region size_region
app_update.bin 0x08004000 0x0000C000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00002000 { ; RW data
.ANY (+RW +ZI)
}
}
//这个区域用来加载bootload镜像
UBOOT 0x08000000 0x00004000 { ; load region size_region
boot.bin 0x08000000 0x00004000 { ; load address = execution address
*(.boot)
}
}
新建一个.S文件
AREA |.boot|, DATA, READONLY
ALIGN 4
EXPORT __uboot_start_addr
__uboot_start_addr ;Must set the top
INCBIN ../BootLoad/HJ-GD32E230-boot.img ;这里就是引用我们的bootload的镜像
END
这里说明一下"__uboot_start_addr",这是用汇编声明的一变量,在这里本来是任何作用,那为什么还要声明呢?是因为如果只是这样将bootload加载到app程序中,bootload并不能被编译到应用程序中,这里就需要在app中调用一下这个变量,这样bootload镜像就能被正常加载,如:printf("%x",__uboot_start_addr);
如果各位大佬就更好的方法请不吝赐教.
bootload代码如果输出.bin或.img文件,使用以下.
C:Keil_v5ARMARMCCbinfromelf.exe --bin --output “ L @ L . i m g " " L@L.img" " L@L.img""L@L.axf”
这里是引用
https://www.jianshu.com/p/2eef44b1cfd3 <
>
https://blog.csdn.net/tq384998430/article/details/81010002<<设计一款STM32的BootLoader>>
https://blog.csdn.net/baideweidao/article/details/82774808<>
http://news.eeworld.com.cn/mcu/2018/ic-news081940854.html<>
https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/<>
https://blog.csdn.net/yangzhao0001/article/details/73293379<>
...
由于我写的GD的32E230 ARM® Cortex®-M23核,与STM32有些库不太一样,根据参考文献自己写了段代码测试发现可以跳转,单独使用boot和app都没有问题,但一组合app就频繁重启,经过同事帮助下才找到问题根本.
MCU启动是从FLASH起始地址开始的;ARM® Cortex®-Mxx常见的FALSH起始地址0x08000000.
我们现在把bootload代码区放在0x08000000,根据需要划分4K~16K的空间,空间必须FLASH最小块的整倍数;剩下的用来放应用程序(APP)代码.
代码划分参考"百度"<<分散加载>>.
bootload跳转代码及注意:
#define APP_ADDRESS (uint32_t)0x08004000
/* Private typedef -----------------------------------------------------------*/
typedef void (*pFunction)(void); /*!< Function pointer definition */
void vJumpToApplication(void)
{
uint32_t JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
pFunction Jump_To_Application;
if (((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000) //ApplicationAddress为新程序的起始地址,检查栈顶地址是否合法,即栈顶地址是否为0x2000xxxx(内置SRAM)
{
usart_disable(USART0); //这里是在跳转前关闭已经初始化的外设
usart_disable(USART1);
rcu_deinit();
__set_MSP(*(__IO uint32_t*) APP_ADDRESS); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
SCB->VTOR = APP_ADDRESS; //重定向中断向量表
JumpAddress = *(__IO uint32_t*) (APP_ADDRESS + 4); //用户代码区第二个字存储为新程序起始地址(新程序复位向量指针)
Jump_To_Application = (pFunction) JumpAddress;
Jump_To_Application(); //设置PC指针为新程序复位中断函数的地址
}
else
{
printf("!!!!!!ERROR:APP_ADDRESS ERR!!!!!!!!!n");
}
}
注意:无意中参考到部分资料中说跳转前要屏蔽中断调用__set_PRIMASK(1),我就在这句话中上当.
在跳转前调用用屏蔽了中断,跳转后如果不及时恢复(正常情况不会有人去恢复)那么代码就会进不了中断造成异常.
正常情况下在跳转前需要关闭在bootload中打开的外设,初始化APP堆栈指针;中断向量表可选择是否重定向.
用户程序(APP)需要修改内容:
在main()第一行加入以下代码
SCB->VTOR = 0x08004000;
如果boolload和APP是分开烧写,就参考普通<<分散加载>>处理就可以了;现在我希望把bootload的代码以库或者镜像的方式直接加载在APP程序中,这样就不用合并两份代码:
链接文件
APP 0x08004000 0x0000C000 { ; load region size_region
app_update.bin 0x08004000 0x0000C000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00002000 { ; RW data
.ANY (+RW +ZI)
}
}
//这个区域用来加载bootload镜像
UBOOT 0x08000000 0x00004000 { ; load region size_region
boot.bin 0x08000000 0x00004000 { ; load address = execution address
*(.boot)
}
}
新建一个.S文件
AREA |.boot|, DATA, READONLY
ALIGN 4
EXPORT __uboot_start_addr
__uboot_start_addr ;Must set the top
INCBIN ../BootLoad/HJ-GD32E230-boot.img ;这里就是引用我们的bootload的镜像
END
这里说明一下"__uboot_start_addr",这是用汇编声明的一变量,在这里本来是任何作用,那为什么还要声明呢?是因为如果只是这样将bootload加载到app程序中,bootload并不能被编译到应用程序中,这里就需要在app中调用一下这个变量,这样bootload镜像就能被正常加载,如:printf("%x",__uboot_start_addr);
如果各位大佬就更好的方法请不吝赐教.
bootload代码如果输出.bin或.img文件,使用以下.
C:Keil_v5ARMARMCCbinfromelf.exe --bin --output “ L @ L . i m g " " L@L.img" " L@L.img""L@L.axf”
举报