1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

bootloaders: add riotboot_tinyusb_dfu bootloader

This commit is contained in:
Gunar Schorcht 2022-11-24 15:13:43 +01:00
parent 37b151111f
commit a4f870f25b
3 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,19 @@
# Default RIOT bootloader
APPLICATION = riotboot_tinyusb_dfu
# Add RIOTBOOT tinyUSB DFU integration
USEMODULE += riotboot_tinyusb_dfu
# Use xtimer for scheduled reboot
USEMODULE += ztimer
USEMODULE += ztimer_init
# USB device vendor and product ID
# pid.codes test VID/PID, not globally unique
# The VID/PID pair allocated for the RIOT bootloader
# as allocated on https://pid.codes/1209/7D02/
USB_VID ?= 1209
USB_PID ?= 7D02
include ../riotboot_common.mk

View File

@ -0,0 +1,86 @@
/**
@defgroup pkg_tinyusb_dfu riotboot tinyUSB DFU
@ingroup pkg_tinyusb
@ingroup bootloaders
# Overview
`riotboot_tinyusb_dfu` is a variation of @ref bootloader_riotboot that adds
USB device firmware upgrade (DFU) based on the tinyUSB device stack package.
It uses a board's USB interface to allow firmware upgrades from inside the
bootloader.
At startup, the DFU mode is entered when either
- none of the slots contains a valid firmware image, or
- the first button was pressed when the board started (configurable at board
level using @ref BTN_BOOTLOADER_PIN), or
- the last running firmware asked the bootloader to go to DFU mode by using a
magic number (see @ref RIOTBOOT_MAGIC_ADDR).
# Prerequisites
- The board must have functional USB support and has to support the
`tinyusb_device` feature.
- The board must have functional `riotboot` support, see
@ref bootloader_riotboot.
# Flashing riotboot_tinyusb_dfu
The `riotboot_tinyusb_dfu` bootloader can be flashed using a regular programmer
like any other application:
```
$ make -C bootloaders/riotboot_tinyusb_dfu BOARD=... all flash
```
Depending on your setup, you may need to select the right `PROGRAMMER`
(and its details) in addition to your board.
# DFU mode
A device in riotboot DFU mode can be recognized in the USB device list by
its VID/PID pair 1209:7d02:
```
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 138a:003f [...]
Bus 001 Device 004: ID 8087:0a2b [...]
Bus 001 Device 045: ID 1209:7d02 Generic USB device
Bus 001 Device 001: ID 1d6b:0002 [...]
```
When running in DFU mode, the bootloader allows writing to either of the
two firmware slots.
When the device is attached and in DFU mode (or the current firmware uses the
`tinyusb_dfu` module), new firmware can be flashed to slot 0 using:
```
$ FEATURES_REQUIRED+=riotboot USEMODULE+=tinyusb_dfu make -C examples/saul BOARD=particle-xenon \
PROGRAMMER=dfu-util USB_VID=1209 USB_PID=7d02 all riotboot/flash-slot0
```
Instead of setting `USB_VID` and `USB_PID`, the variable `DFU_USB_ID` could also
be used to specify the DFU device to be used.
```
$ FEATURES_REQUIRED+=riotboot USEMODULE+=tinyusb_dfu make -C examples/saul BOARD=particle-xenon \
PROGRAMMER=dfu-util DFU_USB_ID=1209:7d02 all riotboot/flash-slot0
```
Note that when building and flashing a different slot (e.g. `flash-slot1`),
not only is the image built for that slot, but also `dfu-util` gets passed
`--alt 1` (via the `DFU_ALT` build variable) to store it in the right place.
# Entering DFU mode
When RIOT applications are built with `USEMODULE=tinyusb_dfu`,
they implement what is called "runtime mode" in DFU.
In runtime mode, it is visible to the `dfu-util` that they are upgradable.
On firmware upgrades, the build system can send a command via USB to enter
DFU mode. This can also be done manually using `dfu-util -e`.
*/

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
* Inria
* 2020 Mesotic SAS
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup bootloaders
* @{
*
* @file
* @brief RIOT-based bootloader with USB-DFU support
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
* @author Dylan Laduranty <dylan.laduranty@mesotic.com>
*
* @}
*/
#include "cpu.h"
#include "panic.h"
#include "riotboot/slot.h"
#include "riotboot/usb_dfu.h"
#include "ztimer.h"
#include "riotboot/bootloader_selection.h"
#ifdef BTN_BOOTLOADER_PIN
#include "periph/gpio.h"
#endif
static bool _bootloader_alternative_mode(void)
{
#ifdef BTN_BOOTLOADER_PIN
gpio_init(BTN_BOOTLOADER_PIN, BTN_BOOTLOADER_MODE);
return (bool)gpio_read(BTN_BOOTLOADER_PIN) != BTN_BOOTLOADER_INVERTED;
#else
return false;
#endif
}
void kernel_init(void)
{
uint32_t version = 0;
int slot = -1;
for (unsigned i = 0; i < riotboot_slot_numof; i++) {
const riotboot_hdr_t *riot_hdr = riotboot_slot_get_hdr(i);
if (riotboot_slot_validate(i)) {
/* skip slot if metadata broken */
continue;
}
if (riot_hdr->start_addr != riotboot_slot_get_image_startaddr(i)) {
continue;
}
if (slot == -1 || riot_hdr->version > version) {
version = riot_hdr->version;
slot = i;
}
}
/* Init ztimer before starting DFU mode */
ztimer_init();
/* Flash the unused slot if magic word is set */
riotboot_usb_dfu_init(0);
if (slot != -1 && !_bootloader_alternative_mode()) {
riotboot_slot_jump(slot);
}
/* Nothing to boot, stay in DFU mode to flash a slot */
riotboot_usb_dfu_init(1);
}
NORETURN void core_panic(core_panic_t crash_code, const char *message)
{
(void)crash_code;
(void)message;
while (1) {}
}