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