Arduino CAN-bus Module

Performance information displayed on my car's factory radio screen!

Introduction

This was one of my favorite personal projects, completed in the summer of 2021. Although an enourmous, months-long undertaking, the end result was exactly as great as I had imagined! It all began when I was researching how to upgrade the radio in my car, and I realized that a lot of people lost functionality of the radio display (which would remain in place) following the stereo upgrade. Because the radio module no longer existed, instead of displaying radio information the screen would default to displaying "FORD FOCUS" anytime the car was running. I wanted to figure out a clever way to bypass this eyesore and turn it into something more elegant and functional instead.

Research & Development

First, I researched the hardware that Ford used within the stereo system. I discovered that starting in 2008, Ford standardized the use of Controller Access Network Bus (also known as "CAN-bus") as the primary module communications protocol in their vehicles. This meant that all but a seldom few of the sensors, displays, buttons, motors, actuators, and engine control periphery would use digital signals instead of analog. All electronic modules throughout the car––e.g. the instrument cluster, engine computer, and most importantly the radio––communicated in parallel over just two wires! This saved Ford millions in production costs and measurably reduced the car's weight as well, allowing it to achieve more desirable fuel economy. What this also meant was that every single piece of data transmitted throughout the car can be read, decoded, and manipulated using an inexpensive CAN-bus interface!

With a high-level of understanding of my car's CAN-bus network, I now had to delve deep into Ford's data transmission techniques. I quickly learned that while CAN-bus is a universal communications protocol, each auto manufacturer has their own unique way of implementing it. Ford actually used two CAN-bus networks in my particular vehicle: a medium-speed bus called "MS-CAN", and a high-speed bus referred to as "HS-CAN". Ford transmits its data using a standard eight-byte-long 'packet' of information with a three-digit identifier tag; the result looks a bit like this: "0x000 00 00 00 00 00 00 00 00", or more realistically, this: "0x337 10 2B 2D 2D 2E 00 2D 20". These packets are broadcast typically once or twice per second between all modules, so as not to clog up the bus. The HS-CAN network is reserved for critical communications, to which signal latency is absolutely detrimental; this could refer to data from the engine computer or from the airbag module. This means that the information I needed for the radio and its display was transmitted via the MS-CAN bus.

Experimental setup on breadboard

With this information, I was ready to begin testing and developing a prototype CAN-bus interface. By adapting a very useful write-up created by user "p1ne" on GitHub.com, I was able to create a breadboard module using an Arduino Nano and an MCP2515 CAN interface board. Using a Python-based script in tandem with an Arduino sketch I sourced from a related CAN-bus project, I was successfully able to "sniff" the MS-CAN bus in my car! The experimental hardware setup is depicted above, and raw CAN-bus data output is shown below.

Raw output from the medium-speed CAN bus

The information shown in the console window above was streamed live, so I could see exactly which characters were changing as I pushed various buttons, revved the engine, turned on the headlights, and lots more. I was able to figure out that the 0x337 line was used to send a burst of several CAN packets all in a row, once every two seconds. This burst was broadcasted by the radio module and recieved by the radio screen module. Using screen capture software, I was able to catch one of these "bursts" and slow the footage down frame-by-frame to decipher the messages. I discovered that the burst began with a "flag" packet, which was blank except for a single message in the first byte. Each of the seven packets that followed were eight-byte strings, following Ford's format. Each byte in these strings represented an alphanumeric character, encoded in hexadecimal format. The screen module was pre-programmed with a hexadecimal character library almost identical to standard ASCII format, so I was able to reverse-engineer the message structure quite simply using online ASCII-to-text converters.

Learning to communicate with CAN-bus

Now it was time to take control. I created a simple proof-of-concept Arduino script that would broadcast information packets in succession. This would simultaneously keep the screen awake, as it would hibernate in the abscence of these messages; this is referred to as a 'pulse'. I then wrote a simple library that would store and broadcast different byte arrays from the Arduino via CAN as information packets, and I set the script to broadcast each packet 50 milliseconds after the previous one, and repeat this 'burst' every second. To my delight, the screen accepted the message sequence, woke up and displayed my message ("Hello, world!")! From this point forward I was in full control. 

In the end, my Arduino script was set to read the engine's air/fuel ratio from a separate analog sensor, accomplished by using an inline voltage divider. This would step the +10V analog sensor output down to the Arduino's ADC rating of +5V. I was also able to read the battery voltage from the accessory power supplied by the car's fuse block; this also required a separate voltage divider. I then was able to cyclically read the engine coolant temperature from a 'gateway' packet, which refers to data from the HS-CAN network that is 'passed-through' by the instrument cluster (a 'gateway module', if you will) to the MS-CAN network. This enabled me to use a single CAN interface board on the MS-CAN network by piggy-backing the connector for the radio screen module, which simplified the controller's design and helped me maintain a compact package that would fit under the shroud where the radio screen was installed! After recieving and processing the necessary messages, the Arduino module would then send the new "custom" messages to the radio screen to achieve the desired output. I increased the screen refresh rate to 10Hz for better accuracy. Below is a photo of the finished product!

End product: wireless CarPlay with functional performance gauges!

Conclusion

The final result was perfectly in line with my original idea. I was able to display helpful information on the previously-defunct radio display, and later I even added in a realtime clock module to my Arduino setup to provide the time, displayed in the original clock portion of the radio display! Overall, the module is a drop-in solution to a silly problem and required no permanent modifications to the car whatsoever. Below is a YouTube video of the screen in action!