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
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.
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.
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