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
  • 2046 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 Venmo (See Profile) Up 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.
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.
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