Flash utility ‘dfu-util’ gotcha: Always use option ‘-a 0’

dfu-util can be used to both read off and to flash (update) firmware on embedded devices, say for the firmware on a QMK-based keyboard like the Keychron V5 (about 50 KB). But it is very poorly documented. In most cases, the option “-a 0” must be included.

The problem

An unintrusive first try is to read off the firmware:

dfu-util -U someKeychronV5firmwareVersion.bin

But this results in:

dfu-util: More than one DFU capable USB device
found! Try `--list' and specify the serial
number or disconnect all but one device

But this is a totally misleading error message… There is only one DFU device connected (and in DFU mode). This is confirmed by using the -l parameter to discover the DFU devices:

dfu-util -l

Output:

dfu-util 0.9

Found DFU: [0483:df11] ver=2200, devnum=7, cfg=1, intf=0, path="3-1", alt=3, name="@Device Feature/0xFFFF0000/01*004 e", serial="205C32845242"
Found DFU: [0483:df11] ver=2200, devnum=7, cfg=1, intf=0, path="3-1", alt=2, name="@OTP Memory /0x1FFF7000/01*0001Ke", serial="205C32845242"
Found DFU: [0483:df11] ver=2200, devnum=7, cfg=1, intf=0, path="3-1", alt=1, name="@Option Bytes  /0x1FFF7800/01*040 e", serial="205C32845242"
Found DFU: [0483:df11] ver=2200, devnum=7, cfg=1, intf=0, path="3-1", alt=0, name="@Internal Flash  /0x08000000/0128*0002Kg", serial="205C32845242"

The serial number, 205C32845242, is exactly the same for all four lines. The four are (directly from the output):

Area Start address Size Alt
Device Feature 0xFFFF0000 01*004 e alt=3
OTP Memory 0x1FFF7000 01*0001Ke alt=2
Option Bytes 0x1FFF7800 01*040 e alt=1
Internal Flash 0x08000000 0128*0002Kg alt=0

The size is in a cryptic format. In this case, it is known the microcontroller is STM32L432 and the flash size is 128 KB (output as “0128*0002Kg”).

A distinguishing field is the “alt” field.

The documentation is in the usual cryptic style: “Specify the altsetting of the DFU interface by name or by number.”

The solution

It is not documented (or at least very indirectly and cryptically), but the “-a” option must be used. In this case, “-a 0” as the flash part has “alt=0” (the “alt” in the output correspond).

For reading off the firmware:

dfu-util -a 0 -s 0x08000000:0x20000 -U someKeychronV5firmwareVersion.bin

For flashing:

dfu-util -a 0 --dfuse-address 0x08000000 -D keychron_v5_iso_encoder_keychron_standardMacros.bin

Output, respectively (note that “upload” is using the convention from embedded devices where it is seen from the device’s perspective – upload from the device to host (computer) for reading off the flash memory):

dfu-util 0.9

Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
Limiting default upload to 16384 bytes
Upload	[=========================] 100%        16384 bytes
Upload done.
dfu-util 0.11

Match vendor ID from file: 0483
Match product ID from file: df11
Opening DFU capable USB device...
Device ID 0483:df11
Device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(10) = dfuERROR, status(10) = Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations
Clearing status
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash  "
Downloading element to address = 0x08000000, size = 48076
Erase   	[=========================] 100%        48076 bytes
Erase    done.
Download	[=========================] 100%        48076 bytes
Download done.
File downloaded successfully

A bonus: Relieve strain on the USB cables…

By default, dfu-util will leave the device in bootloader mode after flashing. To avoid having to power cycle the device, use modifier “:leave” in the argument for –dfuse-address:

dfu-util -a 0 --dfuse-address 0x08000000:leave -D keychron_v5_iso_encoder_keychron_standardMacros.bin

Installing dfu-util

dfu-util has probably been installed as part of installing QMK (it is part of the dependencies for it), but on a pristine system, it can installed by:

sudo apt-get install dfu-util

It can also be installed from source (near “without a dfu-util package”).

Leave a Reply

Your email address will not be published. Required fields are marked *

*