InfiniTimeOrg / pinetime-mcuboot-bootloader

An open source bootloader for the PineTime based on MyNEWT and MCUBoot.
Apache License 2.0
68 stars 18 forks source link

PineTime MCUBoot bootloader

An open source bootloader for the PineTime based on MyNEWT and MCUBoot.

About this project

This repo is based on Lupyuen's amazing work.

Lup is the very first developer to have dared to build a bootloader for the PineTime. And it was a success as version 4.1.7 was preloaded in the new batch of PineTime devkits in September 2020.

Lup uses his repo to conduct many experiments (Rust firmware, mynewt, lvgl,...). In this the, the code of the bootloader was mixed with a lot of other code, and the history was not easy to read.

That's why I decided (with his agreement) to extract the bootloader code into a shiny new project. This will ease the code readability and its maintenance.

Changes between the original repo and the "Initial commit" of this one can be seen in this fork : https://github.com/JF002/pinetime-rust-mynewt/tree/restore-factory-image.

Features

Update

Please see this page for more info about the update procedure.

Memory map

Memory Map

The PineTime is based on 2 flash memories:

Boot flow

The bootloader is the first piece of software that is running on the PineTime. Its main goal is to load the application firmware. It is also responsible to swap the firmware from the secondary and primary slot if a newer version of the firmware is present in the secondary slot. It also provides the possibility to revert to the previous version of the firmware and to restore a recovery firmware that supports OTA.

Boot flow

At startup, the bootloader displays a logo and its version:

Bootloader start

Then, it waits for ~5s in case the user presses the button. The progress is shown by the color of the logo.

When the user just wants to run the current firmware, they won't touch the button, and the logo will be filled in green:

Bootloader normal boot

When the timeout is elapsed, MCUBoot will be run. It'll swap the firmware if needed and then run the firmware from the primary slot.

If the user presses the button until the logo is drawn in blue, the previous version of the firmware will be reverted:

Bootloader revert

If the user presses the button longer, until the logo is drawn in red, the recovery firmware will be loaded into the primary slot and will be run after the next reset:

Bootloader recovery

Recovery firmware

The recovery firmware is a "lightweight" version of InfiniTime. It is stripped of most of its functionalities : it only provides basic UI, BLE connectivity and OTA.

The goal of this firmware is to provide a mean for the user to OTA a new firmware in case the current firmware does not work properly or does not provide OTA.

Bootloader recovery OTA

How to build

Bitmap generation

This project uses 2 bitmaps (defined in graphic.h) :

To reduce the amount of flash memory needed to store them, they are compressed using a simple RLE encoding.

Use the tool rle_encode.py to convert a png file into a RLE encoded buffer:

python tools/rle_encode.py --c libs/pinetime_boot/src/version-1.0.1.png

Here is the corresponding output :

// 1-bit RLE, generated from libs/pinetime_boot/src/version-1.0.1.png, 269 bytes
static const uint8_t version-1.0.1[] = {
  0x59, 0x56, 0x2, 0x56, 0x2, 0x56, 0x2, 0x56, 0x2, 0x2, 0x2, 0xd,
  0x2, 0x5, 0x4, 0x15, 0x5, 0x12, 0x4, 0xa, 0x2, 0x3, 0x2, 0xb,
  0x2, 0x4, 0x6, 0x13, 0x9, 0xe, 0x6, 0xa, 0x2, 0x3, 0x2, 0xb,
  0x2, 0x4, 0x2, 0x2, 0x2, 0x13, 0x2, 0x5, 0x2, 0xe, 0x2, 0x2,
  0x2, 0xa, 0x2, 0x3, 0x3, 0x9, 0x3, 0x8, 0x2, 0x12, 0x2, 0x7,
  0x2, 0x11, 0x2, 0xa, 0x2, 0x4, 0x2, 0x9, 0x2, 0x9, 0x2, 0x12,
  0x2, 0x7, 0x2, 0x11, 0x2, 0xa, 0x2, 0x4, 0x2, 0x9, 0x2, 0x9,
  0x2, 0x11, 0x2, 0x9, 0x2, 0x10, 0x2, 0xa, 0x2, 0x5, 0x2, 0x7,
  0x2, 0xa, 0x2, 0x11, 0x2, 0x9, 0x2, 0x10, 0x2, 0xa, 0x2, 0x5,
  0x2, 0x7, 0x2, 0xa, 0x2, 0x11, 0x2, 0x9, 0x2, 0x10, 0x2, 0xa,
  0x2, 0x5, 0x3, 0x5, 0x3, 0xa, 0x2, 0x11, 0x2, 0x9, 0x2, 0x10,
  0x2, 0xa, 0x2, 0x6, 0x2, 0x5, 0x2, 0xb, 0x2, 0x11, 0x2, 0x9,
  0x2, 0x10, 0x2, 0xa, 0x2, 0x6, 0x2, 0x5, 0x2, 0xb, 0x2, 0x11,
  0x2, 0x9, 0x2, 0x10, 0x2, 0xa, 0x2, 0x7, 0x2, 0x3, 0x2, 0xc,
  0x2, 0x11, 0x2, 0x9, 0x2, 0x10, 0x2, 0xa, 0x2, 0x7, 0x2, 0x3,
  0x2, 0xc, 0x2, 0x11, 0x2, 0x9, 0x2, 0x10, 0x2, 0xa, 0x2, 0x7,
  0x2, 0x3, 0x2, 0xc, 0x2, 0x12, 0x2, 0x7, 0x2, 0x11, 0x2, 0xa,
  0x2, 0x8, 0x2, 0x1, 0x2, 0xd, 0x2, 0x12, 0x2, 0x7, 0x2, 0x11,
  0x2, 0xa, 0x2, 0x8, 0x2, 0x1, 0x2, 0xd, 0x2, 0xa, 0x2, 0x7,
  0x2, 0x5, 0x2, 0x6, 0x2, 0xa, 0x2, 0xa, 0x2, 0x8, 0x5, 0x9,
  0xa, 0x6, 0x2, 0x7, 0x9, 0x6, 0x2, 0x6, 0xa, 0x6, 0x2, 0x9,
  0x3, 0xa, 0xa, 0x6, 0x2, 0x9, 0x5, 0x8, 0x2, 0x6, 0xa, 0x6,
  0x2, 0x56, 0x2, 0x56, 0x59,
};

You can then copy/paste this C array to the corresponding definition in graphic.h.

About the code

This project is based on MyNEWT RTOS and MCUBoot bootloader. The specific code for the PineTime is located in libs/pinetime_boot.

Patches