Flashing your PineTime using an ST-Link and OpenOCD
Published: 2020-01-07 21:34:34

The [PineTime development kits](https://www.pine64.org/pinetime/) are now shipping out, and to do anything interesting with yours, you'll probably be looking to flash a firmware on to it.

With open-source tool OpenOCD and a cheap ST-Link programmer, it's really easy to flash firmware once you know what to do!

# Prerequisites 
There are a few things you need to do before you can follow this guide:

- You'll need to solder wires onto your PineTime's SWD pins so that you can connect it to a programmer (or a Pi to unlock it - see below). See the [wiki page](https://wiki.pine64.org/index.php/PineTime) for a diagram of which pin is which. (Some people have had success with just resting the pins in the holes on the board and not soldering them there, but I haven't tried this.)

- You **must** remove the flash protection your PineTime before you can flash it. It's possible to do this using a J-Link, but they are very expensive. Fortunately, you can also do it with a Raspberry Pi; follow the _Remove nRF52 Flash Protection with Raspberry Pi_ section of [Lup Yuen Lee's fantastic guide](https://medium.com/@ly.lee/coding-nrf52-with-rust-and-apache-mynewt-on-visual-studio-code-9521bcba6004).

- You need an ST-Link programmer; I use [this cheap clone from Amazon UK](https://www.amazon.co.uk/gp/product/B07QBLNDPM). If you haven't yet used an ST-Link on your Linux installation, you'll need udev rules: I followed [this guide](https://fishpepper.de/2016/09/16/installing-using-st-link-v2-to-flash-stm32-on-linux/) to add mine.

# Building OpenOCD
The build of OpenOCD you can get from your package manager might not work for our purposes, as it probably hasn't been built with CMSIS-DAP support. We'll build it from source using a GitHub mirror instead.

On Linux:

```
git clone https://github.com/ntfreak/openocd
cd openocd
./bootstrap
./configure --enable-cmsis-dap
make
```

This will give you an OpenOCD executable inside the repo at `src/openocd`.

# Configuring OpenOCD
You'll need a configuration file to tell OpenOCD to connect to your ST-Link, and tell it what kind of chip we'll be debugging. Save this in `nrf52.cfg`, at the root of your OpenOCD repo:

```
source [find interface/stlink.cfg]
transport select hla_swd
source [find target/nrf52.cfg]
init
```

# Starting OpenOCD
Now we can start an OpenOCD server with our configuration! Run this in the repo root:

```
./src/openocd -s tcl -f nrf52.cfg -d3
```

`-s tcl` tells OpenOCD to look for files it needs in the `tcl` directory, such as the `interface/stlink.cfg` we specified in our config. `-f nrf52.cfg` runs our configuration file on OpenOCD, and `-d3` prints the maximum amount of debugging information so it's easier to diagnose any issues.

# Connecting to OpenOCD
After starting OpenOCD, we now have a telnet server on port 4444 which we can connect to in order to issue commands to our ST-Link. Connect with:

```
telnet localhost 4444
```

You'll get some preamble and a prompt which should look something like this:

```
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> 
```

There are two commands to check to ensure your chip is detected. `targets` should show one device, and `flash banks` should show two results.

```
> targets
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* nrf52.cpu          hla_target little nrf52.cpu          running

> flash banks
#0 : nrf52.flash (nrf5) at 0x00000000, size 0x00000000, buswidth 1, chipwidth 1
#1 : nrf52.uicr (nrf5) at 0x10001000, size 0x00000000, buswidth 1, chipwidth 1
```

Looks good!

# Flashing
Flashing a firmware is now pretty easy. First, we want to ensure that our PineTime is stopped:

```
> reset halt
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x00000462 msp: 0x20000800

```

You may want to clear the PineTime's firmware before flashing a new one. This _should_ happen as part of the programming process, but if you want to do it explicitly:

```
> nrf51 mass_erase
nRF52832-QFAA(build code: E0) 512kB Flash, 64kB RAM
```

Now for the actual flash! Give the path you'd like to program. Note that this path is relative from where you ran OpenOCD, not where you ran telnet, so you'll probably want to give an absolute path here. Make sure you also include the `verify reset` at the end.

```
> program /home/aaron/projects/pinetime/app.bin verify reset
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
** Programming Started **
Adding extra erase range, 0x00005d2c .. 0x00005fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
```

You're all done! If your PineTime didn't restart for some reason, you can always reset it and kick it off with a command:

```
> reset run
```

# Need a pre-built firmware?
Want to make sure you can flash your PineTime, but haven't got round to building a firmware yet? I've built a simple firmware on [go-smartwatch](https://github.com/aykevl/go-smartwatch) which should show "Hello!" on your PineTime's display.

[**Download the pre-built firmware here!**](https://stuff.aaronc.cc/uploads/hello.bin)