问题
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)
}
}
回答1:
You have to jump to "the application address + 4" because the base address of the application holds the initial stack pointer position. So jumping to this address means jumping to the address of stack base. Under the app address + 4 (+4B because of 32-bit architecture) there's the address of reset handler procedure.
回答2:
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.
回答3:
The Hard Fault ISR indicated to me where the fault was. R0 had __initial_sp which is the top of the stack. It made me realise that I had to initialise my application's Stack pointer in the bootloader before jumping to the app. After doing that I can now successfully jump to the app from the bootloader. The jump address also has to be (for some reason I do not quite understand) the application address + 4.
Also, note that you need to modify the main application RAM allocation to start from 0x200000C0 with size 0x00001FD0. This is done so you can relocate the vector table to the internal SRAM at 0x20000000 in the main application "main" function as follows:
/* 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 ***************************/
}
See my new bootloader INTFLASH_execute_main_app function below:
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();
}
Many Thanks
来源:https://stackoverflow.com/questions/21329668/jumping-from-one-firmware-to-another-in-mcu-internal-flash