Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: InfiniTimeOrg/pinetime-mcuboot-bootloader
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: RC1
Choose a base ref
...
head repository: InfiniTimeOrg/pinetime-mcuboot-bootloader
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 19 commits
  • 25 files changed
  • 2 contributors

Commits on Dec 26, 2020

  1. Copy the full SHA
    16e5b05 View commit details

Commits on Jan 2, 2021

  1. Copy the full SHA
    3fae264 View commit details

Commits on Jan 3, 2021

  1. Prevent watchdog reset during bootloader operations by feeding the wd…

    …t during transfer of the recovery firmware and during mcuboot processing.
    
    This is needed because the bootloader is NOT disabled by a softreset (NVIC_systemReset()) or by a reset via the debug interface.
    JF002 committed Jan 3, 2021
    Copy the full SHA
    a6aeafc View commit details
  2. Set version to 0.0.1.

    Add tool to convert png to RLE encoded buffer from wasp-os.
    JF002 committed Jan 3, 2021
    Copy the full SHA
    a2d2f93 View commit details
  3. Merge pull request #1 from JF002/develop

    Develop
    JF002 authored Jan 3, 2021
    Copy the full SHA
    53918c7 View commit details

Commits on Jan 25, 2021

  1. Export the version of the bootloader to the application.

    Set version to 1.0.0
    JF002 committed Jan 25, 2021
    Copy the full SHA
    49d9794 View commit details
  2. Copy the full SHA
    d2a0878 View commit details

Commits on Jan 26, 2021

  1. Merge pull request #2 from JF002/develop

    Export the version of the bootloader to the application.
    JF002 authored Jan 26, 2021
    Copy the full SHA
    2e1a66e View commit details

Commits on Sep 4, 2024

  1. Copy the full SHA
    46c1fd8 View commit details
  2. Copy the full SHA
    ab693a1 View commit details
  3. Copy the full SHA
    5128b32 View commit details
  4. Update the link to the video showing how to update the bootloader (th…

    …e previous one was not playing correctly).
    JF002 committed Sep 4, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    066015a View commit details
  5. Fix memory map (according to this issue in InfiniTime : InfiniTimeOrg…

    …/InfiniTime#1472) and add more information about the sections in the internal memory.
    JF002 committed Sep 4, 2024
    Copy the full SHA
    83e4b24 View commit details
  6. Copy the full SHA
    14a6db8 View commit details
  7. Add support for the new SPI flash memory chip (BY25Q32).

    PineStore notified the community that the SPI flash memory chip (XTX XT25F32B) used in the PineTime was EoL (End-Of-Life) and will be replaced by another chip (BY25Q32).
    
    Since we want to provide a new version of the firmware (bootloader + application) in a short time frame to avoid the production of the next batch of PineTime being delayed, we did our best to add support for the new chip by doing the smallest and less risky changes possible.
    
    The version of MyNewt this project is based on (1.8.0) do not support any of the memory chips out of the box. The current version defines the JEDEC IDs in the [NRF52 "BSP"](hw/bsp/nrf52/syscfg.yml). The downside of this way of specifying the IDs of the chip is that you can only define a single chip. Newer versions of MyNewt allow to ignore the ID, but this is not available in our version.
    
    These changes patches the spiflash driver of MyNewt to add support for both memory chip, and enable them so that the system checks for both IDs at startup.
    JF002 committed Sep 4, 2024
    Copy the full SHA
    2c75463 View commit details
  8. Set the brightness to the lowest level

    This should help prevent devices with fully depleted battery from bootlooping.
    JF002 committed Sep 4, 2024
    Copy the full SHA
    a9d4d96 View commit details
  9. Add support for the new SPI flash memory chip (BY25Q32).

    Add description of the patch in README.md
    JF002 committed Sep 4, 2024
    Copy the full SHA
    b6b8d4d View commit details
  10. Update version to 1.0.1

    Add doc about the generation of the version bitmap
    JF002 committed Sep 4, 2024
    Copy the full SHA
    ae02f94 View commit details
  11. Ensure that all 3 pins controlling the backlight are set to specific …

    …values : LOW is set to 0 (enable) and MEDIUM/HIGH are set to 1 (disable).
    JF002 committed Sep 4, 2024
    Copy the full SHA
    ce0b45c View commit details
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -48,4 +48,3 @@ libusb*/
hidapi*/
.idea/*

/reloader/
64 changes: 61 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -20,17 +20,26 @@ Changes between the original repo and the "Initial commit" of this one can be se
- Load and run a **recovery** firmware
- Basic UI (logo, progress bar, button)

## Update

Please see [this page](docs/howToUpdate.md) for more info about the update procedure.

## Memory map

![Memory Map](docs/pictures/memoryMap.png "Memory map")

The PineTime is based on 2 flash memories:
- **The internal flash** (512KB) : this flash is integrated into the MCU. The MCU runs the code from this memory. It cannot run codes directly from the external SPI flash memory. This internal memory contains the bootloader code as well as the application firmware. The scratch area is used by MCUBoot to swap firmwares from internal and external memories.
- **The external** flash (4MB) : this memory is external to the MCU and is connected to the MCU using an SPI bus. It contains the recovery firmware (in the section *Bootloader Assets*) and the secondary slot for MCUBoot (*OTA section*). The *FS* part is available for the application firmware.
- **The internal flash** (512KB) : this flash is integrated into the MCU. The MCU runs the code from this memory. It cannot run codes directly from the external SPI flash memory. It contains the following sections:
- **Bootloader** (28KB - 0x7000B) : This bootloader.
- **Log** (4KB - 0x1000B) : Space reserved for boot/error logs. Not currently useed.
- **Application firmware** (464KB - 0x74000B) : application wrapped into a MCUBoot image (header, TLV, trailer).
- **Scrach** (4KB - 0x1000B) : the scratch area that allows MCUBoot to swap firmware between the internal and external memories.
- **Spare** (12KB - 0x3000B) : a spare and unused area.
- **The external** flash (4MB) : this memory is external to the MCU and is connected to the MCU using an SPI bus. It contains the recovery firmware (in the section *Bootloader Assets*) and the secondary slot for MCUBoot (*OTA section*). The *FS* part is available for the application firmware.

## Boot flow

The bootloader is the first piece of software that is running on the PineTime. It's 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.
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](docs/pictures/workflow.png "Boot flow")

@@ -72,8 +81,57 @@ The goal of this firmware is to provide a mean for the user to OTA a new firmwar
- Configure mynewt : `newt upgrade`
- Build : `scripts/nrf52/build-boot.sh`. The firmware is generated in `bin/targets/nrf52_boot/app/@mcuboot/boot/mynewt/mynewt.elf` and the DFU file for the reloader : `reloader/build-pinetime/reloader-mcuboot.zip`

### Bitmap generation

This project uses 2 bitmaps (defined in [graphic.h](libs/pinetime_boot/src/graphic.h)) :
- the Pine logo
- the version indicator

To reduce the amount of flash memory needed to store them, they are compressed using a simple [RLE encoding](https://en.wikipedia.org/wiki/Run-length_encoding).

Use the tool [rle_encode.py](tools/rle_encode.py) to convert a png file into a RLE encoded buffer:

```shell
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](libs/pinetime_boot/src/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

- [01-spiflash.patch](libs/pinetime_boot/patches/01-spiflash.patch) - July 2024 : Add support for the new SPI Flash memory chip (BY25Q32) into the `spiflash` driver of MyNewt. See [this issue](https://github.com/InfiniTimeOrg/pinetime-mcuboot-bootloader/issues/11) for more information.
53 changes: 0 additions & 53 deletions bootloader.md

This file was deleted.

55 changes: 55 additions & 0 deletions docs/howToUpdate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#How to update from the original MCUBoot bootloader to this one?
Since September 2020, PineTimes are running [InfiniTime 0.7.1](https://github.com/JF002/InfiniTime/releases/tag/0.7.1) and [Lup's MCUBoot bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7).

InfiniTime can be easily and safely updated Over-The-Air using the DFU file. Users can even install other firmwares like WaspOS using the same OTA functionality.

Upgrading the bootloader is a more difficult task as there is no fallback. When the application firmware is updated, the bootloader is responsible to ensure that everything goes smoothly, and to recover in case of error. When we upgrade the bootloader, there is nothing else to ensure recovery in case of failure.

That's why I need to write this disclaimer : **Upgrading the bootloader is a risky operation that could brick your device in case of error (bad manipulation, software bug, hardware failure,...). Do it at your own risks and neither the contributors of this project or Pine64 or anyone else will be held accountable in case of failure during this operation!**

That being said, we did many tests to ensure that this update goes as smoothly as possible !

## Upgrade procedure

### WARNINGS

- Apply this procedure only from InfiniTime
- Follow the following steps in this exact order
- The recovery firmware is not compatible with the old bootloader. Install this recovery firmware only once the new bootloader is installed.

## Procedure

- Install a relatively recent version of InfiniTime. I recommend >= 0.14 as BLE connectivity was improved in this version
- Ensure the battery is charged, and put it on the charging cradle if possible.
- OTA `reloader-mcuboot.zip`. This file contains a custom firmware that will overwrite the current bootloader with the new version.
- The watch resets and the *old* bootloader swaps InfiniTime with this reloader tool.
- The bootloader runs the reloader which overwrites the old bootloader with the new one and resets the watch when it's done.
- The new bootloader is running! You'll notice that the boot logo changed : The green *PineTime* logo has been replaced by a white PineCone that progressively becomes green.
- The bootloader reverts to InfiniTime (the version you were running just before) and loads it.
- OTA `pinetime-mcuboot-recovery-loader-0.14.1.zip` from InfiniTime repo. This custom firmware will install the recovery firmware into the external flash memory and reset the watch when it's done.
- The bootloader reverts to InfiniTime again and loads it.

[**--> See it in video <--**](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529)

## What changed in this version since the previous version?

We fixed a few bugs that would temporarily *soft brick* the device. In some cases, the firmware and the bootloader would completely freeze, and the only way to work that issue around was to let the battery drain completely to rest the CPU.

This new version also provides a basic UI allowing the users to easily see when they are requesting a rollback or a recovery.

The boot logo is also embedded into the bootloader binary instead of reading it from the external flash memory.

## How to use the bootloader

Most of the time, the bootloader works autonomously : it simply loads the firmware that is installed on the device (ex : InfiniTime).

When a new version of the firmware is OTA'ed, the bootloader automatically applies the updates. No user action is needed.

In normal operations, the bootloader displays a white pinecone that progressively becomes green. During that time (~5s), the user can request a firmware revert or recovery using the button:

- Revert to the previous version of the firmware : press the button until the pinecone becomes blue. The bootloader will restart and reload the version of the firmware that was installed prior to the current one.
- Load and run the recovery firmware : press the button until the pinecone becomes red. The bootloader will restart and run the recovery firmware.

## How to use the recovery firmware

This firmware is a *light* version of InfiniTime that only provides the OTA functionality. You can use it in case of catastrophic failure to install a new firmware, when the bootloader is not able to run the firmware or revert to the previous version.
Binary file modified docs/pictures/memoryMap.odg
Binary file not shown.
Binary file modified docs/pictures/memoryMap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 6 additions & 5 deletions hw/bsp/nrf52/syscfg.yml
Original file line number Diff line number Diff line change
@@ -54,17 +54,18 @@ syscfg.vals:

###########################################################################
# SPI Flash
# XTX XT25F32B 32 Mb (4 MB) SPI NOR Flash (similar to QuadSPI SPI NOR Flash like Macronix 32 Mb (4 MB) MX25L3233F)
# manufacturer (0x0b), device (0x15), memory type (0x40), density (0x16)
# - XTX XT25F32B 32 Mb (4 MB) SPI NOR Flash (similar to QuadSPI SPI NOR Flash like Macronix 32 Mb (4 MB) MX25L3233F)
# manufacturer (0x0b), device (0x15), memory type (0x40), density (0x16)
# - BY25Q32 : manufacturer (0x68), memory type (0x40), density (0x16)
# Settings below are documented at https://github.com/apache/mynewt-core/blob/master/hw/drivers/flash/spiflash/syscfg.yml

SPIFLASH: 1 # Enable SPI Flash
SPIFLASH_SPI_NUM: 0 # SPI Interface 0
SPIFLASH_SPI_CS_PIN: 5 # SPI interface CS pin: P0.05/AIN3, SPI-CE# (SPI-NOR)
SPIFLASH_BAUDRATE: 8000 # Requested baudrate, 8000 is the fastest baudrate supported by nRF52832
SPIFLASH_MANUFACTURER: 0x0B # Expected SpiFlash manufacturer as read by Read JEDEC ID command 9FH
SPIFLASH_MEMORY_TYPE: 0x40 # Expected SpiFlash memory type as read by Read JEDEC ID command 9FH
SPIFLASH_MEMORY_CAPACITY: 0x16 # Expected SpiFlash memory capactity as read by Read JEDEC ID command 9FH (2 ^ 0x16 = 32 Mb)
SPIFLASH_MANUFACTURER: 0 # Expected SpiFlash manufacturer as read by Read JEDEC ID command 9FH. Set to 0 to support multiple chips at once
SPIFLASH_MEMORY_TYPE: 0 # Expected SpiFlash memory type as read by Read JEDEC ID command 9FH. Set to 0 to support multiple chips at once
SPIFLASH_MEMORY_CAPACITY: 0 # Expected SpiFlash memory capactity as read by Read JEDEC ID command 9FH (2 ^ 0x16 = 32 Mb). Set to 0 to support multiple chips at once
SPIFLASH_SECTOR_COUNT: 1024 # Number of sectors: 1024 sectors of 4 KB each
SPIFLASH_SECTOR_SIZE: 4096 # TODO Number of bytes that can be erased at a time: 4 KB sector size
SPIFLASH_PAGE_SIZE: 256 # TODO Number of bytes that can be written at a time
19 changes: 17 additions & 2 deletions libs/pinetime_boot/include/pinetime_boot/pinetime_boot.h
Original file line number Diff line number Diff line change
@@ -25,21 +25,36 @@
extern "C" { // Expose the types and functions below to C functions.
#endif

// Colors
#define BLACK 0
#define WHITE 0xffff
#define RED 0xF800
#define BLUE 0x001F
#define GREEN 0x07E0

/// Init the display and render the boot graphic. Called by sysinit() during startup, defined in pkg.yml.
void pinetime_boot_init(void);

/// Write a converted graphic file to SPI Flash
int pinetime_boot_write_image(void);

/// Display the image in SPI Flash to ST7789 display controller
/// Display the boot logo to ST7789 display controller
int pinetime_boot_display_image(void);

/// Display the boot logo to ST7789 display controller using 2 colors. The first x lines (x = colorLine)
/// will be drawn in color1, the rest in color2.
int pinetime_boot_display_image_colors(uint16_t color1, uint16_t color2, uint8_t colorLine);

/// Display the bootloader version to ST7789 display controller
int pinetime_version_image(void);

/// Clear the display
void pinetime_clear_screen(void);

/// Check whether the watch button is pressed
void pinetime_boot_check_button(void);

int pinetime_boot_display_image_colors(uint16_t color1, uint16_t color2, uint8_t colorLine);


#ifdef __cplusplus
}
2 changes: 2 additions & 0 deletions libs/pinetime_boot/include/pinetime_boot/pinetime_factory.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __PINETIME_FACTORY_H__
#define __PINETIME_FACTORY_H__

/// Copy the recovery firmware from the external SPI Flash memory to the secondary slot.
/// It'll be installed in the primary slot by MCUBoot.
void restore_factory(void);


11 changes: 11 additions & 0 deletions libs/pinetime_boot/include/pinetime_boot/version.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef PINETIME_RUST_MYNEWT_VERSION_H
#define PINETIME_RUST_MYNEWT_VERSION_H

#define PINETIME_BOOTLOADER_VERSION_MAJOR 1u
#define PINETIME_BOOTLOADER_VERSION_MINOR 0u
#define PINETIME_BOOTLOADER_VERSION_PATCH 1u
#define PINETIME_BOOTLOADER_VERSION ((PINETIME_BOOTLOADER_VERSION_MAJOR << 16u) | (PINETIME_BOOTLOADER_VERSION_MINOR << 8u) | (PINETIME_BOOTLOADER_VERSION_PATCH))

void pinetime_set_version(void);

#endif
42 changes: 42 additions & 0 deletions libs/pinetime_boot/patches/01-spiflash.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Subject: [PATCH] spi chip update
---
Index: hw/drivers/flash/spiflash/chips/syscfg.yml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/hw/drivers/flash/spiflash/chips/syscfg.yml b/hw/drivers/flash/spiflash/chips/syscfg.yml
--- a/hw/drivers/flash/spiflash/chips/syscfg.yml
+++ b/hw/drivers/flash/spiflash/chips/syscfg.yml
@@ -491,3 +491,9 @@
SPIFLASH_EON2580B:
description: Add support for EON2580B
value: 0
+ SPIFLASH_XTX25F32B:
+ description: Add support for XTX25F32B
+ value: 1
+ SPIFLASH_BY25Q32:
+ description: Add support for BY25Q32
+ value: 1
Index: hw/drivers/flash/spiflash/src/spiflash.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/hw/drivers/flash/spiflash/src/spiflash.c b/hw/drivers/flash/spiflash/src/spiflash.c
--- a/hw/drivers/flash/spiflash/src/spiflash.c
+++ b/hw/drivers/flash/spiflash/src/spiflash.c
@@ -565,7 +565,12 @@
#if MYNEWT_VAL(SPIFLASH_EON2580B)
EON_CHIP(EN80B, 0x30, FLASH_CAPACITY_8MBIT),
#endif
-
+#if MYNEWT_VAL(SPIFLASH_XTX25F32B)
+ STD_FLASH_CHIP("", 0x0b, 0x40, 0x16, spiflash_release_power_down_generic),
+#endif
+#if MYNEWT_VAL(SPIFLASH_BY25Q32)
+ STD_FLASH_CHIP("", 0x16, 0x40, 0x16, spiflash_release_power_down_generic),
+#endif
{ {0} },
};

Loading