nRF5340 non-simultaneous netcore updates with external QSPI

Development Environment: VS Code on Windows 10, SDK: 2.0.0, HW: nRF5340 Development Kit

I am trying to perform just a network core update on the nRF5340 DK based off of the smp_svr sample where the secondary slot for incoming updates is on an external QSPI. Using the Device Manager app, I can perform application core updates without issue, but when doing a network core update, MCUBoot seems to interpret the incoming image as an application core update no matter what. Which causes a second boot cycle as it swaps the images back.

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
uart:~$ *** Booting Zephyr OS build v3.0.99-ncs1 ***
I: Starting bootloader
I: Primary image: magic=good, swap_type=0x4, copy_done=0x1, image_ok=0x1
I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: test
I: Starting swap using move algorithm.
I: Bootloader chainload address offset: 0xc000
*** Booting Zephyr OS build v3.0.99-ncs1 ***
I: Starting bootloader
I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: revert
I: Starting swap using move algorithm.
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Bootloader chainload address offset: 0xc000
*** Booting Zephyr OS build v3.0.99-ncs1 ***
[00:00:00.017,791] <inf> smp_sample: build time: Jul 6 2022 15:24:46
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

I have an overlay both top level and the child images containing:

Fullscreen
1
2
3
4
5
6
// Choose the external flash to be used by partition manager (and allow MCUBoot to use external flash)
/ {
chosen {
nordic,pm-ext-flash = &mx25r64;
};
};
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And the following config files:
prj.conf:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## Bootloader
# Enable mcumgr.
CONFIG_MCUBOOT_IMAGE_VERSION="1.0.0+0"
CONFIG_MCUMGR=y
CONFIG_MCUBOOT_IMG_MANAGER=y
CONFIG_IMG_MANAGER=y
CONFIG_MCUMGR_CMD_IMG_MGMT=y
CONFIG_MCUMGR_CMD_OS_MGMT=y
# Some command handlers require a large stack.
CONFIG_MAIN_STACK_SIZE=2048
# Ensure an MCUboot-compatible binary is generated andcanp update the net core
CONFIG_BOOTLOADER_MCUBOOT=y
# Enable flash operations.
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_STREAM_FLASH_ERASE=y
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


child_image/mcuboot.conf:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# MCUboot requires a large stack size, otherwise an MPU fault will occur
CONFIG_MAIN_STACK_SIZE=10240
# Net Core Update Support?
CONFIG_PCD_APP=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_STREAM_FLASH=y
CONFIG_STREAM_FLASH_ERASE=y
CONFIG_FLASH_SIMULATOR=y
CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
CONFIG_FLASH_SIMULATOR_STATS=n
CONFIG_MULTITHREADING=y
# This must be increased to accommodate the bigger images.
CONFIG_BOOT_MAX_IMG_SECTORS=256
# External QSPI secondary slot
CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


Am I missing something here? I do notice when I debug to MCUBoot's loader.c line 982, where the vector table of the image is grabbed, the loaded data seems to be from the internal flash rather than the external memory. I have gone through the thread here nRF5340 Netcore firmware update using external flash - Nordic Q&A - Nordic DevZone - Nordic DevZone (nordicsemi.com) but my behavior isn't lining up and discussion is all on pre 2.0.0 SDKs. I tried UPGRADE_ONLY but it seems to do the same thing but not be able to revert back and so end up in a boot loop. As said in the title I have no need for simultaneous updates, I am just trying to perform core updates one at a time from the external QSPI.

Attached at the bottom is my minimal reproduction based off of smp_svr. Would greatly appreciate any assistance or pointers on this.

Regards,

D Miller

smp_svr_ext_qspi.zip

Parents
  • Check out this ticket  Busfault when MCUboot reads Network core secondary image header in external flash 

    Try applying this patch https://github.com/nrfconnect/sdk-mcuboot/pull/197/commits/b628d6e238bb15eae06a9582fb19b00ea4990e13 and see if you're able to update the netcore using external flash.

    Best regards,

    Simon 

  • I have applied the changes in that commit in the pull request and then tried the removal of the code block also suggested, both to no avail, the system still attempts all updates like they are for the application core.

    I see the intention is to use nrf53_hooks.c to trigger a net core update but those hooks are only called in UPGRADE_ONLY configurations and I wish to retain app core reversion. It seems like the code block that was suggested to be removed in the other ticket is supposed to handle the "one core at a time" netcore updates but the flash simulator in RAM just isn't getting set up to pull the data from the external flash like it is in hooks.

    So, I applied the patch like before which correctly runs the header check, but instead of removing the further down lines as the other thread suggested, I turned them into something closer to what is done in nrf53_hooks.c:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS)
    /* If the update is valid, and it targets the network core: perform the
    * update and indicate to the caller of this function that no update is
    * available
    */
    if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) {
    BOOT_LOG_INF("Starting network core update");
    static const struct device *mock_flash_dev;
    void *mock_flash;
    size_t mock_size;
    BOOT_LOG_INF("Reading update image to flash simulator");
    mock_flash_dev = device_get_binding(PM_MCUBOOT_PRIMARY_DEV_NAME);
    if (mock_flash_dev == NULL) {
    swap_type = BOOT_SWAP_TYPE_NONE;
    }
    mock_flash = flash_simulator_get_memory(mock_flash_dev, &mock_size);
    int rc = flash_area_read(secondary_fa, 0U, mock_flash, hdr->ih_hdr_size + hdr->ih_img_size);
    if (rc != 0) {
    return BOOT_SWAP_TYPE_FAIL;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    I also added the needed includes at the top:

    Fullscreen
    1
    2
    3
    4
    5
    #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS)
    #include <dfu/pcd.h>
    #include "flash_map_backend/flash_map_backend.h"
    #include <zephyr/drivers/flash/flash_simulator.h>
    #endif
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    No other changes to the SDK or project. With this, I can now perform net and app core updates one at a time from a single secondary slot on the external qspi in a way that still allows for reversion of the application core.

    I don't feel like I'm doing everything correctly here, especially with the use of the flash simulator, but I can do my update scheme. I've uploaded my loader.c, otherwise it is v2.0.0 SDK.

    loader.c

Reply
  • I have applied the changes in that commit in the pull request and then tried the removal of the code block also suggested, both to no avail, the system still attempts all updates like they are for the application core.

    I see the intention is to use nrf53_hooks.c to trigger a net core update but those hooks are only called in UPGRADE_ONLY configurations and I wish to retain app core reversion. It seems like the code block that was suggested to be removed in the other ticket is supposed to handle the "one core at a time" netcore updates but the flash simulator in RAM just isn't getting set up to pull the data from the external flash like it is in hooks.

    So, I applied the patch like before which correctly runs the header check, but instead of removing the further down lines as the other thread suggested, I turned them into something closer to what is done in nrf53_hooks.c:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS)
    /* If the update is valid, and it targets the network core: perform the
    * update and indicate to the caller of this function that no update is
    * available
    */
    if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) {
    BOOT_LOG_INF("Starting network core update");
    static const struct device *mock_flash_dev;
    void *mock_flash;
    size_t mock_size;
    BOOT_LOG_INF("Reading update image to flash simulator");
    mock_flash_dev = device_get_binding(PM_MCUBOOT_PRIMARY_DEV_NAME);
    if (mock_flash_dev == NULL) {
    swap_type = BOOT_SWAP_TYPE_NONE;
    }
    mock_flash = flash_simulator_get_memory(mock_flash_dev, &mock_size);
    int rc = flash_area_read(secondary_fa, 0U, mock_flash, hdr->ih_hdr_size + hdr->ih_img_size);
    if (rc != 0) {
    return BOOT_SWAP_TYPE_FAIL;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    I also added the needed includes at the top:

    Fullscreen
    1
    2
    3
    4
    5
    #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS)
    #include <dfu/pcd.h>
    #include "flash_map_backend/flash_map_backend.h"
    #include <zephyr/drivers/flash/flash_simulator.h>
    #endif
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    No other changes to the SDK or project. With this, I can now perform net and app core updates one at a time from a single secondary slot on the external qspi in a way that still allows for reversion of the application core.

    I don't feel like I'm doing everything correctly here, especially with the use of the flash simulator, but I can do my update scheme. I've uploaded my loader.c, otherwise it is v2.0.0 SDK.

    loader.c

Children