Firmware does not start when mbed_start_application (POST_APPLICATION_ADDR) gets called

I am working with a MAX32630FTHR and i wanted to implement a bootloader. Down below you can see the bootloader that i have created and how the bootloader and firmware builds. The bootloader starts up and gives output to the serial but when mbed_start_application(POST_APPLICATION_ADDR) gets called the firmware does not get booted. What could be the issue here. Do i need another memory address to start the firmware?

Building Bootloader:

Building project bootloader (MAX32630FTHR, GCC_ARM)
Scan: bootloader
Using ROM regions application, post_application in this build.
Region application: size 0x8a000, offset 0x0
Region post_application: size 0x16a000, offset 0x8a000
Using RAM region application_ram in this build.
Region application_ram: size 0x7d000, offset 0x20000000
Link: bootloader
Elf2Bin: bootloader
Merging Regions
Filling region application with BUILD/MAX32630FTHR/GCC_ARM\bootloader_application.bin
Space used after regions merged: 0x89800
Merging Regions
Filling region application with BUILD/MAX32630FTHR/GCC_ARM\bootloader_application.bin
Space used after regions merged: 0x89800
| Module                    |     .text |    .data |     .bss |
|---------------------------|-----------|----------|----------|
| Serialflash\SerialFlash.o |   224(+0) |    0(+0) |    0(+0) |
| [fill]                    |   104(+0) |    4(+0) |  390(+0) |
| [lib]\c.a                 |  7544(+0) | 2108(+0) |   58(+0) |
| [lib]\gcc.a               |   772(+0) |    0(+0) |    0(+0) |
| [lib]\misc                |   188(+0) |    4(+0) |   28(+0) |
| main.o                    |   668(+0) |    0(+0) |  264(+0) |
| mbed-os\cmsis             |  7902(+0) |  168(+0) | 5952(+0) |
| mbed-os\drivers           |  2332(+0) |    0(+0) |   60(+0) |
| mbed-os\hal               |  1682(+0) |    4(+0) |   58(+0) |
| mbed-os\platform          |  6500(+0) |  260(+0) |  424(+0) |
| mbed-os\rtos              |   218(+0) |    0(+0) |    0(+0) |
| mbed-os\targets           |  6282(+0) |  580(+0) |  410(+0) |
| Subtotals                 | 34416(+0) | 3128(+0) | 7644(+0) |
Total Static RAM memory (data + bss): 10772(+0) bytes
Total Flash memory (text + data): 37544(+0) bytes
Update Image: BUILD/MAX32630FTHR/GCC_ARM\bootloader_update.bin
Image: BUILD/MAX32630FTHR/GCC_ARM\bootloader.bin

Bootloader mbed_app.json:

{

    "target_overrides": {
        "MAX32630FTHR": {
            "target.restrict_size": "0x8B000"
        }
    }
}

Building Firmware:

Building project firmware-bodygraph (MAX32630FTHR, GCC_ARM)
Scan: firmware-bodygraph
Using ROM regions bootloader, application in this build.
Region bootloader: size 0x8a000, offset 0x0
Region application: size 0x16a000, offset 0x8a000
Using RAM region application_ram in this build.
Region application_ram: size 0x7d000, offset 0x20000000
Link: firmware-bodygraph
Elf2Bin: firmware-bodygraph
Merging Regions
Filling region bootloader with d:\Documenten\GitHub\firmwarebodygraph\firmware-bodygraph\bootloader.bin
Filling region application with BUILD/MAX32630FTHR/GCC_ARM\firmware-bodygraph_application.bin
Space used after regions merged: 0x159600
Merging Regions
Filling region application with BUILD/MAX32630FTHR/GCC_ARM\firmware-bodygraph_application.bin
Space used after regions merged: 0xcf600
| Module                     |      .text |    .data |      .bss |
|----------------------------|------------|----------|-----------|
| [fill]                     |    184(+0) |   13(+0) |    67(+0) |
| [lib]\c.a                  |  65476(+0) | 2574(+0) |    97(+0) |
| [lib]\gcc.a                |   7416(+0) |    0(+0) |     0(+0) |
| [lib]\misc                 |    188(+0) |    4(+0) |    28(+0) |
| [lib]\nosys.a              |     32(+0) |    0(+0) |     0(+0) |
| [lib]\stdc++.a             | 170428(+0) |  145(+0) |  5720(+0) |
| mbed-os\cmsis              |   8268(+0) |  168(+0) |  5952(+0) |
| mbed-os\drivers            |   3832(+0) |    0(+0) |   104(+0) |
| mbed-os\hal                |   1932(+0) |    8(+0) |   115(+0) |
| mbed-os\platform           |   6452(+0) |  260(+0) |   424(+0) |
| mbed-os\rtos               |    260(+0) |    0(+0) |     0(+0) |
| mbed-os\targets            |   7872(+0) |  804(+0) |   416(+0) |
| modules\Bluetooth          |   2860(+0) |    0(+0) |     1(+0) |
| modules\ECG                |   1402(+0) |    0(+0) |    20(+0) |
| modules\IMU                |    832(+0) |    0(+0) |     0(+0) |
| modules\Oscillator         |    120(+0) |    0(+0) |     0(+0) |
| modules\PMIC               |    678(+0) |    0(+0) |     0(+0) |
| modules\Serialflash        |     10(+0) |    0(+0) |     0(+0) |
| src\Buttons.o              |     70(+0) |    0(+0) |     0(+0) |
| src\Controller.o           |   3176(+0) |    0(+0) |    13(+0) |
| src\ControllerEventQueue.o |     92(+0) |    0(+0) |     0(+0) |
| src\DataManagement.o       |   1588(+0) |    0(+0) |     1(+0) |
| src\RingBuffer.o           |    112(+0) |    0(+0) |     0(+0) |
| src\StatusLED.o            |    194(+0) |    0(+0) |     0(+0) |
| src\main.o                 |   1222(+0) |    0(+0) | 79354(+0) |
| Subtotals                  | 284696(+0) | 3976(+0) | 92312(+0) |
Total Static RAM memory (data + bss): 96288(+0) bytes
Total Flash memory (text + data): 288672(+0) bytes
Update Image: BUILD/MAX32630FTHR/GCC_ARM\firmware-bodygraph_update.bin
Image: BUILD/MAX32630FTHR/GCC_ARM\firmware-bodygraph.bin

Targets.json:

"MAX32630FTHR": {
        "inherits": [
            "Target"
        ],
        "core": "Cortex-M4F",
        "macros": [
            "__SYSTEM_HFX=96000000",
            "TARGET=MAX32630",
            "TARGET_REV=0x4132",
            "BLE_HCI_UART",
            "OPEN_DRAIN_LEDS",
            "MBED_TICKLESS"
        ],
        "extra_labels": [
            "Maxim",
            "MAX32630"
        ],
        "supported_toolchains": [
            "GCC_ARM",
            "IAR",
            "ARM"
        ],
        "features_add": [
            "STORAGE"
        ],
        "components_add": [
            "SD"
        ],
        "mbed_rom_start": "0x00000000",
        "mbed_ram_start": "0x20000000",
        "mbed_rom_size" : "0x1F4000",
        "mbed_ram_size" : "0x7D000",
        "bootloader_supported": true,
        "device_has": [
            "ANALOGIN",
            "I2C",
            "INTERRUPTIN",
            "LPTICKER",
            "PORTIN",
            "PORTINOUT",
            "PORTOUT",
            "PWMOUT",
            "SD",
            "SERIAL",
            "SERIAL_FC",
            "SPI",
            "STDIO_MESSAGES",
            "USTICKER",
            "MPU",
            "SLEEP",
            "USBDEVICE"
        ],
        "detect_code": [
            "0409"
        ],
        "device_name": "MAX32630",
        "supported_application_profiles" : ["full", "bare-metal"],
        "supported_c_libs": {
            "arm": [
                "std",
                "small"
            ],
            "gcc_arm": [
                "std",
                "small"
            ],
            "iar": [
                "std"
            ]
        }
    },

Code bootloader:

#include "mbed.h"
#include "FATFileSystem.h"
#include "flc.h"
#include "flc_regs.h"
#include "SerialFlash.h"


SPI spiFlash(P1_1, P1_2, P1_0); // MOSI, MISO, SCLK lines from ISSI chip
DigitalOut ceFlash(P1_3, 1);
DigitalOut resetFlash(P1_5, 1);
SerialFlash sf(spiFlash, ceFlash, resetFlash);
UnbufferedSerial pc(P2_1, P2_0, 115200);
void apply_update(uint32_t address);

int main()
{
    spiFlash.format(8, 3);       // Set 8 bit format with spi Mode: 1,1
    spiFlash.frequency(3000000); // Set spi frequency 3Mhz
    resetFlash.write(1);           // Set reset pin high
    uint8_t buffer[100];
    //Read if there is anything on there
    sf.ReadPage(0x0, false, buffer, 1);
    if (buffer[0] == 0x10) {
        printf("Firmware update found\r\n");

        apply_update(POST_APPLICATION_ADDR);
    } else {
        printf("No update found to apply\r\n");
    }

    printf("Starting application at %X\r\n", POST_APPLICATION_ADDR);

    mbed_start_application(POST_APPLICATION_ADDR);
}

void apply_update(uint32_t address)
{
    FLC_Init();
    uint8_t length[100];
    sf.ReadPage(0x0, false, length, 2);
    uint32_t len = length[0] << 24;
    len = len | (length[1] << 16);
    len = len | (length[2] << 8);
    len = len | length[3];
    printf("Firmware size is %d bytes\r\n", len);

    int page_size = 4;
    uint8_t *page_buffer = new uint8_t[page_size];
    uint32_t addr = address;
    //uint32_t next_sector = addr + flash.get_sector_size(addr);
    //bool sector_erased = false;
    size_t pages_flashed = 0;
    uint32_t currentaddress = 0x03;
    while (true) {

        // Read data for this page
        memset(page_buffer, 0, (sizeof(uint8_t) * page_size));
        sf.ReadPage(currentaddress, false, page_buffer, page_size);

        //Erase page on serial flash.
        
        // Erase this page if it hasn't been erased
        FLC_PageErase(addr, MXC_V_FLC_ERASE_CODE_PAGE_ERASE, MXC_V_FLC_FLSH_UNLOCK_KEY);

        // Program page
        FLC_Write(addr, page_buffer, 1, MXC_V_FLC_FLSH_UNLOCK_KEY);

        addr += page_size;
        currentaddress += page_size;
        pages_flashed++;
    }
    printf("Flashed 100%%\r\n");
    delete[] page_buffer;

}

After flashing this firmware the Serial output says:
No update found to apply
Starting application at 0x8a000

And then nothing happens. What could be the issue here?

ARM has some limitations on the vector table offset, you cannot boot into any address. One requirement is that it has to be a power of two, which isn’t the case for your application. Check the “Vector Table Offset Register” section in the Cortex-M4 reference manual. Also check out this post to read more on bootloaders: From Zero to main(): How to Write a Bootloader from Scratch | Interrupt

Why do you use such a large bootloader region anyway?

Hi, I am facing the exact same issue. However I have set the bootloader size to a power of two, it still doesn’t start after. mbed_start_application is supposed to start the reset handler of the next application at the address specified.
I have written two extremely simple applications for my bootloader and main application:

Bootloader:

#include "mbed.h"

#define LINE "\n-------------------------\n"

int main()
{
    printf("%sIn bootloader %s", LINE, LINE);
    printf("Bootloader start address: %X\r\n", APPLICATION_ADDR);
    printf("Bootloader size: %X\r\n", APPLICATION_SIZE);
    printf("Starting application at: %X\r\n", POST_APPLICATION_ADDR);
    printf("Post application size: %X\r\n", POST_APPLICATION_SIZE);

    mbed_start_application(POST_APPLICATION_ADDR);
}

Main application:

#include "mbed.h"

#define LINE "\n-------------------------\n"

int main()
{
    printf("%sIn main program %s", LINE, LINE);
    printf("Bootloader size: %X", BOOTLOADER_SIZE);
    printf("Application size: %X", APPLICATION_SIZE);

    while (true) 
    {

    }
}

The mbed_app.json for the bootloader looks like this:

{

    "target_overrides": {
        "MAX32630FTHR": {
            "platform.stdio-baud-rate"          : 115200,
            "platform.stdio-buffered-serial"    : true,
            "target.device_name"                : "MAX32630",
            "target.bootloader_supported"       : true,
            "target.restrict_size"              : "0x10000"
        }
    }
}

I add the bootloader to the main application with the following mbed_app.json:

{

    "target_overrides": {
        "MAX32630FTHR": {
            "platform.stdio-baud-rate"          : 115200,
            "platform.stdio-buffered-serial"    : false,
            "target.device_name"                : "MAX32630",
            "target.bootloader_supported"       : true,
            "target.bootloader_img"             : "bootloader.bin"
        }
    }
}

0x10000 = 65.536 bytes = 2^16. See the screenshot below for proof that my bootloader.bin really is padded out to the appropriate amount of bytes:
image

The main application text never gets printed. What else could I be doing wrong here? Do I need to set the values in the VTOR register myself? I expected MBED OS to handle that…

I’m not an expert, but from my experience, it’s not a power of two, it’s the beginning of a new sector in the mcu’s flash. You need to check your mcu’s memory map and set the start address accordingly and also actually put the main application there.

1 Like

Thanks for the tip. However I am seriously unable to find an overview of these flash sectors or their size. Closest I have found in the cortex-m4 generic user guide is the following:

Or:


The latter looks more like what you mentioned, but still no hint as to the sizes of the R1 - R12 registers. Simply looking up MAX32630 memory mapping / flash sectors or Cortex-m4 memory mapping/flash sectors yields no good results either… Would you happen to know more about this?

are you sure this MCU is bootloader compatible? it’s not written in target json. mbed-os/targets.json at master · ARMmbed/mbed-os · GitHub

Almost certain. The MAX32630 user guide says the following:

The flash memory controller on the MAX32630 handles control and timing signals for programming and erase operations on the internal flash memory. The flash
controller is used during the application development and release cycle to erase the internal flash memory and then load the application code and data. This is
typically done using an external debug adapter (using the provided JTAG or Serial Wire Debug interfaces), but it is also possible to implement a custom bootloader
to use other interfaces to load or update application code under firmware control.

However, you are right that support isn’t automatically enabled in the target.json, I had to force it via a target override in mbed_app.json like so:

{

    "target_overrides": {
        "MAX32630FTHR": {
            "platform.stdio-baud-rate"          : 115200,
            "platform.stdio-buffered-serial"    : true,
            "target.device_name"                : "MAX32630",
            "target.bootloader_supported"       : true,
            "target.restrict_size"              : "0x10000"
        }
    }
}

This still shouldn’t really stop me from using a bootloader. But perhaps the assembly instructions in the mbed_app_start aren’t correct now. I’m hoping that’s not the case and my bootloader size just isn’t lined up properly.

Edit: I have finally found the flash sector size. In the MAX32630 user guide they are referred to as pages. It’s 256 pages with a size of 8KB each, so 2MB in total. This would mean that it is indeed lined up properly.

0x10000 = 64KB which is divisible by 8KB and such ends on a sector or page.