2023-01-11 07:44 AM
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 */
}
2023-01-11 09:50 AM
Stack usage via auto/local variables looks ridiculously large.
uint8_t progBuffer[PROGSIZE]; // make smaller or static
2023-01-11 09:56 AM
Line 89: __set_PSP(*(volatile uint32_t*) APP_FLASH_ADDR+4U);
What do you think it does?
2023-01-11 10:27 AM
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.
2023-01-11 10:31 AM
Thanks for your answer.
I've tried with smaller sizes without success. I will try with static specifier.
2023-01-12 06:46 AM
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 ?
2023-01-12 06:46 AM
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.
2023-01-12 07:10 AM
>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...
2023-01-12 07:47 AM
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 :