Hello everyone.
I am trying to help my niece with her Mercedes Sprinter W903 2000 model.
The car is facing a well known "Start Error" fault, which is caused by a fault in the immobilizer unit.
I have found a immobilizer emulator which works with the CR2 ECU in the car, but in order to get this to work, i need to overwrite some data in the ST95P08 EEPROM in the ECU.
ST95P08 datasheet link: ST95P08 Datasheet(PDF) - STMicroelectronics
The EEPROM has been desoldered and wired up to my Arduino Uno.
Using the following code, i am able to read the content of all the 1000 addresses in the EEPROM:
#include <SPI.h>
#define CS_PIN 10 // Chip select pin (S)
#define MOSI_PIN 11 // Serial Data input (D)
#define MISO_PIN 12 // Serial data output (Q)
#define SCK_PIN 13 // Serial clock
#define W_PIN 7 // Write Protect (W)
#define HOLD_PIN 6 // Hold
void setup() {
// Set the pin modes
pinMode(CS_PIN, OUTPUT);
pinMode(W_PIN, OUTPUT);
pinMode(HOLD_PIN, OUTPUT);
// pinMode(MOSI_PIN, OUTPUT);
// pinMode(MISO_PIN, INPUT);
// pinMode(SCK_PIN, OUTPUT);
// Start the SPI library
SPI.begin();
// Deselect the EEPROM
digitalWrite(CS_PIN, HIGH);
// Only readmode
digitalWrite(W_PIN, LOW); // Enable write protect (FOR READING)
digitalWrite(HOLD_PIN, HIGH); // Disable HOLD
Serial.begin(9600); // Init serial comm
// Adjust SPI settings for EEPROM
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); // Example settings: 2 MHz, MSB first, Mode 0
}
void loop() {
// Read from address 0x00 to 0x3FF (for a 1 KByte EEPROM)
for (unsigned int address = 0; address < 1024; address++) {
byte data = readEEPROM(address);
Serial.print("Address 0x");
if (address < 0x10) Serial.print("0"); // Print leading zero for addresses less than 0x10
Serial.print(address, HEX); // Print the address in HEX
Serial.print(": 0x");
Serial.println(data, HEX); // Print the data in HEX
delay(50); // Short delay to not overwhelm the serial monitor
}
while(1); // Stop after reading the entire EEPROM
}
byte readEEPROM(byte address) {
digitalWrite(CS_PIN, LOW); // Select the EEPROM
SPI.transfer(0x03); // READ instruction code
// For the ST95P08, which has 1KByte, only one address byte is needed.
SPI.transfer(address); // Send the LSB of address to read from
byte result = SPI.transfer(0x00); // Read the byte
digitalWrite(CS_PIN, HIGH); // Deselect the EEPROM
return result;
}
void writeEEPROM(unsigned int address, byte data) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x02); // WRITE instruction code
SPI.transfer((address >> 8) & 0xFF); // MSB of the address
SPI.transfer(address & 0xFF); // LSB of the address
SPI.transfer(data);
digitalWrite(CS_PIN, HIGH);
// Wait for the write to complete
delay(10); // This delay depends on the EEPROM's write cycle time; adjust as necessary
}
This works fine, and the output (shortened) looks like this:
Address 0x00: 0x61
Address 0x01: 0xFF
Address 0x02: 0xFF
Address 0x03: 0x71
Address 0x04: 0xFF
Address 0x05: 0x16
Address 0x06: 0x16
Address 0x07: 0x30
Address 0x08: 0x39
The four addresses wich needs new data is: 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4
When the data of these addresses are read, i get:
Address 0x1D0: 0xFF
Address 0x1D1: 0xFF
Address 0x1D2: 0xFF
Address 0x1D3: 0xFF
Address 0x1D4: 0xFF
I try to write to these addresses using the following code:
#include <SPI.h>
#define CS_PIN 10 // Chip select pin (S)
#define W_PIN 7 // Write Protect (W)
#define HOLD_PIN 6 // Hold
bool isWritingMode = false; // Set to 'true' for writing, 'false' for reading
// Function Prototypes
void writeEnable();
void writeEEPROM(unsigned int address, byte data);
byte readEEPROM(unsigned int address);
byte readStatusRegister();
void waitForWriteCompletion();
void setup() {
pinMode(CS_PIN, OUTPUT);
digitalWrite(W_PIN, HIGH);
pinMode(W_PIN, OUTPUT);
pinMode(HOLD_PIN, OUTPUT);
digitalWrite(HOLD_PIN, HIGH); // Disable HOLD
digitalWrite(CS_PIN, HIGH); // Ensure EEPROM is not selected
SPI.begin();
Serial.begin(115200);
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
// Test WREN-able, write "0x01" to addr 0x01 (current value: 0xFF)
testWriteEnableLatchAndWrite();
// checkBlockProtection();
// if (isWritingMode) {
// // Disable write protection for writing
// digitalWrite(W_PIN, HIGH);
// // digitalWrite(W_PIN, LOW);
// } else {
// // Enable write protection for reading
// // digitalWrite(W_PIN, HIGH);
// digitalWrite(W_PIN, LOW);
// }
}
void loop() {
}
void testWriteEnableLatchAndWrite() {
writeEEPROM(0x1D0, 0x02);
waitForWriteCompletion();
delay(100);
byte readValue1 = readEEPROM(0x1D0);
Serial.print("Read back value from address 0x1D0: 0x");
Serial.println(readValue1, HEX);
writeEEPROM(0x1D1, 0x02);
waitForWriteCompletion();
delay(100);
byte readValue2 = readEEPROM(0x1D1);
Serial.print("Read back value from address 0x1D1: 0x");
Serial.println(readValue2, HEX);
writeEEPROM(0x1D2, 0x00);
waitForWriteCompletion();
delay(100);
byte readValue3 = readEEPROM(0x1D2);
Serial.print("Read back value from address 0x1D2: 0x");
Serial.println(readValue3, HEX);
writeEEPROM(0x1D4, 0xFF);
waitForWriteCompletion();
delay(100);
byte readValue4 = readEEPROM(0x1D4);
Serial.print("Read back value from address 0x1D4: 0x");
Serial.println(readValue4, HEX);
}
byte readStatusRegister() {
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x05); // RDSR command
byte status = SPI.transfer(0x00); // Dummy transfer to read the status
digitalWrite(CS_PIN, HIGH);
return status;
}
void checkBlockProtection() {
byte status = readStatusRegister();
Serial.print("Status Register: 0x");
Serial.println(status, HEX);
// Extracting BP bits
byte bpBits = (status & 0x0C) >> 2; // BP bits are b3 and b4, shifting right by 2 to get the value
Serial.print("Block Protection Bits (BP1 BP0): ");
Serial.println(bpBits, BIN);
switch(bpBits) {
case 0b00:
Serial.println("No block protection.");
break;
case 0b01:
Serial.println("Upper quarter write-protected.");
break;
case 0b10:
Serial.println("Upper half write-protected.");
break;
case 0b11:
Serial.println("All memory write-protected.");
break;
default:
// This case should not happen as BP bits are only two bits
Serial.println("Invalid Block Protection Bits.");
break;
}
}
byte readEEPROM(unsigned int address) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x03);
SPI.transfer((address >> 8) & 0xFF); // MSB of the address
SPI.transfer(address & 0xFF); // LSB of the address
byte result = SPI.transfer(0x00);
digitalWrite(CS_PIN, HIGH);
return result;
}
void writeEnable() {
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x06); // WREN command
delay(5);
digitalWrite(CS_PIN, HIGH);
}
void waitForWriteCompletion() {
Serial.println("Waiting for write to complete...");
byte status;
do {
status = readStatusRegister();
if (status & 0x01) { // If WIP bit is set, write is still in progress
Serial.println("Write in progress...");
}
delay(10); // Short delay before checking again
} while (status & 0x01); // Loop until WIP bit clears
Serial.println("Write operation completed.");
}
bool checkWELCleared() {
byte status = readStatusRegister();
if (status & 0x02) { // If WEL bit is set, then it's not cleared yet
Serial.println("WEL bit is not cleared yet.");
return false;
} else {
Serial.println("WEL bit cleared.");
return true;
}
}
bool checkWriteEnable() {
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x05); // RDSR command to read the status register
byte status = SPI.transfer(0x00); // Dummy transfer to read the response
digitalWrite(CS_PIN, HIGH);
// Print the status register value for debugging
Serial.print("Status register: 0x");
Serial.println(status, HEX);
// Check if the WEL bit is set
bool isWELSet = status & 0x02; // 0x02 corresponds to the WEL bit
if (isWELSet) {
Serial.println("WEL bit is set. EEPROM is ready for write operation.");
} else {
Serial.println("WEL bit is not set. EEPROM is not ready for write operation.");
}
return isWELSet;
}
void writeEEPROM(unsigned int address, byte data) {
// Serial.println("Enable EEPROM write...");
writeEnable(); // Ensure the EEPROM is write-enabled
delay(100); // Delay after sending WREN, ensure EEPROM has enough time to set WEL
// Serial.println("Checking if WEL bit is set...");
if (!checkWriteEnable()) {
Serial.println("Write Enable Latch not set! Exiting..");
return; // Exit if WEL not set
}
// Serial.println("Setting CS pin low...");
digitalWrite(CS_PIN, LOW);
// Serial.println("Sending WRITE instruction code...");
SPI.transfer(0x02); // WRITE instruction code
// Serial.println("Sending MSB of address...");
SPI.transfer((address >> 8) & 0xFF); // MSB of the address
// Serial.println("Sending LSB of address...");
SPI.transfer(address & 0xFF); // LSB of the address
// Serial.print("Sending data to address: 0x");
// Serial.print(address, HEX);
// Serial.print(" -> Data: 0x");
// Serial.println(data, HEX);
SPI.transfer(data);
// Serial.println("Setting CS pin HIGH...");
digitalWrite(CS_PIN, HIGH);
delay(100);
// delay(10); // Wait for the write to complete
// Serial.println("Waiting for write completion...");
// waitForWriteCompletion();
}
I get this in the serial monitor:
10:42:13.749 -> Write operation completed.
10:42:13.868 -> Read back value from address 0x1D0: 0x2
10:42:13.937 -> Status register: 0xF2
10:42:13.937 -> WEL bit is set. EEPROM is ready for write operation.
10:42:14.047 -> Waiting for write to complete...
10:42:14.047 -> Write operation completed.
10:42:14.183 -> Read back value from address 0x1D1: 0x2
10:42:14.256 -> Status register: 0xF2
10:42:14.256 -> WEL bit is set. EEPROM is ready for write operation.
10:42:14.358 -> Waiting for write to complete...
10:42:14.393 -> Write operation completed.
10:42:14.501 -> Read back value from address 0x1D2: 0x0
10:42:14.589 -> Status register: 0xF2
10:42:14.589 -> WEL bit is set. EEPROM is ready for write operation.
10:42:14.713 -> Waiting for write to complete...
10:42:14.713 -> Write operation completed.
10:42:14.805 -> Read back value from address 0x1D3: 0xFF
10:42:14.922 -> Status register: 0xF2
10:42:14.922 -> WEL bit is set. EEPROM is ready for write operation.
10:42:14.994 -> Waiting for write to complete...
10:42:15.042 -> Write operation completed.
10:42:15.123 -> Read back value from address 0x1D4: 0xFF
Everything seems good so far....
But, when i power-cycle the device, and read the values again using my first read program, the values in addresses 0x1D0-0x1D4 seem to have been reset back to 0xFF.
I have been going at this for days now, and from my understanding everything has been implemented correctly. It sort of seems that the EEPROM is not able to retain the data in these addresses.
I would appreciate all inputs in trying to help solve this issue.