Files
nrfwatch/README.md
T

179 lines
6.4 KiB
Markdown

# nrfwarch
Smartwatch firmware for the [Seeed Xiao nRF54L15 Sense](https://www.seeedstudio.com/XIAO-nRF54L15-Sense-p-6494.html) with a GDEY0154D61LT 1.54" e-ink display.
Built on [Zephyr RTOS](https://docs.zephyrproject.org/) v4.0. Targets the `xiao_nrf54l15/nrf54l15/cpuapp` board. Includes a display simulator that renders the watchface on your desktop using [feh](https://feh.finalrewind.org/).
## Hardware
- **MCU**: Nordic nRF54L15 (ARM Cortex-M33, 128KB RAM, 1MB Flash)
- **Board**: Seeed Xiao nRF54L15 Sense (includes LSM6DSO IMU, PDM mic)
- **Display**: Good Display GDEY0154D61LT 1.54" e-ink, 200x200px, SSD1680 controller, SPI
### E-ink wiring
| Signal | Xiao Pin | Function |
|--------|----------|----------|
| MOSI | D10 | SPI data out |
| CLK | D8 | SPI clock |
| CS | D1 | Chip select |
| DC | D3 | Data/command |
| RST | D0 | Hardware reset |
| BUSY | D5 | Busy status |
## Quick start
### 1. Enter dev shell
```bash
nix develop
```
### 2. Set up Zephyr SDK (first time only)
Downloads Zephyr v4.0 workspace and SDK 0.17.0, patches binaries for NixOS:
```bash
nix run .#setup-sdk
```
### 3. Run the display simulator
Builds and runs the watchface simulator. Time advances 1 minute per second. A feh window opens showing the e-ink output in real time. The simulator uses the same rendering code that runs on the real hardware.
```bash
nix run .#sim
```
This pipes the native_sim binary output through `sim/view.py`, which converts the framebuffer to PBM and auto-launches feh with `--auto-reload`. The output file is `/tmp/nrfwarch.pbm`.
### 4. Run tests
17 ztest cases covering framebuffer operations, font data, and rendering:
```bash
nix run .#test
```
### 5. Build for hardware
Open the project in [nRF Connect for VS Code](https://marketplace.visualstudio.com/items?itemName=nordic-semiconductor.nrf-connect) and add the application with board target `xiao_nrf54l15/nrf54l15/cpuapp`. Or build from the command line:
```bash
west build -b xiao_nrf54l15/nrf54l15/cpuapp .
```
## Display simulation
The simulator lets you develop the watchface visually without any hardware. It runs the actual Zephyr kernel and the real `watchface.c` / `fonts.c` code -- the only difference is the EPD driver writes to a file instead of SPI.
How it works:
1. `sim/src/epd_sim.c` implements the same API as `src/epd_drv.c`, but instead of sending SPI commands it dumps the raw framebuffer over stdout as hex, framed with `!F!` / `!E!` markers
2. `sim/view.py` reads the hex frames from stdin, inverts the polarity (framebuffer uses 1=white, PBM uses 1=black), and writes a PBM image to `/tmp/nrfwarch.pbm`
3. feh watches the file with `--auto-reload` and updates the display window
The simulated time starts at 12:00 and advances 1 minute every 0.8 seconds. Battery decreases by 2% per simulated hour. A full 24-hour cycle runs in about 19 minutes.
### Manual usage
If you want to run the sim without feh or pipe the output yourself:
```bash
# Run the binary directly (outputs hex frames to stdout)
./build-sim/zephyr/zephyr.exe
# Convert a single frame to PBM manually
./build-sim/zephyr/zephyr.exe | python3 sim/view.py
# Just view the current frame
feh /tmp/nrfwarch.pbm
# Convert to PNG for sharing
pnmtopng /tmp/nrfwarch.pbm > watchface.png
```
### Iterating on the watchface
1. Edit `src/watchface.c` or modify digit shapes in `tools/gen_fonts.py`
2. If fonts changed: `python3 tools/gen_fonts.py`
3. Rebuild sim: `cmake -B build-sim -GNinja -DBOARD=qemu_x86 -S sim && ninja -C build-sim`
4. Run: `./build-sim/zephyr/zephyr.exe | python3 sim/view.py`
5. feh auto-reloads when the PBM changes
## Project layout
```
src/
main.c Entry point, minute-by-minute watch face loop
epd_drv.c/h SSD1680 e-ink driver (SPI, full/partial refresh, deep sleep)
watchface.c/h Framebuffer renderer (200x200 monochrome)
fonts.c/h Bitmap fonts (24x40 digits, 8x40 colon)
sim/
src/main.c Simulated main loop (accelerated time, no hardware)
src/epd_sim.c EPD mock - dumps framebuffer as hex over stdout
view.py Reads hex frames, writes PBM, launches feh
CMakeLists.txt Sim build config
prj.conf Sim Kconfig
boards/
xiao_nrf54l15_nrf54l15_cpuapp.overlay Devicetree overlay (SPI, GPIO, I2C, BT)
xiao_nrf54l15_nrf54l15_cpuapp.conf Board-specific Kconfig
dts/bindings/
nrfwarch,epd-ctrl.yaml Custom binding for EPD GPIO control node
tests/
src/main.c 17 ztest cases (framebuffer, pixels, fonts, rendering)
prj.conf Test build config
prj.conf Main application config
CMakeLists.txt Build definition
flake.nix Nix flake (dev shell, setup-sdk, test, sim)
tools/
gen_fonts.py Font generator (run to regenerate src/fonts.*)
```
## Flake commands
| Command | Description |
|---------|-------------|
| `nix develop` | Enter dev shell with all tools |
| `nix run .#setup-sdk` | Download and set up Zephyr SDK + workspace |
| `nix run .#test` | Build and run ztest suite on QEMU |
| `nix run .#sim` | Run display simulator with feh viewer |
## What works
- SSD1680 e-ink driver with full refresh and partial refresh
- Framebuffer-based watch face with time rendering (HH:MM) and battery indicator
- Deep sleep / wake for the display
- Display simulator with real-time feh output
- 17 passing tests covering framebuffer operations, font data integrity, and rendering
## In progress / planned
- BLE Current Time Service (CTS) client for phone time sync
- GRTC-based RTC for persistent timekeeping across deep sleep
- Battery monitoring via ADC (channel 7, VBAT regulator)
- LSM6DSO IMU wrist-tilt wake detection
- System-off power management with regulator control
- Partial refresh for minute updates (avoid full refresh flicker)
- BLE Battery Service (BAS) and notifications
## References
- [Seeed Xiao nRF54L15 Wiki](https://wiki.seeedstudio.com/xiao_nrf54l15_sense_getting_started/)
- [Zephyr RTOS Documentation](https://docs.zephyrproject.org/)
- [Zephyr QEMU x86 Board](https://docs.zephyrproject.org/latest/boards/qemu/x86/doc/index.html)
- [Zephyr ztest Framework](https://docs.zephyrproject.org/latest/develop/test/ztest.html)
- [SSD1680 datasheet](https://www.good-display.com/companyfile/409.html) (GDEY0154D61LT)
- [Sample repo: Toastee0/Seeed-Xiao-nRF54L15](https://github.com/Toastee0/Seeed-Xiao-nRF54L15)
- [E-ink driver reference: jcontrerasf/E-ink-display-Zephyr](https://github.com/jcontrerasf/E-ink-display-Zephyr)
## License
Apache 2.0