Code relocation to the external flash with Mcuboot

Hello,

I am using edge impulse library to achieve on-device classification. I now want to put the edge impulse related code to the external flash and use XIP function there rather than placing them inside my internal flash. I have learned something from the code relocation sample from NCS and zephyr. I now have my own linker script, modified CMakeList and prj.conf, which I show below. For cmakelist: 

zephyr_code_relocate(FILES src/feature/gait_analysis.c LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(FILES src/feature/gait_analysis.c LOCATION EXTFLASH_RODATA NOCOPY)
For linker script: 
#include <zephyr/linker/sections.h>
#include <zephyr/devicetree.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/linker/linker-tool.h>

MEMORY
{
    /* XIP region for Edge Impulse model code + rodata */
    EXTFLASH (rx) : ORIGIN = 0x10120000, LENGTH = 0x00400000
}
#include <zephyr/arch/arm/cortex_m/scripts/linker.ld>
and for prj.conf: 
CONFIG_CODE_DATA_RELOCATION=y
CONFIG_XIP=y
CONFIG_NORDIC_QSPI_NOR_XIP=y
CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y
CONFIG_CUSTOM_LINKER_SCRIPT="linker_arm_nocopy.ld"
. The build process can show part of the code is indeed placed into our external flash partition. But it is complaining about this: Error: Image size (0x10110be8) + trailer (0x630) exceeds requested size 0xe0000. I suspect this is because the relocated section is still included in the mcuboot binary image. We will need to keep mcuboot because we want to use dfu-util on our host machine for firmware upgrade. Is there a way to solve this issue? 

Parents
  • Hi there,

    SO ,

    Key point: MCUboot assumes the application image is one contiguous region of flash.
    It uses __rom_start__ and __rom_end__ from the linker to compute “image size”. That’s just:

    image_size = __rom_end__ - __rom_start__

    If any section is placed at 0x1012_0000 (external QSPI region), __rom_end__ becomes ~0x1012xxxx. So from the point of view of imgtool/MCUboot, your “image” appears to span from address 0x0000xxxx all the way up to 0x1012xxxx. That’s why the “image size” looks like 0x10110be8 – it’s not the amount of code, it’s the distance between the lowest and highest load address.

    So:

    • the relocated XIP section is still part of the MCUboot image, and it completely blows up the image size calculation.

    • Stock MCUboot does not understand “one image spread over disjoint flash ranges (internal + QSPI XIP)” as a single signed binary.

       Short version:

    You can’t just drop XIP sections into external flash and still expect a normal, single MCUboot image (with DFU, signatures, trailers, etc.) to “just work”.

    You have to choose one of these design patterns:

    Option 1 – Keep MCUboot simple, treat external flash as a separate asset

    Concept:

    • The “MCUboot image” lives entirely in internal flash.

    • External QSPI flash holds model / feature code or data, but it is not part of the MCUboot image.

    • You program/update external flash via some other mechanism (second DFU alt-setting, custom mcumgr command, dedicated updater image, etc.).

    What to change technically:

    1. Do not add EXTFLASH to MEMORY in your application linker script in a way that moves __rom_end__.

    2. Keep the normal Zephyr/MCUboot linker flow for internal flash.

    3. For QSPI XIP sections, either:

      • Build a second image or raw binary linked at 0x10120000, and flash it separately, or

      • Keep the model as data and explicitly read/execute from it (e.g., copy critical parts to RAM before running).

    This is the least fragile route if you “must keep MCUboot + dfu-util”.

    Option 2 – Multi-image / external-flash partition managed by NCS

    If you really want a “single update story”, then:

    • Use NCS Partition Manager (pm_static.yml) to define:

      • mcuboot, image_0 (primary), image_1 or scratch in internal flash.

      • A separate extflash_app (or ei_model) partition in external flash, not part of image_0.

    HTH

    GL :-) PJ :v:

  • Hi, yes that bit I can understand now. I am following your option 2 now, which is to create another image but to save data. This works quite well for my self defined source code like gait_analysis.c. But when I try to move edge impulse library, this won't work. There is no error, but the edge impulse code is still there in the internal flash. 

    However as I said earlier, I can see moving edge impulse library to the external flash is mentioned in nordic official page. So I was wondering how can I actually achieve that. 

Reply
  • Hi, yes that bit I can understand now. I am following your option 2 now, which is to create another image but to save data. This works quite well for my self defined source code like gait_analysis.c. But when I try to move edge impulse library, this won't work. There is no error, but the edge impulse code is still there in the internal flash. 

    However as I said earlier, I can see moving edge impulse library to the external flash is mentioned in nordic official page. So I was wondering how can I actually achieve that. 

Children
No Data
Related