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;
}
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
}
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
@ UKHeliBob thanks for bothering!
Data is written correctly because
otherwise the program won't work, alarm would sound, garden won't be irrigated, gates wouldn't obey etc
when I call the ui/read the server response all read data is the expected one. Allways
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;
}
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
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.
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.