Blinky example with WebUSB Device Firmware Upgrade (DFU) detach support for use with a no-offset bootloader.

Dependencies:   USBDevice_STM32F103 mbed-STM32F103C8T6 mbed

Fork of STM32F103C8T6_USBDFU by Devan Lai

Overview

This is an experimental sample program demonstrating support for reprogramming an mbed-compatible device using WebUSB instead of the traditional drag'n'drop step. It is in the early stages of development and is currently very user-unfriendly.

Dependencies

This example currently has some very particular requirements:

  • You must have Chrome 54 or later, which has experimental WebUSB support enabled on select sites through origin trials.
  • Only one target board is currently supported, the STM32F103C8 "bluepill" board.
  • The target board must be initially flashed with a custom bootloader that has WebUSB support and doesn't require a linker offset for the application.

Architecture

There are three main components to this example:

  1. A WebUSB-enabled USB DFU bootloader that can accept and flash new firmware over USB
  2. The main application with USB DFU support that can receive a USB command to switch into DFU mode (aka, this example program)
  3. A website with WebUSB support that can send USB DFU commands to approved USB devices.

Workflow without mbed integration

This workflow effectively takes the normal USB DFU upgrade process and enables the user to use a browser instead of a native program like dfu-util. Note that this is still fully compatible with dfu-util.

During normal operation, the bootloader runs the main application, just like any other program. When the user wants to reprogram the board, the following steps occur:

  1. The user plugs the board in over USB
  2. The main application declares USB DFU and WebUSB support as part of the USB enumeration process. As part of declaring WebUSB support, the device also presents a whitelist specifying exactly which https origins can access it.
  3. Chrome detects WebUSB support and prompts the user to visit the corresponding website
  4. After navigating to the website, the site requests access to the board, which the user can grant or deny.
  5. To enable flashing new firmware, the website can send a DFU detach command to switch into the DFU bootloader
  6. Because the bootloader appears as a different USB device, the user must also approve access to the board in bootloader mode
  7. The user can select a local file from disk and download it to the board over DFU
  8. After successfully flashing the firmware, the bootloader resets and the new application runs.

After the user grants access to the board, the approval popup in steps 4 and 6 should no longer appear.

Workflow with some mbed integration

The mbed compile API allows access to remotely build mbed programs. This can be used to enable a user to authenticate with mbed, and then build and download mbed programs directly from the browser.

The steps are similar to above, but with a different webpage that uses the mbed compile API to build a program and uses the compiled output as an input to the DFU download instead of selecting a previously built local binary.

Limitations

It currently only supports HTTP basic auth, so credentials must entered every time. There's also no way to enumerate which programs / target boards the user has, so the program and target board must be manually specified. Right now, the program is hard-coded to this example program and the STM32F103 target board.

Future Plans

HDK support

Instead of using a WebUSB-enabled DFU bootloader (which I used only because I already had a DFU bootloader lying around), the mbed HDK CMSIS-DAP/DAPLink firmware could be extended to add a new WebUSB interface. The website could then talk to the mbed HDK chip to flash the firmware onto the target board. This would allow any mbed-enabled board to flash firmware via WebUSB without any changes to the target program (and without requiring native USB support).

IDE integration

The end-goal, of course, would be to integrate WebUSB support into the official mbed IDE (or at least a reasonably functional demo-equivalent) to allow the user to flash boards directly from the online IDE without going through the extra drag'n'drop step

Committer:
devanlai
Date:
Mon Aug 29 01:30:30 2016 +0000
Revision:
5:88b6ced3df89
Parent:
4:00ccc80cbeb8
Child:
6:2f7ee2af27f9
Add initial USB DFU blinky example

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:0279e8c1f111 1 #include "stm32f103c8t6.h"
hudakz 0:0279e8c1f111 2 #include "mbed.h"
devanlai 5:88b6ced3df89 3 #include "USBDFU.h"
devanlai 5:88b6ced3df89 4
devanlai 5:88b6ced3df89 5 /*
devanlai 5:88b6ced3df89 6 * This is an example program demonstrating a USB DFU runtime combined with
devanlai 5:88b6ced3df89 7 * a USB DFU bootloader that does not require an offset.
devanlai 5:88b6ced3df89 8 *
devanlai 5:88b6ced3df89 9 * It normally blinks an LED at 1Hz, but when it receives a DFU detach
devanlai 5:88b6ced3df89 10 * request over USB (eg, by running "dfu-util -d 1234:0006 -e"), it
devanlai 5:88b6ced3df89 11 * blinks 3 times rapidly and resets into the bootloader.
devanlai 5:88b6ced3df89 12 *
devanlai 5:88b6ced3df89 13 * New programs can be uploaded by running
devanlai 5:88b6ced3df89 14 * dfu-util -d 1234:0006,1209:db42 -D your_firmware.bin
devanlai 5:88b6ced3df89 15 *
devanlai 5:88b6ced3df89 16 */
hudakz 0:0279e8c1f111 17
hudakz 0:0279e8c1f111 18 DigitalOut myled(LED1);
hudakz 0:0279e8c1f111 19
devanlai 5:88b6ced3df89 20 bool detached = false;
devanlai 5:88b6ced3df89 21 void onDetachRequested() {
devanlai 5:88b6ced3df89 22 detached = true;
devanlai 5:88b6ced3df89 23 }
devanlai 5:88b6ced3df89 24
devanlai 5:88b6ced3df89 25 void resetIntoBootloader() {
devanlai 5:88b6ced3df89 26 // Turn on write access to the backup registers
devanlai 5:88b6ced3df89 27 __PWR_CLK_ENABLE();
devanlai 5:88b6ced3df89 28 HAL_PWR_EnableBkUpAccess();
devanlai 5:88b6ced3df89 29
devanlai 5:88b6ced3df89 30 // Write the magic value to force the bootloader to run
devanlai 5:88b6ced3df89 31 BKP->DR2 = 0x544F;
devanlai 5:88b6ced3df89 32 BKP->DR1 = 0x4F42;
devanlai 5:88b6ced3df89 33
devanlai 5:88b6ced3df89 34 HAL_PWR_DisableBkUpAccess();
devanlai 5:88b6ced3df89 35
devanlai 5:88b6ced3df89 36 // Reset and let the bootloader run
devanlai 5:88b6ced3df89 37 NVIC_SystemReset();
devanlai 5:88b6ced3df89 38 }
devanlai 5:88b6ced3df89 39
hudakz 0:0279e8c1f111 40 int main() {
hudakz 3:dd01afd4f893 41 confSysClock(); //Configure system clock (72MHz HSE clock, 48MHz USB clock)
hudakz 4:00ccc80cbeb8 42
devanlai 5:88b6ced3df89 43 USBDFU usbDFU(0x1234, 0x0006, 0x0001, false);
devanlai 5:88b6ced3df89 44 usbDFU.attach(onDetachRequested);
hudakz 0:0279e8c1f111 45
hudakz 0:0279e8c1f111 46 while(1) {
devanlai 5:88b6ced3df89 47 // Check the DFU status
devanlai 5:88b6ced3df89 48 if (!usbDFU.configured()) {
devanlai 5:88b6ced3df89 49 usbDFU.connect(false);
devanlai 5:88b6ced3df89 50 }
devanlai 5:88b6ced3df89 51 if (detached) {
devanlai 5:88b6ced3df89 52 for (int i=0; i < 5; i++) {
devanlai 5:88b6ced3df89 53 myled = 1;
devanlai 5:88b6ced3df89 54 wait_ms(100);
devanlai 5:88b6ced3df89 55 myled = 0;
devanlai 5:88b6ced3df89 56 wait_ms(100);
devanlai 5:88b6ced3df89 57 }
devanlai 5:88b6ced3df89 58 resetIntoBootloader();
devanlai 5:88b6ced3df89 59 }
devanlai 5:88b6ced3df89 60
devanlai 5:88b6ced3df89 61 // Do normal stuff
hudakz 0:0279e8c1f111 62 myled = !myled;
hudakz 0:0279e8c1f111 63 wait_ms(1000);
hudakz 0:0279e8c1f111 64 }
hudakz 0:0279e8c1f111 65 }
hudakz 0:0279e8c1f111 66