Sneak Peek of PineTime Smart Watch… And why it’s perfect for teaching IoT
After coding on PineTime for a few days (in Rust), it suddenly struck me…
- I felt really comfortable and productive coding the new gadget. Even though I have never coded a smart watch.
- PineTime is a terrific tool for teaching IoT! And I have taught IoT with so many different gadgets.
1️⃣ PineTime is the spiritual successor to BBC micro:bit (the educational gadget)!
Yes it’s blasphemy but if you think about it… BBC micro:bit is really a Nordic nRF51 in an oversized form factor that runs an odd 2.4 GHz wireless protocol. With PineTime we get a supercharged nRF52 and proper Bluetooth support, including Bluetooth Mesh! Imagine a classroom full of meshed PineTime gadgets…
2️⃣ PineTime has a touchscreen!
Millennials expect no less than a touchscreen for learning IoT, since they are used to touchy feely gadgets like Apple Watch and FitBit. How would you explain to a millennial how a touch controller works? Show them a PineTime! (Few of us have actually programmed a touch controller… Here’s the perfect opportunity!)
3️⃣ PineTime has realistic battery life constraints!
I would give every IoT student a PineTime gadget… “Build me a watch face that has the longest battery life!” For the first time ever, we have a simple way to teach the real-world impact of firmware programming on battery life. And there are many options to explore: polling vs callbacks, coroutines vs multitasking, RTOS vs no RTOS, Deep Sleep vs Light Nap, WFI vs WFE, point-to-point vs mesh networks, …
4️⃣ PineTime reminds us that IoT can save lives!
I suffer from Severe Hypertension… I can really drop dead at any moment (probably because of Rust!) I discovered this by chance… I really wished my watch could tell me much earlier. PineTime has a simple Heart Rate Sensor, but it’s a good way to remind our future makers that they have the power to create a gadget that saves our lives.
5️⃣ PineTime is powered by open source!
Coding with PineTime feels exactly like coding on STM32 Blue Pill… Just grab the $20 watch, build a simple SWD cradle (fun creativity exercise!), connect a $2 ST-Link dongle and hack away with the exact same stack of open source tools I used for STM32! Visual Studio Code, Cortex Debugger, GCC for Arm, Embedded Rust, OpenOCD, Apache Mynewt OS, NimBLE Bluetooth stack, … No better way to immerse our future makers into the world of Open Source Collaboration!
6️⃣ PineTime was created for Embedded Rust!
embedded-graphics crate renders text and graphics so easily on PineTime! Rust on PineTime will create the same educational impact that graphical Logo programming gave us so many years ago. More about Rust in a while…
7️⃣ PineTime was designed for millennials!
Some parts inside PineTime are so tiny that they hurt my eyes… But I bet the millennials will love it. It’s a gadget that fits naturally into delicate millennial hands… And begs to be pried open (gently) for deeper inspection. (Compare PineTime with the geriatric Arduino Uno and oversized BBC micro:bit)
8️⃣ PineTime begins a lifelong IoT learning journey…
PineTime has a number of interesting built-in sensors and actuators (on I2C and SPI) to keep learners busy for a while: Colour Touchscreen, Heart Rate Sensor, Accelerometer, Vibrator, Power Management, Bluetooth, … But what if they wish to explore more?
Then just pick up one of the many affordable nRF52 development boards! They will be so happy to see the same code and the same suite of open source tools running on any nRF52 board. (Unlike the Arduino Uno and BBC micro:bit, which turned out to be disappointing deadends)
Here’s my plea to Pine64 (I hope others will join me)… Please keep PineTime open and hackable… For the sake of IoT Education!
Proposed PineTime Smart Watch Firmware
PineTime is extremely hackable (in its current raw form), so you’re free to run any RTOS (FreeRTOS, Zephyr, Mynewt, mbed)… Or none at all (Bare Metal Embedded Rust)!
But as an uptight, severely hypertensive former enterprise architect… I expect no less than this firmware stack (even if it means stacking the kueh lapis by myself!) Because it makes teaching IoT more modular and less crash-prone…
The PineTime Smart Watch Application is coded in Rust… Because Rust has memory safety features that prevent the application from crashing due to bad pointers. And yet it compiles into Arm machine code, running as efficiently as C. (Given a choice to teach Embedded C or Embedded Rust, I would most certainly choose Rust, because it’s modern and friendlier!)
The Rust Application has three jobs…
1️⃣ Render the user interface text and graphics to the LCD display
2️⃣ Respond to touch events that are generated whenever we touch the touchscreen
3️⃣ Receive and transmit sensor data over Bluetooth
main() function implemented in the Rust Application…
Some of the blocks are still missing (like the touchscreen driver), so if you’re keen to help out, drop me a note!
Let’s inspect the three flows in detail…
Render User Interface on PineTime Smart Watch
A Smart Watch Application needs a decent user interface with text and graphics. Coding that in low-level C would be tedious. Fortunately we got Rust and the
embedded-graphics crate to help us. The
embedded-graphics crate makes it really easy to render raster fonts and various shapes with a few simple lines of Rust code.
embedded-graphics crate is designed to render its bitmap directly into a Display Controller Driver that complies with the Rust Embedded Framework (which uses specific types and constructs to access bare-metal hardware on a microcontroller).
We’re now using the standard
st7735_lcd Rust Embedded Driver. It needs some tweaking to make it 100% compatible with PineTime’s ST7789 display controller… But for now it seems to be rendering the display fairly well without any modification.
st7735_lcd driver assumes that the Rust Embedded HAL (Hardware Adaptation Layer) is available for our microcontroller… That’s how the driver accesses the SPI port and GPIO pins connected to the display controller. But we can’t allow Rust to access our hardware directly… Everything must go through Mynewt OS!
The solution is simple… We created a thin Rust Embedded HAL that maps to the Mynewt APIs for SPI and GPIO. And it works!
Now we have a working demo of the screen rendering controlled by Rust. The colours seem OK even though we are using a ST7735 driver for PineTime’s ST7789 display controller.
Respond to Touch Events on PineTime Smart Watch
We now have a simple way to render watch faces in Rust… Yay! But a Smart Watch isn’t really Smart unless it can respond to our tapping and prodding on the touchscreen. And it gets complicated because of “Interrupts” or “中断” in Chinese (learnt that from the Hynitron docs).
How do we check if the screen has been touched? We could poll the Touch Controller over I2C every second. But that would consume too much power. And it would feel laggy.
The right solution is to monitor for Interrupts generated by the Touch Controller. The Touch Controller switches the Interrupt Pin (just a regular GPIO Pin) into the Low state whenever a touch is detected.
Mynewt OS provides a GPIO API that transforms this Hardware Interrupt into a Software Event that we may handle in our C code. That’s how we create a Touch Controller Driver that responds to touch.
How shall we escalate the Touch Event up through the firmware layers to the Rust Application (so that it can update the display)?
Mynewt OS provides a Sensor Framework enables sensors to raise events to the application. So a Temperature Sensor could use this Sensor Framework to alert the application of any variations in temperature. We shall use Mynewt’s Sensor Framework to escalate Touch Events the same way.
This works only when we have a Mynewt Sensor Driver for our Touch Controller… Which I’m still coding in C. I have coded similar drivers previously… Here’s my Mynewt Sensor Driver for the Nordic low-power transceiver nRF24L01 that watches for the Incoming Packet Interrupt and transforms it into a Sensor Data Event for the application:
Handling a Touch Sensor Event with Mynewt and Rust should look like this:
The Touch Sensor Driver is now being implemented… As I figure out how the Hynitron CST816S I2C commands work. Find out more in this article…
Receive and Transmit Sensor Data on PineTime Smart Watch
What about other sensors on the PineTime… the Accelerometer and the Heart Rate Sensor?
Our Rust Application can poll them via the Mynewt Sensor Framework. Mynewt provides a Sensor Driver in C for the BMA2xx Accelerometers that we may customise to derive the BMA421 Sensor Driver for PineTime. Mynewt doesn’t have a Heart Rate Sensor Driver but it should be straightforward to create a new one, like the GPS Sensor Driver that I have created:
What shall we do with the polled Sensor Data?
For some types of Sensor Data we may choose to transmit them over the Bluetooth network that’s supported by the PineTime hardware. The Nordic nRF52 microcontroller includes a 2.4 GHz transceiver radio that may be programmed with a Bluetooth software stack so that the PineTime behaves like a standard Bluetooth gadget.
Most nRF52 developers would probably use Nordic SoftDevice. This is the standard firmware provided by Nordic Semiconductor that implements the Bluetooth LE functions.
The firmware runs as a base system layer underneath our application code and RTOS.
SoftDevice reserves some hardware resources for itself, like the radio transceiver, some timers and some ROM+RAM.
The remaining resources would be available for our application, which would call the SoftDevice API to perform Bluetooth LE functions and receive notifications.
What if we wish to experiment with the Bluetooth LE implementation… Trace it to see how it works, tweak it to improve it, or even roll out a new Bluetooth LE protocol?
SoftDevice is clearly not meant for experimentation… Apache NimBLE is perfect for that! Apache NimBLE is an open-source Bluetooth LE stack that completely replaces SoftDevice. It’s designed to run with the Apache Mynewt embedded OS, so NimBLE feels like a typical Mynewt task.
Apache NimBLE is the Bluetooth LE implementation that we’re adopting for PineTime Smart Watch.
Our PineTime code now includes a fully-functional iBeacon Transmitter, to verify that our PineTime works wirelessly indeed. Let’s probe deeper to uncover the full power of PineTime wireless networking…
Bluetooth Mesh and other networking options for PineTime Smart Watch
I’m particularly excited that PineTime supports Bluetooth Mesh networking. Suppose I’m out at Taipei’s crowded Shihlin Night Market 士林夜市 with my family (and my dog)… I need to make sure that we all stay close. My son may not always be close to me, but as long as he’s near Grandma or his siblings, I’m happy.
Assuming everyone wears a PineTime Smart Watch (even my dog), all we need to implement this proximity safety app is a Bluetooth Mesh. It allows messages to be forwarded from gadget to gadget, peer to peer. And if one of the gadgets has internet access, the messages may be transmitted to the cloud as well. Here’s an example of a Mynewt network driver that routes local network messages (from nRF24L01) to the cloud (via ESP8266)
I have written a tutorial on Bluetooth Mesh networking with nRF52 and the NimBLE stack. It’s easy to port this to the PineTime Smart Watch. Here’s my question for you…
What kind of networking would you need on the PineTime Smart Watch? Would you need Localised Messaging, Cloud Messaging, or both?
I’ll design the NimBLE stack and the Rust messaging API accordingly when I hear from you!
Programming the PineTime Smart Watch
PineTime is not yet on sale so the programming instructions below are not really meant for general consumption… I’m sharing my findings here with other PineTime developers who wish to adopt similar tools.
Dear PineTime Developers: Pardon me if the instructions are not fully fleshed out… Please drop me a note on the PineTime forum and I’ll be happy to explain the details (which I’m still evolving)
But if you’re just casually keen to learn what’s it like to code a smart watch… Then read on!
The programming setup for PineTime is similar to other nRF52 development boards. I’ll be adapting the steps from my earlier article “Coding nRF52 with Rust and Apache Mynewt on Visual Studio Code”
Build SWD Cradle
To program the PineTime Smart Watch via SWD (Serial Wire Debug), we need to construct a sturdy cradle that exposes the four pins of the SWD port. Make sure that the watch button and the touchscreen are accessible.
I created my SWD cradle with Single Core Wire (22 AWG), $2 clear box cover from Daiso, Blu Tack and sticky tape.
Also connect the 5V Charging Pad on PineTime to the 5V Pin of ST-Link. This ensures sufficient power to all components on PineTime. And the battery gets charged properly too.
I used a folded loop of Single Core Wire (22 AWG) like this…
Remove nRF52 Flash Protection
We’ll be flashing and debugging PineTime with a $2 generic ST-Link V2 USB dongle. ST-Link doesn’t implement all SWD functions, just the minimal set of high-level functions needed for flashing and debugging. PineTime is shipped with its flash ROM protected against tampering, and the ST-Link can’t be used to remove the nRF52 Flash Protection.
Fortunately there’s a way to remove the flash protection with a Raspberry Pi. (This only needs to be done once.) Just follow the instructions in the section “Advanced Topic: Remove nRF52 Flash Protection” at the end of the article “Coding nRF52 with Rust and Apache Mynewt on Visual Studio Code”
RESET pin is not needed when connecting PineTime to Raspberry Pi.
Install Source Code and Development Tools
Follow the instructions in the article “Install Apache Mynewt and Embedded Rust for nRF52 and Visual Studio Code on Windows and macOS”.
Stop just before the section “Build The Firmware”
At the lower left corner of Visual Studio Code, click the name of the branch and checkout the branch
This upgrades the downloaded code to the new PineTime source code.
In the PineTime branch, the Mynewt OS Board Support Package has been updated with the correct pins used for the SPI and I2C ports.
Build, Flash and Debug Firmware
Refer to the instructions in the article “Install Apache Mynewt and Embedded Rust for nRF52 and Visual Studio Code on Windows and macOS”
Continue from the section “Build The Firmware” till the end of the article.
We should be able to build, flash and debug the PineTime firmware like this…
PineTime firmware is still in active development by the open-source community (myself included). I’ll keep this article updated. Here’s the next article…
Building a Rust Driver for PineTime’s Touch Controller
Pretend you’re my IoT student. I give you a PineTime Smart Watch and challenge you to “Make it work… Especially the…
If you have ideas how we can make PineTime more newbie-friendly for teaching and learning IoT, drop me a note!
Also check out my article… Do you think Visual Rust is suitable for PineTime? “Visual Embedded Rust Programming with Visual Studio Code”
Mynewt + Rust port of PineTime firmware (work in progress) may be found at the
pinetime branch of this repository…
This pinetime branch contains the firmware source code for PineTime Smart Watch with Apache Mynewt and Embedded Rust…
TinyGo version of PineTime firmware…
This is an attempt to build a toolkit for developing smartwatch firmware in Go (using TinyGo). Supported smartwatches…
Zephyr OS version…
in this repository you will find a manual, created with sphinx: -html -pdf -epub In the manual is explained how you can…
The PINE64 SmartWatch, dubbed "PineTime", is a product of a community effort for an open source smartwatch in…
Nordic nRF52 Microcontroller
Hynitron CST816S Touch Controller
TianYiHeXin HRS3300 PPG Heart Rate Sensor
- HRS3300 PPG Heart Rate Sensor Design Guide in Chinese
- Reference Code for HRS3300 PPG Heart Rate Sensor
- Arduino Driver for HRS3300 PPG Heart Rate Sensor
Bosch BMA421 Accelerometer
- Datasheet for Bosch BMA423 Accelerometer (should be similar to BMA421)
Sitronix ST7789 LCD Display Controller
- Arduino Driver for ST7735 and ST7789 by Adafruit (to identify differences between ST7735 and ST7789)