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

时间:2014-01-24 10:01:40

标签: c memory interrupt stm32 remap

我目前正在开发针对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; index<= (IRQn_Type)28; index++) //Disable all interrupts
    NVIC_DisableIRQ(index);

  AppEntry = (MyFunc_ptr) INTFLASH_calculate_page_addr(IAP_APP_START_PAGE);

  if( mode || intflash_check_main_app() )
  {
    Main_App_ptr = (uint8_t*)AppEntry;
    if( (*Main_App_ptr != 0xFF) &&  (Main_App_ptr) )
    {
      AppEntry();
    }
  }           
  memcpy( (void*)&NVIC->ISER, 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)
  }
}

3 个答案:

答案 0 :(得分:2)

在文件'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,则将所有上述数据保存在全局缓冲区中,以便在到达{后可以查看它{1}}。

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

答案 1 :(得分:2)

你必须跳到&#34;应用程序地址+ 4&#34;因为应用程序的基址包含初始堆栈指针位置。所以跳转到这个地址意味着跳转到堆栈基地址。 在应用程序地址+ 4(由于32位架构而为+ 4B)下,存在重置处理程序过程的地址。

答案 2 :(得分:0)

硬故障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 ***************************/       
}

请参阅下面我的新bootloader 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();
}

非常感谢