Skip to content

CANShift

An open-source dashboard for sport and track cars. ESP32 firmware, browser tuner over Web Serial, mobile companion over BLE. Wire it to your ECU, edit pages live, burn the config.

Pick your doorway

At a glance

  • Target MCUESP32 WROOMno PSRAM required
  • Panel320 × 240ILI9341 + XPT2046
  • Host linkWeb SerialCH340 UART @ 115200
  • Mobile linkBLENimBLE, ~50 KB DRAM
  • Telemetry10 HzJSON over USB CDC
  • ConfigLive burnSPIFFS, atomic, ≤ 16 KB

The packages

canshift-firmware

C++17 on Arduino-ESP32, LVGL 8.4, LovyanGFX. Parses CAN over TWAI, decodes signals, drives the panel. Source of truth for the dashboard’s runtime behaviour.

canshift-core

Shared TypeScript domain — Zod schemas, signal map, design tokens. Pulled by tuner and mobile; mirrored by the firmware’s canshift-core/dist types.

canshift-tuner

Vite + React SPA on Vercel. Talks to the dash over Web Serial. Lets a tuner edit the dashboard, run a CAN scan, and flash firmware — the standalone flasher is gone; /firmware is the route.

canshift-mobile

Expo React Native. Pairs over BLE for in-car telemetry and secondary config. Useful when the tuner laptop isn’t in the car.

The hardware target

Reference build
MCU
ESP32-WROOM-32, 4 MB flash, no PSRAM
Panel
Elecrow CrowPanel 2.8″ — ILI9341 SPI + XPT2046 touch
CAN transceiver
NXP TJA1051T/3 (3.3 V tolerant)
Host port
USB-C → CH340 UART0 (GPIO 1 = TX, GPIO 3 = RX)
CAN GPIO
TX = 17, RX = 16 (TWAI peripheral, 500 kbit/s default)
Wire protocol
Newline-delimited JSON, USB_PROTOCOL_VERSION = 2

Different ESP32 board? Different panel? The signal map and most of the runtime are board-agnostic. See Pinout for the GPIO contract and Build flags for the compile-time switches.

Why this docs site exists

The firmware used to carry a thick comment layer explaining the non-obvious bits — LVGL ownership rules, the heap reservation order on a no-PSRAM WROOM, the PUT_CONFIG burn flow, the cruise control polygon workaround. Comments rot the moment they leave their reviewer’s screen. The architecture section is where that rationale lives now, beside the code rather than inside it.

If you are about to edit a non-trivial subsystem, read the matching architecture page first. The surprises in this codebase are written down — and almost all of them are surprises only the second time.