Software apps and online services
Hand tools and fabrication machines
My wife drives a Toyota Auris Hybrid and sometime ago (winter I think) the TPMS (Tyre Pressure Monitoring System) dashboard warning light came on. Unfortunately that is all the information the car gives - no indication of which tyre is the problem or why. Checking the tyres and resetting the TPMS made it go away for a while before the problem quickly returned. At the next car service, it was mentioned to them and whatever they did, it seemed to go away. They stated that one of the tyres was slightly low on pressure which I disputed because I had checked them on several occasions. Anyway the problem seemed to be 'solved' but the frustration of not knowing why remained.
I was recently using an RTL2832U dongle, SDR (Software Defined Radio) and the excellent RTL_433 software to sniff some 433MHz signals when, to my surprise, up popped some messages about Toyota Tyre pressures. I realised these were coming from my wife's car outside on the driveway. Given the history (see Part 1!), I thought I should be able to come up with a way to display these tyre pressures in the car using a standalone Arduino and without having to resort to the car's ODB2 interface and CAN message decoding.
There are various methods which car manufacturers use for TPMS and I would point out that this solution is targeted specifically at a Toyota Auris Hybrid. It may work on other Toyota hybrids but I can't say for sure. Should you decide to do a similar project, you should ensure you know what type of monitoring system and sensor is used on your car before starting otherwise you will be disappointed.
The TPMS sensors on the Auris Hybrid tyres transmit at 433MHz approximately every 90 seconds although this varies (presumably to avoid repeated collisions). The data transmitted consists primarily of a sensor ID, the tyre pressure, the tyre temperature and a checksum (other status bits are also transmitted).
There is no indication of which sensor ID maps to which wheel so this is trial and error. I have worked out which is which for our car and encoded this in the software to ensure the information is displayed consistently.
The sensor signals do not appear to be very strong so I found I needed to be within 2-3 meters to get a reliable signal.
I'd like to acknowledge the work done by the RTL_433 team (in particular Christian W. Zuckschwerdt) and by 'shcm' on the RAV4 Drivers Club website. Both of these were very helpful to me in understanding the 433MHz transmission protocol from the tyres and therefore speeding up the development.
Two libraries were included for the I2C display:
EasyEDA used for schematic capture
Using the GNU SDR software I was able to work out that the tyres transmit using FSK (Frequency Shift Keying). The centre frequency is about 433.88 MHz with a deviation of around +/- 24-30kHz. The data is Biphase Mark Coded and is 72 bits in length. The data rate is 10kHz and the total message length is about 8ms.
To receive the signal I chose a CC1101 module. This module is based around the CC1101 IC from Texas Instruments and has an SPI interface along with a couple of pins which can be configured in the device to output various signals. I configured it to output the raw receive signal and the carrier sense (CS) signal. The CS hardware signal was not used in the final solution as the same signal is available by polling a register over the SPI however the hardware signal was useful when hooking up the logic analyser to 'frame' the raw receive signal and aid debugging.
Configuration of the CC1101 registers can be a little daunting but there is a software package from TI called SMART RF Studio which can help with this. The CC1101 can be used with the internal FIFO etc. to capture the data bytes directly and read them over the SPI but I could see no way to configure it for the data I was expecting so this project uses it as a basic RF receiver with the RX data being output onto one of the configurable pins and the Arduino then tries to make sense of the data stream.
The CC1101 runs off 3.3volts. Most of the Arduino boards are 5v which means a level translator is required for the interface signals. I did in fact do this with a Mega initially but I wanted the final solution to be as compact as possible so I chose the Arduino Pro Micro 3v3 (note: there is also a 5v version of this so be careful which one is ordered!). This 3v3 board only runs at 8MHz and has limited RAM but I decided I could probably get away with this.
The display used was a 0.96" 128 x 96 yellow and blue I2C module based on the SSD1306 which can be found from various suppliers. My choice of Arduino came back to bite me a bit here as the normal library for these displays uses a 1k buffer to hold a mirror of the display data. This exceeded the RAM limit and meant I had to switch to a text only, low RAM library but it seemed to work well.
Once the basic register settings for the CC1101 were established, a logic analyser assisted in showing that the CC1101 was receiving a reliable signal and was used to decode the biphase mark coding to show the individual bytes (see image below). The logic analyser was triggered from the CS signal when the pulse width was around 8ms. This generally filtered out the analyser being triggered by other unwanted RF signals.
The picture below shows an example of the logic analyser capture from one of the tyres.
The shorter pulses are around 50us and the longer pulses around 100us. Data is transmitted MS bit first. There should be a sync pattern prior to the valid data but I didn't find this a very reliable method for detecting the start of the message (possibly due to my amateurish configuration of the CC1101 AGC etc.?)
Although the data rate is 10kHz, the bi-phase encoding meant the CC1101 needed to be configured at twice this data rate (20kHz) to ensure capturing of all the transitions
As reported in the RTL_433 code, the message structure is 1st 4 bytes = sensor ID, 1 bit status, 8 bits for the pressure (P), 8 bits for the temperature (T), 7 bit status, 8 bit pressure repeated (but inverted) and an 8 bit CRC (0x07 truncated polynomial with 0x80 initial value).
The actual temperature = (T - 40) degrees C
The actual pressure = ((P/4) - 7) PSI
So I could see the message on the analyser, all I had to do now was to implement a method of decoding this using the Arduino.
I tried a few methods but the one which proved the most efficient and reliable was:
- Wait for CS to go high (by reading the CC1101 status) and mark the start time
- Use the Arduino pin interrupt to detect and store the time between edges Timings less than 12us were classified as 'glitches' and ignored. If more than 255 transitions were seen, the interrupt routine stops storing the times (buffer full).
- When the CS goes low again, calculate the width of the CS being high. If it was high for the expected ~8ms, process the timing buffer and look for a valid message. If not ~8ms or no valid message detected, wait for the next CS high again.
- The validation routine checks the timings and converts them to 0s and 1s and stores these in a 'bit buffer'. The number of bits found is returned.
- If the number of bits is the expected 72, the bit buffer is decoded into bytes
- The byte buffer is checked for a valid TPMS message - 9 bytes in all anda includes a checksum check.
- The TPMS data is displayed on the I2C display module (screen position is TPMS sensor ID specific).
The 3 components (Arduino, CC1101, OLED display) were built into a 3D printed case. The design was created using Fusion 360. It isn't the best (although OK for a first prototype) and could do with refining in the following areas:
- A little bigger to allow more room for the cabling (currently a bit tight)
- Close down the USB cable entry aperture slightly
- Close down the OLED display area (an area at the bottom of the display does not form part of the display and could be hidden
Power is supplied through the 5v USB input and can be sourced from the USB socket in the car.
The design and wiring is very simple (see schematic). Make sure the OLED is wired from the correct side to avoid wires getting in the way of any enclosure which might be used.
If you haven't used this particular Arduno board before, you may need to configure the Arduino IDE for the Pro Micro board.
An excellent guide for this can be found on the Sparkfun website here.
Make sure "Sparkfun Pro Micro" is selected from the Tools-> Board list menu.
Also ensure "ATmega32U4 (3.3V 8MHz)" is then selected from the Tools-> Processor menu.
Plug in the Arduino to the computer USB port and select the allocated port from the Tools-> Port menu option.
Load the code (consisting of 5 files) into the IDE and compile and upload it to the Arduino.
To see the decoded information on the Serial port, you should uncomment the SHOWDEGUGINFO line at the top of the globals.h
Line 64/65 in the globals.h file has 4 IDs listed. These are specific to our own car and are in the order of Front Left, Front Right, Rear Left, Rear Right. This ensures that no matter what order the IDS are received in they will always appear in the correct location on the display.
Once you know the IDs for your car (shown on the Serial port with debug enabled. - note: the IDs are not shown on the OLED display) and which wheel they relate to, possibly by altering the tyre pressures one at a time, you can update the code with your IDs. This ensures they are always shown in the correct order on the display.
If the codes received don't match with lines 64/65, the 1st 4 tyre pressures received will still be displayed but the order will be based on 1st come 1st served basis and therefore there will be no relationship with the physical tyre.
Plug into a 5v USB supply.
If functioning, the title (in yellow) should be displayed on the top two lines.
If within range of any Toyota TPMS tyres, the display should show each one in turn. The larger digits show the tyre pressures, the line under the pressure shows that tyre's temperature and a digit from 1-5 giving a rough indication of how long since the last transmission. 5 = very recent, 1 = least recent. If a transmission is not received within 30 minutes, any previous data for that tyre will be erased from the display.
The tyres only transmit every ~90 seconds, so be patient when waiting for the unit to receive and update the information on the display. The closer to the tyres, the better the reception should be but it should also be possible to gather some information from nearby (e.g. in the house) if the car is sufficiently close.
This unit does not remove the need to check tyre pressures regularly with the correct equipment. It is intended only to provide some insight as to why a TPMS alarm might have been raised by the vehicle.
I'm looking at a Renault option for TPMS decode. Here is a shot of some captured timings as a starting point.