nRF52840 with MCUBOOT over SMP using SPI Flash - Fails to boot

Hello,

I'm trying to use MCUBOOT with external flash on a nRF52840 board that has 4MB SPI flash. I'm using nRF Connect SDK v2.6.0.

I've verified that the SPI flash works fine using the "spi_flash" sample.

With CONFIG_BOOTLOADER_MCUBOOT=n, SMP with SPI flash runs fine. I'm able to connect to the "Zephyr" BLE device from nRF Connect for mobile.

However, with CONFIG_BOOTLOADER_MCUBOOT=y, the build is successful but the nRF52840 board fails to boot.

As the nRF52840 board (particle_xenon) has SPI flash instead of QSPI, I've set CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=n and added the required Kconfig dependencies.

Here is the prj.conf:

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_MCUMGR=y
CONFIG_ZCBOR=y
CONFIG_CRC=y
CONFIG_MCUMGR_TRANSPORT_BT=y
CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y
CONFIG_IMG_MANAGER=y
CONFIG_STREAM_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_MCUMGR_GRP_IMG=y
CONFIG_MCUMGR_GRP_OS=y
CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO=y
CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y
CONFIG_BASE64=y
CONFIG_MCUMGR_TRANSPORT_SHELL=y

CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=n
CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU_SPEEDUP=y
CONFIG_BOOTLOADER_MCUBOOT=y

CONFIG_NORDIC_QSPI_NOR=n
CONFIG_FLASH=y
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

CONFIG_LOG=y
CONFIG_PRINTK=y
CONFIG_CONSOLE=y
CONFIG_SERIAL=y

# Preferred SHELL options
CONFIG_SHELL=y
CONFIG_BOOT_BANNER=y
CONFIG_DATE_SHELL=y
CONFIG_POSIX_CLOCK=y
CONFIG_DEVICE_SHELL=n
CONFIG_INIT_STACKS=y
CONFIG_KERNEL_SHELL=y
CONFIG_SHELL_STATS=n
The board configuration "particle_xenon.conf" is set to use SPI flash:
CONFIG_FLASH=y
CONFIG_SPI=y
CONFIG_SPI_NOR=y


The board "particle_xenon.overlay" is configured to use the external SPI flash (
&mx25l32 is defined in "particle_xenon.dts" board):
/ {
	chosen {
		nordic,pm-ext-flash = &mx25l32;
	};
};
For MCUBOOT, folder "child_image > mcuboot > boards" has the board configuration & overlay files as,

particle_xenon.conf:

CONFIG_PM=n

CONFIG_MAIN_STACK_SIZE=10240
CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h"

CONFIG_BOOT_SWAP_SAVE_ENCTLV=n
CONFIG_BOOT_ENCRYPT_IMAGE=n

CONFIG_BOOT_UPGRADE_ONLY=n
CONFIG_BOOT_BOOTSTRAP=n

### mbedTLS has its own heap
# CONFIG_HEAP_MEM_POOL_SIZE is not set

### We never want Zephyr's copy of tinycrypt.  If tinycrypt is needed,
### MCUboot has its own copy in tree.
# CONFIG_TINYCRYPT is not set
# CONFIG_TINYCRYPT_ECC_DSA is not set
# CONFIG_TINYCRYPT_SHA256 is not set

CONFIG_FLASH=y
CONFIG_FPROTECT=y

### Various Zephyr boards enable features that we don't want.
# CONFIG_BT is not set
# CONFIG_BT_CTLR is not set
# CONFIG_I2C is not set

CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y # former CONFIG_MODE_MINIMAL
### Ensure Zephyr logging changes don't use more resources
CONFIG_LOG_DEFAULT_LEVEL=0
### Use info log level by default
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y
CONFIG_CBPRINTF_NANO=y
CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0
### Use the minimal C library to reduce flash usage
CONFIG_MINIMAL_LIBC=y

### Enable serial recovery
CONFIG_MCUBOOT_SERIAL=y
CONFIG_BOOT_SERIAL_CDC_ACM=y
CONFIG_BOOT_SERIAL_NO_APPLICATION=y
CONFIG_UART_CONSOLE=n

### Increase receive buffer to improve transfer speed in serial recovery mode
CONFIG_BOOT_MAX_LINE_INPUT_LEN=8192
CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096

### Enable SPI flash
CONFIG_NORDIC_QSPI_NOR=n
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

### Partition size allocated to bootloader - can be reduced if logging is disabled
CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x12000


particle_xenon.overlay:

/ {
	chosen {
		nordic,pm-ext-flash = &mx25l32;
	};

	aliases {
		mcuboot-button0 = &mode_button;
	};
};



MCUBOOT > zephyr > zephyr.dts does include the "nordic,pm-ext-flash". 
Here's a snippet from the file:

	model = "Particle Xenon";
	compatible = "particle,xenon", "particle,feather";
	chosen {
		zephyr,entropy = &cryptocell;
		zephyr,flash-controller = &flash_controller;
		zephyr,console = &uart0;
		zephyr,uart-mcumgr = &uart0;
		zephyr,shell-uart = &uart0;
		zephyr,sram = &sram0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
		zephyr,ieee802154 = &ieee802154;
		nordic,pm-ext-flash = &mx25l32;
	};



What could be the reason for the application not running?

Am I missing some configuration or is part of it incorrect?  Thank you.
Regards,
Ravi
Parents
  • Hi Ravi,

    Could you post any device logs and or/track where in the code your application reaches before it does not boot? I'm assuming that your fw hangs in the bootloader if it never gets to the application.

    Kind regards,
    Andreas

  • Hi Andreas,

    Thank you for looking at this issue. It's much appreciated.

    The application I'm building for test purposes is "mcuboot_external_flash" for particle_xenon board. I believe its from Nordic or one of the simple SMP sample to demo use of external flash.

    When RTT is enabled, I don't get any output at the J-Link RTT Viewer and no UART console gets enumerated.

    With CONFIG_BOOTLOADER_MCUBOOT=n, I get the expected output at both RTT and UART console, and I'm able to connect to "zephyr" SMP service via nRF Connect app.

    The problem appears to be somewhere within mcuboot code, perhaps due to possible misconfiguration or something else.

    When debugging using J-Link, debugger hits a breakpoint in opt > nordic > v2.6.0 > bootloader > mcuboot > boot > boot_serial > serial > boot_serial.c at line

        " if (rc <= 0 && !full_line) { " in boot_serial_read_console.

     Stepping from there leads to into the depths of  " ... > core > cortex_m > reset.S". The firmware never gets into main().

    /*
     * Task which waits reading console, expecting to get image over
     * serial port.
     */
    static void
    boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms)
    {
        int rc;
        int off;
        int dec_off = 0;
        int full_line;
        int max_input;
        int elapsed_in_ms = 0;
    
    #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
        bool allow_idle = true;
    #endif
    
        boot_uf = f;
        max_input = sizeof(in_buf);
    
        off = 0;
        while (timeout_in_ms > 0 || bs_entry) {
            /*
             * Don't enter CPU idle state here if timeout based serial recovery is
             * used as otherwise the boot process hangs forever, waiting for input
             * from serial console (if single-thread mode is used).
             */
    #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
            if (allow_idle == true) {
                MCUBOOT_CPU_IDLE();
                allow_idle = false;
            }
    #endif
            MCUBOOT_WATCHDOG_FEED();
    #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
            uint32_t start = k_uptime_get_32();
    #endif
            rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
            if (rc <= 0 && !full_line) {
    #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU
                allow_idle = true;
    #endif
                goto check_timeout;
            }
            off += rc;
            if (!full_line) {
                if (off == max_input) {
                    /*
                     * Full line, no newline yet. Reset the input buffer.
                     */
                    off = 0;
                }
                goto check_timeout;
            }
            if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
              in_buf[1] == SHELL_NLIP_PKT_START2) {
                dec_off = 0;
                rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
            } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
              in_buf[1] == SHELL_NLIP_DATA_START2) {
                rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
            }
    
            /* serve errors: out of decode memory, or bad encoding */
            if (rc == 1) {
                boot_serial_input(&dec_buf[2], dec_off - 2);
            }
            off = 0;
    check_timeout:
            /* Subtract elapsed time */
    #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
            elapsed_in_ms = (k_uptime_get_32() - start);
    #endif
            timeout_in_ms -= elapsed_in_ms;
        }
    }
    

    Here is the partitions.yml. As you can see, mcuboot_secondary is using the external flash. Its size is 0xee000, same as mcuboot_primary.

    app:
      address: 0x12200
      end_address: 0x100000
      region: flash_primary
      size: 0xede00
    external_flash:
      address: 0xee000
      end_address: 0x400000
      region: external_flash
      size: 0x312000
    mcuboot:
      address: 0x0
      end_address: 0x12000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0x12000
    mcuboot_pad:
      address: 0x12000
      end_address: 0x12200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0x12000
      end_address: 0x100000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      size: 0xee000
      span: *id001
    mcuboot_primary_app:
      address: 0x12200
      end_address: 0x100000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0xede00
      span: *id002
    mcuboot_secondary:
      address: 0x0
      device: DT_CHOSEN(nordic_pm_ext_flash)
      end_address: 0xee000
      placement:
        align:
          start: 0x4
      region: external_flash
      share_size:
      - mcuboot_primary
      size: 0xee000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000
    


    Does the partition map look ok?

    Anything else in the app and mcboot configuration or overlay that may possibly be incorrect?

    Let me know how I can assist further. I can upload a zipped copy the project if needed.  Thank you.

    Regards,
    Ravi

  • Hello Andreas,
    I tried your suggestion before programming the device but it made no difference.

    Also, please note that the device has SPI flash and not QSPI.

    Regards,
    Ravi

  • Hi Andreas,

    Do you have any updates?

    It may also be worth reaching out to your colleague  , as he provided the "mcuboot_external_flash" example

    Regards,
    Ravi

  •   

    Hi Andrea,

    Do you have any update on a solution? Thanks.


    Regards,
    Ravi

  • Hi Ravi

    Apologies for the long response time, I've unfortunately been occupied with unforeseen things.

    I spent this morning creating a sample showcasing BLE DFU where the secondary slot resides on external flash with SPI instead of QSPI. 

    The sample is not optimized, and prj.conf has some configs that might not be necessary but I've tested and verified that the update goes through using the nRF Connect app following the brief steps mentioned in the samples READme

    smp_ble_feat_spi.zip

    This should hopefully be enough to showcase how to set this up

    Kind regards,
    Andreas

  • HI Andreas,

    It's not an issue at all. I thought you must be either tied up or perhaps on vacation.

    Thank you so much for taking the time to prepare an example. It's much appreciated.

    I'll try your sample with a Particle Xenon (nRF52840) board that has external SPI flash. I'll have to change the "spi2" overlay to point to the board's flash. 


    Regards,
    Ravi

Reply
  • HI Andreas,

    It's not an issue at all. I thought you must be either tied up or perhaps on vacation.

    Thank you so much for taking the time to prepare an example. It's much appreciated.

    I'll try your sample with a Particle Xenon (nRF52840) board that has external SPI flash. I'll have to change the "spi2" overlay to point to the board's flash. 


    Regards,
    Ravi

Children
  • Glad to hear that,

    You may also investigate how the SPI flash is set up in the app.overlay as well as mcuboot.overlay and transfer that to the SPI flash JESD sample  from Zephyr. It should work given that you enter the right parameters.

    As you see, the pins I've selected are based spi2's default pin setup but if you need different pins, you can also modify pin control for &spi2_default and _sleep by doing something like this 

     &pinctrl {
             spi2_default: spi2_default {
                     group1 {
                             psels = <NRF_PSEL(SPIM_SCK, 0, 29)>,
                                     <NRF_PSEL(SPIM_MISO, 0, 31)>,
                                     <NRF_PSEL(SPIM_MOSI, 0, 30)>;
                     };
             };
     
             spi2_sleep: spi2_sleep {
                     group1 {
                             psels = <NRF_PSEL(SPIM_SCK, 0, 29)>,
                                     <NRF_PSEL(SPIM_MISO, 0, 31)>,
                                     <NRF_PSEL(SPIM_MOSI, 0, 30)>;
                             low-power-enable;
                     };
             };
     };
     

    Kind regards,
    Andreas

  • Hello Andreas,

    Success! Thank you for providing the correct configuration for project and mcuboot.

    I changed the project structure a little as I want to use it to target another board as well.

    ├── CMakeLists.txt
    ├── README.rst
    ├── boards
    │   ├── particle_xenon.conf
    │   └── particle_xenon.overlay
    ├── build_xenon
    
    ├── child_image
    │   └── mcuboot
    │       └── boards
    │           ├── particle_xenon.conf
    │           └── particle_xenon.overlay
    ├── prj.conf
    ├── sample.yaml
    └── src
        ├── bluetooth_smp.c
        ├── bluetooth_smp.h
        └── main.c
    

    Here's the partition manager report showing external_flash (4MB) and mcuboot_secondary partition.

    quark11:smp_ble_feat_spi quark11$ west build -t partition_manager_report -b particle_xenon -d build_xenon
    -- west build: running target partition_manager_report
    [1/1] cd /Users/quark11/Documents/2024_dfu_projects/smp_ble...24_dfu_projects/smp_ble_feat_spi/build_xenon/partitions.yml
      external_flash (0x400000 - 4096kB): 
    +---------------------------------------------+
    | 0x0: mcuboot_secondary (0xf0000 - 960kB)    |
    | 0xf0000: external_flash (0x310000 - 3136kB) |
    +---------------------------------------------+
    
      flash_primary (0x100000 - 1024kB): 
    +--------------------------------------------------+
    | 0x0: mcuboot (0x10000 - 64kB)                    |
    +---0x10000: mcuboot_primary (0xf0000 - 960kB)-----+
    | 0x10000: mcuboot_pad (0x200 - 512B)              |
    +---0x10200: mcuboot_primary_app (0xefe00 - 959kB)-+
    | 0x10200: app (0xefe00 - 959kB)                   |
    +--------------------------------------------------+
    
      sram_primary (0x40000 - 256kB): 
    +--------------------------------------------+
    | 0x20000000: sram_primary (0x40000 - 256kB) |
    +--------------------------------------------+
    
    

    I've used nRF Connect iOS to verify DFU over BLE with the secondary application slot (mcuboot_secondary) located on the external flash.

    I did notice that in the nRF Connect iOS, after selecting "DFU" and uploading the "app_update_bin" file, I got "Error: Not supported" message.

    After power cycling the Particle Xenon board, the new firmware ran successfully on the device. So, DFU over BLE seems to work fine.

    I'll review and clean up prj.conf later.

    Here is the console output showing initial firmware and then upload after a minor code change.

    *** Booting nRF Connect SDK v3.5.99-ncs1 ***
    Hello World! particle_xenon
    Sample for BLE DFU feat SPI and external flash!
    [00:00:00.003,967] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                                36 f0 e5 0e 87 68 48 fb  02 fd 9f 82 cc 32 e5 7b |6....hH. .....2.{
                                                91 b1 5c ed                                      |..\.             
    [00:00:00.005,920] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.005,920] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
    [00:00:00.005,950] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 54.58864 Build 1214809870
    [00:00:00.006,713] <inf> bt_hci_core: Identity: DF:FA:B3:62:79:11 (random)
    [00:00:00.006,744] <inf> bt_hci_core: HCI: version 5.4 (0x0d) revision 0x118f, manufacturer 0x0059
    [00:00:00.006,774] <inf> bt_hci_core: LMP: version 5.4 (0x0d) subver 0x118f
    [00:00:00.006,774] <inf> smp_bt_sample: Bluetooth initialized
    [00:00:00.007,598] <inf> smp_bt_sample: Advertising successfully started
    This is version 2.
    [00:00:23.039,611] <inf> smp_bt_sample: Connected
    [00:00:23.238,067] <wrn> bt_l2cap: Ignoring data for unknown channel ID 0x003a
    [00:00:34.385,314] <inf> mcuboot_util: Image index: 0, Swap type: none
    [00:00:34.492,156] <inf> mcuboot_util: Image index: 0, Swap type: none
    [00:00:34.492,431] <inf> mcuboot_util: Image index: 0, Swap type: none
    [00:00:35.695,312] <inf> mcumgr_img_grp: Erased 0x40000 bytes of image slot
    [00:00:36.020,721] <inf> mcumgr_img_grp: Erased 0x10000 bytes of image slot trailer
    [00:01:07.249,877] <inf> mcuboot_util: Image index: 0, Swap type: none
    [00:01:07.251,037] <inf> mcuboot_util: Image index: 0, Swap type: perm
    uart:~$ *** Booting nRF Connect SDK v3.5.99-ncs1 ***
    [00:00:00.251,617] <inf> mcuboot: Starting bootloader
    [00:00:00.252,471] <inf> mcuboot: Primary image: magic=good, swap_type=0x3, copy_done=0x1, image_ok=0x1
    [00:00:00.252,746] <inf> mcuboot: Secondary image: magic=good, swap_type=0x3, copy_done=0x3, image_ok=0x1
    [00:00:00.252,746] <inf> mcuboot: Boot source: none
    [00:00:00.253,204] <inf> mcuboot: Image index: 0, Swap type: perm
    [00:00:00.913,269] <inf> mcuboot: Starting swap using move algorithm.
    
    
    *** Booting nRF Connect SDK v3.5.99-ncs1 ***
    Hello World! particle_xenon
    [00:00:00.003,784] <inf> app: DFU test #2
    
    Sample for BLE DFU feat SPI and external flash!
    [00:00:00.004,455] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                                36 f0 e5 0e 87 68 48 fb  02 fd 9f 82 cc 32 e5 7b |6....hH. .....2.{
                                                91 b1 5c ed                                      |..\.             
    [00:00:00.006,378] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.006,408] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
    [00:00:00.006,439] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 54.58864 Build 1214809870
    [00:00:00.007,171] <inf> bt_hci_core: Identity: DF:FA:B3:62:79:11 (random)
    [00:00:00.007,202] <inf> bt_hci_core: HCI: version 5.4 (0x0d) revision 0x118f, manufacturer 0x0059
    [00:00:00.007,232] <inf> bt_hci_core: LMP: version 5.4 (0x0d) subver 0x118f
    [00:00:00.007,263] <inf> smp_bt_sample: Bluetooth initialized
    [00:00:00.008,087] <inf> smp_bt_sample: Advertising successfully started
    This is version 2.
    uart:~$ 

    In my mcuboot overlay (particle_xenon.overlay), I have 

     
    / {
    	chosen {
    		nordic,pm-ext-flash = &mx25l32;
    	};
    
    	aliases {
    		mcuboot-button0 = &mode_button;
    		mcuboot-led0 = &status_green;
    	};
    };
     
    I can get into MCUBOOT mode using "mode button" & "reset button" but the defined led doesn't turn on.

    Any idea why that may be the case? Thanks.

  • HI Andreas,

    It's ok. I forgot to add the following in the mcuboot configuration.

    CONFIG_MCUBOOT_INDICATION_LED=y


    Thank you for your 
    assistance. It's much appreciated!
    Regards,
    Ravi
  • Hi again Ravi,

    Glad to hear that the sample was good enough to show you how it could be set up for your device! 

    And yes, that would be the missing configuration you needed!

    I will mark this case as verified solved/but feel free to open new cases for new topics or reopen this case if you have additional questions related to this cases topic

    Kind regards,
    Andreas

  • Hi Andreas,

    Thank you for your assistance in resolving my issues. Greatly appreciated!

    The ticket can be marked as closed.

    Best Regards,
    Ravi

Related