Embedded systems & IoT engineer
Embedded firmware and wireless systems, from the radio up.
Nordic nRF parts on Zephyr: bring-up, Bluetooth LE, bootloaders and field-update paths, plus the gateways and cloud links around them. When the logs stop being enough, I build the instrument.
Start here
Selected work
Longer write-ups with hardware details, design decisions and measurements.

BLE & Wireless · 2026
Raccoon: a Seven-Radio BLE Sniffer on One Clock
Seven nRF52832 radios on one SPI bus to a Raspberry Pi 3, every packet on one timeline. On a real bench it follows a connection from CONNECT_IND through a 2M PHY switch into encryption, decrypts it, reads the sync transfer out of it and then follows the PAwR train event by event. The radios take new firmware over the same bus in 15 seconds, through a 2.8 KB bootloader I wrote for them.
- connection events captured by each of two radios while a gateway enrolled an nRF54L15 tag
- 375 / 376
- encrypted PDUs of that connection decrypted with a valid MIC, sync transfer included
- 41 / 41
- to put new firmware on all seven radios over the SPI bus (bootloader: 2,780 bytes)
- 15 s

Embedded Linux · 2026
Yocto for Small Boards: One Image, Remote Access, and an FPGA as the Camera
One Yocto layer builds the same headless Linux for the Raspberry Pi Zero family and the Banana Pi M2 Zero. A device enrols with a server, takes nine fixed commands over MQTT, renews its own certificate and recovers from lost contact without help, and its identity survives a root filesystem replacement. On the Banana Pi, a Tang Nano 20K FPGA drives the camera input at up to 54 MHz without a byte error.
- to taking commands again once the server returned, with the certificate expired during the outage (end-to-end test)
- 13 s
- remote commands the device accepts; none of them runs arbitrary code
- 9
- to healthy telemetry once the server returned, after the device booted with it down for 5 minutes
- 25 s

Embedded & Firmware · 2026
nRF52840 Radar Display: Firmware Updates That Can't Brick It
A round-screen desk display with a 24 GHz presence radar, running Zephyr on an nRF52840. I replaced the board's UF2 bootloader with MCUboot and built an update path that reverts a bad image on its own, a build step that checks the release configuration, and authenticated BLE updates. All of it was tested on hardware with deliberately broken images.
- from reset command to automatic revert of a deliberately bad image, measured over USB
- ≈ 90 s
- for a new image to prove itself before the watchdog reverts it
- 20 s
- BLE update authorisation checks passed on hardware
- 9 / 9

IoT & Cloud · 2026
Thingy:91 X ESL Gateway: BLE PAwR Sensors to MQTT over LTE-M
A complete sensor network on Nordic silicon. nRF52840 tags on a PAwR schedule, a Thingy:91 X gateway whose nRF5340 runs the BLE access point and whose nRF9151 runs everything else, and MQTT over LTE-M. I designed the split between the two gateway chips, the framed SPI link between them, and a firmware-update path that reaches a chip with no network of its own.
- chips in the chain, each updatable in the field through MCUboot
- 3
- fixed SPI frame between the gateway chips, CRC-8, 7 frame types
- 520 B
- lines in the six gateway modules I added on the nRF9151
- 8,300+
How I work
Check the instrument before trusting it
The sniffer was validated against a signal generator I wrote before any capture counted as evidence, and only CRC-good packets counted at all.
Make failure recoverable by design
Updates confirm themselves only after a health check. A deliberately broken image was used to prove that the device reverts on its own.
Keep production and experiments apart
Known-good firmware stays untouched, experiments live in copies, and every run keeps raw logs so someone else can check the conclusion.
All projects

BLE & Wireless · 2026
Raccoon: a Seven-Radio BLE Sniffer on One Clock
Seven nRF52832 radios on one SPI bus to a Raspberry Pi 3, every packet on one timeline. On a real bench it follows a connection from CONNECT_IND through a 2M PHY switch into encryption, decrypts it, reads the sync transfer out of it and then follows the PAwR train event by event. The radios take new firmware over the same bus in 15 seconds, through a 2.8 KB bootloader I wrote for them.
- nRF52832
- nRF5 SDK
- PPI / GPIOTE
- SPI slave

Embedded Linux · 2026
Yocto for Small Boards: One Image, Remote Access, and an FPGA as the Camera
One Yocto layer builds the same headless Linux for the Raspberry Pi Zero family and the Banana Pi M2 Zero. A device enrols with a server, takes nine fixed commands over MQTT, renews its own certificate and recovers from lost contact without help, and its identity survives a root filesystem replacement. On the Banana Pi, a Tang Nano 20K FPGA drives the camera input at up to 54 MHz without a byte error.
- Yocto (Scarthgap)
- kas
- BitBake
- systemd

Embedded & Firmware · 2026
nRF52840 Radar Display: Firmware Updates That Can't Brick It
A round-screen desk display with a 24 GHz presence radar, running Zephyr on an nRF52840. I replaced the board's UF2 bootloader with MCUboot and built an update path that reverts a bad image on its own, a build step that checks the release configuration, and authenticated BLE updates. All of it was tested on hardware with deliberately broken images.
- nRF52840
- Zephyr / NCS 3.2.4
- MCUboot
- MCUmgr SMP

IoT & Cloud · 2026
Thingy:91 X ESL Gateway: BLE PAwR Sensors to MQTT over LTE-M
A complete sensor network on Nordic silicon. nRF52840 tags on a PAwR schedule, a Thingy:91 X gateway whose nRF5340 runs the BLE access point and whose nRF9151 runs everything else, and MQTT over LTE-M. I designed the split between the two gateway chips, the framed SPI link between them, and a firmware-update path that reaches a chip with no network of its own.
- nRF9151
- nRF5340
- nRF52840
- Zephyr

BLE & Wireless · 2026
Hopping Around Occupied Channels: Channel Avoidance on Seven nRF52832 Radios
A frequency-hopping link between two nRF52832 radios, and five more that send test frames on chosen channels in exactly the slots the link uses them. The link finds the occupied channels from its own ack statistics and stops using them; first-try delivery goes from 75 % back to 95 %, with no corrupted value in 22,570.
- nRF52832
- nRF5 SDK
- Raspberry Pi 3
- SPI
Embedded & Firmware · 2026
Pro Micro Maintenance Remote: Signed Updates and a PAwR Sensor Network
A 240×240 display and six buttons on a nice!nano-class nRF52840, turned into the start of a field tool for PAwR sensor networks. It has two independent update paths, watchdog rollback and switched-VCC power gating, and it joins the same ESL network as the production sensors, answering the gateway as reliably as they do.
- nRF52840
- nRF5340
- Zephyr
- nRF Connect SDK

BLE & Wireless · 2026
One Packet, Then Silence: Debugging PAwR on nRF54L15
The access point reported success at every step and the tags still never answered. In May, correlated AP, tag and on-air evidence and a 20-build reproducer traced the fault to the receiving controller and a sharp timing boundary. In October I found the cause, a 32 kHz crystal running 175 ppm fast against a declared 50 ppm, and fixed it with one line of configuration.
- nRF54L15
- nRF52840
- nRF5340
- PAwR

Software & Sims · 2026
Sim Env: Open-Ended Evolution
An artificial-life world in C++20 where bodies, brains and behaviour evolve from nothing but survival and reproduction. A three-tier food chain, weather and climate events, deterministic multithreaded engine, and an always-on server whose world anyone can watch live in the browser.
- C++20
- Multithreading
- Neuroevolution
- raylib

Software & Sims · 2026
Seeing Through Stone: A Top-Down Camera for a Generated 3D World
Good world generation is like an ogre: it has layers. This one has six, and all of them are procedural, from the plan of a city and the underworld beneath it down to the last crack and tuft of grass. Nobody designed its rooms, so a top-down camera in Godot 4 can't rely on hand-authored roof hiding. I built occlusion from the generator's own records: a line-of-sight cube decides what the player sees, a wall-following cutaway decides what the camera may remove, and rendered tests check both.
- Godot 4.7
- GDScript
- GLSL shaders
- Python

Software & Sims · 2026
Inside the Walker: Legs, Weight and a Cockpit Made of Camera Feeds
A four-legged transport for the surface of the generated world: an 11 m machine with a procedural gait, a hull on a spring and three-segment legs. You board it through the belly and drive it from a cabin whose screens show what cameras on the hull see, so looking left means turning your head to the port screen, not turning the world.
- Godot 4.7
- GDScript
- GLSL shaders
- Python

Embedded & Firmware · 2025
nRF52840 Multi-Sensor Board
A Zephyr test bed for the nRF52840 with an IMU, a temperature/humidity sensor and an OLED. It has a command shell over USB and BLE (NUS), and settings are stored in flash with NVS.
- nRF52840
- Zephyr
- nRF Connect SDK
- BLE NUS

Hardware & CAD · 2026
3D-Printed Enclosures & CAD
PETG and TPU enclosures designed around specific boards: the nRF52840 test board, LoRa nodes and a gateway, and a Pi Zero W pan-tilt camera mount.
- FreeCAD
- Fusion 360
- PETG
- TPU

Robotics
Quadruped Robot
A 3D-printed quadruped with 12 LX-16A serial servos. Python handles gait generation, per-leg inverse kinematics and PID body levelling from an MPU-6050 IMU.
- Python
- Inverse kinematics
- PID
- IMU

Software & Sims
Unity Gerrymandering Simulator
A Unity simulation of redistricting. It generates a map with Perlin noise and redraws districts with a local search that scores population equality, compactness and partisan outcome.
- Unity
- C#
- Perlin noise
- Local search

Embedded & Firmware
Yellow Screen Desk Display
A Pomodoro timer and desk dashboard on the ESP32 "Cheap Yellow Display", with touch input, MP3 alerts from SD over I2S, and a Wi-Fi-synced clock.
- ESP32
- C++
- PlatformIO
- TFT_eSPI

Embedded & Firmware
ESP32 Wi-Fi Control Pad
Eight buttons and a rotary encoder on an ESP32-S2. The board serves its own web UI, pushes input state over a WebSocket and has a JSON endpoint for polling.
- ESP32-S2
- C++
- PlatformIO
- ESPAsyncWebServer

Software & Sims · 2026
mapgen: Procedural Ruins and an Underground District
A Python generator for an abandoned world built by giants: eroded terrain, layered megastructure ruins and a multilayer artificial underground, exported as engine-ready glTF. Every triangle can be traced back to the structure or route that made it.
- Python
- NumPy
- SciPy
- NetworkX

Software & Sims · 2026
Language Lab: Invented Languages and Machine Voices for Games
A local pipeline that turns English game lines into invented languages with their own grammar, speaks them with neural TTS and redesigns the voice from subtle to fully alien. Version 5 puts a typed meaning layer between English and the language, so one line comes out SVO in one language and SOV with case and vowel harmony in another.
- Python
- NumPy / SciPy
- ONNX Runtime
- Kokoro TTS

Software & Sims · 2026
Sim Env v1: Browser Evolution Sandbox
The first version of Sim Env: an evolution sandbox in C++ and raylib, compiled to WebAssembly so it runs in the browser. Creatures with pixel bodies and neural brains evolve three feeding strategies with no programmed goals.
- C/C++
- raylib
- WebAssembly
- Emscripten
Nothing in this category yet.
About
I'm an embedded systems engineer. I mostly write firmware for Nordic nRF52, nRF53, nRF54 and nRF91 parts on Zephyr, and debug BLE at the controller and RF level.
The work above covers a multi-radio BLE sniffer, a PAwR investigation on nRF54L15, a cellular ESL gateway on the Thingy:91 X, and an nRF52840 display with signed updates and rollback. Further down are a Yocto image for the Pi Zero W, a quadruped robot, the printed enclosures most of it lives in, and a few software side projects.
- C
- Zephyr / NCS
- MCUboot / MCUmgr
- BLE 5 · PAwR
- SPI / PPI / DMA
- J-Link · RTT
- Python
- MQTT · LTE-M
- Yocto
- Docker
- C++
- FreeCAD · 3D printing
Firmware & BLE
nRF52 / nRF53 / nRF54 / nRF91 on Zephyr and NCS: drivers, BLE 5 (PAwR, PAST, extended advertising), controller-level debugging with RTT and HCI.
Update paths
MCUboot with signed images, health-gated confirmation and automatic rollback; MCUmgr SMP over USB, BLE and SPI, relayed to chips with no network of their own.
Gateways & cloud
Thingy:91 X gateway: framed SPI between nRF9151 and nRF5340, MQTT over LTE-M, boot self-test, remote management.
Test tooling
A seven-radio BLE sniffer with hardware-latched time alignment, correlated log collectors, and minimal reproducers built as build matrices.
Also on t4as.org
Other write-ups are on the tech blog. The WebAssembly sim and a photo gallery are also hosted here.
