IntergatedCircuits / DfuBootloader

STM32 USB device bootloader using DFU class interface
Apache License 2.0
93 stars 18 forks source link

USB firmware update. #1

Closed ghost closed 5 years ago

ghost commented 5 years ago

Hi, I'm new to STM32. I'm developing a device ith a STM32F303C MCU and I'm looking for a way to update the firmware by USB, in the easiest way possible in order to any enduser can do it (like with Arduino does: no buttons to press and connect straight to USB port). Does your DfuBootloader helps to achieve that in any way? Sorry if my questions seems silly, but I'm very lost with this.

Thanks in advance!

benedekkupper commented 5 years ago

The original DFU 1.1 specification aims to define the least intrusive way to update the device firmware, which means that the DFU interface handles not only the firmware update itself, but entering and leaving update mode as well. My DFU implementation reflects this completely. This is how DfuBootloader works: The DFU interface has a fixed memory position and layout, so it is part of the USB device in both bootloader and application mode. (Basically the bootloader's code is used in application mode as well.) In application mode the only permitted commands are status query and entry to update mode. Entry to application mode is implemented by setting a RAM flag and software reset, In update mode a new USB device shows up that only has the DFU interface mounted. The new firmware can be downloaded to the device via this interface (it can also be read back). At the end of the download a manifestation stage takes place (usually checking integrity of firmware and writing a non-volatile flag based on the result), and the new firmware is booted automatically. So when done right (e.g. how it's done on CanDybug) all it really takes is running an updater client on the host machine to get the device updated and running a newer firmware version.

The above laid out method requires the USB device to logically detach from the host. This is accomplished by disabling the 1.5kOhm pullup on the USB DP line. Since the STM32F3 line doesn't have a built-in resistor for this purpose, it is necessary to connect a resistor between DP and a 3.3V GPIO output pin (or an equivalent circuit) that is controlled by software, instead of having fixed pullup.

The DFU implementation comes in two variants:

  1. The original 1.1 specification describes a sequential firmware download, where the firmware start address is device specific, and should remain fixed for a specific USB VID:PID. This is what I personally use as this was much easier to implement for my updater client.
  2. ST has made an extension to this, so DFU version 1.1A refers to their changed implementation. This version allows and requires specifying the start address before downloading a block of firmware to the device. The descriptor string encodes the firmware's memory layout, so instead of having to match the USB VID:PID to a predefined start address, the firmware layout can determined by anyone who has USB access to the device. This allows for multiple discontinuous memory blocks to be updated.

Lastly there's infrastructure. Unfortunately they failed to assign a proper class code for DFU, which means that the DFU interface will not be automatically recognized by any host machine. Commercial products must acquire their own USB VID:PID and assign the proper driver for it. ST has two utilities, DfuSe and STM32CubeProgrammer, that have their own drivers (the latter actually uses libusb/WinUsb), but these utilities only work with ST's ROM DFU, so there's no support for entering or leaving firmware update mode via USB commands. My setup is to use Zadig to get WinUsb driver for the DFU interface, and I have implemented my own update utility based on LibUsbDotNet.

ghost commented 5 years ago

Thank you very much for your quick and detailed response! I'm going to try your DFUBootloader.

ghost commented 5 years ago

Hi again!, The MCU I'll use will be a STM32F303C, but for now I'm testing a Blue Pill (STM32F103CBT6). Does work DFUBootloader with this MCU?

benedekkupper commented 5 years ago

It doesn't work at the moment, the only reason for that is that I didn't write drivers for F1. What's missing is GPIO, RCC clock initialization and Flash drivers, the USB driver is identical to F3.