Size of build image for mcuboot with serial or usb DFU enabled?

Working on a nrf5340 project, and running into limits of the size of the flash to store my application image along with mcuboot bootloader.

I had a mucboot setup that fitted into 56Kb (signed images, secondary slot on external flash). This did NOT include the serial DFU however, and (of course) one of my first units out in the field got bricked during a DFU (using dfu_target lib to update the secondary slot from a file loaded on USB FAT FS mounted on the external flash... not yet got the unit to see what got corrupted...)

I expose the USB interface, so would like to enable the serial DFU functionality in mcuboot so that at least I have a method to DFU even if my main app image gets corrupted...Some questions to get this to work:

1/ The buttons on the device are via a gpio expander on the i2c interface, it seems mcuboot likes a 'dfu button' to be a direct gpio (at least if I set the alias:

mcuboot-button0 = &button2;
then it doesn't build because button2 is 
button2: button_2 {
            gpios = <&ioexp0 4 (GPIO_ACTIVE_LOW)>;    // GPA4
). Is this correct or should it work via a ioexpander?
BTW This is not a deal breaker as I see I can have a 'DFU delay' at boot to always check if the dfu is to be activated on the serial/USB
2/ serial DFU (virtual com port on USB) vs USB DFU : which is better to use? Which gives me a smaller mcuboot image?
3/ Image size : mcuboot with DFU_USB is now 76+Kb
Is this normal? Are there ways to slim this down? also, the mcuboot child_image build has its own mcuboot.conf - does this addon to the usual prj.conf, or replace it completely?
The image size is an issue because my main app uses https over wifi networking (nrf7002) and the wifi code+networking+TLS takes up a LOT of space....
thanks for any tips to get a solid mcuboot in the least flash space!
  • Haven't tried to run mcumgr yet, but thats the next step!

    For mcumgr client, I went with this one (as recommended on the bootloader nordic doc)

    https://github.com/vouch-opensource/mcumgr-client

    This worked fine on the vCDC-ACM USB comm ports on my W11 PC... not a fast download so I also applied the buffer size config values recommended for mcuboot.conf:

    CONFIG_BOOT_MAX_LINE_INPUT_LEN=8192
    CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096
    and the patch for the USB cdc_acm.c file:
    /* Size of the internal buffer used for storing received data */
    -#define CDC_ACM_BUFFER_SIZE (CONFIG_CDC_ACM_BULK_EP_MPS)
    +#define CDC_ACM_BUFFER_SIZE 512
    (by the way, if I just configure CONFIG_CDC_ACM_BULK_EP_MPS=512 in mcuboot.conf, and hack the kconfig.cdc to allow this, it breaks the operation for mcuboot - this value is used elsewhere in the cdc_acm.c and it doesn't like it being changed apparently....so just apply the simple patch as per the readme on the mcumgr site!)

    Download is then around 10x faster as promised!

    However: still can't get the CPU-NET DFU to work, and interestingly the mcumgr 'list' command only reports 1 slot :

    C:\ncs\mcumgr-client-windows-x86>mcumgr-client.exe -d COM3 list
    mcumgr-client 0.0.7, Copyright © 2024 Vouch.io LLC

    17:01:36 [INFO] send image list request
    response: {
    "images": [
    {
    "image": 0,
    "slot": 0,
    "version": "0.1.11.1",
    "hash": "",
    "bootable": false,
    "pending": false,
    "confirmed": false,
    "active": false,
    "permanent": false
    }
    ]
    }

    What do I need to add to my mcuboot.conf (for multi-image build) to get it to know about the 2nd slot? (and then the 3rd for wifi fw....)

    Here's my mcuboot.conf for multi-image build:

    CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot"
    
    CONFIG_FLASH=y
    
    # Want the following functionality, but to fit in 64kB!
    CONFIG_MCUBOOT_SERIAL=y
    CONFIG_BOOT_SERIAL_CDC_ACM=y
    CONFIG_BOOT_SERIAL_NO_APPLICATION=y
    CONFIG_USB_DEVICE_MANUFACTURER="Infrafon GmbH"
    CONFIG_USB_DEVICE_PRODUCT="CC2"
    # USB VID is MCS electronics, who sell individual PIDs. 0x138F is for CC2 purchases 25/08/2024
    CONFIG_USB_DEVICE_VID=0x16D0
    CONFIG_USB_DEVICE_PID=0x138F
    # no functional need for USB HID emulation (and its a big chunk of code)
    CONFIG_USB_DEVICE_HID=n
    CONFIG_USB_MASS_STORAGE=n
    
    CONFIG_BOOT_MAX_LINE_INPUT_LEN=8192
    CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096
    #CONFIG_CDC_ACM_BULK_EP_MPS=512
    
    # DFU by holding down a button at boot time (mcuboot-button0 alias in DTS)
    CONFIG_BOOT_SERIAL_ENTRANCE_GPIO=y
    CONFIG_MCUBOOT_INDICATION_LED=y
    
    CONFIG_BOOT_MAX_IMG_SECTORS=256
    #FPROTECT is n as current primary pad is not aligned on 0x4000 boundary
    CONFIG_FPROTECT=n
    CONFIG_BOOT_BOOTSTRAP=y
    
    CONFIG_MAIN_STACK_SIZE=10240
    # Set QSPI flash layout configuration
    CONFIG_NORDIC_QSPI_NOR=y
    CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
    CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16
    
    #CONFIG_BOOTLOADER_MCUBOOT=y
    CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
    CONFIG_BOOT_SIGNATURE_KEY_FILE="/work/dev/if-device-nrf53/keys/bootloader_priv-ecdsa256.pem"
    CONFIG_BOOT_SWAP_USING_MOVE=y
    
    # allow update of CPU-NET image (image 1)
    # want to update CPU-NET image
    # not allowed with sysbuild CONFIG_NETCORE_APP_UPDATE=y
    # PCD is automagically included depending on if this image is app or net processor
    #CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH=y
    #CONFIG_NRF53_UPGRADE_NETWORK_CORE=y
    #CONFIG_ADD_MCUBOOT_MEDIATE_SIM_FLASH_DTS=y
    # The network core cannot access external flash directly. The flash simulator must be used to
    # provide a memory region that is used to forward the new firmware to the network core.
    CONFIG_FLASH_SIMULATOR=y
    CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
    CONFIG_FLASH_SIMULATOR_STATS=n
    
    CONFIG_MCUBOOT_SHELL=n
    
    CONFIG_DEBUG_COREDUMP=n
    CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING=n
    CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=n
    
    # Use minimal C library instead of the Picolib
    CONFIG_MINIMAL_LIBC=y
    ### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y
    CONFIG_CBPRINTF_NANO=y
    CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=n
    
    #CONFIG_MBEDTLS=y
    #CONFIG_NRF_SECURITY=y
    #CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY=y
    #CONFIG_CUSTOM_MBEDTLS_CFG_FILE=y
    #CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h"
    #CONFIG_MBEDTLS_DTLS=n
    #CONFIG_MBEDTLS_TLS_VERSION_1_2=y
    #CONFIG_MBEDTLS_RSA_C=y
    # this is ignored by build, no way to avoid having ECP crypto code. 
    #CONFIG_MBEDTLS_ECP_C=n
    
    CONFIG_DEBUG=n
    CONFIG_DEBUG_INFO=n
    
    CONFIG_THREAD_NAME=n
    CONFIG_THREAD_ANALYZER=n
    CONFIG_SYS_HEAP_RUNTIME_STATS=n
    CONFIG_INIT_STACKS=n
    CONFIG_ASSERT=n
    CONFIG_ASSERT_VERBOSE=n
    CONFIG_ASSERT_NO_MSG_INFO=y
    CONFIG_ASSERT_NO_COND_INFO=y
    CONFIG_ASSERT_NO_FILE_INFO=y
    CONFIG_STACK_SENTINEL=n
    CONFIG_RESET_ON_FATAL_ERROR=y
    CONFIG_REBOOT=y
    
    # could turn off serial and uart console to save space when no logging required... but need them on to get printk()
    CONFIG_CONSOLE=y
    CONFIG_CONSOLE_HANDLER=n
    CONFIG_SERIAL=y
    CONFIG_UART_CONSOLE=y
    CONFIG_STDOUT_CONSOLE=y
    
    # turn off log to save image size
    CONFIG_LOG=n
    CONFIG_LOG_MODE_MINIMAL=y
    # BUT hack in bootloader/mcuboot/boot/bootutil/include/bootutil/bootutil_log.h to send logs to printk() directly
    
    #CONFIG_LOG_MODE_IMMEDIATE=y
    #CONFIG_LOG_BACKEND_UART=y
    CONFIG_LOG_DEFAULT_LEVEL=3
    ### Use info log level by default
    CONFIG_MCUBOOT_LOG_LEVEL_WRN=y
    CONFIG_LOG_PRINTK=n
    CONFIG_SHELL=n
    CONFIG_SHELL_MINIMAL=n
    
    CONFIG_SHELL_LOG_BACKEND=n
    CONFIG_NCS_SAMPLES_DEFAULTS=n
    CONFIG_NO_RUNTIME_CHECKS=y
    
    CONFIG_MBEDTLS_LOG_LEVEL_ERR=y
    CONFIG_KERNEL_LOG_LEVEL_ERR=y
    CONFIG_I2C_LOG_LEVEL_ERR=y
    CONFIG_GPIO_LOG_LEVEL_ERR=y
    CONFIG_UART_LOG_LEVEL_ERR=y
    CONFIG_PINCTRL_LOG_LEVEL_ERR=y
    CONFIG_FLASH_LOG_LEVEL_ERR=y
    # only enable error level logs for usb, as lots of warnings....
    CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
    CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
    
    CONFIG_GPIO=y
    CONFIG_I2C=y
    CONFIG_GPIO_MCP230XX=y
    
    CONFIG_BT=n
    CONFIG_WIFI=n
    CONFIG_NFC_T2T_NRFXLIB=n
    CONFIG_NFC_T4T_NRFXLIB=n
    CONFIG_NFC_T4T_ISODEP=n
    CONFIG_NFC_NDEF=n
    CONFIG_USE_SEGGER_RTT=n
    CONFIG_SPI=n
    CONFIG_I2S=n
    CONFIG_PWM=n
    CONFIG_CJSON_LIB=n
    CONFIG_JSON_LIBRARY=n
    CONFIG_APP_EVENT_MANAGER=n
    CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0
    
    CONFIG_BOOT_BANNER=n
    CONFIG_TICKLESS_KERNEL=n
    CONFIG_TIMEOUT_64BIT=n
    CONFIG_NRF_ENABLE_ICACHE=n
    
    # Enable LTO
    CONFIG_ISR_TABLES_LOCAL_DECLARATION=y
    CONFIG_LTO=y
    

  • Hi,

    Thank you for sharing the workaround, that resolution is very useful for me as well!

    BrianW said:
    If there is a better way to achieve this let me know...

    I've not seen anyone using anything but either LOG_MODE_MINIMAL, or LOG_MODE=n when logging from the bootloader. The typical usecase where you can't afford logging in the bootloader while developing due to flash restrictions is to be honest relatively rare, but it does occur

    BrianW said:
    yes, it has an issue with definition of the PRIMARY_1 slot for the CPU-NET DFU when built with sysbuild. 

    I've posted a reply in 341508 w.r.t this earlier today

    Kind regards,
    Andreas

  • and if anyone can tell me why building the SAME code, with the SAME config, under sysbuild makes it 3Kb bigger (and so TOO big for the 64kB partition) then that'd be nice....

  • Hi,

    Could you specify what becomes 3kB bigger and what are the same configurations for the same code? Is it your bootloader code and configurations, is it your application code and configurations or is it the combined firmware?

    Kind regards,
    Andreeas

  • mcuboot image for application processor.

    Under multi-image build:

    Memory region Used Size Region Size %age Used
    FLASH: 62864 B 64 KB 95.92%
    RAM: 371112 B 440 KB 82.37%
    IDT_LIST: 0 GB 32 KB 0.00%

    change the west config flag to says sysbuild:true and run same west build command:

    c:/ncs/toolchains/b620d30767/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd.exe: zephyr\zephyr.elf section `usb_descriptor' will not fit in region `FLASH'
    c:/ncs/toolchains/b620d30767/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd.exe: region `FLASH' overflowed by 308 bytes
    Memory region Used Size Region Size %age Used
    FLASH: 65844 B 64 KB 100.47%
    RAM: 379912 B 440 KB 84.32%
    IDT_LIST: 0 GB 32 KB 0.00%
    collect2.exe: error: ld returned 1 exit status

    3000 bytes bigger....the sysbuild/mcuboot/prj.conf and child_image/mcuboot.conf are the same (except for the keys that have to move to sysbuild.conf of course)

    I'm guess that one of the options from the sysbuild.conf is responsible, maybe this:

    SB_CONFIG_NETCORE_APP_UPDATE=y
    Since the multi-image build did not seem to have told mcuboot about the DFUable CPU-NET slot...
    I removed the INF level logs from mcuboot (CONFIG_LOG=n already, but ERR/WRN/INF were compiled in using my printk() hack) and have just managed to squeeze mcuboot into 64kB:
    Memory region Used Size Region Size %age Used
    FLASH: 64732 B 64 KB 98.77%
    RAM: 379912 B 440 KB 84.32%
    IDT_LIST: 0 GB 32 KB 0.00%
    and even better, when I boot mcuboot into serial recovery mode, I get 3 slots showing as updateable:
    C:\ncs\mcumgr-client-windows-x86>mcumgr-client.exe -d COM3 list
    mcumgr-client 0.0.7, Copyright © 2024 Vouch.io LLC

    09:18:50 [INFO] send image list request
    response: {
    "images": [
    {
    "image": 0,
    "slot": 0,
    "version": "0.1.13.1",
    "hash": "",
    "bootable": false,
    "pending": false,
    "confirmed": false,
    "active": false,
    "permanent": false
    },
    {
    "image": 1,
    "slot": 0,
    "version": "0.0.0",
    "hash": "",
    "bootable": false,
    "pending": false,
    "confirmed": false,
    "active": false,
    "permanent": false
    },
    {
    "image": 2,
    "slot": 0,
    "version": "0.1.13.1",
    "hash": "",
    "bootable": false,
    "pending": false,
    "confirmed": false,
    "active": false,
    "permanent": false
    }
    ]
    }
    Just got to test if it actually can do DFU on each one now (using dfu_target library). 
    One point that worries me in the sysbuild build : I get this log when building the app image:
    -- Configuring done
    -- Generating done
    -- Build files have been written to: C:/work/dev/if-device-nrf53/cc1-med/build/cc1-med
    CMake Warning at C:/ncs/v2.9.0/nrf/cmake/sysbuild/debug_keys.cmake:21 (message):


    --------------------------------------------------------------
    --- WARNING: Using generated NSIB public/private key-pair. ---
    --- It should not be used for production. ---
    --- See SB_CONFIG_SECURE_BOOT_SIGNING_KEY_FILE ---
    --------------------------------------------------------------


    Call Stack (most recent call first):
    C:/ncs/v2.9.0/nrf/cmake/sysbuild/provision_hex.cmake:11 (include)
    C:/ncs/v2.9.0/nrf/sysbuild/CMakeLists.txt:55 (include)
    C:/ncs/v2.9.0/nrf/sysbuild/CMakeLists.txt:667 (include_provision_hex)
    cmake/modules/sysbuild_extensions.cmake:583 (nrf_POST_CMAKE)
    cmake/modules/sysbuild_extensions.cmake:583 (cmake_language)
    cmake/modules/sysbuild_images.cmake:23 (sysbuild_module_call)
    cmake/modules/sysbuild_default.cmake:20 (include)
    C:/ncs/v2.9.0/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:75 (include)
    C:/ncs/v2.9.0/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:92 (include_boilerplate)
    C:/ncs/v2.9.0/zephyr/share/sysbuild-package/cmake/SysbuildConfig.cmake:8 (include)
    template/CMakeLists.txt:10 (find_package)

    Despite having this in my sysbuild.conf:

    SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
    SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APPLICATION_CONFIG_DIR}/../keys/bootloader_priv-ecdsa256.pem"
    I undetstood that SB_CONFIG_SECURE_BOOT_SIGNING_KEY_FILE was used for the '2 stage bootloader allowing updateable mcuboot', but I do NOT enable SB_CONFIG_SECURE_BOOT_NETYCORE...
    Any ideas what is going on here? Is my app image signed using my key file or not?
Related