2018-09-07 03:28 AM
Hello there,
I am trying to develop an STM32L4 proof of concept bootloader application. I am basing on this source: https://github.com/akospasztor/stm32-bootloader and Atollic's "Working with bootloaders on Cortex-M devices".
I am trying to do a simple thing: My bootloader should start and jump to a fixed address in flash, under which the regular application lies. The procedure I have done is as follows:
I have programmed the bootloader app to the flash memory (using ST-LINK), ld file contains following flash description:
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 220K
The total flash memory is 512K.
Then I flashed the application code to the memory (with ST-LINK). Its ld file flash parameter looks as follows:
FLASH (rx) : ORIGIN = 0x8037000, LENGTH = 292K
220 * 1024 = 0x37000, so my starting address for the app is 0x08037000.
220K + 292K = 512K, so the memory sizes look fine.
My jump function looks as follows:
typedef void (*pFunction)(void);
/**
* @brief Jumps the program counter to the memory location set by \p address.
* Before the jump is performed vector tables are set.
*/
void boot_jump2Address(const uint32_t address)
{
uint32_t appStack;
pFunction appEntry;
// get the application stack pointer (1st entry in the app vector table)
appStack = (uint32_t)*((__IO uint32_t*)address);
// Get the app entry point (2nd entry in the app vector table
appEntry = (pFunction)*(__IO uint32_t*)(address + 4);
boot_basicClockConfig();
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
// Reconfigure vector table offset to match the app location
#if (SET_VECTOR_TABLE)
SCB->VTOR = address;
#endif
__set_MSP(appStack); // Set app stack pointer
appEntry(); // Start the app
while (1); // never reached
}
I then start to debug the application (not bootloader code). The bootloader starts and it jump to the app code, then my debugger catches the PC and I can debug my application. The problem is that the application crashes. When debugging it, one can see that the line at which it crashes is in the HAL_RCC_OscConfig function generated by CubeMx:
assert_param(IS_RCC_PLLR_VALUE(RCC_OscInitStruct->PLL.PLLR));
This assert is not passed, because the PLLR is visible as 1, instead of 2. 2 is the value set in the code. For some reason its changing itself. But only if I run directly to the breakpoint set at this line- if I go trhough the code line by line until this point, I can see in the debugger view that its 2 correctly. That doesnt matter, because the code crashes later on on similar stages.
My question is- Is there any additional setting I need to modify for my base application in order to place it under different flash address than 0x08000000? I have only changed the linker script (FLASH parameter). But is there anything else?
I would really appreciate all help, as I am out of ideas on how to fix this.
Solved! Go to Solution.
2018-09-09 11:11 AM
>>Other general gotchs are a) don't disable interrupts on the processor, and b) don't call from interrupt context, this includes HAL call backs.
This would be using __disable_irq() instead of actually addressing the issue of turning off interrupts at the source. The App likely uses a different memory map, and the linker has given uwTicks/usTickFreq entirely different addresses.
The "easy" way is to reset the processor and branch directly into the app via an expedited path. The other is to clean up the mess so you don't have any interrupts firing into handlers which have had none of their variables/state defined.
The test here would be to create a vector table where all entries point to HardFault_Handler, point SCB->VTOR to this for a couple of seconds, and see if the thing outputs fault data. The key here being to have HardFault_Handler to output diagnostic information, and not just a while(1) loop. If you can't determine the source of the interrupt use bisection of the table until it is apparent.
The b) point above relates to unlooping all context pushes on the stack, where LR points to user space code and doesn't contain magic values swapping what register map the processor is using, and preemption level the processor is running at.
Look for issues with SysTick, TIM and Watch Dogs.
You could certainly have an initialization/command-line structure you hand between loader/app, this is especially true where you've created contractual obligations between them. ie clocks and PLL's up, frequencies, Debug USART, etc.
2018-09-07 06:06 AM
Hello Lukasz,
Try to cancel every initialization you do (or HAL library do) in boot firmware.
I see you do that but the HAL library can forget some parameters in the DeInit function.
Compare all registers before Init and after DeInit.
Also, verify that every interrupts enable are disable because I don't see that in your code.
Another try is to modify your application software to accept a already clock initialized.
Best regards.
2018-09-07 06:36 AM
You need to manage SCB->VTOR in the SystemInit() code of the application. I usually fix the #define nonsense ST uses and let the linker fix up the address like it was designed to do.
extern void *__Vectors; // Keil forks use this symbol, check your startup.s
void SystemInit (void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Configure the Vector Table ----------------------------------------------*/
SCB->VTOR = (uint32_t)&__Vectors;
...
}
You can also decide not to repeat the SystemClock stuff if you've brought this up properly in the loader.
2018-09-07 07:03 AM
Hello guys, thank you for answer,
From my point of view there are couple places where the address could be changed.
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
After one follows The FLASH_BASE define:
#define FLASH_BASE (0x08000000UL) /*!< FLASH(up to 512 KB) base address */
Should this define be altered as well? Because I tried to change this define to 0x08037000UL and it help solving my problem. I could try omitting another system clock config in the main program but would this cause the crash?
2018-09-07 10:12 AM
I'm saying the code you're quoting is dangerous and easily overlooked.
You shouldn't need to change things in multiple places, it should be sufficient to change the linker script, and everything else works off that address.
Yes, they expect you to change FLASH_BASE and/or VECT_TAB_OFFSET, I think this could be discarded and a single source file could be used in both loader and app context, reducing the chance of error.
At the end of the day for interrupts to function in your application, SCB->VTOR == 0x08037000
Other general gotchs are a) don't disable interrupts on the processor, and b) don't call from interrupt context, this includes HAL call backs.
2018-09-07 10:43 AM
I agree with you on the modification places in 100%. The problem is that certain design patterns are forced by the startup code generated in cubemx. Over the years I have learned to "hack" it, I gues this is doable as well.
This is however not the reason for the application to not work. I call the jumo from an freertos task, which is not an interrupt rouitine. The only thing I can think of from you post that I have missed is disabling the interrupt, I will check that.
So to summarize, The FLASH_BASE define should be altered as well? It is used in various places in the code provided by ST.
2018-09-07 04:03 PM
FreeRTOS might however being running in a user state and not a system state. Is it faulting?
FLASH_BASE is only used for some asserts as far as I can see.
The ST model would have you modify VECT_TAB_OFFSET to 0x37000
SCB->VTOR is far simpler in it's implementation, it should ignore the low order 9-bits based on the size of the vector table, ie the NVIC/CMx feeds the low order bits as it initiates a read for the new PC
2018-09-07 09:19 PM
2018-09-08 09:06 AM
The app code typically sets VTOR pretty early, and is going to overwrite anything the loader does.
The loader shouldn't have any of it's routines running, think TIM and/or SysTick.
2018-09-08 09:41 AM