i2C EEPROM not writing as expected

Greetings,
I have to write specific variables to an i2C EEPROM and i am only getting the last 'half' of my string written to the EEPROM.

This is what i need to write:
[FzgParam]
Fahrzeugadresse=123456
MontageplattenNr=9
Dummy=1

This is what my code is actually writing:
6
MontageplattenNr=9
Dummy=1

I cannot understand why I am only getting half written considering that the string is always written to the first memory location 0x00 in the EEPROM.

#include <Wire.h>

void setup() {
  Wire.begin(); // Initialize I2C bus
  Serial.begin(9600); // Initialize Serial communication (for debugging)
  delay(1000); // Wait for devices to stabilize

  // Check if the device is detected
  if (isDeviceDetected(0x50)) {
    Serial.println("EEPROM detected at address 0x50");
  } else {
    Serial.println("EEPROM not detected at address 0x50. Please check connections.");
    delay(2000);
  }
}

void loop() {
    // Check if the device is detected
  if (isDeviceDetected(0x50)) {
    Serial.println("EEPROM detected at address 0x50");
  } else {
    Serial.println("EEPROM not detected at address 0x50. Please check connections.");
    delay(2000);
  }
  
  //strings to be joined
  String string1 = "[FzgParam]";  // length 10
  String string2 = "Fahrzeugadresse=";  // length 16
  int number1 = 123456;  // Variable digit length 6
  String string4 = "MontageplattenNr="; //length 17
  int number2 = 9;  // Variable digit length 1
  String string6 = "Dummy=1"; //length 7 

  // 10+16+6+17+1+7=57
  // 

// convert numbers into strings 
  String string3 = String(number1);
  String string5 = String(number2);

  // join all strings together with line feed
  String message = string1 + "\n" + string2 + string3 + "\n" + string4 + string5 + "\n" + string6;
  // Calculate the length of the string (including null terminator)
  int messageLength = message.length() + 1;
  Serial.print("messageLength=");
  Serial.println(messageLength);
  
  // Reserve memory for the string and additional bytes
  byte buffer[messageLength]; //byte buffer[messageLength + 2];
  
  // Copy the characters of the string into the buffer
  message.getBytes(buffer, messageLength);
  
  // Write the string data to the EEPROM starting at memory location 0x00
  writeToEEPROM(0x50, 0x00, buffer, messageLength);
  
  // Write additional bytes 0xAA and 0xFF to the next two memory locations
  //writeToEEPROM(0x50, 0x0C, (byte)0xAA);
  //writeToEEPROM(0x50, 0x0D, (byte)0xFF);
  
  // Print the message to Serial for verification
  Serial.println("Data written to EEPROM: " + message);
  
  //TESTING ONLY: Wait for 5 seconds before writing again
  delay(5000);
}

void writeToEEPROM(int deviceAddress, int memoryAddress, byte* data, int length) {
  Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
  Wire.write((int)(memoryAddress >> 8)); // Send upper memory address byte
  Wire.write((int)(memoryAddress & 0xFF)); // Send lower memory address byte
  Wire.write(data, length); // Send data to be written
  Wire.endTransmission(); // End transmission
  delay(10); // Wait for the EEPROM to complete the write operation
}

void writeToEEPROM(int deviceAddress, int memoryAddress, byte data) {
  Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
  Wire.write((int)(memoryAddress >> 8)); // Send upper memory address byte
  Wire.write((int)(memoryAddress & 0xFF)); // Send lower memory address byte
  Wire.write(data); // Send data to be written
  Wire.endTransmission(); // End transmission
  delay(10); // Wait for the EEPROM to complete the write operation
}

bool isDeviceDetected(int deviceAddress) {
  Wire.beginTransmission(deviceAddress); // Start communication with the specified address
  byte error = Wire.endTransmission(); // Check if the device responds
  
  return (error == 0); // Return true if no error occurred, indicating device detection
}

Any help to understand and solve my issue would be great please.

An EEPROM has pages and timing.
Use a library: https://github.com/RobTillaart/I2C_EEPROM

On this forum we sometimes say that the problem is in the part that someone is not showing. How do you know that things are not written ? There is no code to read the data :dizzy_face:
Is the data to the Serial Monitor showing the right data ?
Which Arduino board are you using ?
You say that you need to write " Fahrzeugadresse=321456", but then in the code you use the number "123456" :woozy_face: That is confusing, when writing code and avoiding bugs, it is important to be clear and correct :nerd_face:
This is a bug: int number1 = 123456;
Such a bug number does not fit in a 16-bit integer.
How do you make a new line in the EEPROM ? When writing text to a file, there is often a Carriage Return and Line Feed at the end of each line (or just a Carriage Return or just a Line Feed).
You are building the text with "String" and then write everything to EEPROM. I would avoid the "String" and write each small piece of the text directly to EEPROM.

Thank you for a nice text layout :heart: I can just let my eyes go over the code to spot the problems.

Hi, thanks for the help.
I have an external tool that reads the EEPROM so that's how I know the write is incomplete.
I am using an ESP32 dev board.
You are correct and sorry for the confusion, I have changed the number so many times looking for patterns I forgot to match what I copied to my code. the only requirement for the variable is that it is limited to 6 digits only. I will change to a long.

i think my specific device needs a \n for a line feed and a 0xAA and 0xFF as an end of file terminator but i am guessing as there is no documentation. but that said the third party device that is reading the EEPROM doesn't seem to mind the current format except for the fact that it misses the first half of the string lol.

Hi Koepel,
I have just changed the code to use long data type instead of int and there is no difference to the output. I am also trying to understand how you would "write each piece of the text directly to the EEPROM" as you suggest. Can you give me an example?

#include <Wire.h>

void setup() {
  Wire.begin(); // Initialize I2C bus
  Serial.begin(9600); // Initialize Serial communication (for debugging)
  delay(1000); // Wait for devices to stabilize

  // Check if the device is detected
  if (isDeviceDetected(0x50)) {
    Serial.println("EEPROM detected at address 0x50");
  } else {
    Serial.println("EEPROM not detected at address 0x50. Please check connections.");
    while (true) {} // Hang the program if the device is not detected
  }
}

void loop() {
    // Check if the device is detected
  if (isDeviceDetected(0x50)) {
    Serial.println("EEPROM detected at address 0x50");
  } else {
    Serial.println("EEPROM not detected at address 0x50. Please check connections.");
    delay(2000);
  }
  
  //strings to be joined
  String string1 = "[FzgParam]";  // length 10
  String string2 = "Fahrzeugadresse=";  // length 16
  long number1 = 123456;  // Variable digit length 6
  String string4 = "MontageplattenNr="; //length 17
  int number2 = 1;  // Variable digit length 1
  String string6 = "Dummy=1"; //length 7 

  // 10+16+6+17+1+7=57
  // 

// convert numbers into strings 
  String string3 = String(number1);
  String string5 = String(number2);

  // join all strings together with line feed
  String message = string1 + "\n" + string2 + string3 + "\n" + string4 + string5 + "\n" + string6;
  // Calculate the length of the string (including null terminator)
  int messageLength = message.length() + 1;
  Serial.print("messageLength=");
  Serial.println(messageLength);
  
  // Reserve memory for the string and additional bytes
  byte buffer[messageLength]; //byte buffer[messageLength + 2];
  
  // Copy the characters of the string into the buffer
  message.getBytes(buffer, messageLength);
  
  // Write the string data to the EEPROM starting at memory location 0x00
  writeToEEPROM(0x50, 0x00, buffer, messageLength);
  
  // Write additional bytes 0xAA and 0xFF to the next two memory locations
  //writeToEEPROM(0x50, 0x0C, (byte)0xAA);
  //writeToEEPROM(0x50, 0x0D, (byte)0xFF);
  
  // Print the message to Serial for verification
  Serial.println("Data written to EEPROM: " + message);
  
  //TESTING ONLY Wait for 5 seconds before writing again
  delay(5000);
}

void writeToEEPROM(int deviceAddress, int memoryAddress, byte* data, int length) {
  Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
  Wire.write((int)(memoryAddress >> 8)); // Send upper memory address byte
  Wire.write((int)(memoryAddress & 0xFF)); // Send lower memory address byte
  Wire.write(data, length); // Send data to be written
  Wire.endTransmission(); // End transmission
  delay(10); // Wait for the EEPROM to complete the write operation
}

void writeToEEPROM(int deviceAddress, int memoryAddress, byte data) {
  Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
  Wire.write((int)(memoryAddress >> 8)); // Send upper memory address byte
  Wire.write((int)(memoryAddress & 0xFF)); // Send lower memory address byte
  Wire.write(data); // Send data to be written
  Wire.endTransmission(); // End transmission
  delay(10); // Wait for the EEPROM to complete the write operation
}

bool isDeviceDetected(int deviceAddress) {
  Wire.beginTransmission(deviceAddress); // Start communication with the specified address
  byte error = Wire.endTransmission(); // Check if the device responds
  
  return (error == 0); // Return true if no error occurred, indicating device detection
}

If your library does not include a string write:

  // Write the string data to the EEPROM starting at memory location 0x00
  writeToEEPROM(0x50, 0x00, "[FzgParam]", sizeof("[FzgParam]");

Better wrap this pattern in an overloaded writeToEEPROM() function.

Using String type on 8 bit Controllers will corrupt memory very soon. Better write literals or char* C strings.

Have you seen the source code ? https://github.com/RobTillaart/I2C_EEPROM/blob/master/I2C_eeprom.cpp
The "pages" are important. An EEPROM is not just a continuous memory. To write data of any length, you need a library.

Thanks,

I am reading now but I am afraid its at the limit of my understanding and I am missing the point. I thought I was only working within the first bytes of the first page.

Hi @dannysprogis

What is your EEPROM module, exactly? Reading and writing principles are slightly depends on EEPROM memory size.

Also, according to the device address (0x50) I suspect that it can be a FRAM FM24 module?

hi DrDiettrich,

I'm not sure I understand what you mean, are you suggesting something like this?

where i calculate and define the start address for each srting manually?

writeToEEPROM(0x50, 0x00, "[FzgParam]\n", sizeof("[FzgParam]\n");
writeToEEPROM(0x50, 0x13, "Fahrzeugadresse=\n", sizeof("Fahrzeugadresse=\n");
writeToEEPROM(0x50, 0x29, "123456\n", sizeof("123456n");

Hi b707,
Thanks for the input :slight_smile:

The EEPROM is a microchip 24FC64 64K I2C™ Serial EEPROM

Right.

I just found out that you included the write functions. You missed to handle page boundaries, so that multi-byte writes wrap around on each 32 bytes page boundary.

This makes writing of a long data area, as you do, will effectively write only the last 32 bytes.

To be honest I didn't think I needed a library so my initial code doesn't use one.

I will try to use the I2C_EEPROM library that Koepel suggested but I am not sure how well i will go....

Greetings all,
I have been experimenting and indeed my issue is that I am only writing to the first page of EEPROM if I write 32 bytes (16 ascii characters ) the result is as expected. If I go over the 32byte buffer indeed the first bytes are overwritten as everyone suggests.

The issue now is that i don't understand how to write to the second page?

I thought I should be able to build a second and third string and send it to the address of the next page(s).

Seems that I am so close and should be able to build and send a second string to 0x16 (00000010) which I believe to be the address of the first byte of second page on the 24FC64?

this code doesn't work... lol

I am being a little stubborn to use another library because i don't understand the examples at all and I feel I am really close here...

#include <Wire.h>

void setup() {
  Wire.begin(); // Initialize I2C bus
  Serial.begin(9600); // Initialize Serial communication (for debugging)
  delay(1000); // Wait for devices to stabilize

}

void loop() {
    // Check if the device is detected
  if (isDeviceDetected(0x50)) {
    Serial.println("EEPROM detected at address 0x50");
  } else {
    Serial.println("EEPROM not detected at address 0x50. Please check connections.");
    delay(2000);
  }
  
  //strings to be joined
  String string1 = "[FzgParam]";  // length 10
  String string2 = "Fahrzeugadresse=";  // length 16
  long number1 = 123;  // Variable digit length 6
  String string4 = "Montageplatten="; //length 17
  int number2 = 1;  // Variable digit length 1
  String string6 = "Dummy=1"; //length 7 

  // 10+16+6+17+1+7=57
  // 

// convert numbers into strings 
  String string3 = String(number1);
  String string5 = String(number2);

  // join all strings together with line feed
  String message = string1 + "\n" + string2+ string3 + "\n"; //
  String message2 =string4 + "\n";
  // Calculate the length of the string (including null terminator)
  int messageLength = message.length() + 1;
  Serial.print("messageLength=");
  Serial.println(messageLength);

  int messageLength2 = message2.length() + 1;
  Serial.print("messageLength2=");
  Serial.println(messageLength2);
  
  // Reserve memory for the string and additional bytes
  byte buffer[messageLength]; //byte buffer[messageLength + 2];
  byte buffer2[messageLength2]; //byte buffer[messageLength + 2];
  
  // Copy the characters of the string into the buffer
  message.getBytes(buffer, messageLength);
  message.getBytes(buffer2, messageLength2);
  
  // Write the string data to the EEPROM starting at memory location 0x00
  writeToEEPROM(0x50, 0x00, buffer, messageLength);
  writeToEEPROM(0x50, 0x16, buffer2, messageLength2);
  
  // Write additional bytes 0xAA and 0xFF to the next two memory locations
  //writeToEEPROM(0x50, 0x0C, (byte)0xAA);
  //writeToEEPROM(0x50, 0x0D, (byte)0xFF);
  
  // Print the message to Serial for verification
  Serial.println("Data written to EEPROM: " + message);
  
  //TESTING ONLY Wait for 5 seconds before writing again
  delay(5000);
}

void writeToEEPROM(int deviceAddress, int memoryAddress, byte* data, int length) {
  Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
  Wire.write((int)(memoryAddress >> 8)); // Send upper memory address byte
  Wire.write((int)(memoryAddress & 0xFF)); // Send lower memory address byte
  Wire.write(data, length); // Send data to be written
  Wire.endTransmission(); // End transmission
  delay(10); // Wait for the EEPROM to complete the write operation
}


bool isDeviceDetected(int deviceAddress) {
  Wire.beginTransmission(deviceAddress); // Start communication with the specified address
  byte error = Wire.endTransmission(); // Check if the device responds
  
  return (error == 0); // Return true if no error occurred, indicating device detection
}

The second 32 byte page starts at 0x20. The page number can be obtained from addr & 0x1E00 and page offset from addr & 0x1FF. See the 6.2 Page Write section in the data sheet.

In writeToEEPROM() you have to check for crossing a page boundary. Then split the output into the first page and as many page writes as required into further pages.

Thanks Dr,
I am reading the data sheet but didn't fully understand what it meant. I am afraid I still don't understand how to implement what you said but I am chewing it over now...

As @DrDiettrich pointed out:

Should be:

 writeToEEPROM(0x50, 0x20, buffer2, messageLength2);

greetings,

thanks Jim-p I have noticed that but still not working...

I have tried to improve the function but Im at my programming limits.

This is what I have currently for the writeToEEPROM function but it doesn't work...

void writeToEEPROM(int deviceAddress, int memoryAddress, byte* data, int length) {
  int pageSize = 32; // Define the page size of the EEPROM 
  int currentPageAddress = memoryAddress; // Store the current page address

  for (int i = 0; i < length; i += pageSize) {
    int remainingLength = length - i;
    int writeLength = min(remainingLength, pageSize); // Calculate the length of data to write within the current page

    // Calculate the current page and page offset
    int currentPage = currentPageAddress & 0x1E00;
    int pageOffset = currentPageAddress & 0x1FF;
    
    Serial.print("page: ");
    Serial.println(currentPage);
    Serial.print("offset: ");
    Serial.println(pageOffset);

    // Check if the write crosses a page boundary
    if ((pageOffset + writeLength) > pageSize) {
      writeLength = pageSize - pageOffset;          // Adjust the write length to stay within the current page
    }

    Wire.beginTransmission(deviceAddress); // Start communication with EEPROM
    Wire.write((int)(currentPage >> 8)); // Send upper memory address byte
    Wire.write((int)(currentPage & 0xFF) | pageOffset); // Send lower memory address byte with page offset
    Wire.write(data + i, writeLength); // Send data to be written
    Wire.endTransmission(); // End transmission
    delay(10); // Wait for the EEPROM to complete the write operation

    currentPageAddress += writeLength; // Update the current page address
  }
}

I think that your previous code was simpler and should work.

There have been other posts involving EEPROM problems and the conclusions were that the EEPROMs were fake/conterfiet.

Did you buy from a reputable distributor?

yes thanks, its definitely my code and not the devices.

I have a third party tool and application that work perfectly. this is how I verify my code is not working because the third party software does not read it correctly. if I write with the third party software I get what I expect.

the issue is that i need a laptop to run the third party software and I am trying to minimise everything to a calculator sized tool with 4x4 keypad and OLED display.

my prototype tool only needs to save the following to an EEPROM chip
with the variable Fahrzeugadresse 6 digits being the only thing that changes with keypad entry.

[FzgParam]
Fahrzeugadresse=123456
MontageplattenNr=1
Dummy=1