在MCU内部FLASH中从一个固件跳转到另一个固件

我目前正在开发针对STM32F030C8的引导加载程序固件应用程序。 我在我的分散文件中指定引导加载程序应用程序将占用主存储器位置0x08000000到0x08002FFF(扇区0到扇区2)。 我还写了一个主要的固件应用程序,存储从0x08003000到0x0800C800。 将两个固件下载到MCU内部FLASH后,我使用以下代码从引导加载程序中激活了主应用程序:

/************************************************************//** * \brief Start the main application if available and correct *****************************************************************/ void INTFLASH_execute_main_app(const char mode) { MyFunc_ptr AppEntry; uint32_t temp[1]; IRQn_Type index; memcpy(temp, (void*)&NVIC->ISER, sizeof(NVIC->ISER)); //Save enabled interrupts for( index = (IRQn_Type)0; indexISER, temp, sizeof(NVIC->ISER) ); //Restore interrupts } 

出于某种原因,当它执行AppEntry()时,它会跳转到下面的代码,并且不会在位置0x08003000处执行主应用程序:

 HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP 

我之前在ARM7 MCU上使用过这种逻辑,它工作正常,我无法弄清楚为什么它不适用于这种基于Cortex M0的MCU。 任何帮助将不胜感激。

请参阅下面的引导加载程序和主应用程序的分散文件:

 LR_IROM1 0x08000000 0x00003000 { ; load region size_region ER_IROM1 0x08000000 0x00003000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00002000 { ; RW data .ANY (+RW +ZI) } } LR_IROM1 0x08003000 0x0000C800 { ; load region size_region ER_IROM1 0x08003000 0x0000C800 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00002000 { ; RW data .ANY (+RW +ZI) } } 

您必须跳转到“应用程序地址+ 4”,因为应用程序的基址包含初始堆栈指针位置。 因此跳转到此地址意味着跳转到堆栈基地址。 在app地址+ 4(因为32位架构而为+ 4B)下,有重置处理程序的地址。

在文件’startup_stm32f03xx.s’中,确保您有以下代码:

 EXTERN HardFault_Handler_C ; this declaration is probably missing __tx_vectors ; this declaration is probably there DCD HardFault_Handler 

然后,在同一文件中,添加以下中断处理程序(所有其他处理程序所在的位置):

  PUBWEAK HardFault_Handler SECTION .text:CODE:REORDER(1) HardFault_Handler TST LR, #4 ITE EQ MRSEQ R0, MSP MRSNE R0, PSP B HardFault_Handler_C 

然后,在文件’stm32f03xx.c’中,添加以下ISR:

 void HardFault_Handler_C(unsigned int* hardfault_args) { printf("R0 = 0x%.8X\r\n",hardfault_args[0]); printf("R1 = 0x%.8X\r\n",hardfault_args[1]); printf("R2 = 0x%.8X\r\n",hardfault_args[2]); printf("R3 = 0x%.8X\r\n",hardfault_args[3]); printf("R12 = 0x%.8X\r\n",hardfault_args[4]); printf("LR = 0x%.8X\r\n",hardfault_args[5]); printf("PC = 0x%.8X\r\n",hardfault_args[6]); printf("PSR = 0x%.8X\r\n",hardfault_args[7]); printf("BFAR = 0x%.8X\r\n",*(unsigned int*)0xE000ED38); printf("CFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED28); printf("HFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED2C); printf("DFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED30); printf("AFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED3C); printf("SHCSR = 0x%.8X\r\n",SCB->SHCSR); while (1); } 

如果在执行此特定硬故障中断时无法在执行时使用printf ,则将所有上述数据保存在全局缓冲区中,以便在到达while (1)后查看它。

然后,请参阅http://www.keil.com/appnotes/files/apnt209.pdf上的“Cortex-M故障exception和寄存器”部分以了解问题,或者如果您需要进一步的帮助,请在此处发布输出。

硬故障ISR向我指出故障所在。 R0有__initial_sp,这是堆栈的顶部。 它让我意识到我必须在跳转到应用程序之前在引导加载程序中初始化我的应用程序的堆栈指针。 完成后我现在可以从引导程序成功跳转到应用程序。 跳转地址也必须(由于某种原因我不太明白)应用程序地址+4。

另请注意,您需要修改主应用程序RAM分配,从0x200000C0开始,大小为0x00001FD0。 这样做可以将向量表重新定位到主应用程序“main”函数中0x20000000的内部SRAM,如下所示:

 /* Private macro -------------------------------------------------------------*/ __IO uint32_t VectorTable[48] __attribute__((at(0x20000000))); /************************************************************//** * \brief Main application application entry point * * At this stage the microcontroller clock setting is already configured, * this is done through SystemInit() function which is called from startup * file (startup_stm32f030x8.s) before to branch to application main. * To reconfigure the default setting of SystemInit() function, refer to * startup_stm32f030x8.c file *****************************************************************/ int main( void ) { uint32_t i = 0; uint8_t status; /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ /* Copy the vector table from the Flash (mapped at the base of the application load address 0x08003000) to the base address of the SRAM at 0x20000000. */ for(i = 0; i < 48; i++) { VectorTable[i] = *(__IO uint32_t*)(IAP_BTLUPG_ADDRESS + (i<<2)); } RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable the SYSCFG peripheral clock*/ SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_MODE; /* Remap SRAM at 0x00000000 */ /***************** Application code starts below ***************************/ } 

请参阅下面的新的引导加载程序INTFLASH_execute_main_app函数:

 void INTFLASH_execute_main_app(const char mode) { MyFunc_ptr Jump_To_Application; uint32_t JumpAddress; // __disable_irq(); JumpAddress = *(__IO uint32_t*) (IAP_APP_ADDRESS + 4); Jump_To_Application = (MyFunc_ptr) JumpAddress; if( mode || intflash_check_main_app() ) { App_ptr = (uint8_t*)Jump_To_Application; if( (*App_ptr != 0xFF) && (App_ptr) ) { __set_MSP( *(__IO uint32_t*)IAP_APP_ADDRESS ); // Initialise app's Stack Pointer Jump_To_Application(); } } // __enable_irq(); } 

非常感谢