Image upload over MCUBoot serial recovery not bootable

Hi

I've an application running on nRF Conenct SDK 3.0.2 on an nRF52840DK. Now I tried to enable update support over serial recovery of MCUBoot using the USB ACM.

First I've setup sysbuild to use MCUboot in sysbuild.conf file:

# Enable bootloader with dedicated bootloader image
SB_CONFIG_BOOTLOADER_MCUBOOT=y
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y

In the configuration for the mcuboot image (sysbuild/mcuboot/prj.conf) the following configuration was added:

CONFIG_PM=n

CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x20000

CONFIG_MAIN_STACK_SIZE=10240

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
### Use the minimal C library to reduce flash usage
CONFIG_MINIMAL_LIBC=y
CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0

# NCS boot banner
CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot"




# Partition table set by pm_static.yml
# CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x20000

CONFIG_GPIO=y

CONFIG_SINGLE_APPLICATION_SLOT=y
# CONFIG_BOOT_SWAP_USING_MOVE=y

# Enable MCUboot Serial Recovery
CONFIG_MCUBOOT_SERIAL=y
CONFIG_BOOT_SERIAL_UART=y
CONFIG_UART_CONSOLE=n

# Point Serial Recovery to CDC_ACM
CONFIG_BOOT_SERIAL_CDC_ACM=y

# Enable Serial Recovery by Button
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU=n
CONFIG_BOOT_SERIAL_ENTRANCE_GPIO=y

# USB configuration
CONFIG_USB_DEVICE_VID=0x1915
CONFIG_USB_DEVICE_PID=0x5300
 
By pressing the Button 1 on startup I'm able to enter the MCUBOOT serial revovery now. Also reading the image status work properly. But if I download the created "dfu_application.zip" file by using the newtmgr CLI client the system shows me on RTT log the there is no startable image found. Somehow the downloaded image is not startable.
Anyone had success with getting serial recovery with MCUBoot working? What could be wrong?

Parents
  • Hi,

     

    By pressing the Button 1 on startup I'm able to enter the MCUBOOT serial revovery now. Also reading the image status work properly. But if I download the created "dfu_application.zip" file by using the newtmgr CLI client the system shows me on RTT log the there is no startable image found. Somehow the downloaded image is not startable.

    I haven't used the mynewt CLI tool, but I believe mcumgr requires that you give in a .bin file.

    Could you try to transfer the build-folder/application-name/zephyr/zephyt.signed.bin file and see if this runs as expected afterwards?

     

    Kind regards,

    Håkon

  • Hi Hakon

    Thanks for the input. That was the problem. After using the "build-folder/application-name/zephyr/zephyt.signed.bin" file it worked as expected. It also works with nRF Connect Desktop Programmer MCUBoot Support, but then the "build-folder/application-name/zephyr/zephyt.signed.hex" file needs to be used.

    Why does the nRF Connect App need a different file? I assume it uses the same SMP protocol "image upload" commands to download the application to the device in MCUboot.

    Maybe you can give me a short info about theses related questions:

    1) What isn't there a hash or bootable flag in the MCUboot image? I see this info with the "image list" command.
    The output then is:
    Images:
    image=0 slot=0
    version: 2.1.2
    bootable: false
    flags:
    hash: Unavailable
    Split status: N/A (0)

    2) Are there any options to increase the speed for the download?

    Regards Adrian

  • Hi,

     

    Adrian Eggenberger said:
    Currently we get 3.5kB/s with the newtmgr client.

    This might be a "feature" of the newtmgr CLI tool, as it seems to have a larger sleep between each payload:

     RE: MCUBOOT slow with nRF52840 / Zephyr / USB CDC_ACM protocol 

    Adrian Eggenberger said:
    Is there something that can be configured around the MTU size?

    You could adjust the mtu via the connstring:

    --connstring=COMx,baud=115200,mtu=512

     

    Another option would also be to adjust the baudrate.

     

    Kind regards,

    Håkon

  • Somehow only MTU sizes up to ~130 work. With higher values it doesn't work. What MTU size does the nRF Connect Programmer use? The baudrate seems to be irrelevant. That could be because it is a virtual Uart device?

  • Hi,

    Adrian Eggenberger said:
    Somehow only MTU sizes up to ~130 work.

    I believe this can be changed via mcuboot's CONFIG_BOOT_MAX_LINE_INPUT_LEN.

    Adrian Eggenberger said:
    The baudrate seems to be irrelevant.

    Yes, you're right. With CDC, this has no effect on the overall transmission. Sorry for the confusion.

     

    Adrian Eggenberger said:
    What MTU size does the nRF Connect Programmer use?

    it uses nrfutil to write the image:

    https://github.com/NordicSemiconductor/pc-nrfconnect-programmer/blob/main/src/actions/mcubootTargetActions.ts#L71-L81

    I believe that the mtu does not have much of an effect here, it is more related to timing between each packet.

     

    Did you try the fix proposed in the former linked thread? ie. reduce the wait-time between each payload?

     

    Kind regards,

    Håkon

  • Increasing the MTU did have also a hugh impact. That's fine for now. We will probably go with an MTU of 512. It works now almost as expected.

    I've one thing that is not working. We have own implementaiton for the serial number over USB. In the MCUboot at the moment we have the default USB serial number. How can I override weak methods (e.g. "usb_update_sn_string_descriptor" in my mcuboot image? All attempts I've made did not work.

  • Hi,

     

    Glad to hear that this has improved the scenario.

    The USB transport has a 64 byte EP, which means that increasing the MTU size will effectively send 'n' amount of packets of 64 bytes.

    As you shared, there's two methods of improving speed:

    1. increase mtu

    2. decrease dwell-time between each requested MTU.

     

    Adrian Eggenberger said:
    I've one thing that is not working. We have own implementaiton for the serial number over USB. In the MCUboot at the moment we have the default USB serial number. How can I override weak methods (e.g. "usb_update_sn_string_descriptor" in my mcuboot image? All attempts I've made did not work.

    The default behavior is that the function reads out the FICR.DEVICEID and applies this as the serial number:

    https://github.com/nrfconnect/sdk-zephyr/blob/main/subsys/usb/device/usb_descriptor.c#L328-L355

     

    I checked around with colleagues, and there is no straight-forward way to add a .c file to mcuboot without forking the repo.

    So, I did an exercise to bend sysbuild a bit.

    What you can do is to workaround this by treating your .c file as a out-of-tree driver specific to mcuboot.

    Create sysbuild.cmake file containing:

    set(mcuboot_EXTRA_ZEPHYR_MODULES "${CMAKE_CURRENT_LIST_DIR}/test_usb_sn_override" CACHE INTERNAL "test_module directory")

     

    Then handle "test_usb_sn_override" as a out-of-tree directory by specifying test_usb_sn_override/zephyr/module.yml:

    build:
      cmake: .
      kconfig: Kconfig
    

     

    Then add a small conditional in test_usb_sn_override/CMakeLists.txt:

    if(DEFINED CONFIG_BOOT_SERIAL_CDC_ACM)
        message("Adding override function for USB serial number")
        zephyr_library_sources(test.c)
    endif()

     

    Where test.c holds:

    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/__assert.h>
    #include <zephyr/usb/usb_device.h>
    
    uint8_t *usb_update_sn_string_descriptor(void)
    {
    	/* SN is 16 bytes */
    	static char hex[] = "CAFECAFECAFECAFE";
    	return (uint8_t*)hex;
    }
    

     

    lsusb -d 2fe3:0100 -v
    
    Bus 001 Device 042: ID 2fe3:0100 NordicSemiconductor MCUBOOT
    Couldn't open device, some information will be missing
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass          239 Miscellaneous Device
      bDeviceSubClass         2 [unknown]
      bDeviceProtocol         1 Interface Association
      bMaxPacketSize0        64
      idVendor           0x2fe3 NordicSemiconductor
      idProduct          0x0100 MCUBOOT
      bcdDevice            4.00
      iManufacturer           1 ZEPHYR
      iProduct                2 MCUBOOT
      iSerial                 3 CAFECAFECAFECAFE
      ...
    

     

    Here's a hello_world that does this:

    hello_world_sysbuild_mcuboot_override_usb_sn2.zip

     

    I used the nrf7002dk board for this exercise, so the board files in sysbuild/mcuboot/boards must be altered to match your chosen one.


    PS: remove sysbuild.conf "SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y" if testing on nRF5340.

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    Glad to hear that this has improved the scenario.

    The USB transport has a 64 byte EP, which means that increasing the MTU size will effectively send 'n' amount of packets of 64 bytes.

    As you shared, there's two methods of improving speed:

    1. increase mtu

    2. decrease dwell-time between each requested MTU.

     

    Adrian Eggenberger said:
    I've one thing that is not working. We have own implementaiton for the serial number over USB. In the MCUboot at the moment we have the default USB serial number. How can I override weak methods (e.g. "usb_update_sn_string_descriptor" in my mcuboot image? All attempts I've made did not work.

    The default behavior is that the function reads out the FICR.DEVICEID and applies this as the serial number:

    https://github.com/nrfconnect/sdk-zephyr/blob/main/subsys/usb/device/usb_descriptor.c#L328-L355

     

    I checked around with colleagues, and there is no straight-forward way to add a .c file to mcuboot without forking the repo.

    So, I did an exercise to bend sysbuild a bit.

    What you can do is to workaround this by treating your .c file as a out-of-tree driver specific to mcuboot.

    Create sysbuild.cmake file containing:

    set(mcuboot_EXTRA_ZEPHYR_MODULES "${CMAKE_CURRENT_LIST_DIR}/test_usb_sn_override" CACHE INTERNAL "test_module directory")

     

    Then handle "test_usb_sn_override" as a out-of-tree directory by specifying test_usb_sn_override/zephyr/module.yml:

    build:
      cmake: .
      kconfig: Kconfig
    

     

    Then add a small conditional in test_usb_sn_override/CMakeLists.txt:

    if(DEFINED CONFIG_BOOT_SERIAL_CDC_ACM)
        message("Adding override function for USB serial number")
        zephyr_library_sources(test.c)
    endif()

     

    Where test.c holds:

    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/__assert.h>
    #include <zephyr/usb/usb_device.h>
    
    uint8_t *usb_update_sn_string_descriptor(void)
    {
    	/* SN is 16 bytes */
    	static char hex[] = "CAFECAFECAFECAFE";
    	return (uint8_t*)hex;
    }
    

     

    lsusb -d 2fe3:0100 -v
    
    Bus 001 Device 042: ID 2fe3:0100 NordicSemiconductor MCUBOOT
    Couldn't open device, some information will be missing
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass          239 Miscellaneous Device
      bDeviceSubClass         2 [unknown]
      bDeviceProtocol         1 Interface Association
      bMaxPacketSize0        64
      idVendor           0x2fe3 NordicSemiconductor
      idProduct          0x0100 MCUBOOT
      bcdDevice            4.00
      iManufacturer           1 ZEPHYR
      iProduct                2 MCUBOOT
      iSerial                 3 CAFECAFECAFECAFE
      ...
    

     

    Here's a hello_world that does this:

    hello_world_sysbuild_mcuboot_override_usb_sn2.zip

     

    I used the nrf7002dk board for this exercise, so the board files in sysbuild/mcuboot/boards must be altered to match your chosen one.


    PS: remove sysbuild.conf "SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y" if testing on nRF5340.

     

    Kind regards,

    Håkon

Children
Related