Reverse Engineering an EVAP System - Part 1

related: embedded , c , firmware , cars , msp430

My friend/coworker has a 1997 Volkswagen Jetta (I4) that throws an “EVAP SYSTEM” error, P0440.  Countless mechanics have attempted to diagnose it; none have succeeded.

I, however, enjoy car repair.  In an over-the-top fashion.  So I developed some debug tools for him.

First, a quick explanation of how a fairly modern EVAP system works:

  • The fuel tank is sealed, and cannot vent fumes to the outside air
  • The fuel tank creates fumes, and they must go somewhere
  • The fumes are allowed to collect in a Charcoal Canister in the engine compartment
  • Periodically, the Purge Valve opens a route between the Canister and the Air Intake.  The Air Intake creates a vacuum that sucks the fuel vapors into the engine, and burns them.
  • To check for leaks, a bunch of solenoids can be triggered to close the EVAP system completely, and then a device called a Leak Detection Pump (LD Pump) pressurizes the system and measures: 1) How long it takes to pressurize, and 2) How long it stays pressurized.

It is unclear where the problem on my friends car is.  It could be any of the hoses, or the Purge Valve, or the Canister, or the Leak Detect Pump, or the pressure sensor in the Leak Detect Pump, or the vacuum line that powers the Leak Detect Pump, or the car’s computer itself (ECU), or the wiring harness, or the wiring connectors.

To begin, we needed to test the LD Pump – a mechanic pinpointed it as the problem with a smoke machine, but we aren’t so certain.  We just needed a balloon, a waveform generator, a lab power supply, an air compressor, a venturi pump, and a small switching circuit.


LD Pump Switcher Schematic

The waveform generator connects to J1, and inputs a 5Hz +5V square wave.  It saturates the darlington transistor Q1, which allows ~0.9A to flow across J2, which is hooked to the solenoid in the LD Pump.  A loopback diode, D1, prevents damage to the transistor when the solenoid’s magnetic field collapses.

An air compressor is hooked to a venturi pump to create a constant vacuum.  This vacuum is applied to the LD Pump.  When the solenoid opens, the vacuum pulls a plunger down.  When the solenoid shuts, the vacuum is lost and a strong spring pulls the plunger back up.  This is a vacuum-powered, computer-controlled pump.  We placed a balloon on the output port of the LD Pump, and confirmed that the balloon partially inflated during operation.

The LD Pump has a third pin on its electrical connector; a reed switch that is pulled high (870 ohm?), but shorts to ground when the plunger gets near it.  Under normal operation, the pump would cycle some number of times, during which the reed switch output would toggle between high and low.  Eventually the reed switch would stop toggling and stay low, informing the ECU that enough pressure has built up in the system to prevent the plunger from coming back down.  The ECU would measure the time that the reed switch stays low to determine if there is a large leak, a small leak, or no leak.

After confirming that my friends LD Pump worked as normal – inflated a balloon, and shorted the reed switch to ground – we tested all of the hoses, the Canister, and the Purge Valve for whether they could hold pressure.  All of them could.  Mysterious.

Enter circuit two: an LD Pump simulator.


LD Pump Simulator Schematic

LD Pump Simulator Layout

This circuit is a bit more nefarious than the first.  It is designed to connect to the car’s ECU in place of the LD Pump, and uses an MSP430 µproc to detect pulses from the ECU and fake a valid response.

The three LD Pump signals (LD power, LD ground, and reed switch sense) and constant battery power and ground come in on the left side.  New connections are run from the battery to power the MSP430, because either LD_VCC or LD_GND is switched rapidly by the ECU to pump the solenoid.

A linear voltage regulator makes a wasteful 3.3V for an MSP430 LaunchPad kit.  A voltage divider + optoisolator converts the ECU’s solenoid switching into a clean 3.3V waveform on a GPIO to the MSP430, and a transistor switches the 3.3V GPIO return from the MSP430 back up to car battery voltage.


Firmware Source Code - mspgcc

I’m using the $5 MSP430 LaunchPad devkit with an MSP430G2231 and no external clock.  I build with mspgcc 4.4.3 on OS X, and load with mspdebug 0.12.

The firmware counts pulses on the input pin corresponding to the LD Pump’s solenoid.  After a specified number of pulses, it holds the SENSE pin high for a specified number of seconds.  This simulates the LD Pump’s reed switch responding to a pressurized system after pumping.

Because we don’t know how a working system behaves, the target number of pumps and time to hold high must be tuned.  The firmware records the number of pumps received from the ECU, and also the time (with 100ms accuracy) to reach the target number of pumps.  100ms is probably fine, because the solenoid must pump slowly – probably less than 10Hz.  

The recorded pumps and time are stored in Informational Flash.  48 pairs can be recorded, and the flash can be dumped outside of the car with mspdebug.  Values are also printed out to a 9600 baud TTL serial port, which can be monitored with a laptop while the car is running.  The two LEDs give a bit of additional information so you can tell if anything is happening without any extra hardware hooked up.

The MSP430 sleeps with the LEDs off and in LPM3 mode, which has extremely low current draw – supposedly less than one microamp.  This should be small enough that the car battery won’t drain, despite the circuit being hooked to constant power.


The simulator circuit has not been tested yet… stay tuned for updates!

UPDATE: A little bit more info in Part 2