I wanted the sensor for the GM throttle body injection (TBI) system I retrofitted onto the Jeep's old AMC 360 c.i. V8.
Back when my Jeep was built, vehicle speedometers were driven by a flexible steel cable, the speedometer cable, connected by a tiny gear to the output shaft of the transmission.
Jeep, as with other vehicles of the era, split the speedo cable in half and stuck the VSS in between.
So, with insufficient hobby funds to buy an expensive, off-the-shelf Vehicle Speed Sensor/Buffer, but wanting to reap the benefits of a VSS, I created my own interface. Here's how it went down...
The VSS SignalMade of a rotating coil and fixed magnet (or maybe vice versa), the voltage across the two output wires of the VSS is a sine wave. It puts out 8000 pulses per mile.
As one would hope, the VSS signal's frequency increases with speed. But testing revealed that the amplitude increases too: from less than 1Vpp below 10mph, to a peak of around 4Vpp above 50mph.
The data points were all I could reliably obtain using a cordless drill to run the thing. But it provided sufficient understanding to devise an interface circuit.
|Speed (mph)||Amplitude (Vpp)|
What the ECM WantsUnfortunately for me, the GM ECM expects to see 2000 pulses per mile. And it expects a nice square wave, compatible with 5V logic.
The former can be managed by a counter/divider or MCU. The latter is easily accomplished with a comparator. But that's only if the original signal amplitude is large enough. It wasn't.
My interface circuit would have to amplify the VSS signal first, then convert it to square wave, and finally divide the frequency by 4. But that wasn't all...
AC/DCBefore I can amplify or really do anything at all, the VSS signal's DC offset needs to be kicked to the curb.
That way, when using a single-supply op amp, I can use a 1/2 VCC virtual ground (2.5V) and the amplified output will have a 2.5V DC offset that will work nicely with a comparator.
A series capacitor does this dirty deed dirt cheap. Um. Yeah. Anyway...
AmplificationBelow 10 mph, the VSS signal amplitude was too low to work with. A single-supply operational amplifier with a high gain ensures the output reaches the 0-5V rails at all but vehicle speeds below 2mph, which the ECM doesn't care about anyway.
|Example of a sine wave clipping|
That's called clipping. For music amplification, clipping sucks. For this signal it doesn't matter since we want a square wave in the end anyway.
One problem. After building the amplifier circuit and testing a little, the oscilloscope revealed unpredictable voltage spikes when the VSS spun at extremely low speeds.
FilteringThose spikes, amplified into pulses, would trick downstream logic circuits into reporting a faster-than-actual speed.
Filtering seemed like a perfectly sensible thing to do, assuming the noise was above the maximum frequency of the VSS signal. I suspected it was.
So, what was this magical maximum frequency I designed to?
Figuring on a speed of under, say, 100mph (the Jeep can achieve this only when driving downhill with a subtantial tailwind), one computes the maximum frequency as a unit conversion from pulses per mile to pulses per second (Hz):
The target was a low pass filter with a corner frequency around 200Hz. The low pass filter is the same as the amplifier, but with a capacitor in parallel with the feedback resistor. Use the formula below to find C given the feedback resistor R:
That's all well and good, but why not be a little trickier than that?
Using a smaller capacitor than calculated, the amplifier frequency response have gain at lower frequencies where the input was low amplitude, and would roll off to attenuate the signal at higher frequencies when the signal reached its maximum, while further attenuating higher frequency noise.
If you wanted to get fancy, you could carefully measure more input signal data points of frequency vs. amplitude, determine the best low frequency gain and roll off to maintain signal amplitude to tighter tolerances. Or a filter with sharper roll off could be used if noise is a really big problem.
Sometimes, it doesn't pay to engineer the snot out of stuff. As far as I can tell from testing, as long as the output signal amplitude is over about 2Vp-p across its range of 2-100mph and the noise is somewhat attenuated, then it is good enough for me to get this done so I can work on related projects and get the Jeep through emissions.
I used a trial and error approach to set the corner frequency until I got a reasonable amplitude at the lower speeds without any noise. I ended up using a 0.1uF capacitor.
The frequency response of the circuit starts with a gain of around 30dB rolling off gradually to -40dB by 200Hz, according to LTSpice:
I also found that a 22-33uF series capacitor on the input worked better than lower values that I tried.
Notice in the schematic below that the + input is connected to a virtual ground of 2.5V, half VCC, in turn providing a 2.5V DC offset to the output signal.
Converting to Square WaveWhile a comparator can convert a sine wave to a square wave, in the real world a noisy signal may bounce back and forth across the threshold, causing the comparator to trip when it shouldn't. To prevent this, you need hysteresis.
A normal comparator has one voltage threshold. By contrast, a Schmitt Trigger has two thresholds. The high threshold is for rising waveforms, and the low threshold is for falling waveforms. That way, once the signal rises above the high threshold, it has to fall all the way below the low threshold before the output signal changes. And vice versa.
Fun fact, you can use an operational amplifier to implement a Schmitt Trigger. So I was able to use one dual op amp IC to implement the filter/amplifier and the Schmitt Trigger.
By selecting 100k for all three resistors in the Schmitt Trigger circuit below, you wind up with a high threshold of 2/3 VCC and a low threshold of 1/3 VCC.
Dividing the SignalRather than using a logic divider or flip-flop, since I didn't have any on hand, I just used a cheap ATtiny25. It probably draws less current anyway. It's definitely more flexible.
A simple C program sets up the INT0 pin interrupt to trigger on the rising edge of the conditioned VSS square wave. By toggling the PB3 output pin within the INT0 pin interrupt service routine, and also toggling PB4 every other time the ISR is called, we get a divide-by-2 on PB3 and divide-by-4 on PB4.
Skipping every other interrupt for toggling PB4 is achieved by checking bit 0 of a simple count variable. If it's 1, toggle PB4. If I needed to conserve flash and/or execution time I guess this would be a good way, though probably not the most readable method.
How would you code this? Is there a better way?
The ResultI prototyped the design on a breadboard throughout the development of the circuit, testing it with the VSS I'd pulled from my Jeep.
Once the output signal seemed reasonable, I reinstalled the VSS and hooked up the breadboard in the Jeep and tested it out driving around. I didn't see any anomalous behavior. Then I hooked up TunerPro to my ECM to display the speed as seen by the ECM.
My initial revision was a divide-by-2 circuit, so I quickly refactored the code to look as it does above, and voila, correct speed reading.
The next step was fabricating a prototype circuit board... but more on that in a future post...