Getting startedΒΆ
CAN Bus Demo with ESP32, LVGL, and DBC Code GenerationΒΆ
A demonstration project showcasing CAN bus communication between two ESP32 boards with LVGL GUI, DBC-based code generation, and a modular firmware architecture. This project is ideal for learning CAN protocols, embedded UI development, and code generation workflows.
π― What This Project DemonstratesΒΆ
CAN Bus Communication
Dual ESP32 setup: one TX board (transmitter) and one RX board (receiver)
500 kbps CAN communication using ESP32βs built-in CAN controller
Message filtering, unpacking, and event-driven processing
DBC-Driven Code Generation
Define CAN messages in a standard
.dbcfileAuto-generate C code for encoding/decoding using
c-coderdbcType-safe message handling with generated structs
LVGL Graphical UI (RX Board)
Real-time display of CAN data on TFT touchscreen
SquareLine Studio integration for UI design
Arc gauge for speed, turn signal indicators
Modular Firmware Architecture
Event-driven state machine with message routing
Pub/sub pattern for decoupled components
Health monitoring with automatic degradation and recovery
π Quick StartΒΆ
PrerequisitesΒΆ
Hardware
2x ESP32 boards (e.g., ESP32-EVB or similar)
CAN transceivers (e.g., SN65HVD230 or MCP2551)
TFT display with touch (for RX board)
CAN bus wiring (120Ξ© termination resistors recommended)
Software
PlatformIO (VS Code extension or CLI)
Python 3.x (for optional documentation builds)
Git (to clone this repository)
InstallationΒΆ
Clone the repository
git clone https://github.com/rvxfahim/CAN-Demo-ESP32.git cd CAN-Demo-ESP32
Configure serial ports (if different from defaults)
Editplatformio.iniand set your COM ports:[env:rx_board] upload_port = COM8 ; Change to your RX board port monitor_port = COM8 [env:tx_board] upload_port = COM9 ; Change to your TX board port monitor_port = COM9
Build and upload
RX Board (receiver with display):
pio run -e rx_board -t upload pio device monitor -e rx_board
TX Board (transmitter):
pio run -e tx_board -t upload pio device monitor -e tx_board
Connect the hardware
Wire CAN_H and CAN_L between boards through transceivers
Connect 120Ξ© termination resistors at both ends
Power both boards
TX will start sending
Clusterframes; RX display will update
π Understanding the DBC WorkflowΒΆ
What is a DBC File?ΒΆ
A DBC (CAN Database) file is an industry-standard format for defining CAN messages, signals, and their properties. It serves as the single source of truth for all CAN communication in this project.
Location: tools/Lecture.dbc
Code Generation ProcessΒΆ
This project uses c-coderdbc to auto-generate C encode/decode functions from the DBC file.
Step 1: Edit the DBC FileΒΆ
The example Lecture.dbc defines a Cluster message (ID 0x65) with signals:
Speed(12-bit): 0β4095 rangeLeft_Turn_Signal(1-bit): booleanRight_Turn_Signal(1-bit): boolean
You can edit this file with any text editor or use tools like CANdb++ Editor or SavvyCAN.
Step 2: Run the Code GeneratorΒΆ
Windows:
cd tools\c-coderdbc
.\build\coderdbc.exe -dbc ..\Lecture.dbc -out ..\..\lib\Generated
This regenerates:
lib/Generated/lib/lecture.candlecture.h(generated code, do not edit)Helper files in
lib/Generated/conf/,lib/Generated/inc/, etc.
Linux/macOS:
Youβll need to compile c-coderdbc from source (see tools/c-coderdbc/README.md).
Step 3: Use Generated Types in CodeΒΆ
The firmware uses the generated types exclusively:
#include "lecture.h" // Generated header
// Packing (TX side)
Cluster_t cluster = {0};
cluster.Speed = 2048;
cluster.Left_Turn_Signal = 1;
cluster.Right_Turn_Signal = 0;
uint8_t data[8];
Pack_Cluster_lecture(&cluster, data, 8);
CAN0.sendFrame({ .identifier = 0x65, .data = data, ... });
// Unpacking (RX side)
Cluster_t received;
Unpack_Cluster_lecture(&received, frame.data, frame.data_length_code);
Key principle: Never manually parse CAN bytes. Always use Pack_* and Unpack_* functions.
ποΈ Project StructureΒΆ
CAN-Demo-ESP32/
βββ platformio.ini # Build config (two environments: rx_board, tx_board)
βββ tools/
β βββ Lecture.dbc # CAN message definitions (source of truth)
β βββ c-coderdbc/ # DBC-to-C code generator
βββ lib/
β βββ Generated/ # Auto-generated C code (from DBC)
β βββ CanDriver/ # ESP32 CAN driver abstraction
β βββ Ui/ # LVGL UI (SquareLine Studio exports)
β βββ TouchLibrary/ # Touch controller drivers
βββ src/
β βββ common/ # Shared code (MessageRouter, etc.)
β βββ rx/ # RX board firmware (main + modules)
β βββ tx/ # TX board firmware (main only)
β βββ generated_lecture_dbc.c # Single include wrapper for DBC code
βββ include/ # Global headers (IOPins, TFT config)
βββ docs/ # Sphinx documentation source
βββ README.md # This file
π DocumentationΒΆ
For detailed architecture, sequence diagrams, and API references, see the full documentation:
π GitHub Pages DocumentationΒΆ
Topics covered:
Getting Started: Detailed setup and hardware connections
Architecture: Component diagrams, state machines, data flow
CAN & DBC: In-depth DBC workflow and regeneration steps
Testing: Unit test guidelines and test hooks
API Reference: Doxygen-generated class/function documentation
π§ Configuration and CustomizationΒΆ
CAN ParametersΒΆ
Bitrate: 500 kbps (configurable in
CanInterface.cpp)Pins: GPIO 35 (RX), GPIO 5 (TX) β change in
CanInterface::Initialize()Message ID:
0x65forCluster(defined in DBC)
Display and UIΒΆ
Screen: Configured in
include/TFTConfiguration.handlib/Ui/UI Design: Edit with SquareLine Studio, export to
lib/Ui/Widgets: Arc gauge (
ui_Arc1), labels (ui_RightLabel,ui_LeftLabel)
IO Relays (Blinkers)ΒΆ
Pins: GPIO 25 (left), GPIO 26 (right) β see
include/IOPins.hBlink Rate: 1 Hz (500ms ON/OFF) β adjust in
IOModule::Update()
Health MonitoringΒΆ
Timeout: 1500ms (RX declares
Degradedif no CAN frames) β seeHealthMonitor.cpp
π§ͺ Testing and TroubleshootingΒΆ
Common IssuesΒΆ
RX display doesnβt update:
Verify TX is sending frames (check TX serial monitor)
Check CAN wiring and termination resistors
Ensure both boards have matching bitrate (500 kbps)
Blinkers donβt work:
Confirm relay pins in
include/IOPins.hmatch your hardwareVerify
Left_Turn_Signal/Right_Turn_Signalbits are set in TX
System shows βDegradedβ:
Normal behavior when CAN frames stop arriving (timeout threshold)
Should auto-recover when TX resumes
Build ErrorsΒΆ
Missing LVGL or TFT_eSPI:
PlatformIO will auto-install dependencies from lib_deps in platformio.ini.
Linker errors about Cluster_t:
Ensure src/generated_lecture_dbc.c is included in the build (check build_src_filter).
π€ ContributingΒΆ
Contributions welcome! Please:
Fork the repository
Create a feature branch (
git checkout -b feature/amazing-feature)Commit changes (
git commit -m 'Add amazing feature')Push to branch (
git push origin feature/amazing-feature)Open a Pull Request
π LicenseΒΆ
This project is licensed under the GPLV3 License. See LICENSE file for details.
π Key TechnologiesΒΆ
PlatformIO β Cross-platform embedded build system
LVGL v9.1 β Lightweight graphics library
TFT_eSPI β Fast TFT display driver
SquareLine Studio β Drag-and-drop LVGL UI designer
c-coderdbc β DBC-to-C code generator
ESP32 Arduino β Arduino framework for ESP32
π Questions or SupportΒΆ
Documentation: https://rvxfahim.github.io/CAN-Demo-ESP32/
Issues: GitHub Issues
Repository: github.com/rvxfahim/CAN-Demo-ESP32