Jumping from one firmware to another in MCU internal FLASH

user3065932 picture user3065932 · Jan 24, 2014 · Viewed 8.2k times · Source

I am currently working on a bootloader firmware application targeted to STM32F030C8. I specified in my scatter file that the bootloader app will occupy main memory location 0x08000000 to 0x08002FFF (sector 0 to sector 2). I also wrote a main firmware application that is stored from 0x08003000 to 0x0800C800. After downloading both firmware to the MCU internal FLASH, I lauched the main app from the bootloader using the code below:

/************************************************************//**
* \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
}

For some reason, when it executes AppEntry(), it jumps to the code below and does not execute the main app at location 0x08003000:

HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler              [WEAK]
                B       .
                ENDP

I have used this sort of logic before on ARM7 MCU and it works fine, I cannot quite figure out why it doesnt work on this cortex M0 based MCU. Any help would be greatly appreciated.

See Scatter files for bootloader and main app below:

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)
  }
}

Answer

barak manos picture barak manos · Jan 24, 2014

In file 'startup_stm32f03xx.s', make sure that you have the following piece of code:

EXTERN  HardFault_Handler_C        ; this declaration is probably missing

__tx_vectors                       ; this declaration is probably there
    DCD     HardFault_Handler

Then, in the same file, add the following interrupt handler (where all other handlers are located):

    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

Then, in file 'stm32f03xx.c', add the following 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);
}

If you can't use printf at the point in the execution when this specific Hard-Fault interrupt occurs, then save all the above data in a global buffer instead, so you can view it after reaching the while (1).

Then, refer to the 'Cortex-M Fault Exceptions and Registers' section at http://www.keil.com/appnotes/files/apnt209.pdf in order to understand the problem, or publish the output here if you want further assistance.