Change Bootloader start address

I need to do a DFU via BLE but I do not have enough memory.
For the past few months I have been working on a custom bootloader that would use an external memory to do the DFU.
The problem is that the new bootloader is bigger than the previous one and requires me to change the allocated memory.

Current Memory Layout New Memory Layout
Bootloader Settings Page 0x3F000 to 0x40000 0x3F000 to 0x40000
MBR Params Page 0x3E000 to 0x3F000 0x3E000 to 0x3F000
Bootloader 0x38000 to 0x3E000 0x37000 to 0x3E000

I only have two options:

  • Allocate only 0x500 for the settings page and params page so that they will fit between 0x3F000 and 0x40000.
  • Move the bootloader start address

I know this is not recommended but I have no choice in this case.
I cant change the hardware, I already have tens of thousands of devices with the clients that can only be updated through BLE DFU.

As it was mentioned in another public ticket, for SoftDevice versions beyond 6.1, the bootloader start address is stored in the MBR.
I need to know how can I modify this address correctly.

For now i have disabled the memory flash protection of the MBR, in main.c, so that I can modify the value.
Then in nrf_bootloader_fw_activation.c, i modify that value right before the MBR is called to replace the bootloader by calling this function:

  • nrf_nvmc_write_word(MBR_BOOTLOADER_ADDR, (uint32_t) 0x37000);

However, if I read the value stored in MBR_BOOTLOADER_ADDR, it is not necessarily the value I have written.
How can I change this value?

If this is actually impossible, can I reduce the allocated size for the params and settings pages? they only need  800 bytes each but they allocate 4096 each.

  • Neither of your two options will work. You cannot set bits with the write_word function, you can only reset them to zero. Now look at your hex values in windows calculator binary mode - you have to both set and reset bits.

    The pages also must be as big as one erase page because that is what you can erase at a time for the flash memory.

    Your only option is to mess with compiler and bootloader settings in order to fit the new on in the space for the old.

    Resetting this bootloader setting in MBR or UICR is a manufacturer only thing - you can only do that reliably via SWD connection.

  • As   says, this cannot be done safely. At least not with tens of thousands of devices. The issue is that to update one word in the flash, you need to erase the entire flash page, which in itself is risky. Some error during this operation, and the device is bricked without a programmer. Depending on what SDK you are using, the bootloader may actually be stored in the UICR, and not the MBR (I believe we went back from storing it in the MBR), but I don't remember the details without looking it up. But it is either way a bad idea to change either of these. You may be able to do it on your desk, but doing that successfully 10000 - 90000 times successfully in the field is probably not a good idea.

    Why do you need to change the bootloader size? Perhaps we can come up with something else, less risky?

    Best regards,

    Edvin

  • I think you are right.

    That explains why when I want to write 0x37000, the value i get is 30000. Because 0x37000 & 0x38000 = 0x30000.
    Bits are indeed set to 0 and no bits are set to 1.

  • Basically, I currently use the s112 softdevice and i want to use the s113 because I need 1kbps transfer speeds.
    Since we do DFUs via BLE, that means that the bootloader depends on the softdevice and thus i need to update both at the same time, in theory.
    My problem is that i dont have enough memory to store the old BL + SD and the new BL + SD inside my nRF52820.

    So, i modified the bootloader so that it can use an external SPI flash memory from our device to temporarily store the new SD + BL and then do the update.
    By adding the SPI implementation to the bootloader, i also increased its size which forces me to change the start address of the bootloader to allocate more space.

    I actually have a question regarding BL/SD compatibility.
    If my BL is meant to work with s112 SD, is it really not compatible with s113?

    because, if i remember correctly,  at some point, when i was testing my custom DFU procedure,  i purposely didnt update the BL and the DFU succeded even though i was expecting it to fail.

    by "the DFU succeded" i mean:
      - i updated the SD
      - i did NOT call the mbr function to replace the old bootloader by the new one
      - the DFU continued to phase 2 and started to update the app (this means that the old BL is using the new SD)

  • I understand.

    Andre N said:
    If my BL is meant to work with s112 SD, is it really not compatible with s113?

    I don't dare to say that this will work. You can test, but that is at your own risk. Without changes to the bootloader (that will not increase the size), it will certainly be rejected, but you can change the bootloader to accept it. However, you risk ending up in a state where you have a bootloader and SD that are incompatible.

    You don't happen to have the possibility to use USB/UART instead of the SPI flash?

    And if the SPI flash is the only option, how about this (since you already seem quite familiar with the DFU process):

    Upload the new SD and BL to the external flash (if there is room for both), and then do nothing with them yet. 

    Then upload a temporary SPI bootloader that is capable of reading out the files manually from the SPI flash. This doesn't need BLE support, so perhaps it is small enough to start at the same start address.

    Then update one thing at the time. E.g. if it sees that it has the old SD, then update the SD from the SPI flash. Then if it has the new SD, update the bootloader from the SPI flash. 

    I don't know, but it may work. 

    Disclaimer: This is obviously not tested from our side, so this is something that you need to do at your own risk, in case you end up with a lot of bricked devices out in the field. 

    So the "official answer" is that it is not possible to update the SoftDevice via BLE DFU on our smalles nRF52 devices, because of the reason you describe. It can't fit 2x SD + 2x BL in flash. But you can see whether you manage it using these tricks. 

    I have not tested on the nRF52820, so I don't know the details. In some nRF52 devices it is possible to change the UICR, at least if readbackprotection is not enabled. It is, however, a bit risky. The typical flow then would be to read out the UICR and store it locally in RAM (or possibly even in flash, in case something bad happens). Then do the changes you need to do, and then write it back. It may be worth investigating, as it probably is less work than the thing I suggested above. But this is also at your own risk. 

    To see how to change the UICR during runtime, please see how it is done in the system_nrf52.c file for enabling the NFCT pins as GPIOs:

        #if defined (CONFIG_NFCT_PINS_AS_GPIOS)
            if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
                while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
                NVIC_SystemReset();
            }

    This will work because it is only changing 1's to 0's. In your case, you probably need to change some 0's to 1's as well, which is why you need to erase the UICR before writing it back.

    Best regards,

    Edvin

Related