Creating a Bootloader via the Uart

Because the Seed is based on a STM32H705 device am I right in thinking that because of its limited Flash or more precisely it has only one Sector ( Sector0 ) I cannot create a “traditional” Bootloader / Application ?

I maybe wrong but the STM32H705 Sector0 would be shared by the Bootloader and the Application therefore the Bootloader would not be able to Erase the space needed to load the Application, it would in effect erase itself !
Assuming Erase is Sector based.

I’ve been looking at an STM32F4 Bootloader, this Bootloader downloads the Application bin file via the Uart and stores the Application in Flash memory at a different ‘page’, then alter the vectors etc and jumps to the Application Start.
But the F4 has a different flash memory organisation ( pages ) rather than Sectors.

Table 14 in the following pdf

I’m a bit confused, can anyone help out with this ?

1 Like

It certainly can have a bootloader, but you’d have to load firmware from either QSPI or SDcard (well, if your device has it). And yes, there’s just 1 sector, so if you try fitting both bootloader and application on it, you’d be able to write firmware just once - pretty useless.

There’s ST doc that explains both scenarios and code samples

In case of XiP approach, you will have to use QSPI as read-only storage, because QSPI requires different modes for code execution and writing on flash. This is something that should be considered, because for my use case writing to QSPI from running application was required.

With bootrom scenario you’re supposed to copy firmware image to SDRAM or SRAM from read-only storage. This could be used for storing bootrom image on QSPI too. Then QSPI could be written at runtime. Unfortunately I’ve ran into some issues when trying to get this working (app was hanging when resetting clock on boot) , so can’t offer code that works on Daisy as is.

The general approach that you’ve seen for F4 would be the same (jump to a different stack / interrupt vector), but not being able to use flash makes things a bit more complicated.

1 Like

Cheers for a quick response, I’ll have a read of the article and code and have a think :slight_smile:

@antisvin pretty much hit the nail on the head.

The QSPI driver in libdaisy is already set up to be able to switch between read-only Memory mapped mode, and an indirect polling-based read/write mode. A loader for being able to directly program the chip from outside the firmware is one of the next planned additions to the ecosystem.

The BootROM approach could probably already be implemented by loading the bin file from SD card to either the SDRAM (I’d have to check if the memory map for where its directed is able to be executable or not), or the internal RAM. In the latter approach you could probably have a bootloader on an SD Card that you can load into RAM, and then rewrite the internal flash from there (or vice versa).

There is already a function in sys/system.h for jumping to the QSPI start address for XiP. A similar function could be made for jumping to a RAM region for execution from there. There may be a few other things that would have to be set that I’m not thinking of as well.

1 Like

@shensley I’m well aware how current QSPI code works. What I mean that when FW code is being executed from QSPI rather than flash, it must stay in memory mapped mode. So running FW from QSPI and storing patches/data on it from firmware itself won’t work.

Regarding bootrom example that ST provides, it performs reset and copies data/writes bss as usual, but that requires setting up read access to wherever loaded ROM image is stored. This is done by a function call from ASM startup before HAL is started. So it’s required to configure FMC and init SDRAM with registers. That’s at least one thing that must be added before bootrom is usable.

1 Like

I’m looking forward to the additions to the daisy libs, is there a timeline ?

@antisvin Yeah, you’re totally right; I had forgotten about needing the pre-HAL init for memories. I’ve been considering moving the sdram init to the startup code anyway. That’s a helpful link!

@bikerboyroy I’m working on getting some sort of roadmap of planned features with a rough timeline put together, hoping to be able to post it sometime next week.

1 Like

@shensley , this SDRAM init code would be a very welcome addition. I guess I should let the cat out of the bag and say that I’ve nearly finished porting OpenWare to run on Daisy Patch. That includes Midi-based bootloader, but it’s useless until firmware can run after bootloader jump.

2 Likes

So I’ve got a working bootloader (based on Openware MIDI bootloader). I wasn’t happy about both approaches proposed by ST example apps, because:

  1. XiP means that QSPI can’t be written when firmware is runnning (and I need to store patches/settings)

  2. Bootrom would waste ~512k SDRAM to store a copy of data from flash, even though most of it could be moved to faster RAM/TCM regions. Plus it would require writing SDRAM init with registers, too much pain.

The solution I came up with is based on creating a firmware header placed on flash before firmware itself. It’s populated with addresses of regions that need to be relocated from QSPI flash to various memories by startup file based on values exported from linker script.

Something like this:

struct FirmwareHeader {
    uint32_t magic;
    uint32_t section_0_start; /* ITCM */
    uint32_t section_0_end;
    uint32_t section_0_address;
    uint32_t section_1_start; /* DTCM */
    uint32_t section_1_end;
    uint32_t section_1_address;
    uint32_t section_2_start; /* Code + static */
    uint32_t section_2_end;
    uint32_t section_2_address;
    uint32_t section_3_start; /* Reserved */
    uint32_t section_3_end;
    uint32_t section_3_address;
    uint32_t section_4_start; /* Reserved */
    uint32_t section_4_end;
    uint32_t section_4_address;
};

This is more or less the same approach that is used for defining .data section relocation, except that in this case the copy is performed by bootloader rather than firmware startup code. This is required because we need to relocate .code and .isr_vector section for firmware before it runs.

Result is that firmware uses up to 256k from RAM2 for code and constants, ITCM for ISR vector and various frequentlly used code, DTCM for data/bss/stack. Some LUTs are left on flash, so it should be written to only if no patch is currently running.

2 Likes

@ shensley
Any news on Boot loading ?
I see there is a task in the Trello germinating column from October 2020

I am currently in progress on working on getting proper loading from a programmer (via openocd and/or stm32cubeprog). Once that’s working we’ll be adding a few different methods for dealing with the multiple memories from user applications.

@antisvin’s approach is very flexible, will have the best performance, and will probably be a good starting point. I think it’ll also be possible to do something with XiP method, with the restriction that the QSPI will then be off limits to the user code (applications requiring any persistent memory would have to utilize and SD card or something else), but it would also for much more liberal use of lookup tables, large libraries, etc.

I am actively working on it, though!

2 Likes

Thanks for the update :smiley:

Hi

Any news on boot loading ?
I’ve been away for 6 months working on a totally different tech-stack

They’ve added bootloader to libDaisy recently and made some more changes to it since then. I’m not sure if it has been documented properly yet or used by anyone besides core developers.

Ok, thanks for the info.
@shensley any news from you ? documentation ? example usage ?

Most of the support has been added to libDaisy at this point, but we haven’t streamlined it, or added documentation yet.

The bootloader (currently v4) can load firmware via SD card, USB drive, and/or DFU, and can be flashed to the Daisy over DFU using make program-boot, or by using the electro-smith web programmer.

Code can be compiled to target the bootloader (either to run upto 512kB from internal SRAM, or to run up to ~8MB directly from the QSPI) by manually specifying the LDSCRIPT in the user makefile.

The recipe make program-app has been added for DFU uploading of firmware compiled this way.


So most of the pieces are in place! We’re hoping to have some documentation, and do a more general announcement before the end of the year.

2 Likes

Good news , cheers for that

So I was just doing a few tests with the new bootloader and realized it’s already pretty easy to use (with the most recent libDaisy):

To compile an existing program you can add the following two lines to the application Makefile right after SYSTEM_FILES_DIR is set.

LDSCRIPT = $(SYSTEM_FILES_DIR)/STM32H750IB_sram.lds
C_DEFS += -DBOOT_APP

The linker script here will store the program in QSPI, but load it into the AXI SRAM and execute it from there. So program size can be up to 512kB (with no performance penalty).

Alternatively you can use the STM32H750IB_qspi.lds to execute code directly from the external flash chip on the Daisy (This allows for much larger program sizes, but can incur a bit of a performance penalty)


Once it’s compiled (it’ll be clear by the linker output at the end saying 0GB of flash used), you can flash the bootloader itself via DFU with:
make program-boot

To engage the the bootloader you can press the RESET button, and the usr LED will start to pulse. If there is no application on the QSPI, it will do this indefinitely, otherwise it will jump to the program after a few seconds unless the boot button is tapped during that period of time.

Once engaged, the bootloader will search an SD card, or USB drive (connected to the external USB pins) for a valid .bin file, and load it, or will wait for a dfu connection that can be flashed to with Make using:
make program-app


We’ll probably simplify it a bit more by using just a make variable to configure the project (like we did for adding the proper FATFS files), but this does work for now :slight_smile:

We’ll make a wiki page soon once we iron out the process a bit more, but feel free to start messing around with it!

2 Likes

I wasn’t been able to find bootloader sources. Is it open source? If not, do you have plans opening it up?

The bootloader is not open source.

We will be publishing some more thorough documentation with it’s capabilities, and how to with it once the process has been stabilized a bit (in the next few weeks).