cancel
Showing results for 
Search instead for 
Did you mean: 

Adding HAL_Flash_program to code, without calling it, breaks things. Why?

HugoNEYOS
Associate II

Hi, I'm trying to develop a bootloader. I managed to jump to a program properly when it's already in the flash. I managed to program the flash but then I can't jump to the newly loaded code. Worse, when I add the "HAL_Flash_program" to my code, even when not using it I can't jump anymore. I'm struggling to understand why. Could you please help me ?

I can do both in separate programms, first loading the code and then jumping to it and it works. I checked with stm32cubeProgrammer, the code in flash memory is verified as the file i'm uploading.

My MCU is a STM32L4R9AI, and i'm using the discovery board and stm32cubeIDE. Please find the code here. Empty configuration except for a digital input on PG8, UART3 on PB10/P11 and digital output (user led) on PH4.

/* USER CODE BEGIN PM */
#define APP_FLASH_ADDR 0x080A0000   //Application's Flash Address
#define PROGSIZE 20000
/* USER CODE END PM */
 
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
  uint32_t    ms1,ms2,i;
  uint8_t      bootOrLoad = 0;
  uint64_t    *castedBuffer;
  uint8_t	  progBuffer[PROGSIZE];
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
 
  /* USER CODE BEGIN 2 */
 
  //Detect button press at start. 1 -> update mode. 0 -> Start application mode.
  ms1 = HAL_GetTick();
  do{
	 if (HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8))
	 {
		 bootOrLoad = 1;
		 break;
	 }
	 ms2 = HAL_GetTick();
  }while((ms2-ms1) < 1000);
 
 
  //Button was pressed -> update mode
  if(bootOrLoad)
  {
	NS_UART_Transmit(&huart3, "UPDATE MODE\n\r", 500);
	NS_UART_Transmit(&huart3, "you have 10 sec to send FW...\n\r", 500);
 
	//Receiving FW ...
	HAL_UART_Receive(&huart3,progBuffer,PROGSIZE,10000);
 
	//Unlocking flash
	HAL_FLASH_Unlock()	? NS_UART_Transmit(&huart3, "Unlock KO\n\r", 500)
						: NS_UART_Transmit(&huart3, "Unlock OK\n\r", 500);
 
	//Casting buffer as 64bits because it's the only supported format with L4R9AI
	castedBuffer = (uint64_t*)progBuffer;
 
	//flashing buffer to memory
	for(i=0;i<PROGSIZE/8;i++)
	{
		//EVEN IF bootOrLoad IS AT 0, THIS PART STOPS THE START APPLICATION MODE FROM WORKING
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(APP_FLASH_ADDR)+8*i,castedBuffer[i]))
			NS_UART_Transmit(&huart3, "Write KO\n\r", 500);
	}
 
	//Locking flash back
	HAL_FLASH_Lock()	? NS_UART_Transmit(&huart3, "Lock KO\n\r", 500)
						: NS_UART_Transmit(&huart3, "Lock OK\n\r", 500);
 
	//Reboot
	NS_UART_Transmit(&huart3, "Update over. Reboot...\n\r", 500);
	NVIC_SystemReset();
  }
 
  //Button not pressed -> start application mode
  else
  {
	//
	NS_UART_Transmit(&huart3, "APPLICATION START MODE\n\r", 500);
 
	//Jump to app
	void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (APP_FLASH_ADDR+4U)));
	__set_PSP(*(volatile uint32_t*) APP_FLASH_ADDR+4U);
	app_reset_handler();
  }
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
 
 
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

8 REPLIES 8

Stack usage via auto/local variables looks ridiculously large.

uint8_t progBuffer[PROGSIZE]; // make smaller or static

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III

Line 89: __set_PSP(*(volatile uint32_t*) APP_FLASH_ADDR+4U);

What do you think it does?

Thanks for your answer.

As I understand it, it should set the stack pointer at the start of my application so it starts properly after I jump to it. Honestly, it's here because I saw it on many topic regarding bootloader.

Thanks for your answer.

I've tried with smaller sizes without success. I will try with static specifier.

HugoNEYOS
Associate II

Thanks @Pavel A.​ and @Community member​ for your answers, sadly my problem is still there. I tried to narrow it down more so here it is :

I load a simple blinky application at the address 0x08020000 of my flash using stm32CubeProgrammer :

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  while (1)
  {
	  GPIOH->ODR ^= 0x10;
	  HAL_Delay(500);
  }
}

with the following linker script :

/* Entry Point */
ENTRY(Reset_Handler)
 
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
 
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
 
/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 640K
  RAM2    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  RAM3    (xrw)    : ORIGIN = 0x20040000,   LENGTH = 384K
  FLASH    (rx)    : ORIGIN = 0x8020000,   LENGTH = 1024K
}

I then made this other small program that jumps to it and works properly :

#define APP_FLASH_ADDR 0x08020000
int main(void)
{
  volatile uint8_t dummy = 0;
  HAL_Init();
  SystemClock_Config();
   if(0)
   {
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(0x08010000),0x0);
   }
	void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (APP_FLASH_ADDR+4U)));
	__set_MSP(*(volatile uint32_t*) APP_FLASH_ADDR);
	app_reset_handler();
  while (1)
  {
  }
}

Now, with a change in the condition, it doesn't work anymore. Even if "dummy" is at 0.

#define APP_FLASH_ADDR 0x08020000
int main(void)
{
  volatile uint8_t dummy = 0;
  HAL_Init();
  SystemClock_Config();
	if(dummy)
{
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(0x08010000),0x0);
}
	void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (APP_FLASH_ADDR+4U)));
	__set_MSP(*(volatile uint32_t*) APP_FLASH_ADDR);
	app_reset_handler();
  while (1)
  {
  }
}

But in my bootloader, I would like to be able to programm the flash, then jump to the new application. I don't understand why I cannot do both. Do you have any clue for me please ?

After further research, it should get the new main stack pointer position at the starting address of my application in the flash.The +4U should not be there.

Sadly, it didn't fix my issue. See my next rely.

>Now, with a change in the condition, it doesn't work anymore

Likely because your app_reset_handler variable is on the stack. and then you move the stack pointer...

Thnaks for your answer,

I tried to turn it into a constant with the same result :

#define APP_FLASH_ADDR 0x08020000
int main(void)
{
  volatile uint8_t dummy = 0;
  HAL_Init();
  SystemClock_Config();
  if(dummy)
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(APP_FLASH_ADDR),0x0);
  
  const void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (APP_FLASH_ADDR+4U)));
  __set_MSP(*(volatile uint32_t*) APP_FLASH_ADDR);
  app_reset_handler();
  while (1)
  {
  }
}

Same when it's global :

#define APP_FLASH_ADDR 0x08020000
void (*app_reset_handler)(void);
 
int main(void)
{
  volatile uint8_t dummy = 0;
  HAL_Init();
  SystemClock_Config();
  if(dummy)
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,(APP_FLASH_ADDR),0x0);
 
  __set_MSP(*(volatile uint32_t*) APP_FLASH_ADDR);
  app_reset_handler= (void*)(*((volatile uint32_t*) (APP_FLASH_ADDR+4U)));
  app_reset_handler();
  while (1)
  {
  }
}

If HAL_FLASH_Program is taken into account by the compiler, the jump doesn't occur anymore. It's very strange to me because in both case of the condition (dummy = 0 or just 0) the main stack pointer is properly set at the right adress :

0693W00000Y86KAQAZ.png0693W00000Y86KJQAZ.png0693W00000Y86KOQAZ.png