Dashboard

From 'Engineers of Innovation Wiki'
Jump to navigation Jump to search

The dashboard is the e-paper screen the pilot reads while sailing. It is mounted on the left side of the steering wheel in the cockpit, and shows speed, battery power, state of charge, temperatures and the clock. It measures nothing itself: it listens to the whole CAN bus and draws whatever the other nodes are saying.

The dashboard showing live data

At a glance

Dashboard summary
Property Value
Panel Waveshare 5.79" e-paper, 792 × 272, black and white, SSD1683 controller
Location Cockpit, left of the steering wheel
Controller board STM32L471RGT6 — the same PCB as the height sensor controller
Bus CAN 2.0A, 1 Mbit/s, 11-bit standard identifiers
Transmits Nothing, except replies to bootloader queries on 0x038
Update rate At most once per second, and only when the picture actually changed
Application type 0x03 — its address in the bootloader protocol
Firmware Rust, embassy, binary dashboard
Firmware source firmware/ in the eoi-can monorepo
Screen source draw-display/ in the same repo, shared with the simulator
Hardware source Altium project AKD-CAN_Interface (Altium 365)
Field update Over CAN, no debug probe needed

What is on the screen

The screen is a fixed layout — nothing moves, and a value that goes missing is replaced by dashes in the same place rather than disappearing.

Screen regions
Region Shows
Left column Net Power in watts as the headline, with Power In and Power Out beneath it
Centre Speed in km/h, large, with the GNSS fix state under it (3D fix, 2D fix, No fix, or --- when the receiver is silent)
Right column State of Charge in percent as the headline, over a 2 × 2 grid of temperatures: Motor, Driver, the hottest MPPT, and the hottest battery thermistor
Under the speed Four warning icons, each in a fixed slot
Bottom row Current Time, Race Time, Time to Empty
Top line, small Firmware version and git hash, centred; the datalogger's WiFi IP on the left when it reports one

Power. Currents leaving the battery are negative on the bus, so the three figures are: Power In = charge current × pack voltage, Power Out = (motor + peripherals) × pack voltage, and Net Power = the sum of all three. A positive net power means the battery is charging.

Temperatures. The MPPT cell names the unit it is showing — MPPT F3 forward, MPPT R0 aft — because it always shows whichever MPPT is currently hottest. The Motor cell reads the standalone NTC node on 0x219 only; the VESC reports a motor temperature too, but it is broken on this boat and is deliberately never used as a fallback.

Missing data. Every value has a 5 second staleness timeout. If nothing has arrived for a value within that window it draws as dashes. Dashes therefore mean "not being reported", not "zero".

Warning icons

Each icon appears only while its condition holds, in its own fixed slot, so a warning is always in the same place.

Icon Raised when
Battery Battery state, charge FET or discharge FET is anything other than normal
Low charge State of charge below 15 %
Over-temperature Motor above 50 °C, driver above 70 °C, any MPPT above 80 °C, or a battery thermistor above 45 °C
Throttle The throttle reports any error flag

A stale or missing value never raises an icon — the dashes already show that data is being lost.

Hardware

The board is the Altium project AKD-CAN_Interface, the same PCB as the height sensor controller. Where that board fits four RS-485 channels, this one fits the e-paper panel on SPI2.

Display connections
Signal Pin
SPI2 SCK / MOSI / MISO PB13 / PB15 / PB14
Chip select PC6
Data/command PC9
Reset PC8
Busy PA8
Panel power PB12, held on for the life of the firmware

SPI runs at 2.5 MHz and is DMA-backed, so a full framebuffer transfer (~86 ms) does not block the CAN receive task. Those DMA channels — DMA1_CH4/CH5 — are the only pair SPI2 can use, and they are the ones I²C2 would need, which is why this board has no onboard temperature sensor where its sister boards do.

24 V arrives on the CAN connector and is stepped down on the board, exactly as on the height sensor unit. The safety line passes straight through and is not connected to the microcontroller.

Refreshing

E-paper is slow and wears with every drive cycle, so the firmware avoids refreshes it does not need:

  • The framebuffer is hashed after each render. An identical picture is not sent to the panel at all.
  • Every 60th refresh is a full refresh, which clears the ghosting that the fast differential refresh accumulates. The other 59 are differential.
  • A refresh takes between 0.7 and 2.5 seconds; the render itself costs about half a second. The loop is floored at one second per iteration.

So the screen updates roughly once a second while values are changing, and sits still when they are not.

CAN

The dashboard uses an accept-all hardware filter — it needs the whole bus — and decodes the identifiers it knows about. Everything else is ignored.

What the screen is built from
Source Identifiers Used for
BMS 0x1000x107 State of charge, pack voltage, the three currents, temperatures, battery/charge/discharge states
GNSS 0x200, 0x201, 0x204 Fix state, speed, clock
VESC 0x1009 Driver (FET) temperature
Motor NTC node 0x219 Motor temperature
MPPT / GaN MPPT 0x4000x4FF, 0x7000x77F MPPT temperatures, per-panel power
Throttle 0x1337 Throttle error flags
Datalogger 0x205 WiFi IP shown on the stamp line

The full bus-wide reference is CAN_MESSAGES.md.

The dashboard originates no traffic. The only frames it ever sends are answers to the host's bootloader-protocol queries.

Firmware update over CAN

The first 80 KB of flash holds a CAN bootloader, so the board can be updated in the cockpit without a debug probe. It owns application type 0x03, giving it the identifier block 0x037 (command) / 0x038 (response) / 0x039 (write data); the bootloader's hardware filter rejects every other block, so a command aimed at another board cannot touch this one.

eoi-flash-tool scan                          # what is on the bus?
eoi-flash-tool flash dashboard               # target comes from the ELF
eoi-flash-tool --board dashboard version     # which build is on it?

The version and git hash of whatever is running are also printed along the top of the screen, so the running build can be read off the panel without a laptop.

The protocol, the flash layout and the addressing scheme are shared with the other boards and are documented in full on the Rudder controller page.

Working on the screen without hardware

The whole layout lives in the draw-display crate and is shared by the firmware, a desktop simulator and a Raspberry Pi framebuffer tool — so a screen change can be seen without flashing anything.

cd eoi-can-display-simulator
cargo run -- -ccan0                          # live, against a real bus
EG_SIMULATOR_DUMP=screenshot.png cargo run   # write a PNG instead

The layout is checked at compile time: the positions are const arithmetic, and assertions fail the build if two regions would overlap or a value would not fit its cell. Font metrics are pinned by tests, so a regenerated font that drifts breaks the build rather than the picture.

A second layout, foiling, exists for the foiling trim screen and runs on its own board. Same code, same decoder, different arrangement — pick it with --layout foiling in the simulator.

Diagnostics

Reading the board without a debugger
Symptom Meaning
Green LED toggling once per second Application running normally
Blue LED flickering CAN frames arriving — it toggles once per frame
Red LED on briefly A panel refresh is in progress
Red LED double-flashing Sitting in the bootloader, waiting or flashing
Everything reads dashes Nothing is arriving on the bus. Check bus wiring and termination before suspecting the board.
One column reads dashes That node is silent; the dashboard is fine
Screen frozen but LEDs normal The picture has not changed — identical frames are deliberately skipped
Ghosting or grey smears Normal between full refreshes; cleared by the next one, at most 60 refreshes away

A 4-second independent hardware watchdog is petted once per second, so wedged firmware resets itself. If no frames arrive for several loop iterations the firmware logs the CAN peripheral state and re-arms the receive interrupts by itself. Detailed logging is available over SWD through defmt.

Known gaps

  • Race Time is empty. The block is drawn and labelled, but nothing on the bus signals a race start, so it always shows dashes.
  • Time to Empty is empty. Nothing calculates or broadcasts it yet. The BMS field exists but is not fed to the screen.
  • The clock is hardcoded to UTC+2. Correct for Dutch summer time and wrong by an hour the rest of the year. There is no time zone handling.
  • No onboard temperature sensor. Unavoidable on this board — SPI2's DMA channels are the ones I²C2 would need. The dashboard therefore reports no board temperature of its own.
  • No user input. The board has a sealed rotary switch fitted, but no firmware reads it. The screen cannot be paged or configured from the cockpit.
  • Per-panel MPPT power is decoded but not shown. The data is collected and available to the layout; there is no room for it on the dashboard screen.

See also