Net core not updating on nRF5340 (v2.6.1 of SDK)

I am able to update the app core successfully from an external flash partition via the `mcumgr` desktop tool. However, this is not working for the net core.

It successfully uploads to the same external secondary flash slot used for the app core:

mcumgr -c acm1 image upload -n 2 net_core_app_update.bin
 72.28 KiB / 72.28 KiB [==========================================================================================================] 100.00% 2.97 KiB/s 24s
Done

And the image is shown in image list:

mcumgr -c acm1 image list
Images:
 image=0 slot=0
    version: 0.0.121
    bootable: true
    flags: active confirmed
    hash: 4e3a1762799fb9f1d33471f6f71b1ec5eb9faf89a8416cd01074b1cd81debce2
 image=0 slot=1
    version: 0.0.121
    bootable: true
    flags:
    hash: 4c3470051a94186de9d4fb0f7e71228f2805cb70643da428efc5d7c7b6f10cf5
Split status: N/A (0)

However, neither running a device reset, nor an image test followed by device reset, nor an image confirm followed by a device reset, seem to work. The flags do get updated though:

Images:
 image=0 slot=0
    version: 0.0.121
    bootable: true
    flags: confirmed
    hash: 4e3a1762799fb9f1d33471f6f71b1ec5eb9faf89a8416cd01074b1cd81debce2
 image=0 slot=1
    version: 0.0.121
    bootable: true
    flags: pending
    hash: 4c3470051a94186de9d4fb0f7e71228f2805cb70643da428efc5d7c7b6f10cf5
Split status: N/A (0)
 

But I can't get it to actually update the net app (I confirm via the shell name, `CONFIG_SHELL_PROMPT_IPC` not changing). 

Any ideas what could be happening?

Here is our mcuboot.conf:

# These configurations override those from prj.conf when compiling mcuboot.

CONFIG_SIZE_OPTIMIZATIONS=y
CONFIG_MULTITHREADING=y
# CONFIG_DEBUG=y

# @todo: These are useful for tracing operation with a debugger attached, and have a modest
# size (< 5kB). As long as including them doesn't push us over a 16kB page boundary (SPU
# granularity), no reason to disable them.
CONFIG_USE_SEGGER_RTT=y
CONFIG_CONSOLE=y
CONFIG_RTT_CONSOLE=y
CONFIG_LOG=y
CONFIG_MCUBOOT_LOG_LEVEL_DBG=y

# Enable internal crystal for MCUboot
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y

# Ensure SPI NOR is disabled, as we use our own NAND driver.
CONFIG_SPI_NOR=n

# Enable MCUboot Serial Recovery
CONFIG_MCUBOOT_SERIAL=y
CONFIG_BOOT_SERIAL_CDC_ACM=y
CONFIG_BOOT_SERIAL_NO_APPLICATION=y
CONFIG_BOOT_USB_DFU_GPIO=n
CONFIG_BOOT_SERIAL_BOOT_MODE=n
CONFIG_BOOT_SERIAL_PIN_RESET=n

# After a hard reset, enter serial recovery mode only if the power button is held for
# BOOT_SERIAL_DETECT_DELAY. That allows a button reset and release for a normal restart.
CONFIG_BOOT_SERIAL_ENTRANCE_GPIO=y
CONFIG_BOOT_SERIAL_DETECT_DELAY=5000

# Alternatively comment out the above and use the following to enter serial recovery mode via timeout on reset
# CONFIG_BOOT_SERIAL_WAIT_FOR_DFU=y
# CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT=5000

# LED will be solid red when in recovery mode.
CONFIG_MCUBOOT_INDICATION_LED=y

# Maximize the serial receive size
CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096
# TODO: Adding more buffers might improve image update speed
# CONFIG_BOOT_LINE_BUFS=8

# Secondary slots are in external NAND, defined as partitions.
CONFIG_SINGLE_APPLICATION_SLOT=n
CONFIG_BOOT_MAX_IMG_SECTORS=256
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y

# Use scratch instead of move since it allows more internal flash utilization, and with FTL we
# don't need to worry about wear leveling.
CONFIG_BOOT_SWAP_USING_SCRATCH=y

# With SERIAL_DIRECT_IMAGE_UPLOAD, serial recovery can upload to either the primary or secondary
# slot. -n 0 (or unspecified) and -n 1 both go to primary slot, 2 is first image secondary slot,
# see Kconfig for other values.
CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y

# Net core update.
# CONFIG_UPDATEABLE_IMAGE_NUMBER=1
# CONFIG_BOOT_UPGRADE_ONLY=y
# CONFIG_USE_NRF53_MULTI_IMAGE_WITHOUT_UPGRADE_ONLY=y
CONFIG_NRF53_MULTI_IMAGE_UPDATE=y

# Since cpuapp can't access cpunet flash directly, the cpunet update gets copied to a RAM area
# that's emulated as a flash area through flash simulator
CONFIG_FLASH_SIMULATOR=y
CONFIG_FLASH_SIMULATOR_UNALIGNED_READ=y
CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
CONFIG_FLASH_SIMULATOR_STATS=n

Does it have to do with any of these Kconfigs?

# CONFIG_UPDATEABLE_IMAGE_NUMBER=1
# CONFIG_BOOT_UPGRADE_ONLY=y
# CONFIG_USE_NRF53_MULTI_IMAGE_WITHOUT_UPGRADE_ONLY=y

Note that we are doing this with non-encrypted images for now...

  • Thanks Kazi,

    We were able to make progress after adding these configs plus updating some options that were not obviously needed for non-simultaneous update of net core which is our main use case (we do not plan on updating the interface between app and net cores). We also had to update out pm_static.yml:

    mcuboot:
      address: 0x0
      size: 0x14000
      region: flash_primary
    
    mcuboot_primary:
      address: 0x14000
      size: 0xec000
      span: [ mcuboot_pad, app, mcuboot_trailer ]
      region: flash_primary
    
    mcuboot_pad:
      address: 0x14000
      size: 0x200
      placement:
        align:
          start: 0x4000
      region: flash_primary
    
    mcuboot_primary_app:
      address: 0x14200
      size: 0xeae00
      span: [ app ]
      region: flash_primary
    
    # "app" is implicit, and takes available space here
    
    # When mcuboot uploads an image, it clears the sector containing the trailer, but that may clobber
    # the last part of the image if it extends into that sector. Reserve a full page to ensure that
    # can't happen. imgtool.py will calculate the trailer size relative to the end of the partition,
    # so overlapping with this sector. It will not be larger than 4kB.
    mcuboot_trailer:
      address: 0xff000
      size: 0x1000
      region: flash_primary
    
    
    # External flash
    area_storage_info:
      address: 0x0
      size: 0x10000
      region: external_flash
    
    mcuboot_secondary:
      address: 0x10000
      size: 0xec000 # 944kB, ust match mcuboot_primary size
      region: external_flash
    
    mcuboot_secondary_1:
      address: 0xfc000
      size: 0x40000  # 256 KB, size should match mcuboot_primary_1
      region: external_flash
    
    area_unused:
      address: 0x13c000
      size: 0xc3000  # Remaining space between mcuboot_secondary_1 and mcuboot_scratch
      region: external_flash
    
    mcuboot_scratch:
      address: 0x1FF000
      size: 0x1000
      region: external_flash
    
    area_command:
      address: 0x200000
      size: 0x100000
      region: external_flash
    
    area_capture:
      address: 0x300000
      size: 0x17400000
      region: external_flash
    
    mcuboot_primary_1:
      address: 0x0
      size: 0x40000 # 256 KB
      device: flash_ctrl
      region: ram_flash
    
    pcd_sram:
      address: 0x20000000
      size: 0x2000
      region: sram_primary
    

    We are able to get images on the proper secondary slots 

    Now we are getting stuck on a loop in pcd.c:

    static int network_core_pcd_cmdset(uint32_t cmd, const void *src_addr, size_t len, bool wait)
    {
    	int err;
    	enum pcd_status command_status;
    
    	/* Ensure that the network core is turned off */
    	nrf_reset_network_force_off(NRF_RESET, true);
    
    	err = pcd_cmd_write(cmd, src_addr, len, PCD_NET_CORE_APP_OFFSET);
    	if (err != 0) {
    		LOG_INF("Error while writing PCD cmd: %d", err);
    		return err;
    	}
    
    	enum pcd_status initial_command_status = pcd_fw_copy_status_get();
    
    	nrf_reset_network_force_off(NRF_RESET, false);
    	LOG_INF("Turned on network core");
    
    	if (!wait) {
    		return 0;
    	}
    
    	do {
    		/* Wait for 1 second to avoid issue where network core
    		 * is unable to write to shared RAM.
    		 */
    		k_busy_wait(1 * USEC_PER_SEC);
    
    		command_status = pcd_fw_copy_status_get();
    	} while (command_status == initial_command_status);
    
    	if (command_status == PCD_STATUS_FAILED) {
    		LOG_ERR("Network core update failed");
    		network_core_pcd_tidy();
    		return -EFAULT;
    	}
    
    	nrf_reset_network_force_off(NRF_RESET, true);
    	LOG_INF("Turned off network core");
    	network_core_pcd_tidy();
    	return 0;
    }

    The do/while keeps looping according to our breakpoint debugging. We came across this thread: https://devzone.nordicsemi.com/f/nordic-q-a/101062/nrf5340-net-core-upgrade

    But checked the b0n and network core (hci_ipc) .config files and saw that both have `CONFIG_RESET_ON_FATAL_ERROR=y` set. 

    We then jumped the debugger on network core and saw that we are getting a bus error on b1_validate_firmware. It seems to be doing some comparison of firmware address and fails.

  • Hello,

    Can you please send me your project so I can reproduce this from my side?

Related