Skip to main content
HugoNEYOS
Associate
January 11, 2023
Question

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

  • January 11, 2023
  • 3 replies
  • 2039 views

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

This topic has been closed for replies.

3 replies

Tesla DeLorean
Guru
January 11, 2023

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 VenmoUp vote any posts that you find helpful, it shows what's working..
HugoNEYOS
HugoNEYOSAuthor
Associate
January 11, 2023

Thanks for your answer.

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

Pavel A.
Super User
January 11, 2023

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

What do you think it does?

HugoNEYOS
HugoNEYOSAuthor
Associate
January 11, 2023

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.

HugoNEYOS
HugoNEYOSAuthor
Associate
January 12, 2023

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 ?

Pavel A.
Super User
January 12, 2023

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

HugoNEYOS
HugoNEYOSAuthor
Associate
January 12, 2023

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