Merged bootloader+settings+SD+app not working

Hello,

Issue: after successfully compiling, generating bootloader settings, merging and flashing bootloader+settings+sd+app, the device enters DFU mode while i was expecting to run the app.

I'm developing a solution based on a nRF52832 with a custom board, softdevice S112 version 7.0.2, with SDK 17.0.2.

I have successfully built the micro_eec library, and bootloader from $(SDK)/examples/dfu/secure_bootloader/pca10040e_s112_ble.

My app is tested working when flashing with no bootloader (erase device, flash the softdevice and app). My app also uses two flash pages to store data, as per this definition:

NRF_FSTORAGE_DEF(nrf_fstorage_t my_flash) =
{
.evt_handler = flash_callback,
.start_addr = 0x7E000,
.end_addr = 0x7FFFF,
};

Bootloader setting is generated successfully with the following line:

nrfutil settings generate --family NRF52 --application $(OUTPUT_DIRECTORY)/nrf52810_xxaa.hex --application-version 0 --bootloader-version 0 --bl-settings-version 2 $(OUTPUT_DIRECTORY)/bootloader_setting.hex

Here is the output:

Bootloader DFU Settings:
* File:                     _build/bootloader_setting.hex
* Family:                   nRF52
* Start Address:            0x0007F000
* CRC:                      0x3879A3DC
* Settings Version:         0x00000002 (2)
* App Version:              0x00000000 (0)
* Bootloader Version:       0x00000000 (0)
* Bank Layout:              0x00000000
* Current Bank:             0x00000000
* Application Size:         0x0000D8A4 (55460 bytes)
* Application CRC:          0x74ED94AE
* Bank0 Bank Code:          0x00000001
* Softdevice Size:          0x00000000 (0 bytes)
* Boot Validation CRC:      0xFEBF7781
* SD Boot Validation Type:  0x00000000 (0)
* App Boot Validation Type: 0x00000001 (1)

Bootloader project linker config file:

/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x28000, LENGTH = 0x6000
  RAM (rwx) :  ORIGIN = 0x200022c8, LENGTH = 0x3d38
  uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
  uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
  mbr_params_page (r) : ORIGIN = 0x0002E000, LENGTH = 0x1000
  bootloader_settings_page (r) : ORIGIN = 0x0002F000, LENGTH = 0x1000
}

SECTIONS
{
  . = ALIGN(4);
  .uicr_bootloader_start_address :
  {
    PROVIDE(__start_uicr_bootloader_start_address = .);
    KEEP(*(SORT(.uicr_bootloader_start_address*)))
    PROVIDE(__stop_uicr_bootloader_start_address = .);
  } > uicr_bootloader_start_address
  . = ALIGN(4);
  .uicr_mbr_params_page :
  {
    PROVIDE(__start_uicr_mbr_params_page = .);
    KEEP(*(SORT(.uicr_mbr_params_page*)))
    PROVIDE(__stop_uicr_mbr_params_page = .);
  } > uicr_mbr_params_page
  . = ALIGN(4);
  .mbr_params_page(NOLOAD) :
  {
    PROVIDE(__start_mbr_params_page = .);
    KEEP(*(SORT(.mbr_params_page*)))
    PROVIDE(__stop_mbr_params_page = .);
  } > mbr_params_page
  . = ALIGN(4);
  .bootloader_settings_page(NOLOAD) :
  {
    PROVIDE(__start_bootloader_settings_page = .);
    KEEP(*(SORT(.bootloader_settings_page*)))
    PROVIDE(__stop_bootloader_settings_page = .);
  } > bootloader_settings_page
}

SECTIONS
{
  . = ALIGN(4);
  .mem_section_dummy_ram :
  {
  }
  .log_dynamic_data :
  {
    PROVIDE(__start_log_dynamic_data = .);
    KEEP(*(SORT(.log_dynamic_data*)))
    PROVIDE(__stop_log_dynamic_data = .);
  } > RAM
  .log_filter_data :
  {
    PROVIDE(__start_log_filter_data = .);
    KEEP(*(SORT(.log_filter_data*)))
    PROVIDE(__stop_log_filter_data = .);
  } > RAM
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM

} INSERT AFTER .data;

SECTIONS
{
  .mem_section_dummy_rom :
  {
  }
  .crypto_data :
  {
    PROVIDE(__start_crypto_data = .);
    KEEP(*(SORT(.crypto_data*)))
    PROVIDE(__stop_crypto_data = .);
  } > FLASH
  .log_const_data :
  {
    PROVIDE(__start_log_const_data = .);
    KEEP(*(SORT(.log_const_data*)))
    PROVIDE(__stop_log_const_data = .);
  } > FLASH
    .nrf_queue :
  {
    PROVIDE(__start_nrf_queue = .);
    KEEP(*(.nrf_queue))
    PROVIDE(__stop_nrf_queue = .);
  } > FLASH
  .dfu_trans :
  {
    PROVIDE(__start_dfu_trans = .);
    KEEP(*(SORT(.dfu_trans*)))
    PROVIDE(__stop_dfu_trans = .);
  } > FLASH
    .nrf_balloc :
  {
    PROVIDE(__start_nrf_balloc = .);
    KEEP(*(.nrf_balloc))
    PROVIDE(__stop_nrf_balloc = .);
  } > FLASH
    .svc_data :
  {
    PROVIDE(__start_svc_data = .);
    KEEP(*(.svc_data))
    PROVIDE(__stop_svc_data = .);
  } > FLASH
  .sdh_ble_observers :
  {
    PROVIDE(__start_sdh_ble_observers = .);
    KEEP(*(SORT(.sdh_ble_observers*)))
    PROVIDE(__stop_sdh_ble_observers = .);
  } > FLASH
  .sdh_req_observers :
  {
    PROVIDE(__start_sdh_req_observers = .);
    KEEP(*(SORT(.sdh_req_observers*)))
    PROVIDE(__stop_sdh_req_observers = .);
  } > FLASH
  .sdh_state_observers :
  {
    PROVIDE(__start_sdh_state_observers = .);
    KEEP(*(SORT(.sdh_state_observers*)))
    PROVIDE(__stop_sdh_state_observers = .);
  } > FLASH
  .sdh_stack_observers :
  {
    PROVIDE(__start_sdh_stack_observers = .);
    KEEP(*(SORT(.sdh_stack_observers*)))
    PROVIDE(__stop_sdh_stack_observers = .);
  } > FLASH
  .sdh_soc_observers :
  {
    PROVIDE(__start_sdh_soc_observers = .);
    KEEP(*(SORT(.sdh_soc_observers*)))
    PROVIDE(__stop_sdh_soc_observers = .);
  } > FLASH

} INSERT AFTER .text


INCLUDE "nrf_common.ld"

App project linker config file:

/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x19000, LENGTH = 0x17000
  RAM (rwx) :  ORIGIN = 0x200022c8, LENGTH = 0x3d38
}

SECTIONS
{
}

SECTIONS
{
  . = ALIGN(4);
  .mem_section_dummy_ram :
  {
  }
  .cli_sorted_cmd_ptrs :
  {
    PROVIDE(__start_cli_sorted_cmd_ptrs = .);
    KEEP(*(.cli_sorted_cmd_ptrs))
    PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
  } > RAM
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM
  .log_dynamic_data :
  {
    PROVIDE(__start_log_dynamic_data = .);
    KEEP(*(SORT(.log_dynamic_data*)))
    PROVIDE(__stop_log_dynamic_data = .);
  } > RAM
  .log_filter_data :
  {
    PROVIDE(__start_log_filter_data = .);
    KEEP(*(SORT(.log_filter_data*)))
    PROVIDE(__stop_log_filter_data = .);
  } > RAM

} INSERT AFTER .data;

SECTIONS
{
  .mem_section_dummy_rom :
  {
  }
  .sdh_soc_observers :
  {
    PROVIDE(__start_sdh_soc_observers = .);
    KEEP(*(SORT(.sdh_soc_observers*)))
    PROVIDE(__stop_sdh_soc_observers = .);
  } > FLASH
  .sdh_ble_observers :
  {
    PROVIDE(__start_sdh_ble_observers = .);
    KEEP(*(SORT(.sdh_ble_observers*)))
    PROVIDE(__stop_sdh_ble_observers = .);
  } > FLASH
  .pwr_mgmt_data :
  {
    PROVIDE(__start_pwr_mgmt_data = .);
    KEEP(*(SORT(.pwr_mgmt_data*)))
    PROVIDE(__stop_pwr_mgmt_data = .);
  } > FLASH
  .sdh_req_observers :
  {
    PROVIDE(__start_sdh_req_observers = .);
    KEEP(*(SORT(.sdh_req_observers*)))
    PROVIDE(__stop_sdh_req_observers = .);
  } > FLASH
  .sdh_state_observers :
  {
    PROVIDE(__start_sdh_state_observers = .);
    KEEP(*(SORT(.sdh_state_observers*)))
    PROVIDE(__stop_sdh_state_observers = .);
  } > FLASH
  .sdh_stack_observers :
  {
    PROVIDE(__start_sdh_stack_observers = .);
    KEEP(*(SORT(.sdh_stack_observers*)))
    PROVIDE(__stop_sdh_stack_observers = .);
  } > FLASH
    .nrf_queue :
  {
    PROVIDE(__start_nrf_queue = .);
    KEEP(*(.nrf_queue))
    PROVIDE(__stop_nrf_queue = .);
  } > FLASH
    .nrf_balloc :
  {
    PROVIDE(__start_nrf_balloc = .);
    KEEP(*(.nrf_balloc))
    PROVIDE(__stop_nrf_balloc = .);
  } > FLASH
    .cli_command :
  {
    PROVIDE(__start_cli_command = .);
    KEEP(*(.cli_command))
    PROVIDE(__stop_cli_command = .);
  } > FLASH
  .crypto_data :
  {
    PROVIDE(__start_crypto_data = .);
    KEEP(*(SORT(.crypto_data*)))
    PROVIDE(__stop_crypto_data = .);
  } > FLASH
  .log_const_data :
  {
    PROVIDE(__start_log_const_data = .);
    KEEP(*(SORT(.log_const_data*)))
    PROVIDE(__stop_log_const_data = .);
  } > FLASH
  .log_backends :
  {
    PROVIDE(__start_log_backends = .);
    KEEP(*(SORT(.log_backends*)))
    PROVIDE(__stop_log_backends = .);
  } > FLASH

} INSERT AFTER .text


INCLUDE "nrf_common.ld"

i have no warnings when merging (ie, no overlap)

Thanks,

Martin

Parents
  • Hi Martin,

    Your choice of fstorage pages sticks out. Referring to the memory layout from the bootloader documentation you see that the bootloader settings page and MBR params page (latter is optional but needed for SoftDevice and bootloader updates) are fixed to the two last pages. So using the example bootloader, when you write other data to these pages from your application they will be corrupted. With a corrupt bootloader settings page, the bootloader will enter DFU mode instead of starting the application.

    I see that you have relocated the bootloader settings page and MBR params page in your bootloader linker file though, so at first glance the above is not the issue in your bootloader. However, there are also other parts of the code where the bootloader settings page address is defined. Specifically, the definition of BOOTLOADER_SETTINGS_ADDRESS and NRF_MBR_PARAMS_PAGE_ADDRESS in <nRF5 SDK 17.0.2>\components\libraries\bootloader\dfu\nrf_dfu_types.h. Have you adjusted that?

    (Generally, I would recommend placing your user data below the bootloader (and even below the FDS pages if you use that, as that is also hard coded to always be immediately below the bootloader) just because that is what is supported out of the box. Generally where you locate data should not matter, but changing as little as possible in the SDK code probably makes sense unless there are good reasons to do so.)

  • Hello Einar,

    Thank you very much for your answer.

    First, i want to clarify that i did not make any changes in the bootloader linker script. All values shown in that file are the same as the ones stated in the bootloader documentation, under memory layout, but for the nRF52810 with S112.

    I'm on nRF52832 with S112, so it arises a couple of questions:

    1) is it possible to have the bootloader performing DFU over ble using nRF52832 with s112? all examples i see use S132 with nRF52832

    2) how do change a project (app and bootloader) to use nRF52832 with S112? i mean which defines and where do i need to update? do i have to change linker script by hand? When i change the CFLAGS/ASMFLAGS in the makefile of bootloader project from -DNRF52810_XXAA to -DNRF52832_XXAA, the compiler complains about nRF5_SDK_17.0.2_d674dde/modules/nrfx/mdk/system_nrf52810.c:133:16: error: 'NRF_CCM_Type' has no member named 'MAXPACKETSIZE'
    133 | NRF_CCM->MAXPACKETSIZE = 0xFBul;

    I made no changes about this in my current project (app and bootloader)

    But i did try this: from you answer i got that my settings page and MRB settings were placed incorrectly (according to bootloader linker script). So, as a quick fix i generate new bootloader settings with --family NRF82810. This outputs a setting hex with the information placed in 0x2E000 and 0x2F000. i merged all together (bl+settings+app+sd) and flashed, but i still enter DFU mode and no app shows up even waiting the DFU inactivity timeout.

    Thanks again,

    Martin

  • Hi Martin,

    Can you upload the linker script for the bootloader (not the application) that you are using now, just so I can double check? The best would be to see the full bootloader project. 

    Martin Buc said:
    i am wondering what is the procedure to change de start address. But i really see no need to do so, since i got from s112 release notes that it needs 0x19000 flash bytes and at least 0xeb8 ram bytes.

    The start address you can get from the release notes. The RAM usage differs on use, and is typically higher than the minimal. For the RAM usage you can just set a higher start address and correspondingly lower size, or you can fine tune it if you like and the device is RAM constrained. See Adjustment of RAM and Flash memory for details.

    Martin Buc said:
    this is bootloader settings generation command (as you can see at the end of makefile), and output:

    This looks good.

    Martin Buc said:
    Another thing i noticed is a change in address from hex file compared with what is actually written on the flash, as you can see from the image below:

    The programmer app or nrfjprog should write exactly what what is in the hex file. One thing is to remember to do an erase all ("nrfjprog -e") before writing. But another highly likely explanation here is that the additional data on the IC (right side) is written runtime, for instance if the MBR params and bootloader settings page are still in the wrong (too low) location, it could be that. Or perhaps your application use FDS, either directly or via the peer manager? It does not look like it would overlap with your fstorage region, though.

    Martin Buc said:
    If i erase, then flash softdevice and app alone, then the apps runs ok. It's worth noticing that i moved de flash section i use for app's data as this:

    What is your memory layout now? Where is the bootloader and bootloader settings + MBR page (and even FDS pages if you use it). The release bootloader typically start at 0x00078000 on nRF52832 devices, so this would normally be OK, as long as you don't use FDS. If you do use FDS, this will overlap with FDS which is not OK. Also, if you use the debug bootloader then this would overlap with the bootloader. Regarding the debug bootloader - if this issue persists I would recommend to test with the debug bootloader with RTT logging (example bootloader project suffixed with "_debug"). That has very extensive logging, and you will typically see right away why the application is not started.

    Martin Buc said:
    To write i use nrfjprog, as you can tell from flash commands at the end of the makefile posted above.
    Thanks again, i really appreciate your help.

    That is OK and does not cause any problems. But note that if you do any changes to the bootloader start address for any reason, you must do a full chip erase before programming (this has to do with how the bootloader start address is stored in the UICR).

  • Hello Einar,

    Just a quick answer to try to keep up with this Slight smile

    This is current bootloader linker script:

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x78000, LENGTH = 0x6000
      RAM (rwx) :  ORIGIN = 0x20005968, LENGTH = 0xa698
      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
      mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000
      bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
    }
    
    SECTIONS
    {
      . = ALIGN(4);
      .uicr_bootloader_start_address :
      {
        PROVIDE(__start_uicr_bootloader_start_address = .);
        KEEP(*(SORT(.uicr_bootloader_start_address*)))
        PROVIDE(__stop_uicr_bootloader_start_address = .);
      } > uicr_bootloader_start_address
      . = ALIGN(4);
      .uicr_mbr_params_page :
      {
        PROVIDE(__start_uicr_mbr_params_page = .);
        KEEP(*(SORT(.uicr_mbr_params_page*)))
        PROVIDE(__stop_uicr_mbr_params_page = .);
      } > uicr_mbr_params_page
      . = ALIGN(4);
      .mbr_params_page(NOLOAD) :
      {
        PROVIDE(__start_mbr_params_page = .);
        KEEP(*(SORT(.mbr_params_page*)))
        PROVIDE(__stop_mbr_params_page = .);
      } > mbr_params_page
      . = ALIGN(4);
      .bootloader_settings_page(NOLOAD) :
      {
        PROVIDE(__start_bootloader_settings_page = .);
        KEEP(*(SORT(.bootloader_settings_page*)))
        PROVIDE(__stop_bootloader_settings_page = .);
      } > bootloader_settings_page
    }
    
    SECTIONS
    {
      . = ALIGN(4);
      .mem_section_dummy_ram :
      {
      }
      .log_dynamic_data :
      {
        PROVIDE(__start_log_dynamic_data = .);
        KEEP(*(SORT(.log_dynamic_data*)))
        PROVIDE(__stop_log_dynamic_data = .);
      } > RAM
      .log_filter_data :
      {
        PROVIDE(__start_log_filter_data = .);
        KEEP(*(SORT(.log_filter_data*)))
        PROVIDE(__stop_log_filter_data = .);
      } > RAM
      .fs_data :
      {
        PROVIDE(__start_fs_data = .);
        KEEP(*(.fs_data))
        PROVIDE(__stop_fs_data = .);
      } > RAM
    
    } INSERT AFTER .data;
    
    SECTIONS
    {
      .mem_section_dummy_rom :
      {
      }
      .crypto_data :
      {
        PROVIDE(__start_crypto_data = .);
        KEEP(*(SORT(.crypto_data*)))
        PROVIDE(__stop_crypto_data = .);
      } > FLASH
        .nrf_queue :
      {
        PROVIDE(__start_nrf_queue = .);
        KEEP(*(.nrf_queue))
        PROVIDE(__stop_nrf_queue = .);
      } > FLASH
      .dfu_trans :
      {
        PROVIDE(__start_dfu_trans = .);
        KEEP(*(SORT(.dfu_trans*)))
        PROVIDE(__stop_dfu_trans = .);
      } > FLASH
        .svc_data :
      {
        PROVIDE(__start_svc_data = .);
        KEEP(*(.svc_data))
        PROVIDE(__stop_svc_data = .);
      } > FLASH
      .log_const_data :
      {
        PROVIDE(__start_log_const_data = .);
        KEEP(*(SORT(.log_const_data*)))
        PROVIDE(__stop_log_const_data = .);
      } > FLASH
        .nrf_balloc :
      {
        PROVIDE(__start_nrf_balloc = .);
        KEEP(*(.nrf_balloc))
        PROVIDE(__stop_nrf_balloc = .);
      } > FLASH
      .sdh_ble_observers :
      {
        PROVIDE(__start_sdh_ble_observers = .);
        KEEP(*(SORT(.sdh_ble_observers*)))
        PROVIDE(__stop_sdh_ble_observers = .);
      } > FLASH
      .log_backends :
      {
        PROVIDE(__start_log_backends = .);
        KEEP(*(SORT(.log_backends*)))
        PROVIDE(__stop_log_backends = .);
      } > FLASH
      .sdh_req_observers :
      {
        PROVIDE(__start_sdh_req_observers = .);
        KEEP(*(SORT(.sdh_req_observers*)))
        PROVIDE(__stop_sdh_req_observers = .);
      } > FLASH
      .sdh_state_observers :
      {
        PROVIDE(__start_sdh_state_observers = .);
        KEEP(*(SORT(.sdh_state_observers*)))
        PROVIDE(__stop_sdh_state_observers = .);
      } > FLASH
      .sdh_stack_observers :
      {
        PROVIDE(__start_sdh_stack_observers = .);
        KEEP(*(SORT(.sdh_stack_observers*)))
        PROVIDE(__stop_sdh_stack_observers = .);
      } > FLASH
      .sdh_soc_observers :
      {
        PROVIDE(__start_sdh_soc_observers = .);
        KEEP(*(SORT(.sdh_soc_observers*)))
        PROVIDE(__stop_sdh_soc_observers = .);
      } > FLASH
    
    } INSERT AFTER .text
    
    
    INCLUDE "nrf_common.ld"

    I always perform a chip erase before any test in order to make sure a know starting point. This is the command i use:

    nrfjprog -f nrf52 --eraseall

    I don't use FDS (flashDataStorage). I use "nrf_fstorage_sd.c ".

    I though that you can check memory layout from linker scripts. What do you need to see?

    I will try the _debug bootloader to get more insight about this.

    I think the smoking gun here is that i don read from device what i just wrote. As in the example i posted, the application code portion is clearly on 0x19000 on hex file, but after flashing the device (no bootloader), i read with the programmer tool that application code is now in 0x26000.

    I will keep on trying. Thanks.

    Martin

  • Martin Buc said:
    but after flashing the device (no bootloader), i read with the programmer tool that application code is now in 0x26000.

    That matches the different size of the S112 and the S132 SoftDevices, but there is nothing in what I have seen that indicate that S132 is flashed.  Another thing - why is not the bootloader shown in the screenshot from the programmer app? So there are two things with this screenshot that does not match the rest of the information. 

    If you don't make progress, can you upload the complete bootloader and application projects (zip them up)? Perhaps that way it will be easier to spot what I am missing.

  • The bootloader is not shown on that image because that capture correspond to flashing just the SD and my app. That is working, despite the difference we are seeing about the loaded hex files and the memory read from the device.

    Below you can find a capture showing the loaded the merged hex file (bl+set+app+sd), and memory read from the device after programming the merged hex. This is the scenario we have been talking about. The device enter DFU mode, no app shows running even after inactivity timeout, can perform an OTA DFU, but the OTA uploaded package (app only) does not runs, and enters DFU mode.

    The red warning banner shows up after loading merged hex file into the programming tool.

    I think we can share a folder, perhaps not fully public.

    Thanks!

  • Martin Buc said:
    The bootloader is not shown on that image because that capture correspond to flashing just the SD and my app. That is working, despite the difference we are seeing about the loaded hex files and the memory read from the device.

    I see, then perhaps there is an issue with the graphical representation in the programmer app. I suggest we ignore that for now. By the way, that also applies to the red warning banner, it shows up because there is data outside of the flash region, in this case in the UICR region. That is a known issue that has been reported before but is not yet fixed.

    It would be better to upload the firmware to DevZone rather han in a shared folder. As you don't want to share it publicly, I suggest you open a private support ticket and attach your projects there and refer to this case. That way it is shared in a private manner and we can discuss any private matters in the other thread.

Reply
  • Martin Buc said:
    The bootloader is not shown on that image because that capture correspond to flashing just the SD and my app. That is working, despite the difference we are seeing about the loaded hex files and the memory read from the device.

    I see, then perhaps there is an issue with the graphical representation in the programmer app. I suggest we ignore that for now. By the way, that also applies to the red warning banner, it shows up because there is data outside of the flash region, in this case in the UICR region. That is a known issue that has been reported before but is not yet fixed.

    It would be better to upload the firmware to DevZone rather han in a shared folder. As you don't want to share it publicly, I suggest you open a private support ticket and attach your projects there and refer to this case. That way it is shared in a private manner and we can discuss any private matters in the other thread.

Children
Related