You are not logged in.

Dear visitor, welcome to Mitsubishi Fan Forum. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

Metatr0n

Motorabwürger

  • "Metatr0n" is male
  • "Metatr0n" started this thread

Posts: 47

Vehicle: Mitsubishi Galant EA0

P B
-
M J * * * *

Thanks: 22 / 4

  • Send private message

1

Thursday, July 5th 2018, 12:17am

[Galant] HC Tacho Kilometerstand anpassen (& von Meilen auf KM umstellen)


Inhalt:
  1. Rechtliches
  2. Hinweise
  3. Tacho Umbau
  4. Kilometer-Korrektur
  5. EEPROM lesen
  6. EEPROM verstehen
  7. EEPROM schreiben
  8. Tacho Modifikation
  9. Meilen-Konvertierung
  10. Fazit



Rechtliches

In Deutschland ist die Manipulation des Kilometerstandes im Kombiinstrument NICHT illegal.

Diese Tat wird erst illegal, wenn diese vorsätzlich zur Täuschung und zum Betrug anderer Personen angewendet wird.

Anwendung dieses Tutorials erfolgt ausschließlich auf eigene Gefahr!

Ich distanziere mich ausdrücklich von der illegalen Nutzung des Wissens in diesem Tutorial!

Ich bin Urheber aller Photos und Screenshots in diesem Tutorial.



Hinweise

Dieses Tutorial richtet sich an die unter euch, die sich nicht vor Trial-and-Error scheuen und mit einem Lötkolben umgehen können.
Es gibt 2 wesentlich einfachere, aber teurere Alternativen um zum gleichen Ziel zu kommen:
  1. Serial Programmer kaufen
  2. Serial Programmer selber bauen
Nachteil am kaufen ist, dass es die teuerste Alternative ist. Hochwertige Serial Programmer können bis zu 140€ kosten, günstigere Modelle gibt es natürlich auch, Made in China.
Nachteil am selbstbauen ist, man muss die einzelnen Komponenten für den Serial Programmer kaufen, den Serial Programmer auf einem Breadboard zusammenstecken, oder löten und man benötigt einen alten PC mit Serial Port und Windows XP.
Vorteil von beiden Methoden ist die Einfachheit und die Geschwindigkeit. Ist der Serial Programmer vorhanden (egal ob gekauft, oder gebaut), kann ein serieller EEPROM per OpenSource Software eingelesen und beschrieben werden.
Beides sind sinnvolle Alternativen, jedoch lag mein Arduino bereits seit mehreren Monaten ohne Verwendung auf meinem Schreibtisch und ich wollte eine kleine Herausforderung haben. Näheres im Kapitel "EEPROM lesen".
Solltet ihr euch gegen einen Serial Programmer entscheiden und lieber diesem Tutorial folgen, benötigt ihr:
  • Phillips Schraubendreher
  • Lötkolben und Lötzinn
  • Entlötlitze
  • Arduino
  • Breadboard mit ca. 12 Kabeln



Tacho Umbau

Die Geschichte des HC Tachos ist eine Geschichte voller Missverständnisse.
Jeder der noch keinen hat, aber vor hat sich einen zu besorgen und in seinen Galant einzubauen, empfehle ich den alten Thread von Schrauber zu lesen und auch jegliche andere Threads die schon über den HC Tacho erstellt wurden.

[Elektrik] HC-Tacho Umbau
[Elektrik] Tachotausch auf HC bei GDI

Bitte beachtet die Unterschiede zwischen den Motorisierungen! (4G63, 4G64, 6A13)

Da der mir angebotene HC Tacho (MR559404) Britischer Herkunft war und einen kleinen Riss in der vorderen Blende aufwies, konnte ich diesen für (verhältnismäßig) kleines Geld erstehen. Laut verkäufer stammte dieser aus der EA0 2.0l Variante, laut zwielichtigen russischen Websites stammt er aus der Britischen 2.5l (V6) Variante. Ich wollte es auf einen Versuch ankommen lassen, denn mein eigentlicher Urlaubsplan ist geplatzt und ich brauchte nun eine Alternative mit der ich meinen Kopf während des Urlaubs auf Trab halten konnte.

Wie in so vielen Threads schon beschrieben, standen anfänglich natürlich die standardmäßigen Umbauten an:
  1. A5 unterbrechen
  2. Brücke von A11 nach A5 (vor Unterbrechung)
  3. Brücke von A4 nach A5 (hinter Unterbrechung)



Alles funktionierte einwandfrei, Hintergrundbeleuchtung und Drehzahlmesser. Jedoch, wie bereits vermutet bei einer Britischen Tachoeinheit, zählte der Kilometerzähler in Meilen und war somit wohl eher ein Meilenzähler. :Yp

Nun ging es an die Korrektur des Kilometerstandes / Meilenstandes.


Kilometer-Korrektur

Ich habe leider kein Photo vom alten Kilometerstand gemacht, da die Idee des Dokumentierens erst später kam und ich zu dem Zeitpunkt nichtmehr daran gedacht habe, ein Beweisphoto des Kilometerstandes zu machen.
Der HC Tacho hatte 75.522 Meilen auf der Uhr, während der Kilometerstand meines Galants bereits bei 217.445 km lag. Genau wie viele andere in den älteren HC Tacho Threads, wollte ich auch den originalen Kilometerstand im neuen HC Tacho haben, somit war eine simple Dokumentation im Serviceheft keine Lösung für mich.

Als erstes muss die gesamte Tachoeinheit demontiert werden.



Auf der Rückseite findet man die Platinen der Drehzahlmessereinheit und der Tachoeinheit.



Die Platine der Tachoeinheit lässt sich auf der rechten Seite finden und als Verantwortlichen für die digitale Speicherung aller notwendigen Daten der Tachoeinheit erspähte ich in der unteren, linken Ecke bereits einen heißen Anwärter.



Bingo, ein ST/Microwire 93C46 EEPROM. Beschriftung ist auf dem Photo leider nicht zu erkennen.



Detail-Aufnahme der Rückseite, diese 7 Pins müssen entlötet werden, am besten mit Entlötlitze. Zum Schutz des EEPROMs habe ich einen kleinen Aluminium-Kühlkörper auf ihm befestigt, dieser leitet die Hitze schneller ab.



Hier die Platinenrückseite nach der Entlötung.



Der EEPROM mit Kühlkörper.



Und ohne Kühlkörper.



Edit: Rechtschreibkorrektur

This post has been edited 1 times, last edit by "Metatr0n" (Jul 5th 2018, 12:38am)

Responsible for any content, image rights and attachments of this posting at (Thursday, July 5th 2018, 12:17am) is the author Metatr0n himself.


2 registered users thanked already.

Users who thanked for this post:

schnieder (05.07.2018), EinOger (06.07.2018)

Advertising

Unregistered

Advertising

Kostenlos registrieren oder anmelden um diesen Werbeblock verschwinden zu lassen!

Metatr0n

Motorabwürger

  • "Metatr0n" is male
  • "Metatr0n" started this thread

Posts: 47

Vehicle: Mitsubishi Galant EA0

P B
-
M J * * * *

Thanks: 22 / 4

  • Send private message

2

Thursday, July 5th 2018, 12:20am

EEPROM lesen

So nun sind wir an dem Schritt angekommen an dem entschieden werden muss, wie man mit dem EEPROM weiter umgeht. Wie bereits oben erwähnt gibt es die möglichkeit sich einen Serial EEPROM Programmer zu kaufen. Diese kommen meißt mit eigener Software und EEPROM-Datenbank, das ist eine Sache von 2-3 Clicks und man hat den Inhalt des EEPROMs auf dem Schirm. Wer kein Geld für so ein Gerät ausgeben will, für den gibt es noch die Möglichkeit ein eigenes Serial Interface zu bauen. Dazu benötigt es jedoch einen PC mit Serial Port und Windows XP.
Nach dieser Schaltung könnt ihr verfahren, Vcc sind +5V.



Anschließend könnt ihr mit einem Programm wie PonyProg auf den EEPROM zugreifen, dazu gibt es bereits viele Tutorials online.

Wie oben bereits geschrieben, habe ich mich jedoch dazu entschieden den komplizierteren, rustikaleren Weg zu gehen, der einen wesentlich größeren Lerneffekt mit sich bringt.
Der erste Schritt um zu verstehen was der Tacho eigentlich mit dem EEPROM macht ist zu verstehen wie der EEPROM funktioniert. Das Data-Sheet ist somit die erste Anlaufstelle: 93C46 Data-Sheet
Wir erfahren, dass es sich bei dem 93C46 um einen 1 kb Serial EEPROM handelt und wir erfahren, dass er eine 8-bit Breite, oder 16-bit Breite besitzen kann.
Was es genau damit auf sich hat, können wir im 4. Kapitel (Seite 10) nachlesen:
Das EEPROM hat 2 verschiedene Organisations-Modi:
  • 128 Addressen zu je 7 bit mit 8 bit Platz für Daten
  • 64 Addressen zu je 6 bit mit 16 bit Platz für Daten

Man kann also für die Hälfte der "Speicherplätze" die mögliche zu speichernde Datenmenge verdoppeln. Um den x8 Modus zu wählen, muss Pin 6 (ORG) mit Pin 5 (Vss, Masse) verbunden werden, für den x16 Modus der Pin 6 (ORG) mit Pin 8 (Vcc).
Auf der Platine können wir sehen, dass Mitsubishi sich für den x16 Modus entschieden hat.



Damit kennen wir schonmal einen wichtigen Punkt den wir bei der Verdrahtung unseres EEPROMs mit unserem Arduino zu beachten haben.
Als erstes wird der EEPROM auf dem Breadboard platziert, anschließend wird verdrahtet:
  • Pin 1 des EEPROM (S, Chip Select) mit Pin 10 des Arduino
  • 1k Ohm Widerstand von Pin 1 des EEPROM auf Masse
  • Pin 2 des EEPROM (C, Clock-Signal) mit Pin 13 des Arduino
  • Pin 3 des EEPROM (D, Data Input) mit Pin 11 des Arduino
  • Pin 4 des EEPROM (Q, Data Output) mit Pin 12 des Arduino
  • Pin 5 des EEPROM (Vss, Masse) auf Masse (-Schiene des Breadboards)
  • Pin 6 des EEPROM (ORG, x8/x16 Organisation) auf Spannung! (+Schiene des Breadboards)
  • Pin 8 des EEPROM (Vcc, Spannung) auf Spannung (+Schiene des Breadboards)
  • GND Pin des Arduino auf die -Schiene des Breadboards
  • 5V Pin des Arduino auf die +Schiene des Breadboards

Pin 7 bleibt wie im Data-Sheet beschrieben unbelegt.
Der Widerstand an Pin 1 des EEPROM zieht den Chip Select LOW um zu gewährleisten, dass dieser Input nicht "schwebt", wenn der Arduino keine digitale 1 ausgibt.

Das Resultat sollte so aussehen:



Arduino angeschlossen. (Leider falsch fokussiert)



Nahaufnahme der Pin-Belegung.



Nun, da die Verdahtung komplettiert ist, müssen wir uns um die Kommunikation kümmern, dazu gibt Kapitel 5 (Seite 11) Aufschluss. Jede Kommunikation mit dem EEPROM beginnt mit einer Rising Edge an S (Chip Select) während das Clock-Signal LOW bleibt. Jeder Übertragung geht ein Start-Bit (1) vorraus, welche an D (Data Input) anliegen muss bevor das Clock-Signal die Rising Edge antritt. Anschließend kann der OP-Code des jeweiligen Befehls übermittelt werden, im Falle des Read-Befehls die 10, gefolgt von der 6-bit langen Addresse an welcher man die Daten auslesen möchte.
Da der 93C46 über Microwire kommuniziert und Microwire ein Sub-Set des SPI (Serial Peripheral Interface) ist, habe ich als erstes die SPI-Bibliothek und -Funktionen die der Arduino von Haus aus mitbringt ausprobiert und siehe da, es klappt. (CPOL = 0, CPHA = 0)
Somit kann man sich eine enorme Menge an Bit-Banging sparen.
Ich habe folgendes Programm für den Arduino geschrieben. Den Quellcode habe ich auf Englisch kommentiert, da ich mir die Möglichkeit offen gehalten habe diesen auch auf Englisch-sprachigen Foren zu posten und es ist schon aufwändig genug den Quellcode einmal zu kommentieren. Also warum nicht in der Sprache die Deutsche auch verstehen. (Außerdem bin ich Engländer und es fällt leichter technische Dinge auf Englisch zu erklären :P )

Source code

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*  
 *  Routine to dump contents of addresses 0 to 63 of the 93C46 onto Serial Port Monitor
 *  
 *  93C46 Pin-Layout:  
 *         ______
 *    1 --|O     |-- 8
 *    2 --|      |-- 7
 *    3 --|      |-- 6
 *    4 --|______|-- 5
 *  
 *  1 = S   (Chip Select, INPUT)
 *  2 = C   (Serial Clock, INPUT)
 *  3 = D   (Serial Data input, INPUT)
 *  4 = Q   (Serial Data output, OUTPUT)
 *  5 = Vss (Ground)
 *  6 = ORG (Organization Select, INPUT)
 *  7 = DU  (Don't Use)
 *  8 = Vcc (Supply Voltage)
 *  
 *  Organization Select:
 *  
 *  The memory of the 93C46 can be organized as: 
 *  - 128 addresses with 8-bit storage for each address (7-bit address)
 *  - 64 addresses with 16-bit storage for each address (6-bit address)
 *  To select x8 organization, connect ORG to Vss (GND)
 *  To select x16 organization, connect ORG to Vcc (Supply Voltage)
 *  The 93C46 for the Mitsubishi Galant Odometer is connected to Vcc and thus x16 organization is selected
 *  
 *  Data transfer:
 *  
 *  The 93C46 uses Microwire, which is a subset of SPI, thus the SPI-functionality of the Arduino can be used
 *  
 *  For more information, check the 93C46 data-sheet
 */[/color]

#include<SPI.h>
#define CS        10  //connect to pin 1 of 93C46
#define CLK       13  //connect to pin 2 of 93C46
#define DATAOUT   11  //connect to pin 3 of 93C46 
#define DATAIN    12  //connect to pin 4 of 93C46



void setup()
{
  //set data-pins of the Arduino accordingly
  pinMode(CS,OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(CLK,OUTPUT);
  
  //pull Chip Select LOW
  digitalWrite(CS,LOW);

  //start serial transmission at 9600 Baud
  Serial.begin(9600);

  //start of the SPI Transaction, 2 MHz is selected, the MSB is sent first and SPI-Mode is 0
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  
  //start of the dump() routine
  dump();
}

void loop()
{
  //loop() stays empty, since we want our code to only run once
}

void dump(){
  //print headline to Serial Monitor
  Serial.println("address:\tdata:");

  /* 
   * Since x16 organization is selected, the variables which should receive the data-transfer are cast as word (16-bit)
   * Due to the effect of the 93C46, sending a preceding 0 at the beginning of the data-transfer, and SPI-transfer only being 
   * able to send 16-bit words at once, we can't store the 16 bits in one variable but have to use a second one to catch the
   * last bit of the transfer:
   * 
   * 93C46 sends 17 bits (preceding 0 = 1 bit + data-transfer = 16 bit): 
   * ---------------------------------------------------------------------
   * | 0 | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x |
   * ---------------------------------------------------------------------
   * 
   * SPI-transfer can only send 16 bits at once, so data1 contains:
   * -----------------------------------------------------------------
   * | 0 | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x |
   * -----------------------------------------------------------------
   * 
   * data2 catches the last remaining bit of the transfer:
   * -----------------------------------------------------------------
   * | x | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
   * -----------------------------------------------------------------
   */
  word data1;
  word data2;

  /*
   * The for-loop gives the opportunity to automate the process of reading each memory-position at each address individually.
   * Instructions for the 93C46 have to be preceded by a rising edge on S (Chip Select) on a low C (Serial Clock). The
   * SPI-functionality that the SPI-library offers to Arduino takes care of that automatically.
   * Each OP-code of the instruction-set has to be preceded by a start-bit (1) which is sent first. Right after that the 2-bit
   * OP-code has to be sent. The OP-code for the WRITE-function is 10. After that the 93C46 is expecting an address, which in
   * x16 organization is 6 bits long. (7 bits for x8)
   * After the transfer of the instruction, we have to listen to the data-output of the 93C46 and store the 17 bits of data
   * into data1 and data2. After that, Chip Select is pulled LOW again, data1 is bit-shifted to the left to get rid of the
   * preceding 0 and the last bit (LSB) is set to 1 in case there is a 1 at the first position of data2.
   * 
   * For more optimized code the start-bit (1) is sent individually while the 2-bit OP-code (10) and the 6-bit address is sent
   * as an 8-bit package. To make sure that the first two bits of the 8-bit package is always 10 (WRITE OP-code), the counter
   * for address starts at 128 (Binary: 1000000) and ends at 191 (Binary 10111111).
   */
  for (byte address = 128; address < 192; address++) {
    //pull Chip Select HIGH
    digitalWrite(CS,HIGH);

    //transfer of the start-bit (1)
    SPI.transfer(0b1);

    //transfer of the 2-bit OP-code (10) and the 6-bit address (000000 - 111111)
    SPI.transfer(address);

    //data-output of the 93C46 is stored in data1, preceded by a leading 0
    data1 = SPI.transfer16(0);

    //last bit (LSB) of the data-output is stored in data2
    data2 = SPI.transfer16(0);

    //pull Chip Select LOW again
    digitalWrite(CS,LOW);

    //bit-shift data1 to the left to get rid of the preceding 0
    data1 = data1 << 1;

    //if-branch to detect if the first bit (MSB) of data2 contains a 1
    if (bitRead(data2, 15) == 1){

      //if the first bit (MSB) of data2 contains a 1, change the last bit (LSB) of data1 to 1
      bitWrite(data1, 0, 1);
    }
    //start of printByte-routine with address and data1 as parameters
    printByte(address, data1);
  }
}

/*
 * printByte-routine to print the received data to Serial Monitor
 * The printByte-routine receives address and data1 as parameters and uses them as address and data.
 * Since address still contains the 2-bit OP-code (10), the preceding 1 (MSB) has to be removed. A manual bit-write overwrites
 * the 1 with a 0.
 * After that the data is printed to Serial Monitor in HEX-format.
 * 
 */
void printByte(byte address, word data){
  //overwrite the preceding 1 with a 0
  bitWrite(address, 7, 0);

  //print address and data to Serial Monitor in HEX-format
  Serial.print(address, HEX);
  Serial.print("\t\t");
  Serial.print(data, HEX);
  Serial.print("\n");
}


Diesen Quellcode kann man direkt per Copy&Paste in die Sketch-Oberfläche des Arduino einfügen und auf den Arduino hochladen.
Ausgeführt wird der Code, wenn man über "Tools" den Serial Monitor auswählt. (Oder Strg+Shift+M drückt)
Das Ergebnis schaut dann so aus:



Das Ergebnis sollte man per Copy&Paste in den Windows Editor einfügen und z.B. als "dump.txt" auf der Festplatte speichern. Das sind die Original-Daten die der EEPROM enthält. Sollte im späteren Verlauf etwas schief gehen, hat man zumindest dieses Backup und kann diese wieder aufspielen, somit geht nichts verloren.

Nun der lustige Part.


EEPROM verstehen

Um diese Daten interpretieren zu können habe ich sie in einen HEX-Editor übertragen, der mir in echtzeit die Bytes als HEX, Dezimal, als Inverse der beiden und das ganze auch als Reverse-Byte anzeigen kann. Das wichtigste dabei sind die invertierten HEX Werte, da auf EEPROMs sehr häufig invertiert gespeichert wird.



Nun schaut man nach sich-wiederholenden HEX-Folgen und kontrolliert in den invertierten HEX Werten ob man Zahlen des Kilometerstandes (75522) wiedererkennt. Und bingo:



Diese Folge existiert 3 mal:



Nun muss man sich gedanken machen was für eine Art Reihenfolge dahinter steckt. Nach ein wenig Spielerei und Testen konnte ich folgendes schlussfolgern:



Die Reihenfolge in der gespeichert wird ist:
Tausender, Hunderter, Zehner, Hundertausender, Zehntausender
Zu den Einern konnte ich leider keine Verbindung finden und Änderungen der 3 Nibbles (Halb-Bytes) zwischen den Zehnern und Hundertausendern brachten wirre Ergebnisse. Zumindest lässt sich die Genauigkeit dieses Eingriffs nun auf 0-9 km bestimmen.
Um die Methodik zu erklären:
Der HEX Wert den wir isolieren konnten lautet AA DA FF F8. Jedes Nibble wird nun mit der Inversen-Tabelle unten invertiert. Die Inverse lautet somit 55250007.
Diese wird nun nach oben stehendem System gesplittet und neu zusammen gefügt:
5 * 1000
5 * 100
2 * 10
0 * 100000
7 * 10000
=7552X

Somit ist der zu ändernde Wert im EEPROM bestimmt und wir können mit der Überschreibung beginnen. Jedoch müssen wir die oben erklärte Methodik nun rückwärts anwenden um auf den HEX Wert zu kommen der in das EEPROM geschrieben werden muss.
Ich habe mich dazu entschlossen keine Meilen ins EEPROM zu schreiben, sondern die KM, dazu später mehr.
Wir erinnern uns, dass mein Galant 217.471 km auf der Uhr hat. Somit muss die 217471 nun gesplittet, neu sortiert und invertiert werden. Aus der 217471 wird 747XXX21, wobei jedes X ruhig eine 0 sein kann und invertiert wird daraus 8B 8F FF DE.



Das "Verstehen" des EEPROMs ist damit abgeschlossen.

This post has been edited 1 times, last edit by "Metatr0n" (Jul 29th 2018, 9:39am)

Responsible for any content, image rights and attachments of this posting at (Thursday, July 5th 2018, 12:20am) is the author Metatr0n himself.


2 registered users thanked already.

Users who thanked for this post:

schnieder (05.07.2018), EinOger (06.07.2018)

Metatr0n

Motorabwürger

  • "Metatr0n" is male
  • "Metatr0n" started this thread

Posts: 47

Vehicle: Mitsubishi Galant EA0

P B
-
M J * * * *

Thanks: 22 / 4

  • Send private message

3

Thursday, July 5th 2018, 12:22am

EEPROM schreiben

Als erstes konsultieren wir Kapitel 5.2.1 (Seite 13) des Data-Sheet, dort steht, dass zum Schreiben des EEPROMs erst der Write Enable ausgeführt werden muss um den Schreibschutz aufzuheben. Danach kann der Write-Befehl ausgeführt werden und durch Write Disable der Schreibschutz wieder aktiviert werden.
Laut Kapitel 5 (Seite 11) heißt das, dass als erstes der OP-Code 00 mit anschließender Addresse 11XXXX (Die letzten 4 bits der Addresse ignoriert das EEPROM, für die korrekte bit-Folge müssen sie aber mitgesendet werden) für den Write Enable übertragen werden muss. Danach der OP-Code 01 mit anschließenden 6 bits der Addresse an der der Wert überschrieben werden soll plus 16 bits an Daten die geschrieben werden sollen und zum Schluss der OP-Code 00 mit anschließender Addresse 00XXXX für den Write Disable.

Ich habe folgenden Quellcode erstellt um Werte im EEPROM überschreiben zu können. Da es fast nicht möglich ist diesen Prozess zu automatisieren, habe ich mich dazu entschlossen die Addressen an denen überschrieben werden soll und die Werte mit denen die alten überschrieben werden sollen zu hardcoden. Das bedeutet es gibt keine Eingabemaske, oder ähnliches, sondern die Werte müssen im Quelltext selbst geändert werden.
Man ändert in Zeile 80 also die Addresse an der man überschreiben möchte (im Binär-Format) und in Zeile 87 die Werte mit denen man die alten überschreiben möchte (im HEX-Format), uploaded den Quellcode auf den Arduino und führt ihn über den Aufruf des Serial Monitors aus. Das Programm zeigt nach dem Überschreiben die nun neuen Werte im EEPROM an, so kann man sich davon überzeugen, dass beim Überschreiben nichts falsch gelaufen ist. Ist alles korrekt, wiederholt man die Schritte mit der nächsten Addresse und den nächsten Werten.

Möchte man also an Addresse "04" (6-bit Binär: 000100) den Wert "AF B8" schreiben, ändert man Zeile 80 zu:

Source code

1
SPI.transfer(0b01000100);

und Zeile 87 zu:

Source code

1
SPI.transfer16(0xAFB8);


Hier der Quellcode für Copy&Paste:

Source code

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*  
 *  Routine to write content to addresses 0 to 63 of the 93C46
 *  This routine outputs a dump to Serial Monitor after writing is finished.
 */

#include<SPI.h>
#define CS        10  //connect to pin 1 of 93C46
#define CLK       13  //connect to pin 2 of 93C46
#define DATAOUT   11  //connect to pin 3 of 93C46 
#define DATAIN    12  //connect to pin 4 of 93C46

void setup()
{
  //set data-pins of the Arduino accordingly
  pinMode(CS,OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(CLK,OUTPUT);
  
  //pull Chip Select LOW
  digitalWrite(CS,LOW);

  //start serial transmission at 9600 Baud
  Serial.begin(9600);

  //start of the SPI Transaction, 2 MHz is selected, the MSB is sent first and SPI-Mode is 0
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  
  //start of the write_() routine
  write_();
  
  //start of the dump() routine
  dump();
}

void loop()
{
  //loop() stays empty, since we want our code to only run once
}

void write_(){
  Serial.println("write_ routine start\n");

  //pull Chip Select HIGH
  digitalWrite(CS,HIGH);

  /*
   * Write Enable is executed by sending start-bit (1) followed by OP-code 00 and 6-bit address 11xxxx (x = don't care).
   * This enables usage of the Write OP-code
   */
  Serial.println("Write Enable");
  
  //transfer of start-bit (1)
  SPI.transfer(0b1);

  //transfer of OP-code (00) and address (11xxxx)
  SPI.transfer(0b00110000);

  //pull Chip Select LOW again
  digitalWrite(CS,LOW);

  //small delay for better stability of the on-chip-routines
  delay(100);

  //pull Chip Select HIGH
  digitalWrite(CS,HIGH);

  /*
   * Write is executed by sending start-bit (1) followed by OP-code 01 and 6-bit address of the data-cell to be changed.
   * After OP-code and 6-bit address are transmitted, data-transfer can begin. Since x16 organization is selected, 16 bits
   * of data have to be transmitted.
   */
  Serial.println("Setting Write OP-code and address");

  //transfer of start-bit (1)
  SPI.transfer(0b1);

  //transfer of OP-code (01) and address (xxxxxx)
  //change address-bits according to the position at which you want to overwrite the data
  SPI.transfer(0b01000000);

  //data transfer
  Serial.println("Writing data");

  //data transfer in HEX for easier input
  //change HEX values to the values you want to overwrite the old data with
  SPI.transfer16(0xFFFF);

  //small delay for better stability of on-chip-writing
  delay(10);

  //pull Chip Select LOW again
  digitalWrite(CS,LOW);

  //small delay for better stability of the on-chip-routines
  delay(100);

  //pull Chip Select HIGH
  digitalWrite(CS,HIGH);

  /*
   * Write Disable is executed by sending start-bit (1) followed by OP-code 00 and 6-bit address 00xxxx (x = don't care).
   * This disables usage of the Write OP-code
   */
  Serial.println("Write Disable\n\n");

  //transfer of start-bit (1)
  SPI.transfer(0b1);

  //transfer of OP-code (00) and address (00xxxx)
  SPI.transfer(0b00000000);

  //pull Chip Select LOW again
  digitalWrite(CS,LOW);
}

void dump(){
  Serial.println("Dumping data\n");
  Serial.println("address:\tdata:");
  
  word data1;
  word data2;
  
  for (byte address = 128; address < 192; address++) {
    digitalWrite(CS,HIGH);
    
    SPI.transfer(0b1);
    SPI.transfer(address);
    data1 = SPI.transfer16(0);
    data2 = SPI.transfer16(0);

    digitalWrite(CS,LOW);
    
    data1 = data1 << 1;
    if (bitRead(data2, 15) == 1){
      bitWrite(data1, 0, 1);
    }
    printByte(address, data1);
  }
}

void printByte(byte address, word data){
  bitWrite(address, 7, 0);
  Serial.print(address, HEX);
  Serial.print("\t\t");
  Serial.print(data, HEX);
  Serial.print("\n");
}


Hat man alles richtig gemacht, sieht das Ergebnis so aus: (AA DA FF F8 mit 8B 8F FF DE überschrieben)



So, das schlimmste ist überstanden. Nun kommen wir langsam zum Abschluss, alles muss wieder zusammengesetzt werden. Aber es bleibt Zeit für eine kleine Modifikation die das Leben erleichtert.


Tacho Modifikation

Um unser zukünftiges "Ich" zu verwöhnen löten wir den EEPROM nicht direkt auf die Platine, sondern löten stattdessen einen 4x2 Pin IC-Sockel auf die Platine. Es ist die gleiche Menge Lötarbeit wie den EEPROM direkt auf die Platine zu löten, jedoch hat es den Vorteil, dass man den EEPROM immer und zu jeder Zeit mit sanftem Hebeln eines Schlitzschraubenziehers wieder entnehmen und auf das Breadboard setzen kann. In meinem Fall war es Gold wert.



Und beim Löten kann man sich immer Mühe geben um ein schönes Ergebnis zu erzielen. Der Kunststoff der IC-Sockel ist empflindlich, länger als eine Sekunde muss der Lötvorgang pro Pin nicht dauern, gerne noch weniger Kontaktzeit als eine Sekunde.



Nun darf sich der EEPROM ins Bettchen legen.



Das Ergebnis spricht glaube ich für sich. :gut



Nun zum Spezial-Kapitel:


Meilen-Konvertierung

Wir erinnern uns, dass ich mich dazu entschlossen habe, den Kilometerstand in KM, anstelle von Meilen zu überschreiben. Hintergrund war die Überlegung, ob es nicht möglich ist dem Tacho beizubringen was ein Kilometer ist. Der Tacho muss schließlich eine Art Clock-Signal bekommen anhand dessen er weiß welche Strecke gefahren wurde, oder wie viele Umdrehungen des Rades eine zurückgelegte Längeneinheit ergibt.
Die Lösung befand sich direkt auf der Tachofolie.



Nun geht es darum die 1025 im HEX-Dump zu finden. Diesmal aber nicht in der reverse !HEX...




Wert ist 3 mal vertreten.




Nun folgt ein einfacher Dreisatz und die Konvertierung von Dezimal zu HEX.




Und die Werte im EEPROM überschreiben.




Und nach dem Einbau stellt man fest, dass der Kilometerzähler nun tatsächlich ein Kilometerzähler ist! :#
Aber genau so stellt man auch fest, dass der Stellmotor der Tachonadel anscheinend kein rohes Clock Signal erhält, sondern ein von diesem Wert beeinflusstes Signal des EEPROMs... Im Klartext heißt das, der Tacho zeigt bei Tempo 50 nun 50 mph auf der großen Skala und 80 kmh auf der kleinen...

:%

Heißt für mich entweder, 1) den tatsächlichen Kilometerstand in Meilen umrechnen, neu beschreiben, die 1025 wieder eintragen und damit leben, dass der Kilometerzähler ein Meilenzähler ist, oder 2) ein Breakout-Board mit einem zweiten EEPROM anfertigen auf dem die 1025 eingetragen ist und auf das der Stellmotor zugreift, während der echte gefahrene Kilometerstand im ersten EEPROM bestehen bleibt. Bedeutet natürlich ein erhebliches Reverse-Engineering der Tacho-Platine, aber es kommt bestimmt mal wieder irgendwann ein Urlaub in dem ich Zeit habe.
Werde Möglichkeit 1 morgen umsetzen, damit ich in der Zwischenzeit eine Korrekte mph-/ kmh-Anzeige habe und meine gefahrenen Meilen aufgezeichnet werden. Sollte ich mich dazu entschließen Möglichkeit 2 umzusetzen, werde ich hier ein weiteres Kapitel anfügen.


Fazit

Was ist mein Fazit? Arbeit hat sich gelohnt.
Urlaub ist nicht langweilig und ich hab was gelernt, das sind zwei meiner Lieblingsdinge im Leben.
Ich hoffe ich konnte einige hier animieren, motivieren, mobilisieren, stabilisieren.
Ich sage danke an alle die bis hier her gelesen haben. In dieses Tutorial ist mindestens dreimal so viel Zeit geflossen wie in die ganze Tacho-Aktion an sich. Die Photos, die Screenshots, den Quelltext kommentieren, die Photos und Screenshots hochladen und diesen Text hier zu verfassen und zu formatieren waren ein ganzes Stück Arbeit, aber solange es mindestens einem geholfen hat und einen anderen gut unterhalten hat, war es die Arbeit wert.

Liebe Grüße,

Metatr0n

:GN

Responsible for any content, image rights and attachments of this posting at (Thursday, July 5th 2018, 12:22am) is the author Metatr0n himself.


5 registered users thanked already.

Users who thanked for this post:

EinOger (05.07.2018), sunnytoeter (05.07.2018), Hilt (05.07.2018), Alex. (05.07.2018), schnieder (05.07.2018)