Developing InfiniTime, Open-source Firmware for the PineTime Smartwatch
Today we are going to talk to Jean-François (JF) Milants, the main contributor to the InfiniTime project, open-source firmware for the Pine64 PineTime smartwatch.
Hi Jean-François, can you please tell us about the InfiniTime project? What is it about in a nutshell? How did it get started?
InfiniTime is open-source firmware for the PineTime smartwatch. It provides notifications, a timer, alarm, heart rate sensor, step counting, and a couple of games.
It started as a personal project when Pine64 announced their intention to launch a new device, PineTime, as a community project. They sent development kits to developers interested in creating open-source firmware for this new smartwatch. Being passionate about embedded software development, I applied and quickly received my PineTime development kit.
At the beginning, my goal was to experiment with C++ on embedded systems, and I enjoyed hacking with the development kit, trying to implement the fastest display driver and basic BLE (Bluetooth Low Energy) integration.
A community of developers and enthusiasts quickly formed around the PineTime project. We discussed functionalities, low-level implementation of drivers, and bootloaders, and we experimented with various languages and frameworks. I was sharing my progress in the community chat rooms, on Twitter and on Mastodon, and many people asked me to publish the project.
Many developers quickly joined the project and contributed countless features and functionalities. InfiniTime is now a community project, maintained by 6 core developers and more than 100 contributors from all around the world!
Pine64 began shipping the PineTime-flashed InfiniTime around July 2020, and we released InfiniTime 1.0 in April 2021.
Is there a big community regularly contributing to the project?
Considering the relatively small niche of open-source smartwatches, I would say that the community is pretty big. It’s certainly big enough to provide us with a constant stream of feature requests, ideas, and pull requests!
The project currently has 100 contributors, 589 forks, 1,700 Github stars, 77 open PRs, and 192 issues/feature requests.
I see the firmware targets the PineTime smartwatch platform. Is it used anywhere else?
Indeed, the project started as firmware written specifically for PineTime. The collaboration with Pine64 is really great, as they make the hardware cheaply available to developers and provide help and support to the community so they can build projects around their devices.
Now, the hardware design is very similar to other cheap smartwatches. Some people have already ported it to the Colmi P8, for example, and work is currently ongoing to integrate those changes in InfiniTime.
In the future, I would like for InfiniTime to be more easily portable on other platforms. For example, I have already done some experiments with the Bouffalo BL602 RISC-V microcontroller. InfiniSim, the InfiniTime simulator, would also benefit from more hardware abstraction.
The PineTime smartwatch is based on Nordic Semiconductor nRF52832. Can you tell us about your experience of working with this platform? Why was it selected? Which benefits does it bring?
The PineTime is built by Pine64, and I was not involved in the hardware design, but I guess the nRF52832 was chosen because it’s very well suited for smartwatch use-cases: It integrates a BLE radio, it’s low-power, and it has enough CPU and memory resources.
This was my first time working on the nRF52 ecosystem, and I had a very positive experience. It has good documentation, there’s a lot of resources and information on the web, a FOSS BLE stack (NimBLE) is available, the SDK is very complete, and peripherals are relatively simple to use compared to more complex MCUs like STM32.
What are the main hardware limitations and specifics that InfiniTime firmware has to address?
Memory! As InfiniTime grows and expands its functionality, it uses more and more memory (both RAM and flash), and the amount of available memory decreases very quickly. We are now paying a lot of attention to the memory usage of the new features being added so that we stay within the limit.
Another limitation is the speed of the SPI bus (8 MHz) on which the display is connected. It limits the refresh rate of the display to around 10 fps, so we had to implement a few tricks to “hide” this slowness. For example, refreshing the whole display takes approximately 110 ms, which is very long and doesn’t look good when it’s refreshed from top to bottom. That’s why we implemented this vertical animation based on the vertical scrolling feature of the LCD controller. It makes the navigation in the UI much smoother and more pleasant.
The GitHub page says the project is written in modern C++. Which standard are you using? Which specific modern C++ features are in active use in the project?
The project is currently built with C++14, but we can of course update to a newer version when needed.
As I mentioned earlier, one of my goals with InfiniTime was to experiment with C++ on embedded systems. I try to design the project with OOP principles, find the best abstractions to keep the code as easy to read and maintain as possible, and take advantage of as many zero-overhead abstractions as possible.
If you browse the code, you’ll see we use constexpr, auto, the enum class, the move semantic, and lambdas as function pointers for callbacks from C libraries.
What other technologies and frameworks do you actively use to develop InfiniTime?
InfiniTime is built around multiple open-source projects: FreeRTOS (the OS), LVGL (UI library), NimBLE (BLE stack), LittleFS (filesystem for embedded systems), and MCUBoot (bootloader). We’ve also built InfiniSim, a simulator for InfiniTime that is also based on LVGL.
Then there are multiple companion applications that interact with PineTime via the BLE connection and run on Linux and Mobile Linux (Siglo, Amazfish, ITD), Android (Gadgetbridge), iOS (InfiniLink), and even in the browser (WebBleWatch).
We use BLE (Bluetooth Low Energy) to communicate with those companion apps. BLE is the only type of communication media available on PineTime. It’s used to synchronize the date and time, receive notifications, expose the heart rate and motion data, and update the firmware.
Which tooling (IDEs, testing frameworks, profilers, analyzers, etc.) do you and other contributors actively use when developing InfiniTime?
I don’t know much about the setup of other developers, but I mostly use CLion on my main development machine, and VS Code on my ARM laptop (but I wish CLion was also built to run on ARM64!).
We also need a SWD probe to flash and debug the firmware in the MCU. I mostly use my JLink adapter, but other probes like STLinkV2, BlackMagicProbe, and even RaspberryPi are commonly used, together with OpenOCD.
The project also provides configuration files for clang-format and clang-tidy. There’s also a Docker container that contains everything necessary to easily build the project.
As far as we know, you’ve found FreeRTOS integration in CLion quite useful. Can you share your use case and how you benefit from CLion?
I was very happy when JetBrains released the FreeRTOS integration in CLion. It allows you to quickly get a nice overview of the system, including memory usage, stack usage, queues, mutexes, and more.
It’s quite helpful when debugging and optimizing memory usage, and it’s much more practical than the “printf debugging” method I was using before the integration was available! I also plan on unifying multiple “heaps” (from LVGL and NimBLE) into a single heap managed by FreeRTOS, and I’ll most probably use this integration to check that everything goes as intended.
Together with the embedded GDB server and OpenOCD features, this integration makes flashing and advanced debugging much more comfortable.
You released IntiniTime 1.0 more than a year ago. How has the project evolved since then?
We released InfiniTime 1.0 when we thought that the project was stable enough and provided a minimal set of features to be usable not only by developers but also by actual end users. It provided 2 watch faces, a few apps, some user settings, heart rate monitoring, step counting and BLE connectivity for notifications, date/time settings, and OTA updates (firmware updates over BLE).
Since then, and thanks to the contributions of many developers, the stability of the firmware and of the BLE connectivity have greatly improved, the UI has been refined, new apps and watchfaces have been added (Timer, Alarm, Metronome, Stopwatch, and others), and multiple new features have been integrated (BLE secure pairing, wake up by raising the wrist, step goal, and chimes, among others).
And we’re not stopping there! There are still so many things we would like to add and improve in InfiniTime.
Are you involved in any other embedded development projects?
I’m also working in close collaboration with the developers of companion apps that integrate support for InfiniTime, including Amazfish, Gadgetbridge, Siglo, and ITD, especially when building new features that are accessible via BLE, to get information on how those features could be integrated in both InfiniTime and the companion apps. I even contributed improvements to notification management in Gadgetbridge, the Android companion app!
InfiniTime is by far the project I’ve accomplished the most with, but I’ve also published a few other projects on my Github and Codeberg accounts, such as JFBrew, a temperature controller for my DIY beer fermentation chamber, and drivers for LoRa devices from Pine64.
Thank you for the interview, Jean-François!
I would like to thank all those who participated in some way in the project. InfiniTime would not be here without them!
And I would also like to thank JetBrains for supporting the open-source community by providing free licenses to open-source projects!