Introduction: MegaSquirt Digital Dashboard Display

Project Introduction

This is a digital dashboard display project intended to be used with a MegaSquirt2-Extra or MegaSquirt3 ECU (engine control unit). It's 5-inch high-brightness LCD panel and LED strip makes viewing vital car/engine information quick and easy.

The firmware currently only has the option of displaying three different screens. One demo screen, and two screen showing some live information from the Megasquirt. The screens are flipped by touching the LCD screen (it's a capacitive touch panel).

It's not a simple project but the result is well worth the effort! The parts are relativity cheap to buy and you end up with a completely customizable digital dashboard display that rivals $1000+ commercial units.

As this display is CANbus based, it could also be programmed to work with data from many other aftermarket ECUs from manufacturers like Haltech, Link, EMS, FuelTech, ECUMaster, Motec, Syvecs, Emtron, etc, etc. It could also be programmed to support later model factory cars via a OBDII CANbus interface.

In my case, I have a 1990 Toyota Celica GT4 (aka Alltrac) that is used as a weekend club / race car. It has been running a MegaSquirt3 + MS3X ECU for about 6 years now. Previously I have used Android tablets/phones and RaspberryPi Linux devices to view ECU information, but these devices have proven to be slow to boot, unreliable and generally not fit for use in a harsh automotive environment no matter how much they are modified.


I am employed by Crystalfontz, and have been for well over 10 years now.

This project however was developed for my own use. I needed a better digital dash display for my Celica, and the new Crystalfontz high brightness accelerated display was absolutely perfect for this use.

Why the ESP32?

The ESP32 system-on-chip is great for this project for a few reasons:

  • Speed, dual-core running at 240Mhz
  • Plenty of Flash memory (4MB)
  • Built-in CANbus interface
  • It's fast SPI interface for LCD I/O
  • Ease of use via the Arduino framework
  • Cheap & easy to obtain

So far the Wifi/BLE capabilities of the ESP32 are not used in this project.

Why the Crystalfontz Accelerated LCD?

The particular Crystalfontz LCD panel (CFAF800480E0-050SC-A1-1) is perfect for this because:

  • It's 5-inch size, and 800x480 resolution is a good middle-ground for a dash display.
  • It has a high-brightness backlight, so can be easily seen in sunlight.
  • It's Bridgetek EVE2 graphics accelerator chip makes software development quicker, and reduces the processing power required by the main microcontroller (the ESP32) to render graphics.
  • Crystalfontz also sells an easy-to-use breakout board to use with this display (the CFA10098).

The graphics acceleration is provided by a FTDI/Bridgetek EVE2 FT813 chip on the LCD panel.

Most of the embedded graphics firmware I have personally written in the past has required rendering of graphics in a micro-controller/micro-processor display buffer, which is then pushed out to the LCD panel one whole screen at a time. This requires quite a powerful processor, a lot of graphics rendering code, and careful timing.

The EVE2 graphics accelerator does a lot of this for us. We (using the ESP32) give a list of graphic objects to display (text, lines, circles, bitmaps, etc) to the EVE2, which it then renders on the LCD for us. It's relativity easy to use, yet surprisingly powerful.

It also handles the capacitive touch screen interface for us (not used in this project much so far).

Why CANbus?

CANbus is very flexible, simple, fast and robust. While this project could have supported the Megasquirt serial interface (and may do in the future), using the CANbus interface just makes more sense here. There is less programming needed for obtaining data from the MegaSquirt when using CANbus. The MegaSquirt ECU is set up to blindly send the data out over the CANbus; we just suck it up and display it.

It would also be quite simple to support other aftermarket ECUs that can be configured to send data over CANbus.

Circuit Explanation

The project has 5 main operational parts:

  • Crystalfontz EVE2 accelerated LCD panel
  • ESP32 system-on-chip
  • MCP2551 CANbus transceiver
  • WS2812b LED panel
  • 5V Power supply

The NodeMCU-32s is the brains of the project. It has a ESP32 system-on-chip (micro-processor, ram, flash memory, etc) that runs the firmware we upload to it via the USB connector.

We use the ESP32 to obtain Megasquirt information from the CANbus, decode it, then create a display-list (graphics objects) which we send to the EVE2 accelerated LCD panel via the SPI interface. The ESP32 also sends color/brightness data to the WS2812b LEDs via a PWM (pulse-width modulated) interface.

The ESP32 contains a CANbus interface, but extra interfacing is required between it and the actual CANbus wires that go off to the MegaSquirt. The MCP2551 CANbus transceiver chip/module does this for us.

The two resistors (1K ohm and 2K ohm) are used as a voltage-divider. This is needed as the MCP2551 outputs a 5V signal, but the ESP32 can only handle 3.3V. The voltage divider reduces that 5V to approx 3.3V so we don't damage the input pin on the ESP32.

5 volt supply is required for most of the circuitry in this project, so we need a voltage regulator to take the normal 9V to 16V present in a car (car batteries are 12V, but when a car is running its normally around 14V), down to 5V. It needs to supply up to 2 amps (the LCD backlight and WS2812b can use a decent amount of power).

The CFA10098 breakout board needs a 3.3 volt supply. The NodeMCU-32s has its own 3.3V regulator on-board, so we also use this to supply the CFA10098.

The Project Build

This is not the quickest or simplest project around, actually it's somewhat the opposite. You'll need a decent amount of electronics experience to build the display, and some C programming experience to customise the display.

Every build will be slightly different depending on exactly which components are used, and how they are laid out. The wiring for the most part should stay the same though. Improvements can definitely be made to my first build, on which this guide is based. I'll update this guide with any improvements I do make in the future.

Note: I built this project and had it working before I started documenting and taking photos for this Instructable, hence why there are no photos of a blank unsoldered strip-board, the NodeMCU-32s unmounted, etc.

Future improvements

  • Support easier configuration by loading MegaSquirt INI file, and using a screen-layout configuration file (XML perhaps?)
  • Add analogue inputs for LCD backlight dimming, high-beam indicator, turning signals, fuel level sensor, etc
  • Cache EVE2 display list updates and push them out with a single SPI block write for speed / efficiency
  • Add incoming data timeout checking
  • Add more graphics dial, gauge, etc types and options
  • Add more LED display options
  • Add a background image bitmap
  • Use the speaker output of the EVE2 / CFA10098 for warning signals
  • Add microSD card interface and support data logging (with access via wifi?)
  • Change from using Arduino subsystem to ESP-IF

Step 1: Gather Parts

Main required parts:

Other required parts:


The tools I used are below, but you may be able to use others to perform the same jobs:

  • A half-decent soldering iron with a fine tip
  • Dremel (or similar) with cutting & grinding discs
  • Electric drill with 3mm drill bit
  • Desoldering wick, or a desoldering gun / iron.
  • Razor blade
  • Multimeter
  • Other general electronics tools (small screwdrivers, side-cutters, small needle-nose pliers, etc).

Step 2: Prepare the Strip-board

First cut PCB strip-board to match the exact width of the LCD.

Using a Dremel with a cut-off wheel is preferred, but a hacksaw or similar can also be used.

Then cut the strip-board to match the height of the LCD, plus the height of the WS2812b LED strip if you're using one (read step 7 now for more about this). This will give you room to mount the LEDs facing you across top of the LCD module.

Place the strip-board over the back of the LCD module (making sure the extra height is hanging over the top of the LCD), and mark the location of the 6 mounting bolt holes. The bare side of the strip-board (not the site with the copper tracks) should face outwards. Drill the 6 holes with the 3mm drill bit. Once drilled, make sure you can screw the strip-board down onto the back of the LCD module.

Step 3: Prepare the CFA10098 Breakout Board

The CFA10098 must be modified a little to work for us.

First, carefully desolder the green speaker wire connector from the CFA10098 PCB. It must be removed, as we need to mount the CFA10098 to the strip-board face down and it'll get in the way. It's ROHS solder, so you'll need to get it quite hot, use good flux and good solder wick to soak up all the solder to pop the connector off the PCB.

The PCB is setup to supply 3.3V to the LCD's panel backlight, we need to change that to 5V. A very fine jumper/link needs to be cut. You'll need to look very closely at the bare pads next to the "BL=3.3V" label to see the link between the pads that you need to cut.

Step 4: Locate the CFA10098 on the Strip-board

Location of the CFA10098 on the strip-board is quite important to get right, as the flex cable between the LCD and CFA10098 must be straight and under no stresses.

First, get the male pin headers ready. Break off a single row of 14 pins, and a single row of 2 pins.

Plug & clip one end of the flex cable to the LCD panel. Screw the strip-board loosely to the back of the LCD module. Plug & clip the other end of the flex cable to the CFA10098.

Now wrap the CFA10098 over onto the back of the strip-board, keeping the flex cable aligned. Mark on top of the strip-board where the header pin strips need to be soldered to connect between the CFA10098 and the strip-board.

Unscrew the strip-board from the LCD module and solder the 14 pin header strip and 2 pin header strip in the marked locations. You can now place the CFA10098 down onto those pins and solder it in place (it's a good idea to only solder 2-3 pins to begin with, while laying out all the components just in case a mistake has been made and it needs to be removed).

Note that the 2 pin header pins may need to be bent slightly to match the holes on the CFA10098.

Step 5: Locate the NodeMCU-32s Module on the Strip-board

Place the NodeMCU-32s module on the strip-board off to the right of the CFA10098 module (leave 3-4 columns of strip-board holes between them).

Solder a couple of pins near each corner to keep it in place while laying out the rest of the components.

Step 6: Locate the MCP2551 Module on the Strip-board

Place the MCP2551 module above the NodeMCU-32s on the strip-board, again leaving some room around them. You'll need to have enough room to also place 2 or 3 resistors, and some pin headers next to the MCP2551 during a later step.

Solder a couple of pins near each corner to keep it in place while laying out the rest of the components.

Note: I didnt have a MCP2551 module on hand, but did have the bare IC. So in my photos you'll see the IC glued to the top side of the strip-board with wires soldered from the IC's pins to male header pins. Youll also see an extra resistor used for slope control, and a chip capacitor on the copper side of the strip-board.

Step 7: Locate the Power Supply Module on the Strip-board

If the 5V regulator you're using is compact enough, you can also mount this on the strip-board.

I recommend that it is mounted on the top-left of the strip-board, leaving a decent gap between the power regulator and the MCP2551 module for some power supply header pins, and the 100uF power smoothing capacitor.

Step 8: Locate the WS2812b LED Strip on the Strip-board (optional)

This step will need some adaptation depending on the size of the LED strip you're using (if any), and how it needs to be mounted. Some will need to be soldered in place, some screwed into place, and some glued into place.

There is also no reason why this LED strip needs to be mounted next to the LCD panel. It could be mounted on top the crash-pad, or A-pillar or anywhere else for clear viewing. It only needs 3 wires for connection to the strip-board.

In my case, the aim was to have the LED strip mounted above the LCD panel, so it can be easily hidden behind a mounting plate / bezel with holes to view the LEDs. I used two 8 x LED strips, so first I soldered the two boards together end-on-end making a single 16 LED strip.

I then mounted the strip-board onto the LCD module, positioned the LED strip so it was against the top edge of the LCD and level with the LCD glass, and soldered it in place there using some male header pins to make up the gap, and for connection of the 5V, ground and data-in connections to the strip-board.

Step 9: Strip-board Introduction

First, a quick introduction to using strip-board (also known as Vero board) for those that have not used it before.

Strip-board consist of rows of copper tracks on one side, with through-holes drilled at the standard 0.1 inch (2.54mm) spacing.

The tracks can be broken into smaller sections by using a drill bit. Using your fingers (not a power drill!), twist a 3 to 5mm drill bit into the copper track you wish to break. You just need to drill enough to remove the copper and break the track, there is no need to go all the way through the board. Make sure there are no little pieces of loose copper around the edges of the hole, and brush any other copper and fibre debris off the board. You don't want the loose copper making short-circuits elsewhere.

A short introduction video can be found here:

Note: Due to space constraints, we will be wiring this project using flying lead connection on the back of the board. In some ways this removes the prototyping advantages of using strip-board, but it does make building this project quicker, and require less planning. It does however make the build not quite as robust.

If you have a better construction method in mind, go ahead!

Step 10: Wiring

See the wiring diagram below.

I suggest that you use two rows of tracks for 5V and GND supply to all the components. So first choose two tracks next to each other that are not used by module pins.

  1. Solder all the remaining pins on the ESP32, CFA10098 and MCP2551 modules.
  2. Solder the 5V power smoothing capacitor (100uF) across the 5V power supply tracks you selected.
  3. Solder the CAN-RX voltage divider resistors in appropriate locations on the PCB close to the MCP2551 module.
  4. Solder 2-pin male header pins on the strip-board near the MCP2551 module for wiring of the CANbus lines off the board.
  5. Using a drill bit (see strip-board intro above), isolate the tracks of modules connection pins, and other components into sections.
  6. Using the enamelled copper wire, run point-to-point wires across the back of the PCB (copper track side) to make the required connections as shown on the wiring diagram.

To use enamelled copper wire for component connections:

  1. Cut the piece of wire to the approx required length, making it 5 to 10mm longer than needed so it can be moved around other components.
  2. Place a blob of solder on the end of a hot soldering tip, and insert the end of the enamelled (2 - 3 mm) wire into the solder.
  3. Hold the wire in the solder for 5 to 10 seconds. Youll find that the hot solder melts away the enamel on the wire, and tins the copper.
  4. Trim off the tip of the wire if too much of the enamel has been removed. You dont want the wire shorting to other tracks.

Step 11: Checking Connections & Powering Up

Double check your wiring connections against the wiring diagram. It's especially important to make sure the 5V and GND connections are correct as making a mistake here will probably damage one or more of the modules or LCD panel!

With the LCD panel disconnected (no cable between the CFA10098 and LCD module), apply 12V to the input of the 5V power regulator.
The RED led on the NodeMCU-32s should illuminate showing it has power. It is a good idea using a multimeter to check the voltage of the regulators 5V output, the 5V supply pins on each module, and the 3.3V pin on the CFA10098 to make sure power is being supplied everywhere correctly.

Step 12: Finishing Up the Hardware

Remove power from the regulator. Connect the LCD flat-flex cable to the CFA10098 and the LCD module. Flip the strip-board over onto the back of the LCD module, and screw down into place.

Step 13: Software

The instructions below are for using the PlatformIO IoT integrated development environment (IDE).

PlatformIO is an addition to either Microsoft's VSCode IDE, or the open-source Atom IDE.

The project source code can be modified to build in the Arduino IDE if needed (I'll leave this to you).

Once VSCode/Atom and PlatformIO are installed, you'll need to set up PlatformIO for the ESP32:

  • In the "home" section of PlatformIO, select platforms, and type "esp32" into the search box.
  • Install the "Espressif 32" platform (select the Arduino subsystem if given a choice).

Step 14: Programming

Download the project source-code from the github project:

Extract the source-code and add the project directory inside PlatformIO.

Find and set the ESP32 COM port by:

  • Open the Windows Device Manager, and check the serial COM port numbers currently available (Under "Ports COM & LPT").
  • Power on the project, and plug a USB cable from the PC into the NodeMCU-32s
  • On doing so, a new COM port should appear in the Windows Device Manager.
  • Take note of the COM port number (ie COM5)
  • In PlatformIO, under the project files list, open the "platformio.ini" file.
  • Change the "upload_port=COMx" line to match the COM port number being used by your PC.

If you're using more or less than 16 x WS2812b LEDs:

  • edit "proj_config.h" and set the amount using "#define LEDBAR_LEDNUM xx".

Build the project, and then upload it to the NodeMCU-32s.

If PlatformIO gets stuck at "Connecting....", hold down the "IO0" button on the NodeMCU-32s while it tries to connect.

After uploading the NodeMCU-32s should be running the firmware, and start up showing the demo screen on the LCD and LED bar.

If the two outside LEDs are white and the rest are off, there has been a failure initialising the LCD panel. Carefully recheck your wiring, and if all ok, try dropping the SPI data rate (SPI_SPEED in "proj_conf.h") by half. The quality and length of the CS/SCK/MISO/MOSI wiring has an effect on the maximum SPI data rate that is possible.

If you continue to have problems, some start-up debugging information is output to the virtual COM port (the USB connection) on the firmware starting. You can display this by using the "Serial Monitor" in PlatformIO (select the same COM port, and use a baud rate of 115200).

Step 15: Megasquirt CANbus Connection

Wiring of CANbus from the dash display to the Megasquirt requires the use of a pair of twisted wires plus a ground wire.

Twisted wires are required due to CANbus being a balanced two-wire network:

  • Using one wire of the twisted pair, connect CAN-H from the MCP2551 module on the display, to the CAN-H connection on the Megasquirt.
  • Do the same with the remaining wire for CAN-L.
  • The ground connection between the display and Megasquirt can be a plain wire (power supply ground connection will probably work here).

As CANbus is a high-speed balanced network, termination resistors are required to minimise signal reflections from the ends of wires. Megasquirt ECU's commonly have a termination resistor already built in. Check that it is in place, and if not, add a 120 ohm resistor (see the Megasquirt documentation).

If the dash display is the only other device on the CANbus network, then it'll also need a termination resistor. The termination resistor is a single 120 ohm resistor connected between the CAN-H and CAN-L wires (it is shown in the project wiring diagram).

If you have more devices than the Megasquirt ECU and dash display on the CANbus network, youll need to read up elsewhere on how to wire a multiple node CANbus system. It is quite straightforward, there are a couple of simple rules that need to be followed.

Step 16: MegaSquirt Configuration / Testing

Next the MegaSquirt2-Extra or MegaSquirt3 needs to be setup to broadcast CANbus packets.

The steps here are for the MegaSquirt3, but the MegaSquirt2-Extra configuration is very similar.

  • In TunerStudio, open the "CAN Parameters" dialog. Turn on the "Master Enable", and set the CAN Baud Rate to 500k. The rest can remain at the default settings.
  • In TunerStudio, there are the "CAN Realtime Data Broadcasting X" dialogs. In these we enable the information that is broadcast by the Megasquirt over the CANbus network. Make sure the base address is set to 1250.

Set the minimum data rate needed for the type information being broadcast. Setting too many items too fast may saturate the CANbus network and cause problems.

For example, seeing RPM update quickly is important, so set that item to 20Hz or 50Hz. For slow changing data like pressures and temperatures use a lower rate like 5Hz.

Note: Currently the LCD display is updated around 20 times per second, so broadcasting data faster than this is of no use.

See the screen-captures for the settings required to be changed in TunerStudio for the MegaSquirt3 and Megasquirt2-Extra. Note that the MegaSquirt2-Extra does not support the wide range of information that the MegaSquirt3 does.

Burn the new settings to the MegaSquirt, then power off the MegaSquirt, and power back on both the MegaSquirt and the dash display. If all is working well, you should now be able to touch the screen twice to change to the data list screen, and see UpT, Voltage and other information being shown correctly.

If everything reads 0, you have a CANbus communication problem.

Step 17: Mounting / Power

I'll leave for you to work out how you would like to mount the display in car; be it on a flat panel, in a 3D printed enclosure, etc. I do recommend that it is shaded from direct sunlight though for the clearest viewing, and to keep it away from summer heat (if that's an issue in your part of the world).

I have designed a 3D printable case, but it has not been tested as yet.
You can find the design, and download the STEP files, etc here: OnShape - MegaSquirt Dash Display Case

The display should be powered from a separately fused (5A) ignition power circuit.

Step 18: Display Configuration

At a later date, some easier method of screen configuration may be added but until then it is hard-coded in the firmware. Unfortunately this makes configuration rather complicated for those that are not too familiar with handling data in C. Also, some understanding of how data is packed into CAN packets is required here.

See comments in the source code for information on how to get data from the CAN packets and configure the screens.