Credits: based on the original project by Gh0513d/SVD π
A touch dashboard for VESC based eβscooters, eβbikes and boards, running on cheap ESP32 "Cheap Yellow Display" boards. Version 2 is a complete rewrite on LVGL 9 and LovyanGFX: one code base for the 2.8" and the 3.5" boards, talking to the VESC over UART, CAN or Bluetooth LE β and it can replace the VESC's Bluetooth module, so VESC Tool on your phone connects through the display.
Looking for the old TFT_eSPI version (v1)? It is kept unchanged in the
oldfolder.
| Folder | Content |
|---|---|
firmware/ |
v2 firmware (Arduino sketch + lv_conf.h) |
old/ |
original v1 firmware and its libraries |
tools/ |
build script, font and boot logo generators |
3d_models/ |
housing and mounts |
Dashboard & touch UI
- Big anti-aliased speed (optional decimal) with max/avg, range/efficiency or odometer/ride-time line
- Battery % (Li-ion or LiFePO4 curve, filtered) + voltage, power (W/A), power/regen bar, duty-cycle bar
- 5 configurable cells β choose from 17 values (temperatures, currents, power, voltage, battery %, duty, trip, odometer, range, Wh/km, Wh, Ah, ride time, avg/max speed); long press a cell to change it
- 5 pages β swipe or use the arrows: Dash Β· Trip stats Β· Live data Β· Charts Β· Settings
- Live charts of the last 60 s (speed/power, currents, temperatures, voltage/duty)
- Everything is configurable on the screen and stored in flash
- Back to the dashboard automatically when riding, optional dimming when standing still
Connectivity
- UART (default) β same wiring as v1
- CAN β ESP32 TWAI + 3.3 V transceiver; VESC id auto-detect, bus scan, falls back to CAN status messages
- BLE link β connect to an existing VESC BLE module (when the VESC UART is already used by it)
- BLE bridge for VESC Tool β the display replaces the NRF BLE module (custom name, optional 6βdigit PIN)
- Dual motor β second VESC on CAN (via
COMM_FORWARD_CANin UART mode) - Non-blocking protocol implementation (the v1 library could freeze the screen for 100 ms per request)
Safety, data & hardware
- Warnings: VESC faults (by name), ESC/motor temperature, low/empty/over battery, speed, high duty β on screen, RGB LED and beeper (speaker connector)
- CSV ride log on the microβSD card Β· odometer and (optional) trip kept across restarts
- Auto brightness with the light sensor (adjustable), touch calibration, demo mode without a VESC
- Own boot logo from the SD card β no rebuild needed
| Board | Screen | Touch | PlatformIO env / Arduino define |
|---|---|---|---|
| ESP32β2432S028R | 2.8" 320Γ240 ILI9341 | resistive | esp32-2432s028r / BOARD_ESP32_2432S028R |
| ESP32β2432S028R (2ΓUSB) | 2.8" 320Γ240 ST7789 | resistive | esp32-2432s028r-st7789 / BOARD_ESP32_2432S028R_ST7789 |
| ESP32β3248S035R | 3.5" 480Γ320 ST7796 | resistive | esp32-3248s035r / BOARD_ESP32_3248S035R |
| ESP32β3248S035C | 3.5" 480Γ320 ST7796 | capacitive (GT911) | esp32-3248s035c / BOARD_ESP32_3248S035C |
| Where | Action |
|---|---|
| anywhere | swipe left / right β next / previous page |
| battery (top left) | tap β big value % β volts |
| power (top right) | tap β watts β battery amps |
| speed | tap β MAXΒ·AVG / RANGEΒ·Wh/km / ODOΒ·RIDE TIME |
| a bottom cell | long press β choose what it shows (+ Reset trip on the trip cell) |
| top centre notch | tap β statistics |
| page title | tap β back to the dashboard |
| during the boot logo | touch β touch calibration |
| Board | Connector | UART RX/TX or CAN RX/TX |
|---|---|---|
| ESP32β2432S028R | CN1: GND Β· IO22 Β· IO27 Β· 3V3 | RX = IO22, TX = IO27 (same as v1) |
| ESP32β3248S035R/C | P3: GND Β· IO35 Β· IO22 Β· IO21 | RX = IO35, TX = IO22 |
Power the board with 5 V (e.g. VESC 5 V β board 5 V/VIN) and always connect GND.
UART β display RX β VESC TX, display TX β VESC RX. In VESC Tool App Settings β General β App to Use must include UART, baud rate 115200 (or whatever you select on the display).
CAN β needs a 3.3 V CAN transceiver (SN65HVD230, TJA1051T/3, β¦):
display RX pin ββ transceiver R / CRX transceiver CANH ββ VESC CANH
display TX pin ββ transceiver D / CTX transceiver CANL ββ VESC CANL
3V3, GND ββ transceiver VCC, GND 120 Ξ© termination at both bus ends
VESC default bit rate is 500 kbit/s; VESC CAN ID = AUTO finds the VESC. For the status-message fallback enable App Settings β General β CAN Status Message Mode in VESC Tool.
BLE link β Interface = BLE: the display connects to the nearest VESC BLE module and remembers it once the module answers like a VESC (other "Nordic UART" gadgets nearby are skipped). Settings β Bluetooth β Forget to pair another one.
BLE bridge β Settings β Bluetooth β VESC Tool bridge = on, restart, then scan in VESC Tool for "VESC SVD xxxx" (or the name you set). With Bridge needs PIN the phone asks once for the PIN shown on the display.
- Boards Manager: esp32 by Espressif (2.0.17 or 3.x).
- Library Manager: LovyanGFX (β₯ 1.2.7), lvgl (9.1 β¦ 9.6), NimBLE-Arduino (β₯ 2.2.3).
- Copy
firmware/lv_conf.htoDocuments/Arduino/libraries/lv_conf.h(next to thelvglfolder β back up an existing one; the build stops with a clear message if the wrong or an older file is used. Updating from 2.0.0: copy it again). - Open
firmware/SimpleVescDisplay/SimpleVescDisplay.ino, select your board insrc/config/board_config.h. - Tools β ESP32 Dev Module, Partition Scheme Huge APP (3MB No OTA/1MB SPIFFS) β Upload (hold BOOT if the upload does not start).
pio run -e esp32-3248s035c -t uploadMerged images (*_merged.bin, see Releases) can be flashed at address 0x0 with
https://espressif.github.io/esptool-js/ or esptool.py write_flash 0x0 <file>.
The odometer of v1 is imported automatically on the first start.
- The first build compiles LVGL (β 5 min), later builds only recompile changed files (β 30 s) β keep the
IDE open and do not change
lv_conf.hunless needed. - Each board compiles only the fonts it uses; unused LVGL widgets are disabled in
lv_conf.h. - On Windows, excluding the Arduino build folder (
%LOCALAPPDATA%\arduino) from the antivirus real-time scan typically makes builds 2β3Γ faster.
- No rebuild: copy
splash.pngorsplash.jpg(max 100 KB, any size β scaled to fit, 480Γ320 / 320Γ240 look best) to the root of the SD card. - Built in:
python tools/images/png2header.py my_logo.png firmware/SimpleVescDisplay/src/ui/images/splash_png.h - Edit the default logo: texts and colours are at the top of
tools/images/make_splash.py. - Settings β Display β Boot logo switches it off.
| Section | Options |
|---|---|
| Connection | interface (UART/CAN/BLE), UART baud, CAN bit rate, VESC CAN id (AUTO), display CAN id, 2nd VESC id, poll rate, CAN scan |
| Bluetooth | VESC Tool bridge, PIN pairing, device name, forget paired devices |
| Vehicle | motor poles, wheel diameter, gear ratio, speed correction %, battery type, cells, capacity |
| Dashboard | the 5 cells, speed decimal, power bar scale, start page |
| Units & warnings | km/hΒ·mph, Β°CΒ·Β°F, speed / temperature / duty / low battery limits, beeper, speed beep, touch sound, RGB LED |
| Display | auto brightness (LDR) with minimum level and dark threshold (live sensor value), brightness, idle dimming, rotate 180Β°, invert colours, swap red/blue, back to dash while riding, boot logo, touch calibration |
| Data | keep trip after restart, SD logging, set odometer, reset trip, demo mode |
| System | info, free memory, restart, factory reset (keeps the odometer) |
Compile-time defaults: src/config/app_config.h Β· pins: src/config/board_config.h.
| Problem | Fix |
|---|---|
| colours look negative | Settings β Display β Invert colours |
| red and blue swapped | Settings β Display β Swap red/blue (restart) |
| touch is offset | touch the screen while the boot logo is shown β calibrate |
| "NO VESC LINK" | swap RX/TX, check GND and baud rate, App to Use must include UART |
| CAN: nothing found | 3.3 V transceiver, CANH/CANL not swapped, 120 Ξ© termination, bit rate |
| BLE stays on "scanning" | close VESC Tool on the phone (a VESC BLE module accepts one connection), disable the pairing PIN of a VESC Express |
| image noise | lower TFT_SPI_FREQ in board_config.h (e.g. 27000000) |
| display restarted by itself | after the restart a message shows why; also Live data β Last restart / Settings β System. brownout = the 5 V supply dips (use a better DC/DC converter or shorter, thicker wires); crash = please open an issue with the USB serial log |
The USB serial port (115200 baud) prints diagnostics, including free memory and the reason of the last restart.
- New UI on LVGL 9, 3.5" support, one code base for all boards, everything configurable on the screen
- Own non-blocking VESC protocol (UART / CAN / BLE) instead of ComEVesc, BLE bridge for VESC Tool
- Distance fix: v1 used motor revolutions / 1000 as kilometres (wheel size ignored); v2 uses wheel diameter, motor poles and gear ratio. Correct your odometer once in Settings if needed.
- Settings, odometer and trip in NVS with wear-friendly saving (every km and when stopped)
- Fixed random restarts with Bluetooth: the BLE scan stored every advertising device, so in crowded places (many phones, watches, headphones) the memory ran full and the display rebooted. The scan now keeps only the best VESC candidate.
- Fixed a restart while riding: LVGL allocated a ~13 KB buffer for the big speed digits on every redraw; with Bluetooth and a fragmented heap that eventually failed. A fixed glyph buffer is used now.
- Out-of-memory protection: LVGL allocates through a guard with a 16 KB reserve β a full heap closes the open page and dialogs with a message instead of rebooting; pages, keyboards and choosers only open when enough memory is free; the BLE scan and the SD card wait for memory too.
- Less RAM: smaller draw buffers (allocated before Bluetooth starts), shared styles in the settings, one ride mode at a time in Settings β Ride modes, the dashboard is no longer built twice on a theme change.
- BLE link binds only to a module that answers VESC packets; longer reply timeout over Bluetooth.
- BLE bridge: VESC Tool gets its replies even while the display polls the same data.
- Bigger loop stack, checked Bluetooth start, safe SD log buffer, dialogs keep their own action, no second odometer keypad on a double tap, CAN frames limited to 8 bytes, buffered UART TX (forwarding VESC Tool packets no longer stalls the screen), SD log file number kept in flash.
- Reason of the last restart (brownout, crash, watchdog β¦) on screen and in Live data.
MIT. Fonts: Montserrat & Font Awesome (SIL OFL) as shipped with LVGL.

