wasp-bootloader: a robust SoftDevice bootloader for PineTime
#1
I got chatting on pinetime IRC channel (and the many bridged rooms using other protocols) yesterday evening and the discussion swung round to bootloaders... as I think all PineTime chats must eventually do ;-). So... having been encouraged to discuss the bootloader separately from the MicroPython stuff in the other thread let me summarize what I've been doing.

The very first thing I did when I got my PineTime was extend an existing bootloader to allow me to develop without relying on SWD. In other words I wanted my watch to be capable of BLE OTA updates *and* robust enough that it was difficult (although not impossible) for a broken application to lock me out of my watch.

https://github.com/daniel-thompson/wasp-bootloader

This is derived from the Adafruit nRF52 bootloader used on some of their feather boards.


The main changes are:
  • It uses the PineTime display rather than LEDs to share status with the user
  • It shows a nice pine logo as a splash screen ;-)
  • It preconfigures the watchdog timer with a fairly generous (5 second) timeout
  • It automatically enters OTA DFU mode on a watchdog reset
It is designed to pair with a special WDT feeding routine in the application. In C-ish pseudo-code it would look like the below. Note that writing button_tamper_check_ok() is a work-in-progress. It is very hard to tamper check on an nRF52 because the pin control is decentralized; we have to tour most of the peripherals and check it hasn't tried to "steal" pin 13 or pin 15 (for now I have just been careful when writing code to activate a new peripheral):


Code:
void feed_wdt(void) {
if (button_tamper_check_ok() && !button_pressed())
nrf_wdt_reload_request_set(0);
}

The recommendation is to setup a periodic interrupt (for a 5 second timeout this needs to be roughly every second) in the application and feed the watchdog from it. Normally it is not a great idea to feed a WDT exclusively from an interrupt (unless it implements a soft watchdog) but because the button press can be used to inhibit the feeding of the watchdog then this  essentially implements a long-press reset instead of a traditional watchdog.

The bootloader should work well for any SoftDevice based application providing the version numbers align (currently using S132 6.1.1). In principle it can also support other applications but the SoftDevice uses so much FLASH I think it would not be very practical. Various people on the chat caught me up on the discussions at FOSDEM and a bootloader needs to get a lot more sophisticated if we are to support OTA updates where the payload can use an "arbitrary" BLE stack.

However if you are already using SoftDevice this bootloader should work well... to use it all you have to do is relink you application with the flash size set 24K shorter.

At present the only missing robustness feature (that I have thought off) is providing deep sleep support. At present it is easy for an application to enter deep sleep without setting up a suitable wake up source. If that happens the WDT gets disabled and, worse, the system will use so little power that I suspect it could take over a month for battery to run out and make it possible to reboot the watch. Note that I don't think it is practical to prevent the app from sleeping but we can provide a bootloader service to set up a deep sleep in a safe and well tested way so the application can use that instead.

[Use this direct link if the forum video embedding doesn't work for you: https://www.youtube.com/watch?v=W0CmqOnl4jk ]

PineTime: wasp-os and MicroPython, Pinebook Pro:  Debian Bullseye
#2
Hi @danielt ,

I've finally some free-time, and I would like to test your wasp-bootloader, see how it works and maybe adapt my firmware to be compatible with OTA using wasp-bootloader.

I've managed to build and program the bootloader on my pinetime. Now, I would like to build an image I can send to program my firmware on my pinetime.

Could you give me some info on how to achieve this? How do you create the image? Is it just a zip file containing the HEX/BIN file?
And how do you program it? In your video, it seems you are using NRFConnect? Is there a desktop application that I can use to transfer the image?

EDIT : I found that one can create a DFU image using adafruit-nrfutil:
Code:
$ adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application pinetime-app.hex dfu.zip

Then, this image can be sent to the pinetime running the booloader using NRFConnect (smartphone app).

So far so good, it works as long as the application uses the same BLE stack as the bootloader (which is the case of my firwmare).

Thanks!
Working on InfiniTime, the FOSS firmware for the PineTime: https://github.com/InfiniTimeOrg/InfiniTime

Mastodon : https://mastodon.codingfield.com/@JF
Twitter : https://twitter.com/codingfield
Matrix : @JF002:matrix.org
#3
Here is a quick update on what I've found these last 2 days. These are mostly random notes I've taken while discovering how it's working. I hope they will be useful to anyone wanting to work on OTA updates and DFU Wink


My firmware (https://github.com/JF002/Pinetime) works out of the box with wasp-bootloader. This is because they are built around the same version of Noric's BLE SoftDevice (BLE stack).


@SteveA (on the chat) tried his own firmware (https://github.com/xriss/timecake, which does not use the SoftDevice) without success for now : the bootloader just resets every 1/2 second.


I've also tried to run @Koen's (on the chat too) firmware (https://github.com/bosmoment/PineTime-apps) with no much luck either. This firmware uses Nimble bluetooth stack. I did some modification to the code and the linker script but it would also reset every 500ms. A quick analysis on GDB showed me that it would hardfault in cortex_vector_base() which is pretty bad...


I don't know what causes this issue. It could be a conflict with the softdevice and Nimble, as they both try to drive the BLE radio.
Also, the softdevice is accompanied by an MBR : a small block of code the receives all the IRQ and forward them to the bootloader, softdevice and the application. And I really don't know what happens when the MBR expect the softdevice to be there, but it's not there because the application does not use it...


On the technical side, wasp-bootloader uses GPRERET (General Purpose Retention registers) and UICR (User Information Configuration Register) to store state and other info even when the MCU is reset. It also provides a factory reset option, which is a quite good idea!


Here is the general workflow of the wasp-bootloader:
  • Init board (watchdog, buttons, leds, task scheduler, timer and display)
  • Init bootloader (from the lib nrf_bootloader, provided by NRF52-SDK)
  • Init SoftDevice
  • Start DFU and wait for completion / error / timeout
  • Disable Softdevice
  • Teardown board peripheral
  • If there is a valid image : Jump to the image code
  • else reset and start again

Some links:
Working on InfiniTime, the FOSS firmware for the PineTime: https://github.com/InfiniTimeOrg/InfiniTime

Mastodon : https://mastodon.codingfield.com/@JF
Twitter : https://twitter.com/codingfield
Matrix : @JF002:matrix.org
#4
Thanks for the update. Very interesting. You may be onto something with the MBR. It is definitely important to check what is happening with the interrupt vectors on the other programs.

wasp-bootloader was pretty much the first bit of PineTime software I wrote. At the time I was assuming we'd end up with a bootloader per bluetooth stack that runs on PineTime (maybe with some common library code for all bootloaders to run an update from RAM and SPI flash to make swapping stacks possible) and I hoped wasp-bootloader would be useful for any softdevice based software. The concepts might be interesting for other BLE stacks but ultimately I think softdevice consumes too much flash to be used only by a bootloader.

Note there are other possible approaches to PineTime bootloaders so we don't need a different bootloader for each BLE stack (small shim that loads BLE stack from SPI flash for example) but I haven't yet seen quite how to make that type of bootloader work alongside the MBR

Anyhow, in the coming weeks I'm planning to write a payload for wasp-bootloader that allows us to update the bootloader and softdevice over-the-air. Initially I'll run it from flash but I would like to try running it from RAM since they makes it much easier if/when the flash footprint of the softdevice changes.
PineTime: wasp-os and MicroPython, Pinebook Pro:  Debian Bullseye


Possibly Related Threads…
Thread Author Replies Views Last Post
  Develop a new firmware for PineTime belushi 2 1,282 09-25-2023, 12:32 PM
Last Post: ccchan234
  Bluetooth BLE-MIDI-controller app for PineTime / InfiniTime Luno 0 500 08-20-2023, 05:17 AM
Last Post: Luno
  Zephyr Backlight Examples for PineTime lcj 0 691 05-06-2023, 02:54 PM
Last Post: lcj
  Zephyr is ready for pinetime jandy 1 2,075 05-06-2023, 02:15 PM
Last Post: lcj
  Send a message from Android to pinetime via BLE razrosman 0 905 11-05-2022, 08:24 AM
Last Post: razrosman
  PineTime Stuck in DFU Mode Eesha Barua 1 2,000 07-25-2022, 09:17 PM
Last Post: heyhewmike
  Idle tracking with PineTime: how versatile it is? schaman 1 1,613 07-13-2022, 12:50 AM
Last Post: wibble
  PineTime implemented with partial of pebble API jandy 0 1,535 03-20-2022, 08:58 PM
Last Post: jandy
  "Pine64 USB JTAG Adapter + OpenOCD + PineTime" should it work? ITCactus 4 3,876 03-02-2022, 05:58 AM
Last Post: wibble
  Zephyr based Pinetime jandy 4 4,634 11-11-2021, 05:53 AM
Last Post: jandy

Forum Jump:


Users browsing this thread: 1 Guest(s)