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.

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.

1 Like