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

DFU linker settings in gcc

Dear All

We implement a DFU over USB functionality to the custom board nrf52840 board by compiling via gcc. Somehow there is my understanding problem with the linker for bootloader and app. Here is the important part of the secure_bootloader.ld linker file for the bootloader:

MEMORY
{
  FLASH (rx) : ORIGIN = 0xf4000, LENGTH = 0xa000
  RAM (rwx) :  ORIGIN = 0x20000008, LENGTH = 0x3fff8
  uicr_bootloader_start_address (r) : ORIGIN = 0x00000FF8, LENGTH = 0x4
  bootloader_settings_page (r) : ORIGIN = 0x000FF000, LENGTH = 0x1000
  uicr_mbr_params_page (r) : ORIGIN = 0x00000FFC, LENGTH = 0x4
  mbr_params_page (r) : ORIGIN = 0x000FE000, LENGTH = 0x1000
}

and here is the generic_gcc_nrf52.ld linker file's part for the memory:

MEMORY
{
  FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xca000
  RAM (rwx) :  ORIGIN = 0x20002220, LENGTH = 0x3dde0
  uicr_bootloader_start_address (r) : ORIGIN = 0x00000FF8, LENGTH = 0x4
}

All compiles well and mergehex complains that I am overlapping some regions. Clearly I have a lack of understanding, how to create the linker file, as I am trying to sort it out by looking at the examples and reading the blogs. I am using SDK 15.0.0. Here is my confusion and following some questions:

1. According to the memory map, MBR starts at 0, is the statement correct: mbr_params_page (r) : ORIGIN = 0x000FE000, LENGTH = 0x1000

2. Is including in the app linker file: uicr_bootloader_start_address (r) : ORIGIN = 0x00000FF8, LENGTH = 0x4 immportant?

3. Bootloader and settings are as follows:

Bootloader DFU Settings:
* File:                     bootsettings.hex
* Family:                   NRF52840
* Start Address:            0x000FF000
* CRC:                      0x5593BD4D
* Settings Version:         0x00000001 (1)
* App Version:              0x00000002 (2)
* Bootloader Version:       0x00000001 (1)
* Bank Layout:              0x00000000
* Current Bank:             0x00000000
* Application Size:         0x0002785C (161884 bytes)
* Application CRC:          0x55A80F33
* Bank0 Bank Code:          0x00000001
* Softdevice Size:          0x00000000 (0 bytes)
* Boot Validation CRC:      0x00000000
* SD Boot Validation Type:  0x00000000 (0)
* App Boot Validation Type: 0x00000000 (0)

Any idea why the mergehex complains about possible region overlapping when app and bootloader (and settings) are merged?

4. What are the changes regarding DFU and bootloader from 15.0 to 15.3, would changing to 15.3 resolve these issues?

Best, Emek

  • Thanks a lot for the clear explanation! Which part/command is writing the bootloader start address to the UICR? Is it the app (itself or its linker file) or flashing bootloader+settings? As the first time after flashing bootloader starts, I assume that the app is deleting this information or erase the whole uicr. Is there any way to erase uicr or bootloader address from it by using the app?

    I am using LEDs and not nrf logging (if I want to enable logging in the sdk, the linker complains that the size of the bootloader is bigger than the space reserved for it). LED triggering is very basic and directly in the very beginning of the main in the bootloader, please ignore the MBR part, now I know that I can clean it up, as follows:

    int main(void)
    {
    
        nrf_gpio_cfg_output(RGB_BLUE_PIN);
        nrf_gpio_pin_write(RGB_BLUE_PIN, HIGH);
    
        uint32_t ret_val;
    
        // Write bootloader start address to the MBR
        ret_val = nrf_bootloader_write_bl_addr_to_mbr();
        APP_ERROR_CHECK(ret_val);
        // 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);
    
        (void) NRF_LOG_INIT(app_timer_cnt_get);
        NRF_LOG_DEFAULT_BACKENDS_INIT();
        
    
        ret_val = nrf_bootloader_init(dfu_observer);
        APP_ERROR_CHECK(ret_val);
    
        // Either there was no DFU functionality enabled in this project or the DFU module detected
        // no ongoing DFU operation and found a valid main application.
        // Boot the main application.
        nrf_bootloader_app_start();
    
        // Should never be reached.
        NRF_LOG_INFO("After main");
    }

  • bilenemek said:
    Which part/command is writing the bootloader start address to the UICR? Is it the app (itself or its linker file) or flashing bootloader+settings?

     The bootloader start address is placed in the UICR register at address 0x10001014 in the bootloader project. THis is linked in to the bootloader hex so the bootloader start address is written to the UICR register when you flash the bootloader hex. 

    bilenemek said:
    As the first time after flashing bootloader starts, I assume that the app is deleting this information or erase the whole uicr. Is there any way to erase uicr or bootloader address from it by using the app?

    No, the buttonless DFU example we have does not erase the UICR, otherwise the bootloader would not run on every boot. The application should at not really erase the UICR, but it is possible to erase the UICR at runtime by writting to the ERASEUICR register in the NVMC peripheral. 

     

    bilenemek said:
    I am using LEDs and not nrf logging (if I want to enable logging in the sdk, the linker complains that the size of the bootloader is bigger than the space reserved for it). LED triggering is very basic and directly in the very beginning of the main in the bootloader, please ignore the MBR part, now I know that I can clean it up, as follows:

     Ok, and you're not seeing the LED light up? Is the same GPIO that is connected to the LED used in the applicaiton? Could it be that the jump from bootloader to application happens so fast that you're not able to register it ? If so you should be able to check this with a logic analyzer or oscilloscope.

    Best regards

    Bjørn

  • Thanks, now I did understand, nrf_bootloader_info.h holds the info about the starting address. I was erasing UICR by correcting the voltage regulation, I do not know how to do this without NRF_NVMC->ERASEUICR but this is a subject of another topic.

    Everything is running as expected.

    To your question about LEDs. The bootloader is fast, but slower than 50 ms (eye can see 20 frames per second), so it is a good indicator, at least for testing.

  • You can flip bits from 1 to 0, but if the bits needs to be set from zero to 1, then you will have to trigger NRF_NVMC->ERASEUICR before writing the new value. Note you should read back the all the UICR registers and write the modified values back to UICR.  

    You should also note that NRF_NVMC->ERASEUICR will be blocked when the Debug Access port is disabled, see Access port protection behavior.

Related