2

I am using the attached code. What I am trying to do is:

Test if there is a personalized "board serial number" written in the EEPROM (by previous code run) If data found was not 7 characters (e.g SN-XXXX), then generate a serial number and save it to EEPROM

Problem is: it generates a serial correctly, it even stores and reads it a few times, but when I disconnect the USB cable and reconnect to test again, it returns some bad data from the EEPROM, like: ⸮^R⸮y⸮| which seems to pass my 7 characters test and it doesn't generate a new one.

What am I doing wrong ?


#include <EEPROM.h>

// board SERIAL number
char serial_characters[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"};
// will be filled as SN-A2KH
String serial_number;


void setup() {

  Serial.begin(9600);

  // Get the float data from the EEPROM at position 0
  EEPROM.get(0, serial_number);

  // serial from EEPROM valid
  if (serial_number.length() == 7) {
    Serial.println("Found valid serial in EEPROM");
    Serial.println(serial_number);
  }

  // serial from EEPROM not valid (e.g not: SN-XYZ5)
  if (serial_number.length() != 7) {

    Serial.println("Serial from eeprom is NOT 7 chars, generating a random serial");
    Serial.println(serial_number);

    // if analog input pin 0 is not connected, use noise from it in order to generate a random seed, otherwise random is not so random
    randomSeed(analogRead(0));

    // serial might be empty now, set a "SN-" prefix
    serial_number = "SN-";
    for (int i = 1; i <= 4 ; i++) {
      serial_number = serial_number + serial_characters[random(0, 35)];
    }
    Serial.println("Generated serial now: " + serial_number);

    // save to eeprom if format is valid
    if (serial_number.length() == 7) {
      EEPROM.put(0, serial_number);
      Serial.println("Written serial to EEPROM");
    }

  } // <<< serial from eeprom not correct, generated one

}

void loop() {}

2 Answers 2

7

You are saving a String object in EEPROM, which is useless. A string object does not store the contents of your string. Instead, it just stores:

  • the memory address where the actual contents (the characters) is stored
  • the amount of memory allocated for this contents
  • the number of characters that actually make the string

This is what you are storing to, and retrieving from EEPROM. So you get the correct number of characters (third item in the list above), but the memory address now points to uninitialized RAM.

I suggest instead storing in the EEPROM a raw C string, i.e. an array of 8 chars (7 printable chars plus the terminating NUL). You could achieve this by just changing the declaration of serial_number:

char serial_number[8];

For checking the validity, I would just check that it starts with "SN-" and the last char is a NUL:

if (memcmp(serial_number, "SN-", 3) == 0 && serial_number[7] == '\0') {
    ...
}

You could do a more stringent validation though, and check that the other 4 chars are within the valid set.

Edit: to build serial_number with random chars:

strcpy(serial_number, "SN-");
for (int i = 3; i < 7; i++)
  serial_number[i] = serial_characters[random(0, 36)];
serial_number[7] = '\0'; // terminating NUL
0
3

Just to have the full working code, I ended up with this:

#include <EEPROM.h>

char serial_characters[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"};
// 7 chars for serial and one for string end '\0'
char serial_number[8];

void setup() {

  Serial.begin(115200);

  EEPROM.get(0, serial_number);

  // check found format
  if (serial_number[0] == 'S' && serial_number[1] == 'N'  && serial_number[2] == '-' && serial_number[7] == '\0') {

    Serial.println("serial from eeprom is valid");
    Serial.println((char*)serial_number);

  } else {

    Serial.println("no valid serial found in eeprom, generating new serial");

    // if analog input pin 0 is unconnected, use noise from it in order to generate a random seed, otherwise random is not so random
    randomSeed(analogRead(0));

    // generate a new serial
    serial_number[0] = 'S';
    serial_number[1] = 'N';
    serial_number[2] = '-';

    // overwrite ending chars of serial with random values
    serial_number[3] = serial_characters[random(0, 35)];
    serial_number[4] = serial_characters[random(0, 35)];
    serial_number[5] = serial_characters[random(0, 35)];
    serial_number[6] = serial_characters[random(0, 35)];

    // end string with null as raw C strings ?!
    serial_number[7] = '\0';

    Serial.println((char*)serial_number);

    // write new serial to eeprom
    EEPROM.put(0, serial_number);

  }

}

void loop() {

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.