Skip to content
Colin WolffSYS_DOMAIN: colinwolff.dev // NO_SOCIALS
SYS_STATUS: ONLINE

[SPEC-01 // MCU-884]

Modular Automotive CAN-Bus Head Unit

Double-DIN instrument console that merges real-time CAN telemetry with decoupled host media processing, without touching the factory wiring harness.

[PROJECT]STATUS: NOMINALREV: 2026.10
// Status
NOMINAL
// Reference
MCU-884
// Revision
2026.10
// Published
APR 12, 2026
// Updated
OCT 21, 2026
Signal path from the vehicle CAN bus through the transceiver and STM32U5 coprocessor to the cluster bridge and host snapshot ring.

Context

A 2004 chassis with a dead factory head unit. The requirement was not “add a screen”: it was to keep every factory convenience module talking while giving the driver real instrument data the original cluster never exposed — oil temperature, per-wheel speed, transmission line pressure.

Replacing the head unit on this platform is easy. Replacing it without severing the vehicle bus, and without a two-second black screen on every ignition cycle, is the actual engineering problem.

Constraints

  • The factory harness stays intact. Every connector must be reversible.
  • The host operating system is not real-time and never will be. Media decode and UI composition live there; nothing safety-relevant may depend on it.
  • Ignition-off power budget is 40 mA at 12 V. The unit must cold-start in under two seconds or the reverse camera feed is useless.
  • No cloud dependency. Diagnostics are read locally over USB-C DC.

Architecture

Two processors with a single narrow contract:

  1. STM32U5 coprocessor owns the CAN transceivers, the ignition state machine and the cluster display bridge. It is no_std Rust with a fixed 1 kHz scheduler; the only dynamic allocation is a bounded ring buffer established at boot.
  2. Raspberry Pi 5 host owns media, navigation and the touch surface. It talks to the coprocessor over a framed SPI link carrying two message classes: periodic telemetry snapshots and idempotent commands.

The split exists because the host cannot guarantee latency, and the coprocessor cannot afford a Linux BSP. Telemetry frames are decoded twice — once on the coprocessor for the cluster, once on the host for logging — which sounds wasteful until you measure it: the decode is 40 µs on the M33 and removes an entire failure mode (host stall ⇒ blank gauges).

CAN bus ──► TCAN transceiver ──► M33 decode ──┬─► cluster bridge (SPI)
                                              └─► snapshot ring ──► Pi 5

Trade-offs

  • Snapshot, not stream. The host receives coalesced state at 50 Hz rather than raw frames. Logging resolution drops, but the host can fall behind without dropping bus traffic. Chosen deliberately.
  • Fixed-size rings over queues. A full ring overwrites the oldest sample. For instrumentation this is correct behavior; for an event log it would not be, so events use a separate acknowledged channel.
  • A/B slots cost 512 KB of flash and one extra boot state. Rollback on three consecutive watchdog resets has saved the unit twice during bring-up.

Failure modes handled

  • Ignition churn during crank: the coprocessor holds the cluster alive on a 3.3 V rail while the host reboots.
  • Bus-off: automatic recovery after 128 × 11 recessive bits, logged with a monotonic counter readable over USB.
  • Thermal: host throttling is detected via sysfs and surfaced as a subdued [THERMAL: DERATE] marker rather than a modal dialog. The driver is busy.

Outcome

Ten months in service, ~14,000 km, zero bus faults and no panel artifacts. The reversible harness adapter took two revisions; the firmware contract has not changed since the first bench build.