This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Relocating bootloader by DFU

Description:

We'd like to extend our existing bootloader. It currently supports UART transport and we want to retrofit a bootloader that also supports OTA via BLE. On merging the code bases for pca10056_uart and pca10056_ble it became clear that we run into a space issue: Current bootloader is around 22KB (24KB available), the modified version is 28KB so it doesn't fit. Even with -lto enabled it is still too big (around 26KB)

My question: (having already looked at https://devzone.nordicsemi.com/f/nordic-q-a/16378/relocating-bootloader-by-dfu ):

Is there any possibility to retrofit a bigger bootloader via DFU?

Undesired options:

I know that it is easily possible via debug probe but we have a considerable amount of devices already sold and it would make no sense to maintain two architectures. So it either works and we offer OTA as well or we can't offer it at all.

Setup:

  • Chip: nrf52840
  • Current Bootloader: Secure Bootloader UART (from 15.3.0_59ac345/examples/dfu/secure_bootloader/pca10056_uart)
  • Linker script puts the bootloader at 0xF8000 with a slot of 0x6000
  • Hello

    Have a look at the DEBUG version of the BLE bootloader in the SDK - its start  address is set to 71000 as opposed to 78000 for the non DEBUG version. So yes, just edit the project file, recompile and you are there. (Just update the flash size for your application too). Beware, once you flashed the bootloader with whatever starting address, you won't be able to upgrade it over the air with the bootloader with different starting address, manual flashing will be required.

  • Hi ,

    thanks for taking the time to answer. As I said: manual flashing is not an option here.

    Looking at infocenter.nordicsemi.com it states:

    The size of the bootloader is fixed for the lifetime of the device. This is because the location (MBR_BOOTLOADER_ADDR) that stores the start address of the bootloader is not (safely) updateable.

    So I am interested in what way (possibly unsafe) it could still be done.

  • In recent SDK versions (including 15.3) the bootloader start address is stored in the end of the MBR page (page 0). That gives you a few problems which in sum makes this not possible.

    You cannot do a page erase of the MBR and then write it again as that resides in address 0 and has the interrupt vector table etc. So that cannot be done.

    In theory you could change the bootloader start address if you only require bits in the address to be flipped from 1 to 0 as that way you only need to write to the MBR page and not erase it. You would need to flash a temporary bootloader though, as the bootloader now write protects the bootloader pages and the MBR page using ACL. But this limits the number of possible addresses so much that it is probably not useful in practice.

  • Hi Einar Thorsrud,

    thank you very much for your insight!

    That might still be interesting for us. Currently, the bootloader sits at 0xF8000 with a size of 0x6000. When it could be possible to just flip bit 15 of the start address we'd end up with the new start address being 0xF0000 and a size of 0xE000 which would give us more than enough space to work with.

    However do I understand you correctly that we still would need to flash a bootloader onto the device which does not do this first:

    // Protect MBR and bootloader code from being overwritten.
    ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, false);
    APP_ERROR_CHECK(ret_val);
    ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE, false);
    APP_ERROR_CHECK(ret_val);

    Reading about ACL it seems to be impossible to reset permissions during runtime once they have been set. 

    As a vague Idea I have the following scenario (all DFU) in mind:

    1. Transfer a temporary bootloader to the device via DFU to address 0xF8000. This bootloader would not utilize ACL. 
    2. Transfer an intermediate bootloader to the device via DFU to address 0xF0000. This bootloader utilizes ACL.
    3. Have the temporary bootloader modify the MBR section to just flip bit 15 at MBR_BOOTLOADER_ADDR triggered by a custom DFU command or some other means.
    4. Reset the device to activate the intermediate bootloader.
    5. Now we have ACL back on and a bootloader slot staring at 0xF0000 of size 0xE000, ready to accept our desired UART+BLE bootloader.

    It's not an easy task but it should be possible all by DFU shouldn't it?

  • Hi,

    Yes, it should be doable in this case.

    Regarding point 2 you will not be able to write the bootloader to 0xF0000 via DFU directly, but you could use something form this old post. This describes essentially what you want to do, but with a method that only worked on older SDK's and only on nRF52832, as there the bootloader address was in the UICR and the UICR could be erased and reprogrammed.

    Alternatively and perhaps easier for step 2 it should be possible to make an application image that contains the new temporary bootloader at the new start address, but also with something else (application or just junk / empty space) from the beginning of the application start address.

Related