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:
Fri Nov 25 19:17:45 2016 +0000
Revision:
10:b4ca1a86e204
Parent:
8:6782a1b0dc86
Update libraries

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 8:6782a1b0dc86 3 #include "WebUSBDFU.h"
devanlai 5:88b6ced3df89 4 /*
devanlai 8:6782a1b0dc86 5 * This is an example program demonstrating a WebUSB DFU runtime that can be
devanlai 8:6782a1b0dc86 6 * combined with a bootloader that does not require an offset.
devanlai 5:88b6ced3df89 7 *
devanlai 5:88b6ced3df89 8 * It normally blinks an LED at 1Hz, but when it receives a DFU detach
devanlai 8:6782a1b0dc86 9 * request over USB, it blinks 3 times rapidly and resets into the bootloader.
devanlai 8:6782a1b0dc86 10 *
devanlai 8:6782a1b0dc86 11 * The companion bootloader source and prebuilt binaries can be found on GitHub:
devanlai 8:6782a1b0dc86 12 * https://github.com/devanlai/dapboot/tree/highboot
devanlai 8:6782a1b0dc86 13 * https://github.com/devanlai/dapboot/releases/tag/v0.1
devanlai 5:88b6ced3df89 14 *
devanlai 8:6782a1b0dc86 15 * On Chrome 54 and later (or Chrome 52 with certain flags set), the browser can
devanlai 8:6782a1b0dc86 16 * access the application / bootloader to directly upload new firmware.
devanlai 5:88b6ced3df89 17 *
devanlai 8:6782a1b0dc86 18 * The generic WebUSB dfu-util demo is available here:
devanlai 8:6782a1b0dc86 19 * https://devanlai.github.io/webdfu/dfu-util/
devanlai 8:6782a1b0dc86 20 *
devanlai 8:6782a1b0dc86 21 * An experimental demo to build and download mbed binaries over WebUSB is available here:
devanlai 8:6782a1b0dc86 22 * https://devanlai.github.io/webdfu/mbed-download/
devanlai 6:2f7ee2af27f9 23 *
devanlai 5:88b6ced3df89 24 */
hudakz 0:0279e8c1f111 25
hudakz 0:0279e8c1f111 26 DigitalOut myled(LED1);
hudakz 0:0279e8c1f111 27
devanlai 5:88b6ced3df89 28 bool detached = false;
devanlai 5:88b6ced3df89 29 void onDetachRequested() {
devanlai 5:88b6ced3df89 30 detached = true;
devanlai 5:88b6ced3df89 31 }
devanlai 5:88b6ced3df89 32
devanlai 5:88b6ced3df89 33 void resetIntoBootloader() {
devanlai 5:88b6ced3df89 34 // Turn on write access to the backup registers
devanlai 5:88b6ced3df89 35 __PWR_CLK_ENABLE();
devanlai 5:88b6ced3df89 36 HAL_PWR_EnableBkUpAccess();
devanlai 5:88b6ced3df89 37
devanlai 5:88b6ced3df89 38 // Write the magic value to force the bootloader to run
devanlai 5:88b6ced3df89 39 BKP->DR2 = 0x544F;
devanlai 5:88b6ced3df89 40 BKP->DR1 = 0x4F42;
devanlai 5:88b6ced3df89 41
devanlai 5:88b6ced3df89 42 HAL_PWR_DisableBkUpAccess();
devanlai 5:88b6ced3df89 43
devanlai 5:88b6ced3df89 44 // Reset and let the bootloader run
devanlai 5:88b6ced3df89 45 NVIC_SystemReset();
devanlai 5:88b6ced3df89 46 }
devanlai 5:88b6ced3df89 47
hudakz 0:0279e8c1f111 48 int main() {
hudakz 3:dd01afd4f893 49 confSysClock(); //Configure system clock (72MHz HSE clock, 48MHz USB clock)
hudakz 4:00ccc80cbeb8 50
devanlai 8:6782a1b0dc86 51 /* Note: 1209:0001 is a test VID/PID pair - it should be changed before using in
devanlai 8:6782a1b0dc86 52 * a real application */
devanlai 8:6782a1b0dc86 53 WebUSBDFU usbDFU(0x1209, 0x0001, 0x0001, false);
devanlai 5:88b6ced3df89 54 usbDFU.attach(onDetachRequested);
hudakz 0:0279e8c1f111 55
hudakz 0:0279e8c1f111 56 while(1) {
devanlai 5:88b6ced3df89 57 // Check the DFU status
devanlai 5:88b6ced3df89 58 if (!usbDFU.configured()) {
devanlai 5:88b6ced3df89 59 usbDFU.connect(false);
devanlai 5:88b6ced3df89 60 }
devanlai 5:88b6ced3df89 61 if (detached) {
devanlai 8:6782a1b0dc86 62 for (int i=0; i < 3; i++) {
devanlai 5:88b6ced3df89 63 myled = 1;
devanlai 5:88b6ced3df89 64 wait_ms(100);
devanlai 5:88b6ced3df89 65 myled = 0;
devanlai 5:88b6ced3df89 66 wait_ms(100);
devanlai 5:88b6ced3df89 67 }
devanlai 5:88b6ced3df89 68 resetIntoBootloader();
devanlai 5:88b6ced3df89 69 }
devanlai 5:88b6ced3df89 70
devanlai 5:88b6ced3df89 71 // Do normal stuff
hudakz 0:0279e8c1f111 72 myled = !myled;
devanlai 8:6782a1b0dc86 73 wait_ms(500);
hudakz 0:0279e8c1f111 74 }
hudakz 0:0279e8c1f111 75 }
hudakz 0:0279e8c1f111 76