Eeprom read int returns false value

Hello,
I use the eeprom to log runtime issues as well as run parameters (called args, 16 bits ints) that can be changed via the ui or the server. Logs and args are interleaved.
when I read back an arg value, using a ui peek command, I get argx, the correct value.
When I read with the ui dump command I get argy, a different, wrong value(!)
When I read with server dump command I get again argy, the wrong value
This is so only one one arduino system, the bench one. On two field systems this never happens.
Any I idea?
my eeprom read int


int EEPROMreadInt(const int address) {
  unsigned int b0=EEPROM.read(address);
  unsigned int b1=EEPROM.read(address+1);
  unsigned int result=((b0<<0)&0x00FF)+((b1<<8)&0xFF00);
  return result;
}

Please post a complete sketch showing how the data is stored and read back

Why not use EEPROM.put() and EEPROM.get() to store and read the ints ?

1 Like
unsigned int EEPROMreadInt(const int address) {
  unsigned int b0=EEPROM.read(address);
  unsigned int b1=EEPROM.read(address+1);
  return b0+b1<<8;
}
1 Like

When I combine what UKHeliBob and kolaha wrote, then I would like to demonstrate that with this sketch:

// Testing the EEPROMreadInt() function on a Arduino Uno
// Forum: https://forum.arduino.cc/t/eeprom-read-int-returns-false-value/1130005
// This Wokwi project: https://wokwi.com/projects/365502258690709505

#include <EEPROM.h>

void setup() 
{
  Serial.begin(115200);
}

void loop() 
{
  int addr = 0;
  int rand1 = random(0,256);
  int rand2 = random(0,256);
  EEPROM.write(0, rand1);
  EEPROM.write(1, rand2);
  Serial.print(rand1,HEX);
  Serial.print(rand2,HEX);
  Serial.print(",");
  uint16_t res = EEPROMreadInt(0);      // good
  Serial.print(res, HEX);
  Serial.print(",");
  int signedresult = EEPROMreadInt(0);  // turned into a signed variable
  Serial.print(signedresult, HEX);
  Serial.println();
  delay(100);
}

uint16_t EEPROMreadInt(const int address) {
  unsigned int b0=EEPROM.read(address);
  unsigned int b1=EEPROM.read(address+1);
  return word(b0,b1);                   // word
}

Try it in Wokwi simulation: EEPROM read int returns false value - Wokwi Arduino and ESP32 Simulator

Result:

A7F1,A7F1,FFFFA7F1
D92A,D92A,FFFFD92A
82C8,82C8,FFFF82C8
D8FE,D8FE,FFFFD8FE
434D,434D,434D

Why bother with read and write, when you have get and put?

1 Like

show full sketch and say which board you using

I do not see what is wrong with .read and .write. I was not even aware of any other access methods.

Nevertheless I'll try with put and get and report here.

as for posting the complete sketch.. 7000 lines long! The write procedure should not be relevant here: The program write logs correctly and does write (and read!) read correctly the args. Only issue is with the bench system and with dumps.

Here is the ui dump code

//pad
void pad(char* string, const int number, const byte width, const byte radix) {
  long int currentMax=radix;
  for (byte i=1; i<width; i++) {
    if ((long)number<currentMax) {
      *string++='0';
    }
    currentMax*=radix;
  }
  itoa(number, string, radix);
}


//dumpEeprom
void dumpEeprom() {
  unsigned long debut;// epoch
  report(F("UI-> sending dump page\r\n"), MI_VERB);
  debut=millis();
  const char SEPARATOR='-';
  const byte DUMP_LINE_BYTES=sizeof "RRR:EEEEEEEEEE:LLLL:VVV:SSS\r\n";
  sp(F("rec-epoch------line-ver-sta\r\n"));
  char* insertPointer=genBuf;
  const char* lastGenBufLoc=genBuf+GEN_BUF_SIZE-1;
  memset(genBuf, '\0', sizeof(genBuf));
  for (int record=0; record<LOGGER_RECORDS; record++) {
    if (insertPointer+DUMP_LINE_BYTES>=lastGenBufLoc-1) { //dont erase terminating '\0'
      sp(genBuf); // most data sent here
      memset(genBuf, '\0', sizeof(genBuf));
      insertPointer=genBuf;
    }
    int address=record*BYTES_PER_RECORD;
    pad(insertPointer, record, 3, 10);
    insertPointer+=3;
    *insertPointer++=SEPARATOR;
    //if(virginEpoch(EEPROMreadLong(address))) break; 
    ltoa(EEPROMreadLong(address), insertPointer, 10);
    insertPointer+=strlen(insertPointer);
    *insertPointer++=SEPARATOR;
    byte versionFlag=EEPROM.read(address + VERSION_FLAG_OFFSET);
    int lineArg=EEPROMreadInt(address + LINE_ARG_OFFSET);
    pad(insertPointer, lineArg, 4, versionFlag <= MAX_VERSION ? 10 : 16);
    insertPointer+=4;
    *insertPointer++=SEPARATOR;
    pad(insertPointer, versionFlag, 3, 10);
    insertPointer+=3;
    *insertPointer++=SEPARATOR;
    pad(insertPointer, EEPROM.read(address + STATUS_OFFSET), 3, 10);
    insertPointer+=3;
    strcpy(insertPointer, "\r\n");
    insertPointer+=2;
  }
  if (insertPointer!=genBuf) { // if at this point insert pointer is at start, nothing more to do
    //*insertPointer='\0'; // else, sign the remainding data with zero and send
    sp(genBuf);
  }
  spln(); sp(F("duration ")); spln(millis() - debut);
}

I am not sure what you intended to demonstrate but he main thing that it shows is that it is easy to destroy EEPROM locations by writing to them too many times

I write to same location ~ once in few month and the eeprom appear to be functioning properly

There is nothing wrong with using them if you use them correctlybut put() and get() are simpler to use

That is a very odd thing to say because if you write the data incorrectly then reading it back will not work correctly

        ltoa(EEPROMreadLong(address), insertPointer, 10);

Where is the EEPROMreadLong() defined ?

@ UKHeliBob thanks for bothering!
Data is written correctly because

  1. otherwise the program won't work, alarm would sound, garden won't be irrigated, gates wouldn't obey etc
  2. when I call the ui/read the server response all read data is the expected one. Allways
  3. when I read back explicitly with UI I read the correct values. Always.

readLong here

//EEPROMreadLong
unsigned long EEPROMreadLong(int address) {
  long b0=EEPROM.read(address);
  long b1=EEPROM.read(address+1);
  long b2=EEPROM.read(address+2);
  long b3=EEPROM.read(address+3);
  long result=((b0<<0)&0xFF)+((b1<<8)&0xFF00)+((b2<<16)&0xFF0000)+((b3<<24)&0xFF000000);
  //sp(F("EEPROMreadLong address is "));sp(address);sp(F(" read "));spln(result,HEX);
  return result;
}

Discovering what you are doing is like pulling teeth

My advice would be to use the put() and get() functions and do away with all of your functions to read (and presumably save) data of different types

No wonder your sketch is so long with all of those messy functions

possible. I am mostly hw, less sw
Coded dump with .get, doesn't become notably shorter and does not resolve the issue

And the issue is . . ?

We can solve it, but you have to meet us halfway.

Which Arduino IDE version do you use ?
Which Arduino board do you use ?
Please show the full sketch, 7000 lines is medium size.
If you are more hardware and less software, then it is better to avoid pointers. You might have to rewrite your code to avoid pointers. We can help with the sprintf() to format text.
Please specify what is in the EEPROM. Are those signed or unsigned and 32 or 16 bits values and so on.
Please give the format in which they should be printed.
There are so many conversions between 'int' and 'long' and between signed and unsigned, it makes my head spin.

What is this: currentMax*=radix;
There could be more of those in your code.

When your code runs on other platforms, that might be because they use 32 bit 'int' and the Arduino Uno uses 16 bit 'int'.
It is possible that your code has a number of memory bugs, but runs fine on other platforms. In the Arduino Uno, those bugs might cause a problem. You assume that something is wrong with the sketch on the Arduino Uno, but I assume that your code has a number of bugs :grimacing:
If you assume that a certain part of code is good, that is the first part we have to look into, because there is a good chance that the bug is there.

1 Like

Yes, if you put a 16-bit value with the high-order bit set into a 16-bit signed variable it becomes a negative number. The Serial.print() function promotes all smaller signed integers to signed longs so, when you display in HEX or BIN you get to see those 16 additional sign bits. Generlly, anything you want to display in HEX should be unsigned.

Note: The compiler promotes 8-bit values to 'int' when used in expressions. If the 8-bit value is signed (char or int8_t) it will get sign-extended.

1 Like

I read your post like hearing a sweet music :smile: Thanks

currentMax*=radix;

means in the 'c' jargon
currentMax=CurrentMax*radix
I think it's the big contribution of MM. Kerninghan and Ritchie to the computer science

Id be glade to publish my work, I'll need to change passwords first :smiley:

ok, I found and corrected in 'pad'

void pad(char* string, const int number, const byte width, const byte radix) {

to

void pad(char* string, const unsigned int number, const byte width, const byte radix) {

both ui and server initiated dump used this same erronouse 'pad'

Sorry, I must have been very sleepy :sleeping_bed:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.