我来这里是想问一些有关我的项目的问题。
现在我正在实现一个精简版虚拟机管理程序。
所以我做了三个独立的项目(monitor.bin,OS1.bin,OS2.bin),并划分了内存。
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
RAM1 (xrw) : ORIGIN = 0x20008000, LENGTH = 32K
FLASH1 (rx) : ORIGIN = 0x8020000, LENGTH = 128K
RAM2 (xrw) : ORIGIN = 0x20010000, LENGTH = 32K
FLASH2 (rx) : ORIGIN = 0x8040000, LENGTH = 128K
}
// the part I revised in linker script file for monitor.bin, STM32F407VGTX_RAM.ld, STM32F407VGTX_FLASH.ld
MEMORY
{
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20008000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x8020000, LENGTH = 128K
}
// the part I revised in linker script file for OS1.bin, STM32F407VGTX_RAM.ld, STM32F407VGTX_FLASH.ld.
// In case of OS2.bin, RAM ORIGIN = 0x20010000, FLASH ORIGIN = 0x08040000
并且我修改了每个项目中中断的矢量偏移部分。
#define USER_VECT_TAB_ADDRESS
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
in Sram else user remap will be done in Flash. */
/*#define VECT_TAB_SRAM*/
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00020000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
// this is for OS1.bin
// In case for OS2.bin, OFFSET WAS 0x00040000U
经过修改至此,每个项目都被确认运行良好。
但我想做的是实现从监视器跳转到OS1和OS2。
所以我修改了一些代码,但是当我将程序计数器设置为OS1、OS2时,它不起作用。
int main (void) {
clk();
RCC->CFGR |= 0x04600000;
while(1) {
if(os1 == 0){
if(os1_first == 1){
os1 = 1;
os1_first = 0;
SCB->VTOR = (uint32_t) 0x8020000;
__set_MSP(0x20010000);
__set_PSP(0x20010000);
asm("BX %0" ::"r"(0x8020000));
}
else{
SCB->VTOR = (uint32_t) 0x8020000;
__set_MSP(0x20010000);
__set_PSP(0x20010000);
}
}
else{
if(os2_first == 1){
os1 = 0;
os2_first = 0;
SCB->VTOR = (uint32_t) 0x8040000;
__set_MSP(0x20018000);
__set_PSP(0x20018000);
asm("BX %0" ::"r"(0x8040000));
}
else{
}
}
}
}
// main.c for monitor
int main (void) {
clk();
//GPIO, Timer Interrupt init part omitted
while(1) {
if(jump_monitor == 1){
jump_monitor = 0;
__set_MSP(0x20000000);
__set_PSP(0x20000000);
asm("BX %0" ::"r"(0x8000000));
}
}
}
void TIM2_IRQHandler() {
TIM2->SR = 0;
GPIOD->ODR ^= (1<<13);
if(first == 1){
first = 0;
}
else{
jump_monitor = 1;
}
}
main.c for OS1.bin
我想要的代码流程如下。
监控 -> OS1(2秒左右) -> 监控 -> OS2(2秒左右) -> 监控....
但是每次我尝试使用 asm("BX") 更改程序计数器时,都会陷入硬故障。
我认为我想要的行为与bootloader的行为类似,所以我对bootloader做了一些参考。
我思考了问题的可能性。
:在STM32CUBEIDE中,我在“运行配置”-“启动”选项卡中使用了加载图像和符号,但不起作用。
:所以我使用了STM32CubeProgrammer,并在下载选项卡中选中了“编程前跳过闪存擦除”选项。 并加载三个二进制文件(monitor.bin、OS1.bin、OS2.bin),并修改起始地址。
:我在设置程序计数器值之前设置了SCB->VTOR、MSP、PSP。 但是在设置程序计数器之前还需要设置什么吗?
:我检查了引导加载程序代码,发现它们在跳转到应用程序之前设置了 VTOR、MSP、PSP 值。
:我认为跳转到应用程序的起始地址可以使执行工作,从启动代码到 main.c 。
我写的时候问题有点长,有人能回答吗?
我想从monitor.bin跳转到OS1.bin和OS2.bin
监视器.bin RAM 起始地址:0x20000000 闪存起始地址:0x08000000
OS1.bin 内存起始地址:0x20008000 闪存起始地址:0x08020000
OS1.bin 内存起始地址:0x20010000 闪存起始地址:0x08040000
我解决了。但我不太明白这个机制。
我没有使用BX(通过内联汇编跳转到应用程序),而是使用函数指针到达地址,然后发生跳转。
使用函数指针和使用内联汇编到达地址有什么区别?