C 在STM32F1上的应用程序之间跳转 背景

C 在STM32F1上的应用程序之间跳转 背景,c,arm,microcontroller,stm32,qemu,C,Arm,Microcontroller,Stm32,Qemu,我试图在STM32F1微控制器上实现应用程序之间的跳转。我正在使用qemu(由GNU MCU Eclipse提供)来模拟使用STM32F103RBT6微控制器的Olimex-H103板。我正在用我在ebay上买的“蓝色药丸”在实际硬件上测试它。蓝色药丸配备STM32F103C8T6微控制器。这两个微控制器非常相似,甚至共享来自某些来源的数据表 STM32F103RBT6 Olimex总管板 STM32F103C8T6蓝丸 我的应用程序是一个主应用程序,它将第二个应用程序加载到内存中,然后跳转

我试图在STM32F1微控制器上实现应用程序之间的跳转。我正在使用qemu(由GNU MCU Eclipse提供)来模拟使用STM32F103RBT6微控制器的Olimex-H103板。我正在用我在ebay上买的“蓝色药丸”在实际硬件上测试它。蓝色药丸配备STM32F103C8T6微控制器。这两个微控制器非常相似,甚至共享来自某些来源的数据表

STM32F103RBT6 Olimex总管板

STM32F103C8T6蓝丸

我的应用程序是一个主应用程序,它将第二个应用程序加载到内存中,然后跳转到内存中。主应用程序作为默认的STM32F1项目由GNU MCU Eclipse编译和链接,而第二个应用程序是一个C程序,通过链接脚本编译和链接(只指定内存位置和大小),因此向量表没有对齐方式。第二个应用程序与主应用程序捆绑在一起,它是一个复制到内存中的字符数组。主应用程序还有一个查找表,用于将要向辅助应用程序公开的应用程序

void hello_world();

unsigned int lookup_table[] = {
      (unsigned int)&hello_world
};
将辅助应用程序放入内存(并验证其已正确复制)后,主应用程序跳转到该应用程序并将引用传递到其查找表:

typedef int(*AppFunc)(unsigned int);
// Application is compiled with -mthumb, hence the +1 to the address
AppFunc appFunc = (AppFunc)(((uint32_t)0x20003000) + 1);
appFunc((unsigned int)&lookup_table);
然后,辅助应用程序应该能够从查找表中的引用调用函数

void start(unsigned int *lookup_table)
{
    typedef void(*void_f)();
    static void_f hello_func = (void_f)*(lookup_table);

    hello_func();
}
当应用程序完成时,执行应该返回到主应用程序(因为返回地址在堆栈上?)

澄清:我(目前)不更改向量表或堆栈指针,因为我希望它们保持一致(如果可能的话)


问题 这一切在qemu上都可以正常工作,但在真正的硬件上却不行。在qemu中,它跳转到第二个应用程序,在主应用程序中执行函数,完成后跳回主应用程序。但是,在实际的硬件上,如果start()调用查找表中的方法,它会在jump之后暂停,否则它可以正常工作(空start()),但我希望能够跳回主应用程序并在那里执行函数

这是qemu中的一个bug吗?是硬件问题还是代码问题?我真的不明白问题出在哪里,因为qemu可以完美地运行应用程序


提前谢谢

第二个应用程序的链接器知道它在内存中的位置吗?您不能将其链接为从flash运行,然后将其复制到其他地址空间并期望其正常工作

向量表中的第一个位置是堆栈顶部的地址。您需要更改
AppFunc-AppFunc=(AppFunc)((uint32_t)0x20003000)+1)
AppFunc-AppFunc=(AppFunc)((uint32_t)0x200003004))
以获取重置处理程序的地址


您不需要+1地址,它由编译器为您处理。您的地址中有一个指针,指向重置向量所在的位置。

我正在使用以下函数

typedef void (application_t)(void);

typedef struct vector
{
    uint32_t        stack_addr;     // intvec[0] is initial Stack Pointer
    application_t*   func_p;        // intvec[1] is initial Program Counter
} vector_t;

void jump_to(const uint32_t addr)
{
    const vector_t* vector_p = (vector_t*)addr;

    // TODO peripheral deinit

    /* Disable interrupt */
    NVIC->ICER[0]=0xFFFFFFFF;
    NVIC->ICPR[0]=0xFFFFFFFF;
#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2
    NVIC->ICER[1]=0xFFFFFFFF;
    NVIC->ICPR[1]=0xFFFFFFFF;
#endif

    /* Set new vector table */
    SCB->VTOR = (uint32_t)addr;

    /* Jump, used asm to avoid stack optimization */
    asm("\n\
        msr msp, %0; \n\
        bx %1;" : : "r"(vector_p->stack_addr), "r"(vector_p->func_p));
}

无论如何,如果有疑问,或者工具没有帮助,请不要使用+1地址,而不是添加地址。在这种情况下,尽管地址必须设置lsbit,或者它不能在cortex-m上工作,但在硬编码时,您必须以某种方式设置该位。您的分支目的地是0x20003000还是您的表是0x20003000,并且地址是表中的一项?省去您的烦恼,想想还是一个不加一,在这种情况下,如果这是branchIt的目标地址,则两者都可以。在我看来,您不需要设置表地址的lsbit,相反,hello_world应该已经设置了lsbit,但这取决于工具和调用方式等。qemu可能实际上没有查看lsbit(因此执行良好)因此,检查表,反汇编,看看你看到了什么。可移植性备注:1)指针不能保证适合
int
,2)函数指针不能保证适合数据指针。如果启用所有警告并将其设置为错误,则需要一个合理的编译器。