2025 - Dec 5

Maker Systems

N.O.V.A. Logger: Building a Teensy-Based Telemetry Stack From Scratch

Dec 5, 2025 Fisher Armstrong ~14 min read
Telemetry Embedded Systems GPS IMU CAN Bus Motorsports Data

The Teensy 4.1 is fast enough to log GPS, IMU, and CAN data simultaneously without choking. That sounds like a simple statement until you actually try to build a system around it that doesn't fall apart under real-time load. N.O.V.A. Logger started as a hardware integration problem and turned into a lesson in how quickly “fast enough” stops meaning anything if your data pipeline isn't disciplined.

This is the architecture behind the system — and what building it exposed about real-time constraints in environments that don't forgive timing mistakes.

System Overview

At a high level, the stack is straightforward: a central microcontroller coordinating three primary data sources — GPS for position and velocity, an IMU for acceleration and rotational data, and CAN for vehicle-state telemetry. The complexity isn't in what it does. It's in keeping all three synchronized without dropping samples or blocking the loop.

Core Hardware Stack

Primary Compute

Teensy 4.1 — Cortex-M7 @ 600MHz, running bare-metal loop with structured interrupt handling for time-critical sensor reads.

Sensor Inputs

u-blox M9N GPS module for positional data, LSM6DSO32 IMU for acceleration/gyro tracking, and MCP2515 CAN controller for vehicle network data acquisition.

Real-Time Problem: Everything Wants the CPU at Once

GPS wants UART time. IMU wants consistent polling. CAN wants deterministic interrupt servicing. On paper, the Teensy can handle all of it. In practice, the moment you let one subsystem block the loop, everything else starts degrading.

The first version of N.O.V.A. failed exactly this way: CAN polling introduced latency spikes that corrupted IMU sampling consistency. The result wasn't a crash — it was worse. It produced data that looked valid until you actually tried to align it.

Architecture Shift: Interrupt First, Poll Second

The fix wasn't more power. It was restructuring priorities. CAN moved to interrupt-driven reads. IMU sampling was decoupled into a fixed-timestep loop. GPS remained buffered through UART DMA-style reads where possible.

Once the system stopped pretending everything was equally urgent, the timing stabilized.

Failure Mode

If IMU and CAN share synchronous polling in the same loop, you will eventually get phase drift between motion and vehicle state data. It won't fail immediately. It fails silently.

What Real-Time Actually Means Here

Real-time in embedded logging isn't about speed. It's about predictability. A 1ms delay that always happens is acceptable. A 200µs jitter spike that happens randomly every few seconds destroys data integrity over long sessions.

That distinction is the entire system design constraint.

Data Pipeline Structure

Data is staged through a three-layer buffer model:

Sensor layer → sampling buffers → aggregation frame → SD write queue.

The SD write is intentionally isolated from acquisition. If logging ever blocks acquisition, the system is already compromised.

What This Actually Taught Me

The interesting part wasn't that the Teensy could handle the workload. It obviously can. The interesting part was how quickly system design problems masquerade as hardware limitations when timing integrity breaks down.

Most embedded failures in systems like this aren't CPU-bound. They're architecture-bound.

Where This Goes Next

The next iteration of N.O.V.A. will likely push toward better timestamp discipline between subsystems and tighter synchronization between CAN and IMU streams. GPS remains the least reliable reference source in the chain, which makes it the least trusted anchor for alignment.

For now, the system works. More importantly, it works consistently — which is the only metric that matters at speed.