Arm Mbed OS support forum

Bootloader tutorial not working with certain targets

Hi,

I’m trying to create a bootloader for my project by following the tutorial here: https://os.mbed.com/docs/mbed-os/v5.15/tutorials/bootloader.html. I get the code to build on Mbed studio when building for some processors, but unfortunately not when building for the target I’m using - F401RE.

The main.cpp code is from this example here: https://github.com/ARMmbed/mbed-os-example-bootloader and the mbed_app.json is as seen below:

{
“config”: {
“update_file”: {
“help”: “Path to the application update binary on the SD card”,
“value”: ““mbed-os-example-blinky_application.bin””
},
“sd_card_mosi”: {
“help”: “MCU pin connected to the SD card’s SPI MOSI pin”,
“value”: “PC_12”
},
“sd_card_miso”: {
“help”: “MCU pin connected to the SD card’s SPI MISO pin”,
“value”: “PC_11”
},
“sd_card_sck”: {
“help”: “MCU pin connected to the SD card’s SPI SCK pin”,
“value”: “PC_10”
},
“sd_card_cs”: {
“help”: “MCU pin connected to the SD card’s SPI CS pin”,
“value”: “PC_4”
}
},
“target_overrides”: {
“NUCLEO_F429ZI”: {
“target.components_add”: [“SD”],
“target.restrict_size”: “0x40000”
},
“NUCLEO_F401RE”: {
“target.components_add”: [“SD”],
“target.restrict_size”: “0x40000”
},
“NUCLEO_F411RE”: {
“target.components_add”: [“SD”],
“target.restrict_size”: “0x40000”
}
}
}

When trying to build for F429ZI (as in the example mbed_app.json) or F411 (or several other seemingly unrelated processors) it builds fine, but with F401 it does not seem to find the target.restrict_size configuration.

[Error] main.cpp@9,2: “target.restrict_size must be set for your target in mbed_app.json”

Hello @samulinyman,

Both, the NUCLEO_F429ZI and NUCLEO_F411RE targets have an

        "bootloader_supported": true,

entry in the mbed-os/targets/targets.json file. But the NUCLEO_F401RE doesn’t. Try to add such also for that target. Maybe it will fix the issue.

Best regards, Zoltan

Hi Zoltan,

Thanks for the suggestion. After adding that line, the build gives more information.

Configuration error: No sector info available

Does that mean that the F401RE just does not support bootloaders?

Best,

Samuli

Hello Samuli,

The Flash IAP is used to get information about the target’s flash properties (including sector size). Try to run this simple Flash IAP example program to see whether it works on the NUCLEO-F401RE:

#include "mbed.h"

FlashIAP flash;

int main() {
    printf("Starting...\r\n");

    flash.init();

    const uint32_t  flash_start = flash.get_flash_start();
    const uint32_t  flash_size = flash.get_flash_size();
    const uint32_t  flash_end = flash_start + flash_size;
    const uint32_t  page_size = flash.get_page_size();                  // in bytes
    uint32_t        sector_size = flash.get_sector_size(flash_end - 1); // in bytes
    uint32_t        addr = flash_end - sector_size;                     // address of first byte in the last sector

    printf("flash_start = 0x%.8x\r\n", flash_start);
    printf("flash_size = 0x%.8x\r\n", flash_size);
    printf("flash_end = 0x%.8x\r\n", flash_end);
    printf("page_size = 0x%.8x\r\n", page_size);
    printf("sector_size = 0x%.8x\r\n", sector_size);
    printf("addr = 0x%.8x\r\n", addr);
    printf("----------------------\r\n");
    flash.deinit();
}

Hi Zoltan,

I really appreciate the effort you are putting into this.

The output from this program on F401 is:

Starting…
flash_start = 0x08000000
flash_size = 0x00080000
flash_end = 0x08080000
page_size = 0x00000001
sector_size = 0x00020000
addr = 0x08060000

Hello Samuli,

The Flash IAP seems OK. Try to add also:

        "components_add": [
            "FLASHIAP"
        ],

entry into the mbed-os/targets/targets.json file for the NUCLEO_F401RE target (NUCLEO_F411RE has it).

Hi,

Unfortunately that did not have an effect. It still gives

Configuration error: No sector info available

The F401 target in the mbed-os/targets/targets.json looks now like this:

“NUCLEO_F401RE”: {

    "inherits": ["FAMILY_STM32"],

    "supported_form_factors": ["ARDUINO", "MORPHO"],

    "core": "Cortex-M4F",

    "extra_labels_add": ["STM32F4", "STM32F401xE", "STM32F401RE"],

    "components_add": ["FLASHIAP"],

    "config": {

        "clock_source": {

            "help": "Mask value : USE_PLL_HSE_EXTC | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI",

            "value": "USE_PLL_HSE_EXTC|USE_PLL_HSI",

            "macro_name": "CLOCK_SOURCE"

        }

    },

    "detect_code": ["0720"],

    "device_has_add": [

        "SERIAL_ASYNCH",

        "FLASH",

        "MPU"

    ],

    "release_versions": ["2", "5"],

    "device_name": "STM32F401RE",

    "bootloader_supported": true

},

Hello Samuli,

Unfortunately, I was not able to make it work :frowning: Since Flash IAP works correctly I think it must be some configuration problem (performed by mbed python tools).

Best regards, Zoltan

Hi Zoltan, thank you anyway for your efforts. Really appreciate it!

Have a good one,

Samuli

Hello Samuli,

I think I have found the file defining the sectors info for the bootloader. You can modify it as follows:

  • Open the mbed-os/tools/arm_pack_manager/index.json file
  • Search for STM32F411RETx. You should find something like:
        "name": "STM32F411RETx", 
        "processor": {
            "Symmetric": {
                "core": "CortexM4", 
                "fpu": "SinglePrecision", 
                "mpu": "Present", 
                "units": 1
            }
        }, 
        "sectors": [
            [
                134217728, 
                16384
            ], 
            [
                134283264, 
                65536
            ], 
            [
                134348800, 
                131072
            ], 
            [
                536836096, 
                528
            ], 
            [
                536854528, 
                4
            ]
        ], 
  • Select the “sectors” section for copying and then search for STM32F401RETx. You should find something like:
"name": "STM32F401RETx", 
        "processor": {
            "Symmetric": {
                "core": "CortexM4", 
                "fpu": "SinglePrecision", 
                "mpu": "Present", 
                "units": 1
            }
        }, 
        "sectors": null,
  • Paste the “sectors” section from the STM32F411RETx here so it becomes:
"name": "STM32F401RETx", 
        "processor": {
            "Symmetric": {
                "core": "CortexM4", 
                "fpu": "SinglePrecision", 
                "mpu": "Present", 
                "units": 1
            }
        }, 
        "sectors": [
            [
                134217728, 
                16384
            ], 
            [
                134283264, 
                65536
            ], 
            [
                134348800, 
                131072
            ], 
            [
                536836096, 
                528
            ], 
            [
                536854528, 
                4
            ]
        ], 
  • Save the file and compile the bootloader for the NUCLEO_F401RE target.

Best regards, Zoltan

Wow thank you Zoltan, it compiles now! Unfortunately it still does not seem to start the post application.

The post application has the same changes to mbed-os files as the bootloader to make it compile with this mbed_app.json

{
“target_overrides”: {
“NUCLEO_F401RE”: {
“target.bootloader_img”: “mbed-os-bootloader.bin”
}
}
}

and the build process seems to set the options correctly.

Using ROM regions bootloader, application in this build.
Region bootloader: size 0x20000, offset 0x8000000
Region application: size 0x60000, offset 0x8020000

When flashing only the mbed-os-bootloader.bin to the F401RE through ST-link, it runs once and stops after not finding any application, as expected. However, when flashing either mbed-os-example-blinky.bin (the merged application) through ST-link or mbed-os-example-blinky_application.bin (the unmerged application) from the SD-card, the F401RE goes to infinite boot loop, always booting back into the bootloader and never starting the application. Furthermore, the post-application works normally when the bootloader is not present i.e. when programming the processor with the post-application only through ST-link.

Best regards,

Samuli

Hello Samuli,

Which toolchain do you use, ARM or GCC ARM ? In case you use GCC ARM please notice that the NUCLEO-F401RE linker file:

mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F401xE/TOOLCHAIN_GCC_ARM/STM32F401RE.ld

is not adapted for bootloader builds (the MBED_APP_START and MBED_APP_SIZE symbols are not used). The simplest way how to fix that is to replace it with the content of the

mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TOOLCHAIN_GCC_ARM/STM32F411RE.ld

linker file.

However, because the NUCLEO_F401RE has less RAM than the NUCLEO_F411RE, then replace

RAM (rwx)  : ORIGIN = 0x20000198, LENGTH = 128k - 0x198

with

RAM (rwx)  : ORIGIN = 0x20000198, LENGTH = 96k - 0x198

Best regards, Zoltan

Hi,

I am using ARM, which is the default in Mbed Studio.

Best,

Samuli

Hello Samuli,

  • For testing, build a simple “application starter” rather than a complete “bootloader”.
    For example:
#include "mbed.h"

#if !defined(POST_APPLICATION_ADDR)
#error "target.restrict_size must be set for your target in mbed_app.json"
#endif

int main()
{
    printf("Starting the application starter\r\n");
    printf("About to start the application at address: 0x%x\r\n", POST_APPLICATION_ADDR);
    mbed_start_application(POST_APPLICATION_ADDR);
}
  • Copy the “application starter” bin file to the application project’s folder, for example “mbed-os-blinky” and build the application (as described in “Creating the main program” of the bootloader tutorial).

  • The GCC ARM toolchain includes a utility program called arm-none-eabi-objdump which can display some useful info about the application. So install the GCC ARM toolchain, open a terminal window in the application build directory containing the .bin and .elf files and run the following command:

arm-none-eabi-objdump -h mbed-os-blinky_application.elf

It should display something like:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000077a0  08008c00  08008c00  00000094  2**2
...
  • Run the serial terminal program on the PC and connect to the NUCLEO_F401RE virtual COM port.
    Program your NUCLEO_F401RE with the mbed-os-blinky.bin file (not with the mbed-os-blinky_application.bin one) using the drag&drop method.

  • Check the application address displayed on the serial terminal. It should match the VMA (Virtual Memory Address) and LMA (Load Memory Address) shown by the arm-none-eabi-objdump above and the application should start up and run.

  • If the application address does not match the VMA value then go back to step one. Replace the value of the “target.restrict_size” in the mbed_app.json file with “VMA value - 0x08000000” (in this case 0x8c00) and repeat all steps again.

Once the “application starter” works you can proceed with building the “bootloader” in similar way.

Best regards, Zoltan

Hi Zoltan,

Thanks for the suggestion. I ran the command for mbed-os-blinky_application.bin built with the “application starter” with GCC Command Prompt and it printed the result below. Notably, VMA and LMA of Idx 0 are both 08000000 which would result target.restrict_size of 0.

Idx Name          Size      VMA       LMA       File off  Algn
  0 ER_IROM1      00009a5c  08000000  08000000  00000034  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 RW_IRAM1      00000100  20000198  20000198  00009a90  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 RW_IRAM1      00001fd0  20000298  20000298  00009b90  2**3
                  ALLOC
  3 ARM_LIB_STACK 00000400  20017c00  20017c00  00009b90  2**2
                  ALLOC
  4 .debug_abbrev 0001608d  00000000  00000000  00009b90  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_frame  0000a848  00000000  00000000  0001fc1d  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_info   0016568f  00000000  00000000  0002a465  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_line   0005303c  00000000  00000000  0018faf4  2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_loc    000384d6  00000000  00000000  001e2b30  2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_str    000ea090  00000000  00000000  0021b006  2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_ranges 00008c78  00000000  00000000  00305096  2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .note         00000020  00000000  00000000  003209f4  2**2
                  CONTENTS, READONLY
 12 .comment      00003ea8  00000000  00000000  00320a14  2**0
                  CONTENTS, READONLY

Furthermore, the ROM regions at the beginning of build of the mbed-os-blinky seem to depend on the code in the main.cpp, not the restriction set in mbed_app.json. I don’t know if this is right. The ROM regions printed when building the code you provided are:

Using ROM regions bootloader, application in this build.
Region bootloader: size 0xc000, offset 0x8000000
Region application: size 0x74000, offset 0x800c000

whereas with the main.cpp with the example code they are:

Using ROM regions bootloader, application in this build.
Region bootloader: size 0x20000, offset 0x8000000
Region application: size 0x60000, offset 0x8020000

Have a nice weekend,

Samuli

Hello Samuli,

It seems that mbed-os 6.0.0 doesn’t build the bootloader correctly. Update the Mbed library to mbed-os 6.1.0. The NUCLEO_401RE linker files have been already fixed by mbed. However, you still have to modify the mbed-os/targets/targets.json and mbed-os/tools/arm_pack_manager/index.json files as suggested above.

Best regards, Zoltan

Hi Zoltan,

Thank you so much, updating to mbed-os 6.1.0 and following all the steps except for the linker file fix made the bootloader example work. I am really grateful for your help!

Best regards,

Samuli Nyman