2021-07-26 09:09 AM
The bootloader checks the CRC of the application code and passes control to the application code it matches a saved value. If it doesn't match, it waits for commands from the host system to update the application firmware. The application will clear the saved CRC when commanded from the host system. The host system requests a reset which is supposed to run the bootloader. I have already verified the bootloader and application code separately. Combining them is my problem. I think it's related to the .isr_vector definition in the linker files but I'm not certain. I am redefining VTOR, but that alone isn't working. I've been trying to find what registers or where the isr and reset pointers are kept.
2021-07-26 09:30 AM
Hi,
For our STM32L4x6 products with a custom bootloader project we use attached linker files:
Memory Definitions:
The following command in App code to switch to its vector table before BEFORE any interrupts enabled:
Paul
2021-07-26 09:34 AM
2021-07-27 06:45 AM
Thank you.
It looks like what I'm doing is similar but, I'm not specifying separate memory blocks for the vector table and BL flash. I'm also trying to use the reset to jump from the application to the bootloader. My AP linker has a section for sending the reset vector to the BL Flash which keeps me from loading the BL first then debugging AP. If I remove it then the reset restarts the AP. Seems like I can ditch using the reset and make my own function to jump to BL from the AP.
2021-07-27 06:54 AM
We use a location in the DataFLASH block we defined.
To force BL the App zeros that location and reset's MCU (Zeroing + reset means minimal code in App).
On startup the BL checks that location for a specific value (your choice),
and if finds it then does a CRC on the App block,
and if CRC passes then jumps to App block.
If anything fails stays in BL mode.
When BL successfully receives a new app it updates both the value and App CRC in DataFlash, then resets.
Feel free to implement BL any way you wish, to the BL it is just updating FLASH data.
You can have the BL's Vector table in the BL block, that is also choice, Just ensure it is at the MCU's default vector table location for proper reset.
Paul
2021-07-27 06:58 AM
Default should be BL call App (not App call BL).
If the App load is interrupted then you wouldn't be able to recover if:
Reset > Incomplete App > Can't start BL
That's also why we added a CRC for the App load, bit of paranoia doesn't hurt when self programming the FLASH.
2021-07-27 09:07 AM
RAM Flags instead of FLASH (Bonus of can return to App if BL didn't happen)
2021-07-27 11:15 AM
Thank you again.
I have the same thing as the DataFLASH block as you mentioned, and I'm not really calling the BL from AP code. It's called with a reset as you mentioned, poor choice of words on my part. I changed my AP linker file to remove the reset vector pointer (which I didn't need) and now I think I've narrowed my issue down to either how I'm transferring from the BL to the AP or how I'm disabling stuff in the AP before allowing the reset. I've tried a couple of ways dummy loop in the BL put at the address of the start of AP code that gets over written when the AP is installed and a goto the starting address. Both send me to hard_fault_interrupt jail. The good part is I can see in the general registers that the BL was running.
2021-08-02 05:22 AM
Careful in jump from BL to App
i.e.:
void vStartApp(void)
{
if (!BL_App::bCheckCRC()) // App CRC invalid?
{
dprintf(EV_LOWVERBOSE, context(CON_BL | CON_ERROR), "CRC verification failed, entering bootloader\n");
vRebootToBootloader(); // App invalid, reboot to bootloader
}
dprintf(EV_UNVERBOSE, CON_BL, "Starting App...\n");
vUartForceStdAll("BOOTINGa");
// Begin app booting process
__disable_irq();
HAL_DeInit(); // Uninitialize all configured devices
for(int i = 0;i < 8;i++) NVIC->ICER[i] = 0xFFFFFFFF;// Disable all interrupts @suppress("C-Style cast instead of C++ cast") @suppress("Field cannot be resolved")
for(int i = 0;i < 8;i++) NVIC->ICPR[i] = 0xFFFFFFFF;// @suppress("C-Style cast instead of C++ cast") @suppress("Field cannot be resolved")
__set_CONTROL(0); // Reset all control
__set_MSP(*(__IO uint32_t*)D1_FLASH_AF_ADDR_START); // Set stack pointer to new program @suppress("C-Style cast instead of C++ cast")
//uint32_t JumpAddress = *((__IO uint32_t*) (D1_FLASH_AF_ADDR_START + 4)); // Jump address pointer @suppress("C-Style cast instead of C++ cast")
uint32_t JumpAddress = (((uint32_t*)D1_FLASH_AF_ADDR_START)[1]); // Jump address pointer @suppress("C-Style cast instead of C++ cast")
__ISB();//Before Jump to Unknown Code: Instruction Synchronization Barrier == Empty CPU Instruction Pipeline
__DSB();//Before Jump to Unknown Code: Data Synchronization Barrier == Wait till all CPU Data accesses completed
SysTick->CTRL &= ~(SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk); // @suppress("C-Style cast instead of C++ cast") @suppress("Field cannot be resolved")
reset_handler Jump = (reset_handler)JumpAddress; // Cast address pointer to a function pointer @suppress("C-Style cast instead of C++ cast") @suppress("Field cannot be resolved")
Jump(); // Execute Jump
// End app booting process. Function should never get past this point unless there was a failure
dprintf(EV_UNVERBOSE, context(CON_BL | CON_ERROR), "Failed to jump to app, rebooting to Bootloader...\n");
vRebootToBootloader();
}
Paul