Making the Tach Work: 58X vs 24X, 3 PPR vs 2 PPR
Unfortunately for me, all the older LS based engines use a 24 tooth reluctor wheel to keep track of the crankshaft speed and position (LS3 uses 58x. Lucky you!). The Porsche engine uses a 58X reluctor, meaning I cannot just plug in the GM sensor into Porsche DME. The other option is to use the tach output signal directly from the ECU. Unless both engines have the same number of cylinders, this will not work without some modifications to the signal. In general this is what the output is for each engine layout:
- 4 cylinder : 2 PPR (pulses per rotation)
- 6 cylinder: 3 PPR
- 8 cylinder : 4 PPR (in case of GM engines, it’s 2 PPR)
I did some research on this and came across a 944 thread where the OP changed out some resistors in the cluster to adjust for the signal difference. I thought that I could possibly use this approach myself, so I took apart the cluster. Things are much more complex in the 986 unit, the entire cluster is just one huge PCB and I really wouldn’t want to mess with it even if I knew what I was doing. The only easy option that’s left is to buy a converter from Summit Racing for about 90 USD, but I’m not made of money, so I wanted to tackle this myself.
I plugged in an Arduino board to the tach wire and sent a 3 PPR pulse signal for which I knew a corresponding RPM just to check if they would match. Indeed, the tach input is 3 PPR. If you want to find the tach wire, it’s a purple/green, and you can access it at pin 9 on the OBD plug, pin 15 on the white cluster plug, or I believe pin 17 on DME plug #4.
The way to find the pulse length is pretty straightforward. Lets use 7000 RPM for example:
7000 RPM = 7000/60 RPS = 116.7 RPS (rotations per second)
There are three pulses per second at 50% duty cycle, which looks like a square wave. While there are 3 pulses (peaks), there are also 3 valleys, hence the total number of intervals is:
116.7RPS * 6 intervals/rotation = 700 intervals/s
interval = 1s/700intervals/s = 1.428 milliseconds or 1428 microseconds
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int PINOUT = 13; void setup() { pinMode(PINOUT, OUTPUT); } void loop() { int state = 0; while(1){ if(state==0) { digitalWrite(PINOUT, LOW); state=1; } else { digitalWrite(PINOUT, HIGH); state=0; } delayMicroseconds(1428); //enter the delay in microseconds for each pulse. Regular delay is too slow } } |
I then took out the cluster and brought it home. You have to hook up all the term 30, term 31 pins on the black plug to positive terminal and term 15 to negative to supply power. The tach signal wire goes to pin 15 of the white plug. I used one Arduino to simulate 2 PPR signal and the second Arduino to modify the signal. Here is the code that I have so far; it seems to work Ok without any noticeable delay. The key is to keep the code as short as possible, or else your intervals will get all screwed up. The micros() function relies no interrupts to keep count, so when you call an ISR, the counter stops. Please let me know if you have a way to improve this or approach it from a different angle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
int PINOUT = 13; int PININ = 2; int signalState = LOW; unsigned long currentMillis; volatile long interval = 0; //use volatile to store in RAM. Used to ensure variables are updated correctly from inside ISR long prevMillisOut = 0; //records previous millis()count on output pin long prevMillisIn = 0; //records previous millis()count on input pin void setup() { Serial.begin(9600); //only use Seria.read for testing your code. It will mess up your interval timing pinMode(PINOUT, OUTPUT); pinMode(PININ, INPUT); attachInterrupt(0, duration, CHANGE); //an interrupt to check for changes in the input signal } void loop() { currentMillis= micros(); //initiate the counter and assign it to currentMillis if((currentMillis - prevMillisOut > interval) && (signalState == LOW)){ // if counter reached interval duration change state and reset the timer prevMillisOut = currentMillis; signalState = HIGH; digitalWrite(PINOUT, signalState); } else if((currentMillis - prevMillisOut > interval) && (signalState == HIGH)){ prevMillisOut = currentMillis; signalState = LOW; digitalWrite(PINOUT, signalState); } } void duration(){ //to record input signal pule interval interval = (currentMillis - prevMillisIn)/1.7; //1.7 is an adjustment factor that works well for me. Ideally to go from 2 PPR to 3 PPR you would divide by 1.5 prevMillisIn = currentMillis; |