SPARKFUN external EEPROM library - issue with arrays

I'm using a struct (~272 byte) to manage my data. Within the struct there are two two-dimentional float arrays each 128 Byte.
When I read out the struct, some data (always [3][4]) of one array is corrupt - showing "-inf".
When I access the dedicated corrupt entry directly the value is read out correctly. (reading single bytes in the suspected areas did als not show any wrong data ...
Are there limitations when using arrays ?

I'm using 24LC256

initialisation:

        myMem.setMemoryType(256); // Valid types: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1025, 2048   // 21kByte
        myMem.setPageSizeBytes(64);          // 64 Bytes pro Page 
        myMem.setAddressBytes(2);            // 2 Byte Addressierung (16 Bit) für >16 kbit
typedef struct                
{
    uint8_t version;             // 1 byte
    uint8_t reserved[3];       // 3 Byte  padding

    bool   cal_A[4];      // 4 Byte
    bool   cal_B[4];      // 4 Byte
    float   korr_B[4][8];   // 128 Byte
    float   korr_A[4][8];   // 128 Byte

    uint16_t reserved2;        // 2 Byte
    uint16_t crc;              // 2 Byte        
} calstruct;

// TEST read out [3][0] to [3][7] - > value of [3][4] corrosponts to test array[4] is correct

float   mem_valuefloat;
float   test_array[8];
float  test_value2;
offset = offsetof(calstruct, korr_A[3][0]);
for (int i = 0; i < 8; i++) {
       myMem.get((LOCATION_CAL_LIPO + offset + i*(sizeof(float))), mem_valuefloat);  
      test array[i] =  mem_valuefloat;  
}
test_value2 = korr_A[3][4];    -> corrupt data "-inf"
1 Like

What does Serial.print(sizeof(calstruct)); print?

depends on what you stored in it I assume.

Have you tried to read the whole struct and then read the korr_A values.

The array is filled with 1.0

Well, this message says the content is invalid representing a negative inifite value. It sounds to me like a corrupted data and/or bad storage, or a defective EEPROM, I don't know.
What happens if you comment out the entire "for()"?

Are you sure the data is written to the EEPROM?

Some EEPROMs are initialized with 0xFF for every byte, which could read as -inf.
(depending on platform)
So what platform are you using?

Can you provide a minimal sketch that shows the problem?
(the code snippet does not compile)

A quick test on UNO R3 & UNO R4 prints NAN, but ...

Show a complete sketch that demonstrates the problem.

struct size is: 272

I will prepare it asap (will be mostlikely tomorrow)
I'm using platformIO with XIAO SAMD21.

I do not have any issues with other data (single variables) read or write works perfect

Inf or -Inf requires the max exponent, and the significand must be zero. Otherwise it is NaN (which seems like a waste of bits. Looked it up: turns out there are both quiet and signaling NaNs, and they can contain a payload in the significand bits.)

Due to the biased exponent, that's just one or two bits off

value float as int
1.0 0x3f800000
Inf 0x7f800000
-Inf 0xff800000

You can print the float-as-int

Serial.println(*reinterpret_cast<int32_t*>(&mem_valuefloat), HEX);

How are you showing the value? Serial.print does not print the negative sign unless it's a valid number

size_t Print::printFloat(double number, int digits)
{
  if (digits < 0)
    digits = 2;

  size_t n = 0;

  if (isnan(number)) return print("nan");
  if (isinf(number)) return print("inf");
  if (number > 4294967040.0) return print ("ovf");  // constant determined empirically
  if (number <-4294967040.0) return print ("ovf");  // constant determined empirically

  // Handle negative numbers
  if (number < 0.0)
  {
     n += print('-');
     number = -number;
  }

Also the offset of korr_A[3][4] is 252, which means it ends just before offset 256. (Might be more of a lead if it started there.) What does setMemoryType do?

If I read back the whole struct always byte 255 is showing wrong 0xff. If I read out byte by byte the data is correct.

I think you could try and check the EEPROM content first byte per byte, to make sure you correctly stored the arrays or not (indicating another kind of problem). Write a small memory dump to serial and see if the value 1.0 is correctly stored (float32 should be 0x7F 0x00 0x00 0x00).
Something like this one, it's a code I wrote for another project where I had a "cfg" struct (so you need to adapt it to read from your EEPROM):

      for (int a = 0; a < sizeof(cfg); ++a) {
        byte b = EEPROM.read(a);
        if (b < 16) Serial.print("0");
        Serial.print(b, HEX);
        Serial.print(" ");
      }
      Serial.println();

Then post here the results.

So 255 at offset 255. Interesting. And as I mentioned, that does change it from 1.0 to -Inf, since the most significant byte (with the sign bit) is last.

How about larger payloads? 512, 1024, etc. And in the other direction, what if you read 128 or 64 at a time? (Depending on the available functions, may have to read it into a generic buffer and then memcpy it into the right place.) A byte at a time is of course simplest, and maybe it's not too slow.

You have to decide whether you want to try and fix the problem, find a clean solution, or just do a workaround.


this is hexdump of calstruct directly after call
myMem.get(LOCATION_CAL_LIPO, calstruct);

as said read out eeprom byte wise I can not see these FF at position 255

I prefilled in the first array with 1.0 and in the second 2.2 - just if you wonder about the values

sorry 2.1

Easy enough (and educational) to understand float encodings: https://float.exposed/0x40066666

If you right-click and Go to Definition on that get call, is it meaningfully different than what I have handy for R4:

    template< typename T > T &get( int idx, T &t ){
        EEPtr e = idx;
        uint8_t *ptr = (uint8_t*) &t;
        for( int count = sizeof(T) ; count ; --count, ++e )  *ptr++ = *e;
        return t;
    }

which reads one byte at a time anyway?

The 1.0 value (I must correct my previous statement) as float32 (IEE-754) is the 4-bytes sequence:

3f 80 00 00

After the first 12 bytes, I see float values 1.0 are stored as "00 00 80 3F" so it looks ok to me because it's a Big Endian encoding. Are you sure you (or the library..) are using the same when writing and reading?

Dealing with the standard EEPROM library, I can write and read back a structure with a single instruction using EEPROM.put(0, cfg); and EEPROM.get(0, cfg);. I wonder why you can't do the same with Sparkfun EEPROM functions, loading the whole struct in memory with myMem.get(LOCATION_SETTINGS, calstruct); and access its values, instead of reading single floats with a for() statement?

Current solution is to make two blocks < 256 Byte to prevent this behavior - I will follow up this topic later again