Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLE NRF52840 : Building Custom bootloader (FOTA/UART) for Cordio BLE applications. #9827

Closed
yogeshk19 opened this issue Feb 24, 2019 · 19 comments

Comments

Projects
None yet
10 participants
@yogeshk19
Copy link

commented Feb 24, 2019

Description

  • Target : NRF52840
  • Toolchain : GCC_ARM
  • mbed-cli
  • Mbed OS 5.11.2

Since we are not using the Nordic Softdevice and the sample bootloader that Nordic provides for both flashing OTA and via an UART interface and since we are using the Cordio BLE API's to build the custom BLE application, I was wondering if the mbed BLE team can provide an example bootloader that can flash the firmware over the air and/or via an UART interface? Currently we flash the firmware using a JLink interface using Nordic's NRFGo studio application, but this is not feasible once the custom board is packaged and only can be flashed OTA. So any help that MBED BLE team can provide to support a custom bootloader that would be help us be production ready.

Issue request type

[ ] Question
[X] Enhancement
[ ] Bug

Thanks,
Yogesh

@pan-

This comment has been minimized.

Copy link
Member

commented Feb 25, 2019

@donatieng

This comment has been minimized.

Copy link
Member

commented Feb 25, 2019

Hi @yogeshk19,

As you can imagine a BLE update/bootloader feature for Mbed OS + Cordio is an important requirement for many use cases and we're aware of this.
I can't communicate how/when we'd provide a solution for it but that's something we're looking into. Sorry I can't give you a better answer at this stage - there's a bunch of priorities we're balancing, I'll have a chat with our product team to see if we can clarify roadmap a bit.
That being said I think we should gather interest in this use case using this issue.

Cheers,
Don

@ciarmcom

This comment has been minimized.

Copy link
Member

commented Feb 25, 2019

@40Grit

This comment has been minimized.

Copy link

commented Feb 28, 2019

Interested very much.

Would like to see uVisor concepts revival considered for this target as well.

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Mar 3, 2019

@donatieng, Thanks for your response. We have very specific deadlines and we are evaluating whether to use ARM's Cordio BLE platform or should we wait until we have all the Cordio BLE related functionalities in place including the ease of building a custom bootloader that supports both OTA and UART channels to flash the firmware. We are currently in testing phase of using the BLE Cordio API and we are hoping to be in pre-production phase in a few weeks from now. However if you think there are no plans to support a custom secure bootloader in the near future, it would be great to know what the road map would be and so we can plan on adopting BLE Cordio when all the pieces are in place.

Also if were to build a custom bootloader on our own, I was hoping to get some guidance from the ARM team as to how best to achieve this, to support flashing firmware OTA.

Thanks,
Yogesh

@trowbridgec

This comment has been minimized.

Copy link
Contributor

commented Mar 4, 2019

We are very interested in something like this as well.

@loverdeg-ep

This comment has been minimized.

Copy link
Contributor

commented Mar 4, 2019

@dlfryar any thoughts?

@dlfryar

This comment has been minimized.

Copy link
Contributor

commented Mar 4, 2019

We actually looked at doing this type of thing using Nordic's nRFConnect app. Something that can be doubly signed where images are stored in the same compatible location which makes it compatible with the Nordic FOTA/app and Pelion.

It's technically possible today, but no implementation/example exists.

@marcuschangarm can add more detail.

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Mar 5, 2019

@dlfryar Thanks for letting us know there was some effort made in this direction. However I am wondering if we were to build a bootloader on our own, is there any guidance that you or @marcuschangarm can provide that could help us come up with an implementation as we need to be production ready if we are to continue use the Cordio BLE API.

Thanks,
Yogesh

@BrianBlumARM

This comment has been minimized.

Copy link

commented Mar 5, 2019

@yogeshk19 I am the Product Manager for Mbed BLE and Cordio and would love to chat more about your use case / requirements. If you are open to discussing please email me at cordio-mbed@arm.com.

Thanks,
Brian

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Apr 14, 2019

I am in the process of creating a custom OTA/UART bootloader for a BLE application for NRF52840 BLE module and I was wondering what should I be setting for target.restrict_size, as the bootloader sample that are available to seems to set this at 0x40000 and was wondering if this value would work? Also there was an issue #9949 called out regarding bootloader merging region errors, would this be an issue in the recently released mbed os 5.12?

What else bootloader settings such as the "target.restrict_size" should I be configuring, in order to get a simple bootloader working? As far as the bootloader sample one of the values that needed to be set was POST_APPLICATION_ADDR and I was wondering what would be the best way to determine this for NRF52840 BLE module?

Thanks,
Yogesh

@loverdeg-ep

This comment has been minimized.

Copy link
Contributor

commented Apr 14, 2019

@trowbridgec

This comment has been minimized.

Copy link
Contributor

commented Apr 16, 2019

We were able to get the mbed bootloader to work on the nRF52840 with firmware updates via Pelion with a couple of tweaks. Note, we used an external NOR flash for firmware update storage.

One tip is that you need to have certain settings match between the bootloader app and the main app.

Here's an excerpt from our bootloader mbed_app.json file:

{
    "config": {
        "documentation": {
            "options": [
                    "In this configuration:",
                    "- Firmware storage is on an external SPIF block device",
                    "The flash regions are as follows:",
                    "1. Bootloader - 64KiB from the beginning of flash",
                    "2. Active App Metadata Header - (1KiB) immediately following the bootloader",
                    "3. Active App - From end of header to the start of the KVSTORE",
                    "4. KVSTORE - 2 4KiB sections at the end of the flash",
                    "+--------------------------+",
                    "|                          |",
                    "|         KVSTORE          |",
                    "|                          |",
                    "+--------------------------+ <-+ storage_tdb_internal.internal_base_address",
                    "|                          |",
                    "|                          |",
                    "|                          |",
                    "|        Active App        |",
                    "|                          |",
                    "|                          |",
                    "|                          |",
                    "+--------------------------+ <-+ mbed-bootloader.application-start-address",
                    "|Active App Metadata Header|",
                    "+--------------------------+ <-+ update-client.application-details",
                    "|                          |",
                    "|        Bootloader        |",
                    "|                          |",
                    "+--------------------------+ <-+ 0, MBED_ROM_START",
                    "Firmware Candidate Storage is on external SPIF at an address of 0x0.",
                    "The storage size is the size of the maximum application size (i.e. Active",
                    "Application region size) multiplied by the number of storage-locations.",
                    "(storage-locations is set to 1 in this configuration)"
            ]
        },
        "application-start-address": {
            "help": "Address to the beginning of the active application firmware in flash",
            "value": null
        },
        "application-jump-address": {
            "help": "Jump address for running the active application firmware",
            "value": null
        },
        "max-application-size": {
            "help": "Maximum size of the active application",
            "value": null
        },
        "flash-start-address": {
            "help": "Start address of internal flash. Only used in this config to help the definition of other macros.",
            "value": null
        },
        "flash-size": {
            "help": "Total size of internal flash. Only used in this config to help the definition of other macros.",
            "value": null
        }
    },
    "macros": [
        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE",
        "MBED_BOOTLOADER_SIZE=(64*1024)",
        "MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE=1024",
        "MBED_ROM_START=0x0",
        "MBED_ROM_SIZE=(1024*1024)"
    ],
    "target_overrides": {
        "*": {
            "target.features_remove"                    : ["LWIP", "BLE", "CRYPTOCELL310"],
            "target.extra_labels_remove"                : ["PSA", "SOFTDEVICE_COMMON", "SOFTDEVICE_S140_FULL", "NORDIC_SOFTDEVICE"],
            "target.extra_labels_add"                   : ["SOFTDEVICE_NONE"],
            "target.components_remove"                  : ["FLASHIAP", "QSPIF"],
            "target.macros_remove"                      : ["MBEDTLS_CONFIG_HW_SUPPORT"],
            "target.device_has_remove"                  : ["QSPI"],
            "target.restrict_size"                      : "0x10000",
            "target.OUTPUT_EXT"                         : "hex",
            "platform.stdio-baud-rate"                  : 115200,
            "platform.stdio-flush-at-exit"              : false,
            "platform.use-mpu"                          : false,
            "flash-start-address"                       : "0x0",
            "flash-size"                                : "(1024*1024)",
            "mbed-bootloader.application-start-address" : "(MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS + MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE)",
            "mbed-bootloader.max-application-size"      : "MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS",
            "mbed-bootloader.use-kvstore-rot"           : 1,
            "update-client.application-details"         : "0x10000",
            "update-client.storage-address"             : "0x0",
            "update-client.storage-size"                : "((MBED_ROM_START + MBED_ROM_SIZE - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS) * MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)",
            "update-client.storage-page"                : 1,
            "update-client.storage-locations"           : 1,
            "update-client.firmware-header-version"     : "2",
            "storage.storage_type"                      : "FILESYSTEM",
            "storage_filesystem.internal_base_address"  : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))",
            "storage_filesystem.rbp_internal_size"      : "(2*4*1024)"
        }
    }
}

Here's an example from our main application mbed_app.json:

{
    "config": {
        "documentation": {
            "options": [
                    "In this configuration:",
                    "- Firmware storage is on an external SPIF block device",
                    "- Root of Trust is obtained from internal flash in kvstore",
                    "The flash regions are as follows:",
                    "1. Bootloader - 64KiB from the beginning of flash",
                    "2. Active App Metadata Header - (1KiB) immediately following the bootloader",
                    "3. Active App - From end of header to the start of the KVSTORE",
                    "4. KVSTORE - 2 4KiB sections at the end of the flash",
                    "+--------------------------+",
                    "|                          |",
                    "|         KVSTORE          |",
                    "|                          |",
                    "+--------------------------+ <-+ device-management.sotp-section-1-address",
                    "|                          |",
                    "|                          |",
                    "|                          |",
                    "|        Active App        |",
                    "|                          |",
                    "|                          |",
                    "|                          |",
                    "+--------------------------+ <-+ target.app_offset",
                    "|Active App Metadata Header|",
                    "+--------------------------+ <-+ update-client.application-details, target.header_offset",
                    "|                          |",
                    "|        Bootloader        |",
                    "|                          |",
                    "+--------------------------+ <-+ 0, device-management.flash-start-address, MBED_ROM_START",
                    "Firmware Candidate Storage is on external SPIF at an address of 0x0.",
                    "The storage size is the size of the maximum application size (i.e. Active",
                    "Application region size) multiplied by the number of storage-locations.",
                    "(storage-locations is set to 1 in this configuration)"
            ]
        },
        "developer-mode": {
            "help": "Enable Developer mode to skip Factory enrollment",
            "options": [
                null,
                1
            ],
            "value": 1
        }
    },
    "macros": [
        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE",
        "MBED_BOOTLOADER_SIZE=(64*1024)",
        "MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE=1024",
        "MBED_ROM_START=0x0",
        "MBED_ROM_SIZE=(1024*1024)",
        "MBED_CONF_APP_MAIN_STACK_SIZE=6000"
    ],
    "target_overrides": {
        "*": {
            "target.features_remove"                            : ["BLE"],
            "target.extra_labels_remove"                        : ["SOFTDEVICE_COMMON", "SOFTDEVICE_S140_FULL", "NORDIC_SOFTDEVICE"],
            "target.extra_labels_add"                           : ["SOFTDEVICE_NONE"],
            "target.components_remove"                          : ["QSPIF", "FLASHIAP"],
            "target.features_add"                               : ["LWIP", "STORAGE", "BOOTLOADER"],
            "target.OUTPUT_EXT"                                 : "hex",
            "target.bootloader_img"                             : "path/to/bootloader.hex",
            "target.header_offset"                              : "0x10000",
            "target.app_offset"                                 : "0x10400",
            "platform.stdio-baud-rate"                          : 115200,
            "platform.default-serial-baud-rate"                 : 115200,
            "platform.stdio-convert-newlines"                   : true,
            "platform.stdio-buffered-serial"                    : true,
            "drivers.uart-serial-txbuf-size"                    : 1024,
            "drivers.uart-serial-rxbuf-size"                    : 1024,
            "mbed-trace.enable"                                 : 1,
            "device-management.flash-start-address"             : "0x0",
            "device-management.flash-size"                      : "(1024*1024)",
            "device-management.sotp-section-1-address"          : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))",
            "device-management.sotp-section-1-size"             : "(4*1024)",
            "device-management.sotp-section-2-address"          : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))",
            "device-management.sotp-section-2-size"             : "(4*1024)",
            "device-management.mcc_transport_mode"              : 0,
            "device-management.pal_dtls_peer_min_timeout"       : "20000",
            "device-management.pal-udp-mtu-size"                : 1358,
            "update-client.application-details"                 : "0x10000",
            "update-client.storage-address"                     : "0x0",
            "update-client.storage-size"                        : "((MBED_ROM_START + MBED_ROM_SIZE - (MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS + MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE)) * MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)",
            "update-client.storage-locations"                   : "1",
            "update-client.firmware-header-version"             : "2"
        }
    }
}

@yogeshk19 You may need to tweak some of the settings to match your hardware, but hopefully this will give you a good start. Let us know if you are able to get any traction on your bootloader as we'd be very interested in something like that!

@maclobdell

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Apr 19, 2019

@trowbridgec Thanks so much for putting down the configuration you have used. We are a bit side tracked we are dealing with some other issues on our custom board. But as soon as I get a chance to play around with a custom bootloader, I will update this issue with my findings.

Thanks,
Yogesh

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Jun 13, 2019

@trowbridgec Is there a way for the bootloader to upgrade the firmware using UART? I managed to BLE version to work, however we are looking to support via UART as well on our custom board which uses the NRF52840 BLE module. Have had any success updating the firmware over UART?

Thanks,
Yogesh

@40Grit

This comment has been minimized.

Copy link

commented Jun 13, 2019

@AGlass0fMilk might have insight.

You might also look into the mcuboot project.

@trowbridgec

This comment has been minimized.

Copy link
Contributor

commented Jun 13, 2019

@yogeshk19 I asked the bootloader team about BLE during one of the recent Mbed Office Hours on the mbed bootloader (https://www.youtube.com/watch?v=Bszg2PAT5iA), and their answer was that the bootloader simply checks for a new version of firmware at the storage location you specify. Therefore, they didn't see a real reason to add BLE/UART/etc. support to the bootloader itself as it's rather agnostic to how the update got to the storage location. It just so happens that their normal use case is to marry the bootloader up with the Pelion cloud client.

With that in mind, you could use any method you want in your application to write an update to the update storage location, and if the bootloader sees it, it will do its thing and copy it over. This would then necessitate that you have to write the application yourself to read in the raw bytes over UART and write them to the update storage location.

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Jun 19, 2019

@trowbridgec Thanks for the youtube link. I was wondering based in the mbed_app.json you attached earlier in the thread, did you use the Nordic's NRF tools the first time to flash the bootloader and the application over JLink? Since you seem to have reference to the Bootloader in the Application's MBED_APP.JSON, I was wondering did you convert the hex file into a .bin file before flashing it or are you flashing a .hex file?

Since my Bootloader supports both BLE & UART mode to flash the firmware or atleast in theory :), the bootloader is pretty much increased in size and so I am have little lesser Flash space compared to 64kb limit that you have restricted in your bootloader. Is it better to control where the bootloader and application start address using the target.MBED_APP_START or target.restrict size and specifying additional offsets?

Thanks,
Yogesh

@yogeshk19

This comment has been minimized.

Copy link
Author

commented Jun 28, 2019

I have a bootloader finally that works over UART and BLE. However the BLE based bootloader is a little more fragile than the one over UART. Closing this issue. Hopefully we have a bootloader available from the MBED OS team which is more out of box and supports multiple modes of transport to flash the firmware.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.