DFU AT commands

This page describes AT commands related to Device Firmware Update (DFU) operations. These commands allow you to update the application firmware, delta modem firmware, full modem firmware, or the MCUboot second-stage bootloader through UART.

Note

The DFU commands use data mode to receive firmware data. See the Data mode section for more information about data mode.

DFU types

The following DFU image types are supported:

  • 0 - Application firmware (MCUboot)

  • 1 - Delta modem firmware

  • 3 - MCUboot second-stage bootloader self-update. Only available when the device uses the NSIB (B0) and MCUboot as a second-stage bootloader. The host must stream the signed image for the inactive s0/s1 slot.

Caution

Full modem firmware DFU is disabled by default.

If the full modem firmware update fails after firmware data has been programmed to modem flash, the modem remains unusable until a successful update is completed.

DFU initialize #XDFUINIT

The #XDFUINIT command initializes the DFU target for a specific image type.

Set command

The set command initializes the DFU target.

Syntax

AT#XDFUINIT=<type>[,<size>]

The parameters and their defined values are the following:

<type>

Integer. The DFU image type as specified in the DFU types section.

<size>

Integer. The total firmware image size in bytes. Required for application (type 0), delta modem firmware (type 1), and MCUboot bootloader (type 3) updates.

For full modem firmware (type 2), the command triggers an immediate reboot into bootloader mode.

The #XDFUINIT, #XDFUWRITE, and #XDFUAPPLY commands use the same modem DFU area as the #XFOTA and #XNRFCLOUDFOTA commands. For delta modem firmware (type 1), they return ERROR in one of the following cases:

  • A FOTA update started with the #XFOTA or #XNRFCLOUDFOTA command is in progress.

  • Such an update is downloaded, but not yet activated.

When one of these commands succeeds, it reserves the modem DFU area for direct DFU until the modem is reset, for example with the #XMODEMRESET or #XRESET command. While the area is reserved, the #XFOTA and #XNRFCLOUDFOTA commands cannot start a modem firmware update or erase the modem DFU area.

Example

AT#XDFUINIT=0,123456
OK

AT#XDFUINIT=2
// device reboots into bootloader mode
Bootloader mode ready

Read command

The read command is not supported.

Test command

The test command tests the existence of the command and provides information about the type of its subparameters.

Syntax

AT#XDFUINIT=?

Response syntax

#XDFUINIT: <list of supported types>,<size>

Example

AT#XDFUINIT=?

#XDFUINIT: (0,1,2,3),<size>

OK

DFU write #XDFUWRITE

The #XDFUWRITE command writes firmware data to the DFU target. The command enters data mode to receive the firmware chunk.

Set command

The set command initiates a firmware data write operation.

Syntax

AT#XDFUWRITE=<type>,<addr>,<len>

The parameters and their defined values are the following:

<type>

Integer. The DFU image type as specified in the DFU types section.

<addr>

Integer. The address offset for the data.

<len>

Integer. The length of the data chunk to write.

After the command returns OK, the Serial Modem enters data mode to receive exactly <len> bytes of firmware data. When the data has been received and written, the Serial Modem sends a #XDFU unsolicited notification with the status. For delta modem firmware (type 1), the command returns ERROR under the same conditions as the #XDFUINIT command.

Example

AT#XDFUWRITE=0,0,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 0,1,0

Read command

The read command is not supported.

Test command

The test command tests the existence of the command and provides information about the type of its subparameters.

Syntax

AT#XDFUWRITE=?

Response syntax

#XDFUWRITE: <list of supported types>,<addr>,<len>

Example

AT#XDFUWRITE=?

#XDFUWRITE: (0,1,2,3),<addr>,<len>

OK

DFU apply #XDFUAPPLY

The #XDFUAPPLY command finalizes the firmware update and schedules it for activation.

Set command

The set command applies the firmware update.

Syntax

AT#XDFUAPPLY=<type>

The parameters and their defined values are the following:

<type>

Integer. The DFU image type as specified in the DFU types section.

For application (type 0), delta modem firmware (type 1), and MCUboot bootloader (type 3), the update is scheduled and will be activated on the next reset, which can be done with the AT#XRESET command. For full modem firmware (type 2), the command applies the current segment (bootloader or firmware) and triggers a reboot if needed. For delta modem firmware (type 1), the command returns ERROR under the same conditions as the #XDFUINIT command.

Example

AT#XDFUAPPLY=0
OK
#XDFU: 0,2,0

AT#XRESET
OK
Ready

Read command

The read command is not supported.

Test command

The test command tests the existence of the command and provides information about the type of its subparameters.

Syntax

AT#XDFUAPPLY=?

Response syntax

#XDFUAPPLY: <list of supported types>

Example

AT#XDFUAPPLY=?

#XDFUAPPLY: (0,1,2,3)

OK

DFU unsolicited notification #XDFU

The Serial Modem sends the #XDFU unsolicited notification to report the status of DFU write and apply operations.

Unsolicited notification

#XDFU: <type>,<operation>,<status>

The parameters and their defined values are the following:

<type>

Integer. The DFU image type as specified in the DFU types section.

<operation>
  • 1 - Data write completed.

  • 2 - Apply update completed.

<status>
  • 0 - Success.

  • -1 - Failure.

Complete DFU examples

The following sections showcase a complete example of application, delta modem, and full modem firmware update.

Application firmware update

The following example shows a complete application firmware update:

// Note the current application version (major.minor.patch from app/VERSION)
AT#XSMVER
#XSMVER: "v1.99.0-7-gdf00f46-dirty","3.3.0-rc1"
OK

// Initialize DFU for application firmware (total size 123456 bytes)
AT#XDFUINIT=0,123456
OK

// Write first chunk (4096 bytes at offset 0)
AT#XDFUWRITE=0,0,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 0,1,0

// Write second chunk (4096 bytes at offset 4096)
AT#XDFUWRITE=0,4096,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 0,1,0

// ... continue writing chunks ...

// Apply the update
AT#XDFUAPPLY=0
OK
#XDFU: 0,2,0

// Reset to activate the new firmware
AT#XRESET
OK
Ready

// Verify the VERSION prefix increased (here 1.99.0 -> 1.99.1)
AT#XSMVER
#XSMVER: "v1.99.1-8-gf0fd0f46-dirty","3.3.0-rc1"
OK

Delta modem firmware update

The following example shows a complete delta modem firmware update:

// Note the current modem firmware
AT%SHORTSWVER
%SHORTSWVER: nrf91x1_2.0.0
OK

// Initialize DFU for delta modem firmware (total size 65536 bytes)
AT#XDFUINIT=1,65536
OK

// Write first chunk (4096 bytes at offset 0)
AT#XDFUWRITE=1,0,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 1,1,0

// Write second chunk (4096 bytes at offset 4096)
AT#XDFUWRITE=1,4096,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 1,1,0

// ... continue writing chunks ...

// Apply the update
AT#XDFUAPPLY=1
OK
#XDFU: 1,2,0

// Reset the modem to activate the new firmware
AT#XMODEMRESET
#XMODEMRESET: 0
OK

// Verify that the modem is running the new firmware
AT%SHORTSWVER
%SHORTSWVER: nrf91x1_2.0.4
OK

Full modem firmware update

The following example shows a complete full modem firmware update.

For full modem firmware update, enable the CONFIG_SM_DFU_MODEM_FULL Kconfig option.

Important

If the update fails after the first 8 kB block of firmware data has been programmed, the modem remains unusable until a successful update is performed. The bootloader remains intact for retries. Ensure a reliable connection between the host and Serial Modem, and stable power supply before starting the update.

The full modem update consists of two phases:

  1. Bootloader segment - Writes the bootloader data.

  2. Firmware segment - Writes the firmware data.

Note

Firmware segment data is buffered and programmed to modem flash in 8 kB blocks. A #XDFU: 2,1,0 notification means the data was accepted, not that it was programmed. With contiguous writes of 8 kB or less, the first block is programmed during the write that brings the total amount of firmware data to 8 kB or more. If that write fails, the modem rejected the firmware, for example, because it is an older version. In that case, the existing modem firmware is left untouched, and you can return to normal mode with the AT#XRESET command. If a later write or AT#XDFUAPPLY fails, the modem remains unusable until a full modem firmware update is completed successfully.

// Note the current firmware version of the modem
AT%SHORTSWVER
%SHORTSWVER: nrf91x1_2.0.0
OK

// Initialize DFU for full modem firmware
AT#XDFUINIT=2
// device reboots
Bootloader mode ready

// Phase 1: Write bootloader segment
AT#XDFUWRITE=2,0,4096
OK
// 4096 bytes of bootloader data
#XDATAMODE: 0
#XDFU: 2,1,0

// ... continue writing bootloader chunks ...

// Apply bootloader segment (switches to firmware segment mode)
AT#XDFUAPPLY=2
OK
#XDFU: 2,2,0

// Phase 2: Write firmware segments
// Warning: Data is programmed to modem flash in 8 kB blocks. A failure after the first block is programmed leaves the modem unusable until the update is completed successfully.
AT#XDFUWRITE=2,0,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 2,1,0

// ... continue writing firmware chunks ...

// Apply firmware segment (triggers reboot)
AT#XDFUAPPLY=2
OK
#XDFU: 2,2,0
// device reboots
Ready

// Verify that the modem is running the new firmware
AT%SHORTSWVER
%SHORTSWVER: nrf91x1_2.0.4
OK

MCUboot firmware update

Important

NSIB (B0) uses monotonic counter values to prevent rollback of the MCUboot bootloader. When performing an MCUboot DFU, the host must ensure that the new MCUboot image has a strictly higher monotonic counter value than the currently running MCUboot to avoid update failure.

This means that updates for MCUboot images are limited to the number of slots defined in the SB_CONFIG_SECURE_BOOT_NUM_VER_COUNTER_SLOTS Kconfig option. In Serial Modem, it is set to 40 by default.

The following example shows a complete MCUboot firmware update:

// Query the current slot for MCUboot image
AT#XBOOTINFO=1
#XBOOTINFO: 0
OK

// Download the correct MCUboot image for the inactive slot.
// The default NCS image names for MCUboot are:
// - Slot 0: signed_by_mcuboot_and_b0_mcuboot.bin
// - Slot 1: signed_by_mcuboot_and_b0_s1_image.bin

// In this example, the device is currently running slot 0, so the host should download the signed image for slot 1, which is signed_by_mcuboot_and_b0_s1_image.bin.

// Note the current monotonic counter value for MCUboot
AT#XBOOTINFO=0
#XBOOTINFO: 1
OK

// Initialize DFU for MCUboot firmware (total size 23456 bytes)
AT#XDFUINIT=3,23456
OK

// Write first chunk (4096 bytes at offset 0)
AT#XDFUWRITE=3,0,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 3,1,0

// Write second chunk (4096 bytes at offset 4096)
AT#XDFUWRITE=3,4096,4096
OK
// 4096 bytes of firmware data
#XDATAMODE: 0
#XDFU: 3,1,0

// ... continue writing chunks ...

// Apply the update
AT#XDFUAPPLY=3
OK
#XDFU: 3,2,0

// Reset to activate the new firmware
AT#XRESET
OK
Ready

// Verify that the monotonic counter value for MCUboot was updated
AT#XBOOTINFO=0
#XBOOTINFO: 2
OK

// (Optional) Verify that the MCUboot slot was switched
AT#XBOOTINFO=1
#XBOOTINFO: 1
OK

DFU host example

See app/scripts/sm_dfu_host.py for an example of how to implement a DFU host. The script demonstrates the DFU AT command flow and can be used as a starting point for custom implementations.

Install dependencies:

pip install -r app/scripts/requirements.txt

Note

cbor2 5.8.0 does not work with the sm_dfu_host.py script due to a known bug introduced in that version. Versions older and newer than that work. See cbor2 bug for more information.

Usage

python sm_dfu_host.py --port <serial_port> --baudrate <baud> --file <path-to-firmware> --type <dfu_type>

Where <dfu_type> is one of: application, modem-delta, or modem-full.

After the DFU transfer completes:

Note

Applying application and delta modem firmware can take some time.

  • For application updates, reset the device to activate the new firmware:

    python sm_dfu_host.py --port <serial_port> --baudrate <baud> --reset
    
  • For delta modem updates, reset the modem to apply the update:

    python sm_dfu_host.py --port <serial_port> --baudrate <baud> --modem-reset
    
  • Full modem updates handle the reset automatically.

To check if the device is operating in normal mode:

python sm_dfu_host.py --port <serial_port> --baudrate <baud> --ping

Note

Ping will return an error if the device is in bootloader mode.