cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 custom bootloader jump ends up in hard fault

Florian Moser
Senior

MCU: STM32F429IIT

I've written my first custom bootloader for the STM32. It takes a .hex-file from an SD-card, flashes it and jumps to that application.

The hex-parser and writing the flash works perfectly, I've double-checked that.

I've written a small example project (500ms timer toggles LED in interrupt). With the .hex file of that project, the bootloader works totally fine. (Flashes the application, jumps to the start-address and executes the application).

Now I want to do the same thing with my actual project, but it ends up in a hard fault everytime. The Fault Analyzer says "Attempt to switch to invalid state" after I execute the jump command.

Register content during fault exception:

 0693W00000D0JXBQA3.jpg 

 Jump-Command:

void bootloader_jumpToAddress(uint32_t address)
{
	void (*SysMemBootJump)(void);
 
	_bootloader_DeInitTasks(); //custom function to disable SDIO, GPIO, Timers,...
	__disable_irq();
	SYSCFG->MEMRMP = 0x01;
 
	SysMemBootJump = (void (*)(void)) (*((uint32_t *)(address + 4)));
	__set_MSP(*(uint32_t *)address);
 
	SysMemBootJump();
}

STM32F429IITX_FLASH.ld (example project)

MEMORY
{
  CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 192K
  
  FLASH_BOOT		(rx)    :	ORIGIN = 0x8000000,  
  								LENGTH = 64K
  
  FLASH				(rx)	:	ORIGIN = ORIGIN(FLASH_BOOT) + LENGTH(FLASH_BOOT),
  								LENGTH = 2048K - LENGTH(FLASH_BOOT) - 256K	
}

STM32F429IITX_FLASH.ld (actual project)

MEMORY
{
  CCMRAM    		(xrw)   :	ORIGIN = 0x10000000,
  								LENGTH = 64K
  								
  RAM    			(xrw)   :	ORIGIN = 0x20000000,
  								LENGTH = 192K
  
  FLASH_BOOT		(rx)    :	ORIGIN = 0x8000000,  
  								LENGTH = 64K
  
  FLASH				(rx)	:	ORIGIN = ORIGIN(FLASH_BOOT) + LENGTH(FLASH_BOOT),
  								LENGTH = 2048K - LENGTH(FLASH_BOOT) - 256K			
  
  EMULATED_EEPROM 	(rw) 	:	ORIGIN = 0x8200000 - 2 * 128K,
  								LENGTH = 2 * 128K
  
  XRAM				(xrw)	: ORIGIN = 0xD00BF400,	LENGTH = (8M - 0xBF400) /* allocate 1M for LTDC framebuffer */
}

system_stm32f4xx.c (actual and example project):

/* Note: Following vector table addresses must be defined in line with linker
         configuration. */
/*!< Uncomment the following line if you need to relocate the vector table
     anywhere in Flash or Sram, else the vector table is kept at the automatic
     remap of boot address selected */
#define USER_VECT_TAB_ADDRESS
 
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
     in Sram else user remap will be done in Flash. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS   SRAM_BASE       /*!< Vector Table base address field.
                                                     This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET         0x00000000U     /*!< Vector Table base offset field.
                                                     This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS   FLASH_BASE      /*!< Vector Table base address field.
                                                     This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET         0x00010000U     /*!< Vector Table base offset field.
                                                     This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
/******************************************************************************/

main.c (actual and example project):

/* USER CODE BEGIN 1 */
	__enable_irq();
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
...
...
...

I'm not sure where to start my debugging session. The actual project is kinda big and has a lot of potential harms: FreeRTOS, TouchGFX, EMULATED-EEPROM (using flash as eeprom), XRAM (external RAM on FMC), audio applications, ARM-CMSIS, FATFS, USB-DEVICE, RTC,...)

Thanks in advance!

4 REPLIES 4

In the register list, PC is zero, so you probably read zero when SysMemBootJump = (void (*)(void)) (*((uint32_t *)(address + 4)));

Single-step that code in disasm view (instruction-step) while observing the registers' content.

JW

pc gets set to zero after SysMemBootJump();

directly after SysMemBootJump():

  1. pc = 0x80164a4
  2. pc = 0x0
  3. <signal handler called>() at 0xfffffff9 pc = 0xfffffff9
  4. pc = 0x8010a6c

I've tried to add FreeRTOS to my example project and now it also ends up in a similar hard fault.

As I've found some threads from people with the same problem, I think it has something to do with FreeRTOS.

The bootloader ends at 0x0800ffff and the application starts at 0x08010000. That's the disassembly after SysMemBootJump():

0693W00000D0KNHQA3.jpg

The application starts with the vector table, there's no point in disassembling that, you should look at its content as data. You presumably read the Reset vector address from offset 4 (i.e. from addres 0x08001004), so look at that. But maybe there's some other problem.

What I suggested was to single-step through bootloader_jumpToAddress() in the disasm view, i.e. instruction by instruction, to see, what address is used to read the Reset vector from, what is actually read from that address i.e. what address is jumped onto.

> directly after SysMemBootJump():

No, you want to look at what happens *before* SysMemBootJump()

JW