Getting into the cluster repair game

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I've had a few cluster needs lately, and being pretty handy with a soldering iron I decided to delve into it. Derek (@ChubsAuto) is a crazy smart dude, and I've been reading a lot of his old posts. I've also been talking to @TDIDaveNH , and I'm pretty sure we'll be trying to meet up at some point so I can procure all of Derek's old tools and parts from him.

Over the last couple of weeks I've been compiling all the information I can, and gleaning info from the MFA Conversion Article, Derek's farewell thread, Derek's ELMOS replacement thread, and others.

I'm sure there are a lot of people on the forum more knowledgeable with electronics and programming than myself. However, as I typically do, if I find something new to be interested in, I tend to go all-in. It looks like I'll be outfitting myself with a lot more tools and parts very soon, and I want everything I find to be public knowledge. I've already had to research several things in the last few days, and want to share it all with the B4 community; Whether it's to fix your own cluster, a buddy's cluster, or someone who needs the info 20 years from now.

I'm already capable of several necessary fixes at the moment, but don't have a ton of spare parts just yet. I'm going to document some things I've done recently in this thread, as well as ask for some advice and give out a bit of my own. If there's anyone else who's been doing repairs since Derek quit, I'm not intending to take anyone's business. But it seems to be a need in our community, and I want to do everything I can to help keep our cars going.

- Charlie
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
After reading the horror stories of bad caps burning out people's gauge clusters, I decided to fix my own car before it grenades. You can see a writeup of that procedure here. It includes all 4 capacitor locations, values, and basic instructions for replacement.

The next thing I wanted to learn was how to reprogram odometers, for anyone who had to swap their cluster out. I utilized Chat GPT to figure out the coding algorithm and make a Hex-mileage converter. All that information can be found here, and you can download my Hex converter here. It's just a python program, so install Python on your machine before running it.

A few things I learned while decoding the odometer:
The lowest mileage you can have is 15. This is accomplished by making the first two lines of the bin file into all zeros. If they're all FF, you'll get "------" across the odometer, but it won't advance.

------.jpg

I set an odometer to 15, then drove it to 16 and dumped the file. There was no change in the .bin between 15 and 16, so I'm not sure how to set an odometer that closely. That being said, if my hex-odometer converter program isn't dead-on, it's +/- a couple of miles.
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
It seems Derek already made a bench testing rig which I may be acquiring, but being curious about it I went ahead and pinned out all the connections from the back of the cluster to the corresponding connections on the fuse block, as well as each function and required input.

Screenshot 2025-07-06 113319.png

As you can see, the MIL is triggered by the second connector on the back of the cluster with only one wire on it. If you do the MFA conversion, (or at least read the article) you'll see that this wire is specific only to the B4 TDI. If you want to swap a gas cluster into your car, you'll have to rig it up to work.
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I already had a factory TDI cluster with a burned circuit board, and a good cluster from a GLS. I think I've successfully turned this into a functional TDI cluster, although I've yet to verify that the RPM and MPH is completely accurate because it's out of the case.

Here's what I started with:

20250404_134436.jpg

I removed the large brownish red connector socket from the bad TDI board and soldered it into the GLS board.

20250404_173548.jpg

Then I added the two missing resistors, as outlined in the MFA conversion article. As you can see above, the MIL functions properly. I didn't have the exact resistance values needed, so I had to add them together.

20250404_175554.jpg
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I've made good progress on my testing board today. Figured out a few changes to the pinout, which I updated in post 3. Just waiting for my Digikey order to show up with some trimmer pots for the fuel and temp gauges, and the Arduino which will allow me to create a pulsed square wave for the tach and speedo.

20250413_184423.jpg

Does anybody know if there's a light on the cluster for Auto cars that the manual cars don't have? I think the red/white wire on pin 28 connects to the TCM, but I'm not sure what the function is.
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I got a spontaneous visit from @TDIDaveNH this weekend, and he delivered a veritable goldmine of cluster parts and tools. I think most people on the forum already know this, but Dave is a most excellent human being. Not only did he made a straight shot from New Hampshire to Kentucky on a whim just to deliver some parts, but he did so with no expectation of anything in return. He's the kind of guy who will sacrifice his own time and money all for the benefit of the community, and I can't speak highly enough of him. Sadly he didn't get to drive his B4 down, but we got in plenty of B4 talk while he was here!

The haul: Two totes of cluster bezels, two totes of cluster housings, a tote of plastic bits, a tote full of assorted PCBs, loads of faceplates and other assorted parts, soldering/desoldering equipment, a function generator, and a microscope.

20250420_113204.jpg

The first thing I played around with was the function generator. I've been able to get the speedometer to move a bit with my Arduino, but the function generator was the magic key to making it dance. On the cluster, pin 27 is the speedometer input. I updated my spreadsheet again, but the signal needs a 10k pull up resistor to the 12v rail, and I also utilized a .1uf capacitor to ground to act as a low-pass filter and help smooth the signal.

For settings, you'll need to use a square wave with a 5v amplitude, 5v offset, and 50% duty cycle. 100 Hz is pretty much dead-nuts 60 MPH on the speedometer, although after running for 90 minutes I think it came up to about 89.6 miles on the odometer. So far I'm not having any luck getting a response on the tach, but I do know it works because I've run it in my car.

20250420_165819.jpg

Here you can see everything hooked up with my breadboard, and the speedo reading 60 mph.

20250420_170906.jpg

And here's my updated breadboard setup for anyone curious. I have 0-330 ohm trimmer pots on the temp and fuel gauges with a 40 ohm resistor inline, effectively making the range from 40-370 ohm. It's not quite enough to simulate really low temps or a completely full fuel tank, but good enough to make sure everything is working. If you go all the way to 0 ohms it won't show anything. To the top you can see I have two NPN transistors, which are necessary for switching to ground to create a square wave from the Arduino. I don't need it for the speedometer when using the function generator, but I'm trying to get to where I can write the Arduino program to an ATTiny 85 chip that fits in a DIP8 socket. This way I can simulate the entire cluster just with the breadboard and no external equipment.

20250421_070735.jpg

Here are the faceplates I received. One very cool silver set in metric, which I've never seen before. There are a couple other styles which are very unique, like the one in the middle row first column that only shows H/C for temp and 1/1 to 1/2 for fuel. The part number on that is 5 1519 049 10. I have huge stacks of the ones on the far right.

20250420_211338.jpg

Likewise, lots of RPM faces.

20250420_212127.jpg

Here's a tote full of plastic retainers and lenses.

20250420_213000.jpg

And the holy of holies, PCBs. I was told there are several good TDI boards still in here, so I'm going to try and make a few working clusters from the parts I have available.

20250420_213311.jpg

If anybody needs some of this stuff, feel free to reach and I'll let you have it for shipping cost. There's no way I'll ever need all these cases, bezels, and lenses. And as always, I'm going to keep updating with whatever tech info I discover.
 

garciapiano

Veteran Member
Joined
Feb 12, 2018
Location
Los Angeles
TDI
1997 Jetta TDI (1Z)
The Mk2 guys would love you. They’re using motors on the back of their clusters to put in a speedo signal…
 

TDIDaveNH

Left Lane Coal Roller at Large
Joined
Feb 17, 2009
Location
North Conway, NH
TDI
1997 Passat TDI x2 1984 Buick Century 4.3 diesel. 2012 X5d 2012 Passat 6-speed
Charlie, you're too kind. I'm glad the stuff finally found it's correct place in the universe. I originally bought the lot when Dereck had it on Ebay for several reasons... it went for ridiculously cheap, it was a great excuse for a road trip and I didn't want the stuff to get tossed in a dumpster or go to someone who wasn't going to continue what Dereck had done...so I had to buy it. However, way leading onto way...life gets in the way. I was slowly becoming the guy that wasn't going to do anything with it. Nice to see you're making real strides quickly with it all. There should be 10 boards in there that are still good, according to what Dereck told me years ago.

On another note, it was nice to happen to roll by the Marriott in Lexington which was the site of the 2011 TDiFest, the first one I attended...good memories. I'm working on my B4 as I type this...it was the preferred car to take but despite my reservations, the NMS did fine, all 2,300 miles in 2 days.
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I've learned through a bit of trial and error how to run the speedometer with an Arduino, utilizing a potentiometer and sweeping the gauge from 20-140mph in 10mph steps. This isn't really necessary if you have a signal generator, but I like having the full testing board in a small footprint. This is the way to wire it up and the Arduino program, if anyone is interested to try it out.

Arduino Uno Connections:
  • 5V pin → Left pin of the potentiometer
  • GND pin → Common ground rail (negative rail on breadboard) Also needs jumper wire between ground pins on each rail.
  • Analog Input A0 → Potentiometer center pin
  • PWM Digital Output Pin 5 → 1kΩ resistor → Base pin of transistor
Potentiometer Connections:
  • Left pin → Arduino 5V
  • Middle pin → Arduino A0
  • Right pin → Common ground (breadboard negative rail)
NPN Transistor (2N2222) Connections:
  • Base pin → Arduino pin 5 through 1kΩ resistor
  • Collector pin → Cluster Pin 27 (speed signal line)
  • Emitter pin → Common ground rail
Gauge Cluster Connections:
  • Pin 27 (speedometer input) → Collector of transistor AND 220Ω resistor to +12V (pull-up resistor)
  • Cluster Ground pin → Common ground rail
  • Cluster +12V ignition pin → +12V power supply rail
External 12V DC Power Supply or Battery:
  • Positive (+12V) → Gauge cluster +12V power and 220Ω resistor pull-up
  • Ground → Common ground rail (shared Arduino, transistor, gauge cluster grounds)
Here's how it looks while running, and I currently have it pegged at 140mph.

20250426_141028.jpg

And here's the program you'll upload to your Arduino:

// VSS Preset Pulse Generator: 16-Step Potentiometer Version (0–140 MPH)
// Reverted to 50% duty cycle (square wave)

const int outputPin = 5;
const int potPin = A0;

unsigned int delayMicros = 10000;
int selectedMPH = 0;
int step = 0;

void setup() {
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, LOW);
Serial.begin(9600);
}

void loop() {
int potValue = analogRead(potPin);
step = potValue / 64; // 1024 / 16 = 64 steps

switch (step) {
case 0: selectedMPH = 0; delayMicros = 500000; break;
case 1: selectedMPH = 20; delayMicros = 15500; break;
case 3: selectedMPH = 30; delayMicros = 10200; break;
case 4: selectedMPH = 40; delayMicros = 7505; break;
case 5: selectedMPH = 50; delayMicros = 6000; break;
case 6: selectedMPH = 60; delayMicros = 5000; break;
case 7: selectedMPH = 70; delayMicros = 4285; break;
case 8: selectedMPH = 80; delayMicros = 3750; break;
case 9: selectedMPH = 90; delayMicros = 3333; break;
case 10: selectedMPH = 100; delayMicros = 2975; break;
case 11: selectedMPH = 110; delayMicros = 2690; break;
case 12: selectedMPH = 120; delayMicros = 2455; break;
case 13: selectedMPH = 130; delayMicros = 2260; break;
case 14: selectedMPH = 140; delayMicros = 2100; break;
case 15: selectedMPH = 140; delayMicros = 2100; break; // cap top speed
}

if (step > 0) {
digitalWrite(outputPin, HIGH);
delayMicroseconds(delayMicros);

digitalWrite(outputPin, LOW);
delayMicroseconds(delayMicros);
} else {
digitalWrite(outputPin, LOW);
delayMicroseconds(10);
delayMicroseconds(delayMicros);
}

static unsigned long lastSerial = 0;
if (millis() - lastSerial >= 1000) {
float freq = 1000000.0 / (delayMicros * 2);
Serial.print("Step: "); Serial.print(step);
Serial.print(" | MPH: "); Serial.print(selectedMPH);
Serial.print(" | Delay: "); Serial.print(delayMicros);
Serial.print(" µs | Freq: "); Serial.print(freq, 2);
Serial.println(" Hz");
lastSerial = millis();
}
}
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Actually, if you're talking about converting a cable driven cluster into a digital one, I'm assuming the answer is no. There wouldn't be any traces on the board to support the motor even if you were able to mount it.
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
This weekend's project was dumping all the EEPROM chips I could find and comparing them. I'm no whiz in Python, so I utilized the help of Chat GPT to create a program for examining multiple bin files at once, finding the differences, and even setting mileage right inside the GUI. I dumped about 8 clusters, unfortunately most of the boards didn't have the memory chips. But I did learn quite a bit messing around with what I had. If anyone wants to try it out, you can download the program here.

EDIT 4/30/25: I made some changes to the EEPROM editor and updated the link. Now it shows programmed mileage next to the "help" button, and automatically updates the displayed miles if you change it. You can also now select one file for a base, and as many others as you want for comparison. I was having trouble sharing the file as a compiled .exe, so it can only be downloaded as a .py or pasted into IDLE.

Here I've selected a total of 11 bin files for comparison. This includes TDI, GLS, and GLX files. Among them, only the yellow bytes are different, and of course the entire top two rows are just mileage data.

Eeprom editor.jpg

When you click a cell it will show you each value seen in that cell, as well as the corresponding bin file names. If you change a cell, it will turn blue. If you change it back to the value with an asterisk, it will turn back yellow to indicate it hasn't been altered. The "original" bin file you're working with will the first one you select in the folder, and it will display that as the file name in the window (GLS North American Auto in this case).

Eeprom editor2.jpg

I was mainly able to verify number-of-cylinders, MFA coding, Regional coding, and a few other bytes that just so happened to be narrowed down to specific variants.

EDIT: 7/6/25 Updated to show full info

Screenshot 2025-07-06 113530.png

The next thing I'm working on is MFA swapping, which should be pretty simple. Swap out the LCD and Change the 01 to a 02 in the D0 block, and it appears to be programmed correctly. This is the same GLS cluster I've been testing with for the last few weeks.

20250427_174801.jpg

I left the small clock screen in place just to see what would happen, and as you can see it isn't happy anymore.

20250427_174805.jpg

I noticed every time I switch the ignition power off and back on, the MFA screen changes modes. First it'll be MFA 1, then I cycle the ignition and it goes to MPG. The cluster pins controlling the MFA should be as follows:

1 & 19 - make a closed loop to the Outside Air Temp sensor
4 & 6, MFA Reset Switch & MFA Memory Switch, make a closed loop to the wiper stalk
5 - main ground
15 - MFA Mode Switch
17 - Oil temp

I currently have no wires going to these connections, so perhaps it's expecting a different input than "open" to keep it in a specific mode. I found this diagram of the MFA wiper stalk and labeled the connections:

20250427_221642.jpg

The MFA mode switch seems to be a clean switch to ground. But pins 4 and 6 have to work in a specific combination of Grounded and Open terminals to control the selected memory, and to clear that memory. With what it's seeing right now I would think it would be set to data #2, as both pins 4 and 6 would be open. But without having driven an MFA car before I have no idea how it normally functions.

So at this point and I'm trying to figure out if I can't cycle through the MFA modes due to a wiring problem or a coding problem. Dave is sending me a cluster Derek already converted to MFA, so if there are any additional changes on the EEPROM I should be able to see it.

Screenshot_20250427_224725_eBay.jpg
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Update from last night. I got out an old MFA board and checked pins 4, 6, and 15 - they all had 12 volts to ground. So apparently there are at least some pull-up resistors missing on the TDI boards and possibly other connections as well.

I texted Derek and confirmed what I thought - he converted the MFA boards to TDI, not the other way around. And it really makes the most sense - all you need to do is add the two pull-up resistors, swap on the second PCB connector for the MIL, and edit the bin file. But with MFA boards being arguably more scarce than the TDI boards, I'll probably try to map out the connections and see if it's possible to add the missing components to the TDI boards.
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Today's finished project - Speedometer controlled by ATTiny85 chip. I'm sure few people care to know the specifics, but in case they do - and in case I forget later - I'm posting all the details of building this setup.

ATtiny85 Breadboard Hookup Pinout Guide


This guide shows how to connect an ATtiny85 microcontroller to a breadboard, including power, analog input (potentiometer), and digital output (speed pulse). Orientation assumes the notch or dot on the chip is facing to the LEFT (standard DIP package).



ATtiny85 Pinout (Top View with Notch on Left):

Notch → ┐───────┐
| 1 8 |
| 2 7 |
| 3 6 |
| 4 5 |
└───────└


Pin #FunctionTypical Use
1RESET(Connect to Arduino Pin 10 for programming)
2PB3 (A3/D3)(Not used in most VSS setups)
3PB4 (A2/D4)(Optional I/O)
4GNDConnect to breadboard ground
5PB0 (D0)Speed pulse output (to transistor)
6PB1 (D1/A1)Analog input from potentiometer
7PB2 (D2)(Optional I/O or SPI SCK)
8VCCConnect to +5V (regulated)


Typical Connections for Speed Signal Generator Project:


  • Pin 8 (VCC): +5V from 7805 regulator
  • Pin 4 (GND): Breadboard/common ground
  • Pin 6 (A1): Center pin of potentiometer
  • Pin 5 (D0): Output square wave pulse (connects to transistor base via resistor)
  • Potentiometer Outer Pins: 5V and GND


Transistor Circuit Example:


  • ATtiny Pin 5 → 330Ω resistor → NPN transistor base
  • NPN emitter → Ground
  • NPN collector → Cluster signal input (Pin 27)
  • Cluster Pin 27 also has a 10K pull-up resistor to +12V


Power Supply:


  • Use a 7805 linear regulator to drop 12V down to 5V
  • Feed ATtiny85 VCC (Pin 8), potentiometer, and any other logic devices with the regulated 5V


This layout enables the ATtiny85 to act as a fully independent speed signal simulator with a pot-controlled MPH output.

And here is the ATTiny85 program that you can upload via Arduino as ISP.

// VSS Preset Pulse Generator for ATtiny85
// 50% duty cycle, 20–140 MPH preset steps

const int outputPin = 0; // ATtiny85 Pin 5
const int potPin = A1; // ATtiny85 Pin 7

unsigned int delayMicros = 10000;
int selectedMPH = 0;
int step = 0;

void setup() {
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, LOW);
}

void loop() {
int potValue = analogRead(potPin);
step = potValue / 64; // 1024 / 16 steps = about 64 raw per step

switch (step) {
case 0: selectedMPH = 0; delayMicros = 500000; break;
case 1: selectedMPH = 20; delayMicros = 17250; break;
case 3: selectedMPH = 30; delayMicros = 11200; break;
case 4: selectedMPH = 40; delayMicros = 8500; break;
case 5: selectedMPH = 50; delayMicros = 6700; break;
case 6: selectedMPH = 60; delayMicros = 5600; break;
case 7: selectedMPH = 70; delayMicros = 4800; break;
case 8: selectedMPH = 80; delayMicros = 4175; break;
case 9: selectedMPH = 90; delayMicros = 3700; break;
case 10: selectedMPH = 100; delayMicros = 3325; break;
case 11: selectedMPH = 110; delayMicros = 3025; break;
case 12: selectedMPH = 120; delayMicros = 2750; break;
case 13: selectedMPH = 130; delayMicros = 2550; break;
case 14: selectedMPH = 140; delayMicros = 2350; break;
case 15: selectedMPH = 140; delayMicros = 2350; break; // cap top speed
}

if (step > 0) {
digitalWrite(outputPin, HIGH);
delayMicroseconds(delayMicros);
digitalWrite(outputPin, LOW);
delayMicroseconds(delayMicros);
} else {
digitalWrite(outputPin, LOW);
delayMicroseconds(10);
delayMicroseconds(delayMicros);
}
}

And a full guide to programming an ATTiny chip using your Arduino as ISP.

Programming an ATtiny85 Using an Arduino Uno (Breadboard Layout + Setup Guide)


PARTS NEEDED

  • 1 × ATtiny85 chip
  • 1 × Arduino Uno (or Nano, etc.)
  • 1 × Breadboard
  • 1 × 10µF capacitor (optional but recommended)
  • Jumper wires
  • USB cable for Arduino

STEP 1: Prepare Arduino as ISP

  1. Open the Arduino IDE.
  2. Go to:
    File > Examples > 11.ArduinoISP > ArduinoISP
  3. Upload this sketch to your Arduino Uno.

STEP 2: Add ATtiny Board Support to the IDE

  1. Open Preferences:
    File > Preferences
  2. In "Additional Boards Manager URLs", add:

    (Separate with commas if you already have other URLs.)
  3. Now go to:
    Tools > Board > Boards Manager
  4. Search for “attiny” and install the package by David A. Mellis.

STEP 3: Hook Up the ATtiny85 on the Breadboard
Pinout Reference for ATtiny85 (8-pin DIP)
_____
1 -|° |- 8 Vcc (5V)
2 -| |- 7 SCK (Pin 2)
3 -| |- 6 MISO (Pin 1)
4 -|_____|- 5 MOSI (Pin 0)

Pins:
1 = RESET
2 = Pin 3 (Analog 3 / Digital I/O)
3 = Pin 4 (Analog 2 / Digital I/O)
4 = GND
5 = Pin 0 / MOSI
6 = Pin 1 / MISO
7 = Pin 2 / SCK
8 = Vcc


STEP 4: Wiring From Arduino to ATtiny85

Arduino UnoATtiny85 PinFunction
Pin 10Pin 1RESET
Pin 11Pin 5MOSI
Pin 12Pin 6MISO
Pin 13Pin 7SCK
5VPin 8Vcc
GNDPin 4Ground

Optional:
Place a 10µF capacitor between RESET and GND on the Arduino, with negative leg to GND. This disables auto-reset during upload.


STEP 5: Burn the Bootloader (Set Fuses)

  1. Go to Tools > Board → Select "ATtiny25/45/85".
  2. Go to Tools > Processor → Select "ATtiny85".
  3. Go to Tools > Clock → Select "8 MHz (internal)" (or 1 MHz if you want low power).
  4. Go to Tools > Programmer → Select "Arduino as ISP".
  5. Click: Tools > Burn Bootloader

This sets the fuses for the selected clock.


STEP 6: Upload Your Sketch

  1. Write your code.
  2. Make sure the Programmer is still set to “Arduino as ISP”.
  3. Click Sketch > Upload Using Programmer (or press Shift+Upload).

Your sketch will upload directly to the ATtiny85!


Wiring Diagram (Text Version)
[ATtiny85] [Arduino Uno]
Pin 1 (RESET) <---> Pin 10
Pin 5 (MOSI) <---> Pin 11
Pin 6 (MISO) <---> Pin 12
Pin 7 (SCK) <---> Pin 13
Pin 4 (GND) <---> GND
Pin 8 (Vcc) <---> 5V

Optional:
Arduino RESET ---||--- GND (10µF cap)
Here's a photo of my testing board running the speedometer at 60mph. Like the arduino setup, the speedometer goes from 20-140mph in steps controlled with the potentiometer. No there's no signal generator or Arudino involved, it's all on the breadboard.

20250503_112355.jpg

And this is the breadboard I soldered together for easy chip programming with the Arduino without having to run jumper wires from a testing board every time.

20250503_103615.jpg
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Today I've finally figured out how to correct one of the biggest pet-peeves I've had with my car for years - the improperly calibrated odometer.

I'm not entirely sure how accurate the odometer was when I was running stock tires, but ever since I went up to 195/65/R15s back in 2019 the speedometer and odometer have been horribly out of whack. After comparing the cluster odometer to my GPS-calibrated Scangauge, I determined my correction factor was about 6.82%. For every 1000 miles my odometer showed, I actually drove 1068.2 miles. In that time I've lost about 8k miles, which isn't a ton, but it's pretty inconvenient when calculating fuel mileage.

Thanks to a post from @roadrunner89 in this thread, I knew the address of the K value, or speedometer calibration. This is located in block DC-DD in the bin file. All the clusters I've dumped have a value of 17-AF in this block, so this morning I started playing with the values to see what happens. Here's a collage showing the difference in the speedometer after changing the first block. I had my simulator set to 60mph.

14af_Fotor_Collage.jpg

The second block changed the reading as well, just not by nearly as much per digit. For instance, 17-00 read just about 62mph, while 17-FF read slightly under 60mph. Like I said previously, I've been using Chat GPT to quickly break down data and create python scripts. It already knew all the data from programming my speedometer simulator, and after inputting all my new data it was able to create what should be a mathematically perfect formula to properly set the K value. Now I have a python script that I made into an .exe for determining the correct K value. I put in my data, and it spit out the corrected value - 16-2C instead of 17-AF.

20250504_111930.jpg

Clearly 13.8 miles isn't a proper break-in test, but I would have been off by close to a mile at this point before I corrected it. It's very, very close, and I'll get to see just how close after a full tank of fuel. Also, the Scangauge apparently doesn't care about the cluster coding. It still matched my GPS speed after adapting the cluster. I didn't really expect that it would matter anyway, but it was worth mentioning.

20250504_124733.jpg

Anyway, I'm excited to be able to offer odometer calibration without any external hardware. And obviously, if you have the means to do it yourself, I will gladly share the calibration program - you can find the .py file Here. I'm currently working on integrating this and other functionality into my bin comparison program.

If you want to get your odometer calibrated, I would try to drive at least 1,000 miles with a good GPS before recording your numbers. The bigger the number, the closer we can calibrate it.

EDIT: later this same day...

I found my MFA wiper stalk and wire harness from my parts car, so I went ahead and put in an MFA cluster I built with Derek's parts. Setting the MFA cluster to work with the TDI is no big deal. Swap in the lower-speed tach face, change the number of cylinders and tachometer end-value in the bin file, set the mileage (and in this case, the speedometer calibration) and it's good to go.

20250504_132954.jpg

The speedometer was still off by a couple MPH when the needle was set right at 0 (as seen in the above photo) but it seems like almost all manufacturers make the speedometer show a bit fast than you're actually driving. I took it for a drive with the lens removed so I could adjust my needles accordingly. After I set the zero point about 3 mph under 0 mph then it showed dead accurate. At least, it matched the scan gauge perfectly for 30, 40, 50, 60, and 70 mph.

20250504_171233.jpg

And this is where all the gauges zero-out with the key off.

20250504_171541.jpg
 
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
I've been working on my mileage correction calculator today and implemented a tire size adjustment as well. If your odometer/speedometer is already accurate with the current tire size, you can input the hex value, current tire size, and tire size you're switching to. It's not *quite* as accurate as using the GPS method, but the margin of error is less than 1%.

I'm using 16-2C as my new hex value, because this was the "actual" number after putting in my real mileage. In the tire-corrected method, you can see it's giving me 16-02, which is still very close, but actually about .8% different than the GPS calculated value. Lots of things can affect the actual value, like tire wear, different manufacturing standards, tire pressure, and vehicle load. But if your stock size tires are already giving you accurate mileage, this will get it close enough.

Download here.

Screenshot 2025-05-05 154656.jpg
 
Last edited:

starrd

Veteran Member
Joined
Nov 24, 2003
Location
Canada
TDI
1996 Passat
A few things I learned while decoding the odometer:
The lowest mileage you can have is 15. This is accomplished by making the first two lines of the bin file into all zeros. If they're all FF, you'll get "------" across the odometer, but it won't advance.

View attachment 143082

I set an odometer to 15, then drove it to 16 and dumped the file. There was no change in the .bin between 15 and 16, so I'm not sure how to set an odometer that closely. That being said, if my hex-odometer converter program isn't dead-on, it's +/- a couple of miles.
Charlie, you were so close - 0 miles is done like this:

The eeprom read above was done by me on a brand new cluster from a fellow member that purchased it from VW years ago - US spec TDI Passat. The interesting thing was this cluster didn't work when I first tried it. Even though it had never been used, the 2 capacitors had leaked and needed to be replaced before it came back to life - so change those capacitors people!
Also, on the last line of the eeprom dump (row $FF, first 5 bytes) 61 60 66 30 15
That is the Cluster ID Number: = 616.066.3015
 
Last edited:

starrd

Veteran Member
Joined
Nov 24, 2003
Location
Canada
TDI
1996 Passat


That is really interesting. Based on your GPS readings if your car is getting 48 MPG on the uncorrected miles, once corrected you are really getting really getting 51.27 MPG
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan


That is really interesting. Based on your GPS readings if your car is getting 48 MPG on the uncorrected miles, once corrected you are really getting really getting 51.27 MPG
Unfortunately it didn't quite pan out that way. The larger diameter of the tires did some good by lowering RPM quite a bit, but at the end of the day it seems to take about as fuel to move a certain distance regardless. That being said, it I keep it at 55 I can definitely get over 51 MPG - but I never want to drive that slow. :)
 

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Last edited:

thechoochlyman

Vendor , w/Business number
Joined
May 7, 2015
Location
Campbellsville, Kentucky
TDI
1997 B4 Sedan
Been busy converting the MFA cluster from my new parts car - decided to start playing with the zero point calibration for all the needles.
Seems odd the way the did it from the factory, I guess they just popped the needles on and played with the coding until it matched the correct reading. I would MUCH rather set the needles at actual zero and know they'll be accurate when it's powered on, so here's a quick view of how much the needles can be adjusted with the software.

20250705_145612.jpg20250705_145658.jpg

The temp is supposed to be at 180, the fuel at 12 gallons. Setting the fuel gauge needle at the bottom red line seems to make it accurate, but the temp gauge needle needs to be set below the bottom line in order for it to sit right on the line between 160 and 200. Also seems to work with the speedometer, although putting in 00 make the needle not move at all, whereas 01 worked fine and seemed accurate through the whole sweep. So I'll probably set all four zero-points to 01 going forward.

Also, some genius had already been in this cluster and DRILLED OUT the PCB to disable the CEL. Can't shake my head any harder. Hopefully I can trace it back and make it work properly again.

20250705_132626.jpg
 

ToddA1

Top Post Dawg
Joined
Aug 3, 2011
Location
NJ 08002
TDI
'96 B4V, '97 B4 (sold), '97 Jetta (scrapped)
Very cool stuff…. I don't understand the process, but i understand the end result!

Even though it had never been used, the 2 capacitors had leaked and needed to be replaced before it came back to life - so change those capacitors people!
I got lucky and had Derek swap mine, when the B4V’s cluster started having issues. Derek had of of my A3 clusters for well over a year. It was the second time it was there and he couldn’t fix it the second time. I remember him saying the lack of good spares was one of the reasons he was closing down. I think the board failed, then failed again.

-Todd
 
Top