nRF5340 Firmware Update from external NOR QSPI flash

Hi

I have gone through the following link and I have working firmware OTA update with BLE SMP.
https://devzone.nordicsemi.com/guides/nrf-connect-sdk-guides/b/software/posts/ncs-dfu#http_dfu_ext_flash

But my device design also has a cloud connection via nRF9160. Following is the complete connection diagram.

Cloud<==HTTPS==> nRF9160 <== UART ==> nRF5340 <== QSPI ==> NOR flash

My requirement is to receive the firmware update file via HTTPS to nRF9160 and it will be transmitted to nRF5340 and eventually will be written in NOR flash.

external_flash:
  address: 0x0
  end_address: 0x200000
  region: external_flash
  size: 0x200000

mcuboot_secondary:
  address: 0x00000
  device: mx25r16
  end_address: 0xf4000
  region: external_flash
  size: 0xf4000

littlefs_storage:
  address: 0x100000
  device: mx25r16
  region: external_flash
  size: 0x200000

My understanding is I will need to enable the QSPI flash access in Mcuboot by adding following lines to the file "/child_image/mcuboot/prj.conf"

# SPI Flash
CONFIG_SPI=y
CONFIG_NORDIC_QSPI_NOR=y

Then write the firmware update file "app_update.bin" in the external NOR flash partition "mcuboot_secondary". File packets will be received over UART and then written via flash write operation. Once file write is complete I will need to restart the SOC.
Is my understanding correct? Also, will I need to update any other flag or message to start firmware update on reboot?

Many Thanks

Parents
  • Hi,

    Yes, your understanding seems correct. Note that this scheme is not officially fully supported yet, but there is a PR here that adds support for this:

    https://github.com/nrfconnect/sdk-nrf/pull/8839

  • I facing the following error while compiling the source code. I am not sure what setting I need to update. 

    C:/Users/Dilawar_Ali/ncs/v2.1.2/nrf/modules/mcuboot/hooks/nrf53_hooks.c: In function 'boot_read_image_header_hook':
    C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:28:28: error: 'PM_MCUBOOT_PRIMARY_1_ADDRESS' undeclared (first use in this function); did you mean 'PM_MCUBOOT_PRIMARY_ADDRESS'?
       28 |   img_head->ih_load_addr = PM_MCUBOOT_PRIMARY_1_ADDRESS;
          |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
          |                            PM_MCUBOOT_PRIMARY_ADDRESS
    C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:28:28: note: each undeclared identifier is reported only once for each function it appears in
    C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:29:27: error: 'PM_CPUNET_APP_SIZE' undeclared (first use in this function)
       29 |   img_head->ih_img_size = PM_CPUNET_APP_SIZE;
          |                           ^~~~~~~~~~~~~~~~~~
    In file included from C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\toolchain\gcc.h:88,
                     from C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\toolchain.h:50,
                     from C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\sys\__assert.h:11,
                     from C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\lib\libc\minimal\include\assert.h:11,
                     from C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:7:
    C:/Users/Dilawar_Ali/ncs/v2.1.2/nrf/modules/mcuboot/hooks/nrf53_hooks.c: In function 'network_core_update':
    C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\device.h:96:39: error: '__device_dts_ord_DT_N_NODELABEL_PM_MCUBOOT_PRIMARY_1_DEV_ORD' undeclared (first use in this function)
       96 | #define DEVICE_NAME_GET(name) _CONCAT(__device_, name)
          |                                       ^~~~~~~~~
    C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\device.h:276:37: note: in expansion of macro 'DEVICE_NAME_GET'
      276 | #define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_NAME(node_id))
          |                                     ^~~~~~~~~~~~~~~
    C:\Users\Dilawar_Ali\ncs\v2.1.2\zephyr\include\zephyr\device.h:296:34: note: in expansion of macro 'DEVICE_DT_NAME_GET'
      296 | #define DEVICE_DT_GET(node_id) (&DEVICE_DT_NAME_GET(node_id))
          |                                  ^~~~~~~~~~~~~~~~~~
    C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:85:19: note: in expansion of macro 'DEVICE_DT_GET'
       85 |  mock_flash_dev = DEVICE_DT_GET(DT_NODELABEL(PM_MCUBOOT_PRIMARY_1_DEV));
          |                   ^~~~~~~~~~~~~
    C:\Users\Dilawar_Ali\ncs\v2.1.2\nrf\modules\mcuboot\hooks\nrf53_hooks.c:98:20: error: 'PM_CPUNET_B0N_ADDRESS' undeclared (first use in this function)
       98 |   if (reset_addr > PM_CPUNET_B0N_ADDRESS) {
          |                    ^~~~~~~~~~~~~~~~~~~~~
    [171/289] Building C object zephyr/drivers/pinctrl/CMakeFiles/drivers__pinctrl.dir/pinctrl_nrf.c.obj
    [172/289] Building C object modules/nrf/lib/fatal_error/CMakeFiles/..__nrf__lib__fatal_error.dir/fatal_error.c.obj
    [173/289] Linking C static library zephyr\drivers\flash\libdrivers__flash.a
    [174/289] Building C object modules/nrf/subsys/fw_info/CMakeFiles/..__nrf__subsys__fw_info.dir/fw_info.c.obj
    [175/289] Building C object modules/nrf/drivers/hw_cc310/CMakeFiles/..__nrf__drivers__hw_cc310.dir/hw_cc310.c.obj
    [176/289] Building C object modules/mbedtls/CMakeFiles/modules__mbedtls.dir/zephyr_init.c.obj
    [177/289] Linking C static library zephyr\drivers\serial\libdrivers__serial.a
    [178/289] Building C object modules/mbedtls/CMakeFiles/modules__mbedtls.dir/C_/Users/Dilawar_Ali/ncs/v2.1.2/modules/crypto/mbedtls/library/aes.c.obj
    [179/289] Linking C static library zephyr\drivers\timer\libdrivers__timer.a
    ninja: build stopped: subcommand failed.
    [341/382] Linking C executable zephyr\zephyr_pre0.elf
    
    [345/382] Linking C executable zephyr\zephyr_pre1.elf

  • Adding changes as per suggested in above links. The issue related to PM_MCUBOOT_PRIMARY_1_ADDRESS is resolved. But now I am facing following error.

    C:/Users/Dilawar_Ali/ncs/v2.2.0/nrf/modules/mcuboot/hooks/nrf53_hooks.c: In function 'boot_read_image_header_hook':
    C:\Users\Dilawar_Ali\ncs\v2.2.0\nrf\modules\mcuboot\hooks\nrf53_hooks.c:29:41: error: 'PM_CPUNET_APP_SIZE' undeclared (first use in this function)
       29 |                 img_head->ih_img_size = PM_CPUNET_APP_SIZE;
          |                                         ^~~~~~~~~~~~~~~~~~
    C:\Users\Dilawar_Ali\ncs\v2.2.0\nrf\modules\mcuboot\hooks\nrf53_hooks.c:29:41: note: each undeclared identifier is reported only once for each function it appears in
    C:/Users/Dilawar_Ali/ncs/v2.2.0/nrf/modules/mcuboot/hooks/nrf53_hooks.c: In function 'network_core_update':
    C:\Users\Dilawar_Ali\ncs\v2.2.0\nrf\modules\mcuboot\hooks\nrf53_hooks.c:98:34: error: 'PM_CPUNET_B0N_ADDRESS' undeclared (first use in this function)
       98 |                 if (reset_addr > PM_CPUNET_B0N_ADDRESS) {
          |                                  ^~~~~~~~~~~~~~~~~~~~~
    [165/283] Linking C static library zephyr\lib\libc\minimal\liblib__libc__minimal.a
    [166/283] Building C object modules/nrf/lib/fatal_error/CMakeFiles/..__nrf__lib__fatal_error.dir/fatal_error.c.obj
    [167/283] Building C object modules/nrf/subsys/fw_info/CMakeFiles/..__nrf__subsys__fw_info.dir/fw_info.c.obj

    I am trying to compile the Hello World example https://github.com/simon-iversen/sdk-zephyr/tree/serial_dfu_ext_flash_hello_world/samples/hello_world to make the secure boot work with external flash.

    This is the prj.conf

    # nothing here
    
    # Enable mcumgr.
    CONFIG_MCUMGR=y
    
    # Enable most core commands.
    CONFIG_MCUMGR_CMD_IMG_MGMT=y
    CONFIG_MCUMGR_CMD_OS_MGMT=y
    
    CONFIG_SECURE_BOOT=y
    # Ensure an MCUboot-compatible binary is generated.
    CONFIG_BOOTLOADER_MCUBOOT=y
    
    # Enable the serial mcumgr transport.
    CONFIG_MCUMGR_SMP_UART=y
    
    # Disable UART Console and enable the RTT console
    CONFIG_UART_CONSOLE=n
    CONFIG_RTT_CONSOLE=y
    CONFIG_USE_SEGGER_RTT=y
    
    # Some command handlers require a large stack.
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
    
    CONFIG_NORDIC_QSPI_NOR=y
    CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16

    This is cihild_image/mcuboot/prj.conf

    # MCUboot requires a large stack size, otherwise an MPU fault will occur
    CONFIG_MAIN_STACK_SIZE=10240
    
    CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x10000
    
    CONFIG_DEBUG_OPTIMIZATIONS=y
    
    # Enable flash operations
    CONFIG_FLASH=y
    
    # This must be increased to accommodate the bigger images.
    CONFIG_BOOT_MAX_IMG_SECTORS=256
    
    #---------------------------------------------------------------------
    CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y
    # The following configurations are required to support simultaneous multi image update
    CONFIG_PCD_APP=n
    CONFIG_UPDATEABLE_IMAGE_NUMBER=2
    CONFIG_FLASH_SIMULATOR=y
    CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
    CONFIG_FLASH_SIMULATOR_STATS=n
    CONFIG_BOOT_UPGRADE_ONLY=y
    

    This is pm_static.yml

    external_flash:
      address: 0x0
      end_address: 0x200000
      region: external_flash
      size: 0x200000
    
    mcuboot_secondary:
      address: 0x00000
      device: mx25r16
      end_address: 0xFFFFF
      region: external_flash
      size: 0x100000
    
    mcuboot_primary_1:
      address: 0x0
      size: 0x40000
      device: flash_ctrl
      region: ram_flash
    
    mcuboot_secondary_1:
      address: 0x100000
      size: 0x40000
      device: mx25r16
      region: external_flash
    
    
    pcd_sram:
      address: 0x20000000
      size: 0x2000
      region: sram_primary
    

    After build (ended with error) following build/partitions.yml was generated

    EMPTY_0:
      address: 0x18200
      end_address: 0x1c000
      placement:
        before:
        - s1_pad
      region: flash_primary
      size: 0x3e00
    EMPTY_1:
      address: 0x2c200
      end_address: 0x30000
      placement:
        before:
        - mcuboot_pad
      region: flash_primary
      size: 0x3e00
    app:
      address: 0x30200
      end_address: 0x100000
      region: flash_primary
      size: 0xcfe00
    app_image:
      address: 0x30200
      end_address: 0x100000
      orig_span: &id001
      - app
      region: flash_primary
      size: 0xcfe00
      span: *id001
    b0:
      address: 0x0
      end_address: 0x8000
      placement:
        after:
        - start
      region: flash_primary
      size: 0x8000
    b0_container:
      address: 0x0
      end_address: 0x8000
      orig_span: &id002
      - b0
      region: flash_primary
      size: 0x8000
      span: *id002
    external_flash:
      address: 0x0
      end_address: 0x200000
      region: external_flash
      size: 0x200000
    mcuboot:
      address: 0x8200
      end_address: 0x18200
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      sharers: 0x1
      size: 0x10000
    mcuboot_pad:
      address: 0x30000
      end_address: 0x30200
      placement:
        align:
          start: 0x4000
        before:
        - mcuboot_primary_app
      region: flash_primary
      sharers: 0x2
      size: 0x200
    mcuboot_primary:
      address: 0x30000
      end_address: 0x100000
      orig_span: &id003
      - app
      - mcuboot_pad
      region: flash_primary
      size: 0xd0000
      span: *id003
    mcuboot_primary_1:
      address: 0x0
      device: flash_ctrl
      end_address: 0x40000
      region: ram_flash
      size: 0x40000
    mcuboot_primary_app:
      address: 0x30200
      end_address: 0x100000
      orig_span: &id004
      - app
      region: flash_primary
      size: 0xcfe00
      span: *id004
    mcuboot_secondary:
      address: 0x0
      device: mx25r16
      end_address: 0x100000
      region: external_flash
      size: 0x100000
    mcuboot_secondary_1:
      address: 0x100000
      device: mx25r16
      end_address: 0x140000
      region: external_flash
      size: 0x40000
    otp:
      address: 0xff8380
      end_address: 0xff83fc
      region: otp
      size: 0x7c
    pcd_sram:
      address: 0x20000000
      end_address: 0x20002000
      region: sram_primary
      size: 0x2000
    provision:
      address: 0xff8100
      end_address: 0xff8380
      region: otp
      size: 0x280
    ram_flash:
      address: 0x40000
      end_address: 0x40000
      region: ram_flash
      size: 0x0
    s0:
      address: 0x8000
      end_address: 0x18200
      orig_span: &id005
      - s0_pad
      - mcuboot
      region: flash_primary
      size: 0x10200
      span: *id005
    s0_image:
      address: 0x8200
      end_address: 0x18200
      orig_span: &id006
      - mcuboot
      region: flash_primary
      size: 0x10000
      span: *id006
    s0_pad:
      address: 0x8000
      end_address: 0x8200
      placement:
        after:
        - b0_container
        align:
          start: 0x4000
      region: flash_primary
      share_size:
      - mcuboot_pad
      size: 0x200
    s1:
      address: 0x1c000
      end_address: 0x2c200
      orig_span: &id007
      - s1_pad
      - s1_image
      region: flash_primary
      size: 0x10200
      span: *id007
    s1_image:
      address: 0x1c200
      end_address: 0x2c200
      placement:
        after:
        - s1_pad
        - s0
      region: flash_primary
      share_size:
      - mcuboot
      size: 0x10000
    s1_pad:
      address: 0x1c000
      end_address: 0x1c200
      placement:
        after:
        - s0
        align:
          start: 0x4000
      region: flash_primary
      share_size:
      - mcuboot_pad
      size: 0x200
    sram_primary:
      address: 0x20002000
      end_address: 0x20080000
      region: sram_primary
      size: 0x7e000
    

  • Hi,

    Try setting 

    CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y
    Also the discussions in this post here seems relevant for your use-case:
  • setting CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y did not resolve the issue. Still facing the error "error: 'PM_CPUNET_APP_SIZE' undeclared"

    But Setting the CONFIG_BOOT_IMAGE_ACCESS_HOOKS=n and removed the primary_1 and secondary_1 partition. This way I am able to do DFU update for app core from external flash and secure boot enabled.

    I still need assistance to enable netcore image update as well.

  • Dilawar Ali said:
    I still need assistance to enable netcore image update as well.

    There are some known issues with NSIB(secure boot)+MCUBOOT and incompatible with multi image DFU on nRF53, that are getting fixed in the upcoming NCS v2.3.0 release. Relevant PR: https://github.com/nrfconnect/sdk-nrf/pull/9169/files#diff-3618c46f4d0a530f32e99d83263fe217269f73f927f5c110f8aed6db3b8800db

  • After a whole lot of trial and error, I managed to get my firmware to compile with the two-stage bootloader + network core update + mcuboot_secondary on external flash.

    First, I copied partitions.yml into pm_static_<custom-board-name>_cpuapp.yml, and added this to the end:

    mcuboot_primary_1:
      address: 0x0
      device: flash_ctrl
      end_address: 0x40000
      region: ram_flash
      size: 0x40000
    mcuboot_secondary_1:
      address: 0xce000
      device: MX25R64
      end_address: 0x10e000
      region: external_flash
      size: 0x40000
    ram_flash:
      address: 0x40000
      end_address: 0x40000
      region: ram_flash
      size: 0x0

    I added these flags to my prj.conf:

    CONFIG_NRF53_UPGRADE_NETWORK_CORE=y
    CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y
    CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
    CONFIG_ADD_MCUBOOT_MEDIATE_SIM_FLASH_DTS=y
    
    CONFIG_SECURE_BOOT=y

    I added these flags to my mcuboot.conf:

    CONFIG_PCD_APP=y
    CONFIG_UPDATEABLE_IMAGE_NUMBER=2
    CONFIG_FLASH_SIMULATOR=y
    CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
    CONFIG_FLASH_SIMULATOR_STATS=n
    CONFIG_BOOT_UPGRADE_ONLY=y

    For some reason, setting CONFIG_BOOT_UPGRADE_ONLY=n makes it explode with the error 'PM_MCUBOOT_PRIMARY_1_ADDRESS' undeclared. If someone knows why this is happening, I'm all ears.

    In a nutshell, I'm pretty sure this is what you have to do to make it work:

    • DO NOT name the static partition file pm_static.yml, name it pm_static_<boardname>_cpuapp.yml
    • CONFIG_BOOT_UPGRADE_ONLY must be set to 'y' for some reason
    • Set ADD_MCUBOOT_MEDIATE_SIM_FLASH_DTS to import the flash simulator into your device tree

    Now to see if it actually runs.

Reply
  • After a whole lot of trial and error, I managed to get my firmware to compile with the two-stage bootloader + network core update + mcuboot_secondary on external flash.

    First, I copied partitions.yml into pm_static_<custom-board-name>_cpuapp.yml, and added this to the end:

    mcuboot_primary_1:
      address: 0x0
      device: flash_ctrl
      end_address: 0x40000
      region: ram_flash
      size: 0x40000
    mcuboot_secondary_1:
      address: 0xce000
      device: MX25R64
      end_address: 0x10e000
      region: external_flash
      size: 0x40000
    ram_flash:
      address: 0x40000
      end_address: 0x40000
      region: ram_flash
      size: 0x0

    I added these flags to my prj.conf:

    CONFIG_NRF53_UPGRADE_NETWORK_CORE=y
    CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y
    CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
    CONFIG_ADD_MCUBOOT_MEDIATE_SIM_FLASH_DTS=y
    
    CONFIG_SECURE_BOOT=y

    I added these flags to my mcuboot.conf:

    CONFIG_PCD_APP=y
    CONFIG_UPDATEABLE_IMAGE_NUMBER=2
    CONFIG_FLASH_SIMULATOR=y
    CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
    CONFIG_FLASH_SIMULATOR_STATS=n
    CONFIG_BOOT_UPGRADE_ONLY=y

    For some reason, setting CONFIG_BOOT_UPGRADE_ONLY=n makes it explode with the error 'PM_MCUBOOT_PRIMARY_1_ADDRESS' undeclared. If someone knows why this is happening, I'm all ears.

    In a nutshell, I'm pretty sure this is what you have to do to make it work:

    • DO NOT name the static partition file pm_static.yml, name it pm_static_<boardname>_cpuapp.yml
    • CONFIG_BOOT_UPGRADE_ONLY must be set to 'y' for some reason
    • Set ADD_MCUBOOT_MEDIATE_SIM_FLASH_DTS to import the flash simulator into your device tree

    Now to see if it actually runs.

Children
No Data
Related