cancel
Showing results for 
Search instead for 
Did you mean: 

Custom bootloader running HEX file

oren_perry
Associate II

I am attempting to make a custom bootloader for the STM32L431 series uC.

using the st videos on the subject (https://www.youtube.com/watch?v=OkUQ3iMmiYQ&list=PLnMKNibPkDnEb1sphpdFJ3bR9dNy7S6mO&ab_channel=STMicroelectronics),  I managed to load the hex file from another project (just the data) into the flash starting at an address set by FLASH_APP_ADDR in the bootloader code. I manually verified that the flash is exactly the same as in the original project for this region with all the hex data.

My question is, how do I then run this code? The go2App function crashes with hardfault and I'm pretty sure I'm missing something very obvious, but I am very new to bootloaders.

My final goal is to allow the bootloader to receive this data via canbus and write it manually, but for that i'll have to understand how to save/run data from a hex file in this bootloader. 

1 ACCEPTED SOLUTION

Accepted Solutions
oren_perry
Associate II

Ok, I got it all figured out.

1) Thank you to the two comments above this, both good replies.

2) The following site and included video really helped me understand how to do this: https://embetronicx.com/tutorials/microcontrollers/stm32/bootloader/simple-stm32-bootloader-implementation-bootloader-tutorial/

3) some of my lessons for anyone who is also in need of help:

  • The "App" project needs to know where to point for all of it's functions, this doesn't just mean that setting the flash base address is enough. Set the VECT_TAB_OFFSET to your offset after un-commenting the USER_VECT_TAB_ADDRESS definition.
  • If you return to your bootloader, all the interrupt vectors will be off because the offset definition is not set in the bootloader by default, so repeat the last step for the bootloader (with an offset of 0).
  • Flash works differently for every series of stm32, make sure you understand yours before starting anything else, modify any example to fit your needs.
  • The "go2APP" function that worked best for me was NOT the one that was given as an example by ST, but the following code:

void go2APP(void)
{
void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (FLASH_APP_ADDR + 4U)));
app_reset_handler(); //call the app reset handler
}


 

View solution in original post

9 REPLIES 9
oren_perry
Associate II

I should add that I have defined a section in flash starting at the same address (as was shown in the video) with the code:


.myBufBlockFLASH 0x8008000 :
{
KEEP(*(.myBufSectionFLASH))
} >FLASH

and the hardfault crash includes a "Break at address "0x8003820" with no debug information available, or outside of program code." line. which confuses me because my code is saved at 0x8008000.

Is there some definition or code that I didn't include to point to the code or make it executable? maybe a start/finish pointer other than go2APP to push to the starting address?

Pavel A.
Evangelist III

Could you elaborate what code or data have you loaded to your STM32L4 at FLASH_APP_ADDR?

I have not watched the video but it seems to be about STM32G0.

Unless it is a program built specially for this STM32 and linked at exactly this address, you cannot expect just jump to it and see it running. Look for another video (or better STM32 Cube or github example) of bootloader or "in-application programming" (IAP).

Please don't tell that you write the hex file into the flash as is, without decoding to binary (sorry but it happens). 

1. The code I wrote is another complete project's output hex file, what do you mean by "what code"?
2. This is why I followed the steps to write my own simple code and set my own device's flash address and app address. If you know of such a video or example of a can based IAP solution then I would LOVE to see it, even if it's for a different stm32.
3. Yes, One thing I have found very little if any explanation for is the form in which the code is saved in the flash. any example I found simply skips this or shows a GUI that does some parsing of the bin/hex files which is never explained. So I manually verified while debugging that the data is saved in the memory exactly the same for the entire section I wrote and the original code's memory (loaded directly with cube ide). What would be the difference if the final data is identical when attempting to use the code?

The entire point of pre-programming the hex file into this code was so I can learn how the data is supposed to be saved into the flash so it can be run as code before looking at making an actual IAP program. I am just trying to learn here so I can use it later.

Data in memory is a linear image equivalent to what you'd see in the .BIN file.  The Intel or Motorola format HEX files are typically about 2.5x in size as they have an overly verbose ASCII format describing each memory byte with two ASCII digits.

The 0x8003820 address would be in your loader, likely the control transfer point. Perhaps check the .MAP file for addresses, or do a disassembly / listing file and inspect. Probably trying to branch to an invalid address. Perhaps add diagnostic / instrumentation to print out values and actions to a serial port so as not to be looking at this blindly.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

So for the first part, I understand and have already changed it to actual hex values so while it required more initial work for me it shouldn't matter (assuming I'm not missing anything).

as for the second part, I don't understand what that means. I haven't found any resources online that actually explain how this part functions from the beginning and i've been looking non-stop. Also why would It be branching to this address? the main "bootloader" project is built like a normal project, the only memory jumping I do is to an address much larger than that, so it should either be part of the base code, or be skipped entirely which is what confuses me so much.

If you can direct me to any videos/lectures that go through this without assuming that i've already been working with bootloaders for years, I would really appreciate it.

I'm not from the video generation. Some of the undergirding principles should be in texts like "assemblers, compliers, linkers and loaders", and don't need to be STM32 specific.

When you build an application you should modify the linker script (.ld) so that the linker places the code deeper into the flash memory, code in SystemInit() should point to the vector table at this deeper address, so the interrupts work and the NVIC knows where to pull the values. In the loader you're trying to fish out the entry point from the application's vector table. ie the Reset_Handler address.

The vector table is a list of addresses, not code. The Reset_Handler for the app should be at some address beyond 0x08008000, but within the addressable space of the FLASH, say 0x0801FFFF for a 128KB device.

Your perhaps overthinking this, the MCU has some relatively simple expectations, it pulls an initial pair of SP/PC (Stack Pointer, Program Counter) and starts step through the instruction stream. The base vector table it starts with here is always going to the zero, and the 0x08000000 basis for the FLASH is mapped here by way of the BOOT pin settings. Your loader has 32KB of FLASH within which it resides, and once it determines that there's a valid firmware image at 0x08008000 it then transfers control by a branch or jump, or setting the PC to the address of the Reset_Handler, by way of the vector table, from the application.

The application and loader are basically two separate and free standing blocks of code, residing within different address ranges within the flash memory.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III

@oren_perry The programming and jump is covered in "IAP" examples for every STM32 series.

For L4 see this one: https://github.com/STMicroelectronics/STM32CubeL4/tree/master/Projects/STM32L476G-EVAL/Applications/IAP

Like @Tesla DeLorean , I am not from the 'video generation' too ))

So you do convert the hex to binary, and the result looks good after write. Then it should work. Try to step thru the jump function in the debugger. The fault analyzer of the CubeIDE debugger will show what exactly is wrong.

The code really is as simple as it looks, no rocket science. Just make sure that all interrupt sources are disabled (or not enabled) before the jump.

oren_perry
Associate II

Ok, I got it all figured out.

1) Thank you to the two comments above this, both good replies.

2) The following site and included video really helped me understand how to do this: https://embetronicx.com/tutorials/microcontrollers/stm32/bootloader/simple-stm32-bootloader-implementation-bootloader-tutorial/

3) some of my lessons for anyone who is also in need of help:

  • The "App" project needs to know where to point for all of it's functions, this doesn't just mean that setting the flash base address is enough. Set the VECT_TAB_OFFSET to your offset after un-commenting the USER_VECT_TAB_ADDRESS definition.
  • If you return to your bootloader, all the interrupt vectors will be off because the offset definition is not set in the bootloader by default, so repeat the last step for the bootloader (with an offset of 0).
  • Flash works differently for every series of stm32, make sure you understand yours before starting anything else, modify any example to fit your needs.
  • The "go2APP" function that worked best for me was NOT the one that was given as an example by ST, but the following code:

void go2APP(void)
{
void (*app_reset_handler)(void) = (void*)(*((volatile uint32_t*) (FLASH_APP_ADDR + 4U)));
app_reset_handler(); //call the app reset handler
}


 

It's the same ST's broken code as everywhere... For an actually decent solution, read this:

https://community.st.com/t5/embedded-software-mcus/using-nvic-systemreset-in-bootloader-lt-gt-application-jumps/m-p/398389