Bootloader not working on Cortex-M4 processor

Hello, I am using a MAX32630 MCU which uses the Cortex-m4(f). But, I am seriously unable to get the bootloading functionality of mbed OS working on it in any shape or form. I’ve tried everything under the sun. Is it just not supported at all?

The tutorial on bootloaders by Mbed Creating and using a bootloader - Program setup | Mbed OS 6 Documentation basically comes down to it being a very simple system to set up.
First of all, this tutorial is incorrect, it says that target_restrict_size should pad out the bootloader image, but it never does. So I took a fix from an old git push request: Fix expansion of application to target.restrict_size by icsys-omh · Pull Request #14994 · ARMmbed/mbed-os · GitHub, which fixes the padding. image
as can be seen in the screenshot above. I have set restrict_size to 0x10000 which comes down to the bytes shown in the screenshot.

0x10000 also lines up with the requirements for bootloaders on the Cortex-m4 which partially have to do with the Vector table offset register. Those being:

  • A power of 2 (64KB = 65.536 Bytes = 2^16).
  • Lines up with a flash sector/page (The flash page size on my MAX32630 is 8KB as seen in the corresponding user guide, there’s 256 pages of it which makes for the 2MB internal flash).

This being the case, simply building the bootloader with the right paramters, dropping it into my main application program and adding the bootloader.bin to the bootloader parameter there. It should just work, right?

Here’s the output when I compile the application:

Elf2Bin: application
Merging Regions
Filling region bootloader with c:\Users\Tijn\Mbed Programs\application\bootloader.bin
Filling region application with BUILD/MAX32630FTHR/ARMC6\application_application.bin
Space used after regions merged: 0x18af8
Merging Regions
Filling region application with BUILD/MAX32630FTHR/ARMC6\application_application.bin
Space used after regions merged: 0x8af8

The program then boots up into the bootloader, but never actually goes through with starting the application. So does that mean the implementation mbed_start_application() doesn’t work?

To be sure I wrote my own version of it based on that version as can be seen below. (I hardcoded the assembly registers to the proper addresses just to be sure!):

int startApplication(uint32_t address)
{
    printf("\r\n");

    void* stackPointer = (void*)address;
    printf("Stack pointer in StartApplication function (hex): 0x%X\r\n", stackPointer);

    void* startAddress = (void*)(address);
    printf("Start address in StartApplication function (hex): 0x%X\r\n", startAddress);

    if (uint32_t(address) & 0x7F)
    {
        printf("Not 32 word aligned!\r\n");
        return 0;
    }

    jumpToApplication(stackPointer, startAddress);
    return 1;
}

void jumpToApplication(void* startAddress, void* stackPointer)

{
    disableInterrupts();
    setVtor((uint32_t)stackPointer);

    /*Ensure new MPU configuation is used by subsequent instructions, see the Cortex-M4 generic user guide*/
    __DSB();
    __ISB();

    /*Disable Systick timer*/
    SysTick->CTRL = 0x00000000;

    /*Ensure new MPU configuation is used by subsequent instructions, see the Cortex-M4 generic user guide*/
    __DSB();
    __ISB();

    /*Assembly code*/
    __asm__(
        "mov    r0, 0x10000     \n" //Copy stack pointer to R0
        "mov    r1, 0x10001     \n" //Copy program counter to R1
        "mov    r2, #0          \n" //Copy empty value into R2
        "msr    control,    r2  \n" //Clear control register - switches to main stack. 
        "mov    sp, r0          \n" //Copy address of stack pointer to stack pointer register
        "msr    primask, r2     \n" // Enable interrupts
        "blx    r1              \n" //Branch indirect with link to program counter address
    );
}

void disableInterrupts()
{
    /*Disable global intterupt*/
    __disable_irq();

    /*Clear all interrupts*/
    for (int i = 0; i < 8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
    }

    //Clear pending interrupts
    for (int i = 0; i < 8; i++)
    {
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }
}

void setVtor(uint32_t address)
{
    /*Ensure new MPU configuation is used by subsequent instructions, see the Cortex-M4 generic user guide*/
    __DSB();
    __ISB();

    /*Set VTOR-TBLOFF to start address, see the Cortex-M4 generic user guide vector table offset register*/
    SCB->VTOR = (address & SCB_VTOR_TBLOFF_Msk);

}

But alas, this doesn’t work either. My next thought was checking the memory after compiling the application with the bootloader to see if there really was application code on address 0x10000 like there should be. But I know of no way of checking this.

Any solutions/help are greatly appreciated!