Partition manager and FOTA

Hi,

I have a nrf52833 with MCUBoot and BLE, I am using NCS v3.0.1. 

I need also a custom NVS partition to store user data, so i create a data_partition for this purpose.

Now to the fun part, i am having trouble with the partition manager when i'm using FOTA. My project works fine but when i wanted to add FOTA, i got an flash error everytime i try an update. After digging a bit, i understand that is a write error in the smcuboot_secondary partition. 

The mcuboot_secondary partition start at address 0x41800 and don't respect the 0x1000 page size of the nrf52833 which explain why i couldn't update (cf pm_static.yml.working)

app:
  address: 0x7200
  end_address: 0x41800
  region: flash_primary
  size: 0x3a600
data_storage:
  address: 0x7c000
  end_address: 0x7e000
  placement:
    align:
      start: 0x1000
  region: flash_primary
  size: 0x2000
mcuboot:
  address: 0x0
  end_address: 0x7000
  placement:
    align:
      end: 0x1000
    before:
    - mcuboot_primary
  region: flash_primary
  size: 0x7000
mcuboot_pad:
  address: 0x7000
  end_address: 0x7200
  placement:
    align:
      start: 0x1000
    before:
    - mcuboot_primary_app
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0x7000
  end_address: 0x41800
  orig_span: &id001
  - app
  - mcuboot_pad
  region: flash_primary
  sharers: 0x1
  size: 0x3a800
  span: *id001
mcuboot_primary_app:
  address: 0x7200
  end_address: 0x41800
  orig_span: &id002
  - app
  region: flash_primary
  size: 0x3a600
  span: *id002
mcuboot_secondary:
  address: 0x41800
  end_address: 0x7c000
  placement:
    after:
    - mcuboot_primary
    align:
      start: 0x1000
  region: flash_primary
  share_size:
  - mcuboot_primary
  size: 0x3a800
settings_storage:
  address: 0x7e000
  end_address: 0x80000
  placement:
    align:
      start: 0x1000
    before:
    - end
  region: flash_primary
  size: 0x2000
sram_primary:
  address: 0x20000000
  end_address: 0x20020000
  region: sram_primary
  size: 0x20000

I edit the file to place it at 0x41000 and decrease the image size (cf pm_static.yml.not_working)

EMPTY_0:
  address: 0x7b000
  end_address: 0x7c000
  region: flash_primary
  size: 0x1000
app:
  address: 0x7200
  end_address: 0x41000
  region: flash_primary
  size: 0x39e00
data_storage:
  address: 0x7c000
  end_address: 0x7e000
  region: flash_primary
  size: 0x2000
mcuboot:
  address: 0x0
  end_address: 0x7000
  region: flash_primary
  size: 0x7000
mcuboot_pad:
  address: 0x7000
  end_address: 0x7200
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0x7000
  end_address: 0x41000
  orig_span: &id001
  - app
  - mcuboot_pad
  region: flash_primary
  size: 0x3a000
  span: *id001
mcuboot_primary_app:
  address: 0x7200
  end_address: 0x41000
  orig_span: &id002
  - app
  region: flash_primary
  size: 0x39e00
  span: *id002
mcuboot_secondary:
  address: 0x41000
  end_address: 0x7b000
  region: flash_primary
  size: 0x3a000
settings_storage:
  address: 0x7e000
  end_address: 0x80000
  region: flash_primary
  size: 0x2000
sram_primary:
  address: 0x20000000
  end_address: 0x20020000
  region: sram_primary
  size: 0x20000

But it don't boot anymore, i can't get anything on RTT or serial or anything that make me believe the bootloader successfully start the image.

Do you know what is happening ? 

Best regards,

Nathan

  • I managed to launch a debug session with J-Link GDB server v8.18, you will find the log below : 

    JLinkGDBServerCL: SEGGER J-Link GDB Server V8.18 Command Line Version
    JLinkGDBServerCL: 
    JLinkGDBServerCL: JLinkARM.dll V8.18 (DLL compiled Mar  5 2025 14:42:43)
    JLinkGDBServerCL: 
    JLinkGDBServerCL: -----GDB Server start settings-----
    JLinkGDBServerCL: GDBInit file:                  none
    JLinkGDBServerCL: GDB Server Listening port:     57790
    JLinkGDBServerCL: SWO raw output listening port: 2332
    JLinkGDBServerCL: Terminal I/O port:             2333
    JLinkGDBServerCL: Accept remote connection:      localhost only
    JLinkGDBServerCL: Generate logfile:              off
    JLinkGDBServerCL: Verify download:               off
    JLinkGDBServerCL: Init regs on start:            off
    JLinkGDBServerCL: Silent mode:                   on
    JLinkGDBServerCL: Single run mode:               on
    JLinkGDBServerCL: Target connection timeout:     0 ms
    JLinkGDBServerCL: ------J-Link related settings------
    JLinkGDBServerCL: J-Link Host interface:         USB
    JLinkGDBServerCL: J-Link script:                 none
    JLinkGDBServerCL: J-Link settings file:          none
    JLinkGDBServerCL: ------Target related settings------
    JLinkGDBServerCL: Target device:                 nRF52833_xxAA
    JLinkGDBServerCL: Target device parameters:      none
    JLinkGDBServerCL: Target interface:              SWD
    JLinkGDBServerCL: Target interface speed:        4000kHz
    JLinkGDBServerCL: Target endian:                 little
    JLinkGDBServerCL: 
    =thread-group-added,id="i1"
    =cmd-param-changed,param="pagination",value="off"
    main () at C:/Workspace/001_CAPTAIN_BLINK/blinker/bootloader/mcuboot/boot/zephyr/main.c:611
    611	        FIH_PANIC;
    Execute debugger commands using "-exec <command>" or "`<command>", for example "-exec info registers" or "`info registers" will list registers in use (when GDB is the debugger)
    
    

    It appears to be stuck in the FIH_PANIC but i don't know why


    int main(void)
    {
        struct boot_rsp rsp;
        int rc;
        FIH_DECLARE(fih_rc, FIH_FAILURE);
    
        MCUBOOT_WATCHDOG_SETUP();
        MCUBOOT_WATCHDOG_FEED();
    
    #if !defined(MCUBOOT_DIRECT_XIP)
        BOOT_LOG_INF("Starting bootloader");
    #else
        BOOT_LOG_INF("Starting Direct-XIP bootloader");
    #endif
    
    #ifdef CONFIG_MCUBOOT_INDICATION_LED
        /* LED init */
        io_led_init();
    #endif
    
        os_heap_init();
    
        ZEPHYR_BOOT_LOG_START();
    
        (void)rc;
    
        mcuboot_status_change(MCUBOOT_STATUS_STARTUP);
    
    #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO
        if (io_detect_pin() &&
                !io_boot_skip_serial_recovery()) {
            boot_serial_enter();
        }
    #endif
    
    #ifdef CONFIG_BOOT_SERIAL_PIN_RESET
        if (io_detect_pin_reset()) {
            boot_serial_enter();
        }
    #endif
    
    #if defined(CONFIG_BOOT_USB_DFU_GPIO)
        if (io_detect_pin()) {
    #ifdef CONFIG_MCUBOOT_INDICATION_LED
            io_led_set(1);
    #endif
    
            mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_ENTERED);
    
            rc = usb_enable(NULL);
            if (rc) {
                BOOT_LOG_ERR("Cannot enable USB");
            } else {
                BOOT_LOG_INF("Waiting for USB DFU");
                wait_for_usb_dfu(K_FOREVER);
                BOOT_LOG_INF("USB DFU wait time elapsed");
            }
        }
    #elif defined(CONFIG_BOOT_USB_DFU_WAIT)
        rc = usb_enable(NULL);
        if (rc) {
            BOOT_LOG_ERR("Cannot enable USB");
        } else {
            BOOT_LOG_INF("Waiting for USB DFU");
    
            mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_WAITING);
    
            wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS));
            BOOT_LOG_INF("USB DFU wait time elapsed");
    
            mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_TIMED_OUT);
        }
    #endif
    
    #ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
        /* Initialize the boot console, so we can already fill up our buffers while
         * waiting for the boot image check to finish. This image check, can take
         * some time, so it's better to reuse thistime to already receive the
         * initial mcumgr command(s) into our buffers
         */
        rc = boot_console_init();
        int timeout_in_ms = CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT;
        uint32_t start = k_uptime_get_32();
    
    #ifdef CONFIG_MCUBOOT_INDICATION_LED
        io_led_set(1);
    #endif
    #endif
    
        BOOT_HOOK_GO_CALL_FIH(boot_go_hook, FIH_BOOT_HOOK_REGULAR, fih_rc, &rsp);
        if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) {
            FIH_CALL(boot_go, fih_rc, &rsp);
        }
    
    #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
        if (io_detect_boot_mode()) {
            /* Boot mode to stay in bootloader, clear status and enter serial
             * recovery mode
             */
            boot_serial_enter();
        }
    #endif
    
    #ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
        timeout_in_ms -= (k_uptime_get_32() - start);
        if( timeout_in_ms <= 0 ) {
            /* at least one check if time was expired */
            timeout_in_ms = 1;
        }
        boot_serial_check_start(&boot_funcs,timeout_in_ms);
    
    #ifdef CONFIG_MCUBOOT_INDICATION_LED
        io_led_set(0);
    #endif
    #endif
    
        if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
            BOOT_LOG_ERR("Unable to find bootable image");
    
            mcuboot_status_change(MCUBOOT_STATUS_NO_BOOTABLE_IMAGE_FOUND);
    
    #ifdef CONFIG_BOOT_SERIAL_NO_APPLICATION
            /* No bootable image and configuration set to remain in serial
             * recovery mode
             */
            boot_serial_enter();
    #elif defined(CONFIG_BOOT_USB_DFU_NO_APPLICATION)
            rc = usb_enable(NULL);
            if (rc && rc != -EALREADY) {
                BOOT_LOG_ERR("Cannot enable USB");
            } else {
                BOOT_LOG_INF("Waiting for USB DFU");
                wait_for_usb_dfu(K_FOREVER);
            }
    #endif
    
            FIH_PANIC;
        }
    
    #ifdef CONFIG_BOOT_RAM_LOAD
        BOOT_LOG_INF("Bootloader chainload address offset: 0x%x",
                     rsp.br_hdr->ih_load_addr);
    #else
        BOOT_LOG_INF("Bootloader chainload address offset: 0x%x",
                     rsp.br_image_off);
    #endif
    
        BOOT_LOG_INF("Image version: v%d.%d.%d", rsp.br_hdr->ih_ver.iv_major,
                                                        rsp.br_hdr->ih_ver.iv_minor,
                                                        rsp.br_hdr->ih_ver.iv_revision);
    
    #if defined(MCUBOOT_DIRECT_XIP)
        BOOT_LOG_INF("Jumping to the image slot");
    #else
        BOOT_LOG_INF("Jumping to the first image slot");
    #endif
    
        mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND);
    
    #if USE_PARTITION_MANAGER && CONFIG_FPROTECT
    
    #ifdef PM_S1_ADDRESS
    /* MCUBoot is stored in either S0 or S1, protect both */
    #define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS)
    #define PROTECT_ADDR PM_S0_ADDRESS
    #else
    /* There is only one instance of MCUBoot */
    #define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS)
    #define PROTECT_ADDR PM_MCUBOOT_ADDRESS
    #endif
    
        rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE);
    
        if (rc != 0) {
            BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup.");
            while (1)
                ;
        }
    
    #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP)
    #if defined(PM_TFM_SECURE_ADDRESS)
        pcd_lock_ram(false);
    #else
        pcd_lock_ram(true);
    #endif
    #endif
    #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */
    
        ZEPHYR_BOOT_LOG_STOP();
    
        do_boot(&rsp);
    
        mcuboot_status_change(MCUBOOT_STATUS_BOOT_FAILED);
    
        BOOT_LOG_ERR("Never should get here");
        while (1)
            ;
    }

  • Hello,

    This indicates that the bootloader did not find a bootable image. Did you program the merged.hex file generated by your build which contain both the application and bootloader?

  • Hi Vidar,

    Sorry for the late answer, i found and fix my problem.

    The issue was my image was more than 95% occupency and it is a know issue with mcuboot. As soon as i turn off log for saving memory, the program was booting as expected.

    I close this ticket.

  • Thank you for update. I'm glad to hear that it works now. It is on our to do list to catch this issue at build time. 

Related