I2C NVRAM odd behavior

Status
Not open for further replies.

EK701

Well-known member
OK, now that (I think) I fixed my I2C issues, I'm seeing odd behavior read/writing data to the NVRAM (Adesto RM24EP32). If I write values of zero to the NVRAM a subsequent read returns zeros. But, if I write non-zero numbers to the NVRAM, it returns either 0, 4294967295.////// or -4294967295.////// I'm sure I'm missing something simple.

Any help is appreciated!

Code:
#include <i2c_t3.h>
//#include <Wire.h>

#define DEBUGNVRAM

const int dblVal = 64;
const int floatVal = 32;
//const int intVal = 32;
//const int shortVal = 16;
//const int byteVal = 8;

const int NVRAM_I2C_ADDR = 0x53;               // NVRAM address on the I2C bus
const int NVRAM_ADDR = 0;                      // NVRAM register start address 
const int TRIPA_ADDR = NVRAM_ADDR;             // Tripmeter A - float
const int TRIPB_ADDR = TRIPA_ADDR + floatVal;  // Tripmeter B - float
const int LAT_ADDR = TRIPB_ADDR + floatVal;    // Latitude - double
const int LON_ADDR = LAT_ADDR + dblVal;        // Longitude - double

float f_TripA, f_TripB;
double longitude, latitude;

void setup() {
  Serial.begin(115200);
  delay(4000);

#ifdef DEBUGNVRAM
  Serial.println(F("Start I2C"));
#endif
  // Start the I2C 
  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_400);
//  Wire.begin();

  Serial.println(F("\nEnd of setup()\n"));
}

void loop() {
  writeNVRAM(0.0,0.0,0.0,0.0);
  readNVRAM();
  writeNVRAM(999.9,8888.8,45.123456,-121.654321);
  readNVRAM();
  writeNVRAM(1111.1,22.2,-15.111111,85.222222);
  readNVRAM();
  Serial.println(F("\n\n"));
  delay(5000);
}

void readNVRAM() {
#ifdef DEBUGNVRAM
  Serial.println(F("Reading NVRAM values"));
#endif
  f_TripA = NVRAM_ReadFloat(TRIPA_ADDR); // Read the stored Tripmeter A value so we can display it
  f_TripB = NVRAM_ReadFloat(TRIPB_ADDR); // Read the stored Tripmeter B value so we can display it
  latitude = NVRAM_ReadDouble(LAT_ADDR);  // Read the stored Latitude value so we can display it
  longitude = NVRAM_ReadDouble(LON_ADDR); // Read the stored Longitude value so we can display it
  Serial.print(F("TripA: "));
  Serial.println(f_TripA,2);
  Serial.print(F("TripB: "));
  Serial.println(f_TripB,2);
  Serial.print(F("Lat: "));
  Serial.println(latitude,6);
  Serial.print(F("Lon: "));
  Serial.println(longitude,6);
  Serial.println(F("----------------------"));
}

void writeNVRAM(float tempTripA,float tempTripB,double tempLat,double tempLon) {
#ifdef DEBUGNVRAM
  Serial.println(F("Writing new NVRAM values"));
#endif
  Serial.print(F("tempTripA: "));
  Serial.println(tempTripA,2);
  Serial.print(F("tempTripB: "));
  Serial.println(tempTripB,2);
  Serial.print(F("tempLat: "));
  Serial.println(tempLat,6);
  Serial.print(F("tempLon: "));
  Serial.println(tempLon,6);
  NVRAM_WriteFloat(TRIPA_ADDR, tempTripA);
  NVRAM_WriteFloat(TRIPB_ADDR, tempTripB);
  NVRAM_WriteDouble(LAT_ADDR, tempLat);
  NVRAM_WriteDouble(LON_ADDR, tempLon);
  Serial.println(F("----------------------"));
}

// Reads a 4-byte float value from the NVRAM RAM registers
float NVRAM_ReadFloat(int valAddr) {
  float value;
  byte *byteArray = (byte *) &value;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read 4 bytes 
  Wire.requestFrom(NVRAM_I2C_ADDR, 4);
  byteArray[3] = Wire.read();
  byteArray[2] = Wire.read();
  byteArray[1] = Wire.read();
  byteArray[0] = Wire.read();

  return value;
}

// Writes a 4-byte float value to the NVRAM RAM registers
void NVRAM_WriteFloat(int valAddr, float value) {
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write 4 bytes
  byte  *byteArray;
  byteArray = (byte *) &value;
  Wire.write(byteArray[3]);
  Wire.write(byteArray[2]);
  Wire.write(byteArray[1]);
  Wire.write(byteArray[0]);

  Wire.endTransmission();
}

// Reads a 8-byte double value from the NVRAM RAM registers
float NVRAM_ReadDouble(int valAddr) {
  double value;
  byte *byteArray = (byte *) &value;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read 8 bytes 
  Wire.requestFrom(NVRAM_I2C_ADDR, 8);
  byteArray[7] = Wire.read();
  byteArray[6] = Wire.read();
  byteArray[5] = Wire.read();
  byteArray[4] = Wire.read();
  byteArray[3] = Wire.read();
  byteArray[2] = Wire.read();
  byteArray[1] = Wire.read();
  byteArray[0] = Wire.read();

  return value;
}

// Writes a 8-byte double value to the NVRAM RAM registers
void NVRAM_WriteDouble(int valAddr, double value) {
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write 8 bytes
  byte  *byteArray;
  byteArray = (byte *) &value;
  Wire.write(byteArray[7]);
  Wire.write(byteArray[6]);
  Wire.write(byteArray[5]);
  Wire.write(byteArray[4]);
  Wire.write(byteArray[3]);
  Wire.write(byteArray[2]);
  Wire.write(byteArray[1]);
  Wire.write(byteArray[0]);

  Wire.endTransmission();
}

And here's the result:

Code:
Start I2C

End of setup()

Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: -4294967295.//////
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: 4294967295.//////
----------------------



Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: -4294967295.//////
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: 4294967295.//////
----------------------


Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: -4294967295.//////
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: 4294967295.//////
----------------------

And repeat...
 
OK, now that (I think) I fixed my I2C issues, I'm seeing odd behavior read/writing data to the NVRAM (Adesto RM24EP32). If I write values of zero to the NVRAM a subsequent read returns zeros. But, if I write non-zero numbers to the NVRAM, it returns either 0, 4294967295.////// or -4294967295.////// I'm sure I'm missing something simple.

Code:
// Reads a 4-byte float value from the NVRAM RAM registers
float NVRAM_ReadFloat(int valAddr) {
  float value;
  byte *byteArray = (byte *) &value;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read 4 bytes 
  Wire.requestFrom(NVRAM_I2C_ADDR, 4);
  byteArray[3] = Wire.read();
  byteArray[2] = Wire.read();
  byteArray[1] = Wire.read();
  byteArray[0] = Wire.read();

  return value;
}

// Writes a 4-byte float value to the NVRAM RAM registers
void NVRAM_WriteFloat(int valAddr, float value) {
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write 4 bytes
  byte  *byteArray;
  byteArray = (byte *) &value;
  Wire.write(byteArray[3]);
  Wire.write(byteArray[2]);
  Wire.write(byteArray[1]);
  Wire.write(byteArray[0]);

  Wire.endTransmission();
}
You really, really, really, really do not want to write code like this. You are not guaranteed that the compiler won't move things around. If you write code that must pick apart a data type by bytes, use a union type. That will tell the compiler that the two types overlap storage space. The ISO C standard says that you can only do aliasing like that if the types are the same (I believe the ISO C++ standard says something similar).

Here is the way I would write the read/write function. Note, your functions would order the bytes in a different fashion than I do. Since the NVRAM isn't shared with other processors, it doesn't matter (and if it were, you might need to deal with big vs. little endian). I used sizeof to protect against assumptions of how big float and double are (in AVR processors like the Arduino Uno/Leonardo or the Teensy 2.0, double is 4 bytes just like float):

Code:
// Reads a 4-byte float value from the NVRAM RAM registers
float NVRAM_ReadFloat(int valAddr) {
  union {
    float value;
    unsigned char bytes[sizeof (float)];
  } u;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read bytes for the float 
  Wire.requestFrom(NVRAM_I2C_ADDR, sizeof (float));
  for (size_t i = 0; i < sizeof (float); i++) {
    u.bytes[i] = Wire.read ();
  }

  return u.value;
}


// Writes a 4-byte float value to the NVRAM RAM registers
void NVRAM_WriteFloat(int valAddr, float value) {
  union {
    float value;
    unsigned char bytes[sizeof (float)];
  } u;

  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write Float
  u.value = value;
  for (size_t i = 0; i < sizeof (float); i++) {
    Wire.write (u.bytes[i]);
  }

  Wire.endTransmission();
}
 
You really, really, really, really do not want to write code like this.

Thank you! I'm pretty much a hack programmer, so I really appreciate the feedback.

I modified my code, using your example. However, I'm still getting essentially the same result. Again, any ideas are appreciated.

Code:
#include <i2c_t3.h>
//#include <Wire.h>

#define DEBUGNVRAM

const int doubleVal = sizeof(double);
const int floatVal = sizeof(float);
const int intVal = sizeof(int);
const int shortVal = sizeof(short);
const int byteVal = sizeof(byte);

const int NVRAM_I2C_ADDR = 0x53;               // NVRAM address on the I2C bus
const int NVRAM_ADDR = 0;                      // NVRAM register start address 
const int TRIPA_ADDR = NVRAM_ADDR;             // Tripmeter A - float
const int TRIPB_ADDR = TRIPA_ADDR + floatVal;  // Tripmeter B - float
const int LAT_ADDR = TRIPB_ADDR + floatVal;    // Latitude - double
const int LON_ADDR = LAT_ADDR + doubleVal;        // Longitude - double

float f_TripA, f_TripB;
double longitude, latitude;

void setup() {
  Serial.begin(115200);
  delay(4000);

#ifdef DEBUGNVRAM
  Serial.println(F("Start I2C"));
#endif
  // Start the I2C 
  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_400);
//  Wire.begin();

  Serial.println(F("\nEnd of setup()\n"));
}

void loop() {
  writeNVRAM(0.0,0.0,0.0,0.0);
  readNVRAM();
  writeNVRAM(999.9,8888.8,45.123456,-121.654321);
  readNVRAM();
  writeNVRAM(1111.1,22.2,-15.111111,85.222222);
  readNVRAM();
  Serial.println(F("\n\n"));
  delay(5000);
}

void readNVRAM() {
#ifdef DEBUGNVRAM
  Serial.println(F("Reading NVRAM values"));
#endif
  f_TripA = NVRAM_ReadFloat(TRIPA_ADDR); // Read the stored Tripmeter A value so we can display it
  f_TripB = NVRAM_ReadFloat(TRIPB_ADDR); // Read the stored Tripmeter B value so we can display it
  latitude = NVRAM_ReadDouble(LAT_ADDR);  // Read the stored Latitude value so we can display it
  longitude = NVRAM_ReadDouble(LON_ADDR); // Read the stored Longitude value so we can display it
  Serial.print(F("TripA: "));
  Serial.println(f_TripA,2);
  Serial.print(F("TripB: "));
  Serial.println(f_TripB,2);
  Serial.print(F("Lat: "));
  Serial.println(latitude,6);
  Serial.print(F("Lon: "));
  Serial.println(longitude,6);
  Serial.println(F("----------------------"));
}

void writeNVRAM(float tempTripA,float tempTripB,double tempLat,double tempLon) {
#ifdef DEBUGNVRAM
  Serial.println(F("Writing new NVRAM values"));
#endif
  Serial.print(F("tempTripA: "));
  Serial.println(tempTripA,2);
  Serial.print(F("tempTripB: "));
  Serial.println(tempTripB,2);
  Serial.print(F("tempLat: "));
  Serial.println(tempLat,6);
  Serial.print(F("tempLon: "));
  Serial.println(tempLon,6);
  NVRAM_WriteFloat(TRIPA_ADDR, tempTripA);
  NVRAM_WriteFloat(TRIPB_ADDR, tempTripB);
  NVRAM_WriteDouble(LAT_ADDR, tempLat);
  NVRAM_WriteDouble(LON_ADDR, tempLon);
  Serial.println(F("----------------------"));
}

// Reads a 4-byte float value from the NVRAM RAM registers
float NVRAM_ReadFloat(int valAddr) {
  union {
    float value;
    unsigned char bytes[floatVal];
  } u;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read bytes for the float 
  Wire.requestFrom(NVRAM_I2C_ADDR, floatVal);
  for (size_t i = 0; i < floatVal; i++) {
    u.bytes[i] = Wire.read ();
  }

  return u.value;
}

// Writes a 4-byte float value to the NVRAM RAM registers
void NVRAM_WriteFloat(int valAddr, float value) {
  union {
    float value;
    unsigned char bytes[floatVal];
  } u;

  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write Float
  u.value = value;
  for (size_t i = 0; i < floatVal; i++) {
    Wire.write (u.bytes[i]);
  }

  Wire.endTransmission();
}

// Reads a 8-byte double value from the NVRAM RAM registers
float NVRAM_ReadDouble(int valAddr) {
  union {
    float value;
    unsigned char bytes[doubleVal];
  } u;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read bytes for the float 
  Wire.requestFrom(NVRAM_I2C_ADDR, doubleVal);
  for (size_t i = 0; i < doubleVal; i++) {
    u.bytes[i] = Wire.read ();
  }

  return u.value;
}

// Writes a 8-byte double value to the NVRAM RAM registers
void NVRAM_WriteDouble(int valAddr, double value) {
  union {
    double value;
    unsigned char bytes[doubleVal];
  } u;

  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write Float
  u.value = value;
  for (size_t i = 0; i < doubleVal; i++) {
    Wire.write (u.bytes[i]);
  }

  Wire.endTransmission();
}

Result:

Code:
Start I2C

End of setup()

Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: -0.00
Lat: -0.000000
Lon: -0.000000
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: -4294967295.//////
----------------------



Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: -0.00
Lat: -0.000000
Lon: -0.000000
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: -4294967295.//////
----------------------



Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.000000
tempLon: 0.000000
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 999.90
tempTripB: 8888.80
tempLat: 45.123456
tempLon: -121.654321
----------------------
Reading NVRAM values
TripA: 0.00
TripB: -0.00
Lat: -0.000000
Lon: -0.000000
----------------------
Writing new NVRAM values
tempTripA: 1111.10
tempTripB: 22.20
tempLat: -15.111111
tempLon: 85.222222
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: -4294967295.//////
Lon: -4294967295.//////
----------------------
 
Are you observing the correct timing when writing? Writing one byte typically takes 50us (datasheet p.12), so writing 4 bytes will take about 200us during which time the device will not respond to further commands.

Pete
 
Looks like the timing is right. Here's the results from a speed test:

Going to test single byte writes and reads
Time taken for 1000 writes with one byte was: 44299 us
Write time per byte, in microseconds: 44
-------------------------
Time taken for 1000 reads with one byte was: 93049 us
Read time per byte, in microseconds: 93
-------------------------
Going to test readBlock
Using 1000 blocks of 4
Time taken for 1000 reads with blocks was: 132084 us
Read time per byte, in microseconds: 33
-------------------------
Going to test readBlock
Using 1000 blocks of 8
Time taken for 1000 reads with blocks was: 183547 us
Read time per byte, in microseconds: 22
-------------------------
Going to test readBlock
Using 1000 blocks of 16
Time taken for 1000 reads with blocks was: 286575 us
Read time per byte, in microseconds: 17
-------------------------
Going to test readBlock
Using 1000 blocks of 32
Time taken for 1000 reads with blocks was: 492472 us
Read time per byte, in microseconds: 15
-------------------------
Going to test readBlock
Using 1000 blocks of 64
Time taken for 1000 reads with blocks was: 904342 us
Read time per byte, in microseconds: 14
-------------------------
Going to test readBlock
Using 1000 blocks of 128
Time taken for 1000 reads with blocks was: 1728078 us
Read time per byte, in microseconds: 13
-------------------------
Going to test writeBlock
Using 1000 blocks of 4
Time taken for 1000 writes with blocks was: 190444 us
Write time per byte, in microseconds: 47
-------------------------
Going to test writeBlock
Using 1000 blocks of 8
Time taken for 1000 writes with blocks was: 383044 us
Write time per byte, in microseconds: 47
-------------------------
Going to test writeBlock
Using 1000 blocks of 16
Time taken for 1000 writes with blocks was: 767302 us
Write time per byte, in microseconds: 47
-------------------------
Going to test writeBlock
Using 1000 blocks of 32
Time taken for 1000 writes with blocks was: 1589673 us
Write time per byte, in microseconds: 49
 
OK, I finally had time to get back to this. I can write and read a single byte value without problem, but I'm still having problems with multi-byte values not writing and/or reading properly. Again, any ideas are appreciated!

Here's the current code:

Code:
//
//#include <i2c_t3.h>
//#ifdef I2C_DEBUG
//#include <rbuf.h>
//#endif
#include <Wire.h>

const unsigned int doubleVal = sizeof(double);
const unsigned int floatVal = sizeof(float);
const unsigned int intVal = sizeof(int);
const unsigned int shortVal = sizeof(short);
const unsigned int byteVal = sizeof(byte);

const int NVRAM_I2C_ADDR = 0x53;               // NVRAM address on the I2C bus
const unsigned int NVRAM_ADDR = 0;                      // NVRAM register start address 
const unsigned int TRIPA_ADDR = NVRAM_ADDR;             // Tripmeter A - float
const unsigned int TRIPB_ADDR = TRIPA_ADDR + floatVal;  // Tripmeter B - float
const unsigned int LAT_ADDR = TRIPB_ADDR + floatVal;    // Latitude - double
const unsigned int LON_ADDR = LAT_ADDR + doubleVal;        // Longitude - double
const unsigned int valA_ADDR = LON_ADDR + doubleVal + floatVal;  // add a float val buffer
const unsigned int valB_ADDR = valA_ADDR + floatVal;
const unsigned int valC_ADDR = valB_ADDR + floatVal;
const unsigned int valD_ADDR = valC_ADDR + floatVal;

float f_TripA, f_TripB;
double longitude, latitude;

void setup() {
  Serial.begin(115200);
  delay(4000);
  
  Serial.print(F("Size of double is: "));
  Serial.println(doubleVal);
  Serial.print(F("Size of float is: "));
  Serial.println(floatVal);
  Serial.print(F("Size of int is: "));
  Serial.println(intVal);
  Serial.print(F("Size of short is: "));
  Serial.println(shortVal);
  Serial.print(F("Size of byte is: "));
  Serial.println(byteVal);

  Serial.println(F("Start I2C"));
  // Start the I2C 
//  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_400);
  Wire.begin(0x53);
  
    // NVRAM setup
  Serial.println(F("Read NVRAM"));
  //  Read trip and location data from NVRAM storage to init vals
  readNVRAM();
  delay(3000);


  Serial.println(F("\nEnd of setup()\n"));
}

void loop() {

  bool error = true;
  Wire.beginTransmission(NVRAM_I2C_ADDR);       // slave addr
  error = Wire.endTransmission();               // no data, just addr

  writeNVRAMtemp(2,88,12,150);
  readNVRAMtemp();
  writeNVRAMtemp(201,77,181,5);
  readNVRAMtemp();
  writeNVRAMtemp(66,207,3,99);
  readNVRAMtemp();
  writeNVRAM(0,0,0,0);
  readNVRAM();
  writeNVRAM(10.00,40.98,-75.123456,150.654321);
  readNVRAM();
  writeNVRAM(99.12,222.00,11.111111,-6.666666);
  readNVRAM();
  Serial.println(F("\n\n"));
  delay(4000);
}

void readNVRAMtemp() {
  byte valA, valB, valC, valD;
  Serial.println(F("Reading NVRAM values"));
  valA = NVRAM_ReadByte(valA_ADDR); // Read the stored Tripmeter A value so we can display it
  valB = NVRAM_ReadByte(valB_ADDR); // Read the stored Tripmeter B value so we can display it
  valC = NVRAM_ReadByte(valC_ADDR);  // Read the stored Latitude value so we can display it
  valD = NVRAM_ReadByte(valD_ADDR); // Read the stored Longitude value so we can display it
  Serial.print(F("valA: "));
  Serial.println(valA);
  Serial.print(F("valB: "));
  Serial.println(valB);
  Serial.print(F("valC: "));
  Serial.println(valC);
  Serial.print(F("valD: "));
  Serial.println(valD);
  Serial.println(F("----------------------"));
}

void writeNVRAMtemp(byte tempA,byte tempB,byte tempC,byte tempD) {
  Serial.println(F("Writing new NVRAM values"));
  Serial.print(F("tempA: "));
  Serial.println(tempA);
  Serial.print(F("tempB: "));
  Serial.println(tempB);
  Serial.print(F("tempC: "));
  Serial.println(tempC);
  Serial.print(F("tempD: "));
  Serial.println(tempD);
  NVRAM_WriteByte(valA_ADDR, tempA);
  NVRAM_WriteByte(valB_ADDR, tempB);
  NVRAM_WriteByte(valC_ADDR, tempC);
  NVRAM_WriteByte(valD_ADDR, tempD);
  Serial.println(F("----------------------"));
}

void readNVRAM() {
  Serial.println(F("Reading NVRAM values"));
  f_TripA = NVRAM_ReadFloat(TRIPA_ADDR); // Read the stored Tripmeter A value so we can display it
  f_TripB = NVRAM_ReadFloat(TRIPB_ADDR); // Read the stored Tripmeter B value so we can display it
  latitude = NVRAM_ReadDouble(LAT_ADDR);  // Read the stored Latitude value so we can display it
  longitude = NVRAM_ReadDouble(LON_ADDR); // Read the stored Longitude value so we can display it
  Serial.print(F("TripA: "));
  Serial.println(f_TripA,2);
  Serial.print(F("TripB: "));
  Serial.println(f_TripB,2);
  Serial.print(F("Lat: "));
  Serial.println(latitude,6);
  Serial.print(F("Lon: "));
  Serial.println(longitude,6);
  Serial.println(F("----------------------"));
}

void writeNVRAM(float tempTripA,float tempTripB,double tempLat,double tempLon) {
  Serial.println(F("Writing new NVRAM values"));
  Serial.print(F("tempTripA: "));
  Serial.println(tempTripA);
  Serial.print(F("tempTripB: "));
  Serial.println(tempTripB);
  Serial.print(F("tempLat: "));
  Serial.println(tempLat);
  Serial.print(F("tempLon: "));
  Serial.println(tempLon);
  NVRAM_WriteFloat(TRIPA_ADDR, tempTripA);
  NVRAM_WriteFloat(TRIPB_ADDR, tempTripB);
  NVRAM_WriteDouble(LAT_ADDR, tempLat);
  NVRAM_WriteDouble(LON_ADDR, tempLon);
  Serial.println(F("----------------------"));
}


// Writes a 1-byte value to the NVRAM RAM registers
void NVRAM_WriteByte(int valAddr, byte value) {
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr >> 8);
  Wire.write(valAddr & 0xFF);
  Wire.write(value);
  Wire.endTransmission();
}

// Reads a 1-byte value from the NVRAM RAM registers
byte NVRAM_ReadByte(int valAddr) {
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr >> 8);
  Wire.write(valAddr & 0xFF);
  Wire.endTransmission();
  Wire.requestFrom(NVRAM_I2C_ADDR, 1);
  return Wire.read();
}

// Reads a float value from the NVRAM 
float NVRAM_ReadFloat(int valAddr) {
  union {
    float value;
    unsigned char bytes[floatVal];
  } u;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read bytes for the float 
  Wire.requestFrom(NVRAM_I2C_ADDR, floatVal);
  for (size_t i = 0; i < floatVal; i++) {
    u.bytes[i] = Wire.read ();
  }

  return u.value;
}

// Writes a float value to the NVRAM 
void NVRAM_WriteFloat(int valAddr, float value) {
  union {
    float value;
    unsigned char bytes[floatVal];
  } u;

  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write Float
  u.value = value;
  for (size_t i = 0; i < floatVal; i++) {
    Wire.write(u.bytes[i]);
  }
  Wire.endTransmission();
}

// Reads a double value from the NVRAM 
float NVRAM_ReadDouble(int valAddr) {
  union {
    double value;
    unsigned char bytes[doubleVal];
  } u;

  // Set the register pointer
  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);
  Wire.endTransmission();

  // Read bytes for the float 
  Wire.requestFrom(NVRAM_I2C_ADDR, doubleVal);
  for (size_t i = 0; i < doubleVal; i++) {
    u.bytes[i] = Wire.read ();
  }

  return u.value;
}

// Writes a double value to the NVRAM 
void NVRAM_WriteDouble(int valAddr, double value) {
  union {
    float value;
    unsigned char bytes[doubleVal];
  } u;

  Wire.beginTransmission(NVRAM_I2C_ADDR);
  Wire.write(valAddr);

  // Write double
  u.value = value;
  for (size_t i = 0; i < doubleVal; i++) {
    Wire.write(u.bytes[i]);
  }
  Wire.endTransmission();
}


And here's the output:

Code:
Size of double is: 8
Size of float is: 4
Size of int is: 4
Size of short is: 2
Size of byte is: 1
Start I2C
Read NVRAM
Reading NVRAM values
TripA: 4294967295.//
TripB: 4294967295.//
Lat: 0.000000
Lon: 0.000000
----------------------

End of setup()

Writing new NVRAM values
tempA: 2
tempB: 88
tempC: 12
tempD: 150
----------------------
Reading NVRAM values
valA: 2
valB: 88
valC: 12
valD: 150
----------------------
Writing new NVRAM values
tempA: 201
tempB: 77
tempC: 181
tempD: 5
----------------------
Reading NVRAM values
valA: 201
valB: 77
valC: 181
valD: 5
----------------------
Writing new NVRAM values
tempA: 66
tempB: 207
tempC: 3
tempD: 99
----------------------
Reading NVRAM values
valA: 66
valB: 207
valC: 3
valD: 99
----------------------
Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.00
tempLon: 0.00
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 10.00
tempTripB: 40.98
tempLat: -75.12
tempLon: 150.65
----------------------
Reading NVRAM values
TripA: -0.00
TripB: -0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 99.12
tempTripB: 222.00
tempLat: 11.11
tempLon: -6.67
----------------------
Reading NVRAM values
TripA: 4294967295.//
TripB: 4294967295.//
Lat: 4294967295.//////
Lon: 4294967295.//////
----------------------



Writing new NVRAM values
tempA: 2
tempB: 88
tempC: 12
tempD: 150
----------------------
Reading NVRAM values
valA: 2
valB: 88
valC: 12
valD: 150
----------------------
Writing new NVRAM values
tempA: 201
tempB: 77
tempC: 181
tempD: 5
----------------------
Reading NVRAM values
valA: 201
valB: 77
valC: 148
valD: 5
----------------------
Writing new NVRAM values
tempA: 66
tempB: 207
tempC: 3
tempD: 99
----------------------
Reading NVRAM values
valA: 66
valB: 207
valC: 3
valD: 99
----------------------
Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.00
tempLon: 0.00
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 10.00
tempTripB: 40.98
tempLat: -75.12
tempLon: 150.65
----------------------
Reading NVRAM values
TripA: -0.00
TripB: -0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 99.12
tempTripB: 222.00
tempLat: 11.11
tempLon: -6.67
----------------------
Reading NVRAM values
TripA: 4294967295.//
TripB: 4294967295.//
Lat: 4294967295.//////
Lon: 4294967295.//////
----------------------



Writing new NVRAM values
tempA: 2
tempB: 88
tempC: 12
tempD: 150
----------------------
Reading NVRAM values
valA: 2
valB: 88
valC: 12
valD: 150
----------------------
Writing new NVRAM values
tempA: 201
tempB: 77
tempC: 181
tempD: 5
----------------------
Reading NVRAM values
valA: 201
valB: 77
valC: 181
valD: 5
----------------------
Writing new NVRAM values
tempA: 66
tempB: 207
tempC: 3
tempD: 99
----------------------
Reading NVRAM values
valA: 66
valB: 207
valC: 3
valD: 99
----------------------
Writing new NVRAM values
tempTripA: 0.00
tempTripB: 0.00
tempLat: 0.00
tempLon: 0.00
----------------------
Reading NVRAM values
TripA: 0.00
TripB: 0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 10.00
tempTripB: 40.98
tempLat: -75.12
tempLon: 150.65
----------------------
Reading NVRAM values
TripA: -0.00
TripB: -0.00
Lat: 0.000000
Lon: 0.000000
----------------------
Writing new NVRAM values
tempTripA: 99.12
tempTripB: 222.00
tempLat: 11.11
tempLon: -6.67
----------------------
Reading NVRAM values
TripA: 4294967295.//
TripB: 4294967295.//
Lat: 4294967295.//////
Lon: 4294967295.//////
----------------------
 
I think you have completely missed my point about timing.
When you send, say, eight bytes to be written to the device, it stores them in a temporary buffer. It isn't until you execute the Wire.endTransmission() function that the data are actually written to the NVRAM and during the time that it takes to write those bytes the device will not respond to another command. When writing eight bytes, the device will ignore you for about 400 microseconds. You must implement a way of handling that - whether you just add a delayMicroseconds() or you poll the device until it responds is up to you. See pages 7 and 8 of the datasheet.

Pete
 
Pete, thank you for the pointers. I'll try hacking with a delayMicroseconds() first to see if that solves the problem and if it does, then go for a solution that waits for the NVRAM to to acknowledge the write being complete. I should probably look at page writes as well.
 
Last edited:
Ok, so adding a delayMicroseconds() didn't help. Time to dig into it deeper...
 
Last edited:
Had some more time to dig into this. Of course, it turned out to be something simple - I got "bit" by the bit vs byte size difference. I thought I was giving the NVRAM addresses in bytes, but I was actually specifying the address in bits. This caused the data addresses to overlap which in turn corrupted the data. Once I resolved that, everything worked great. The Adesto NVRAM chips are inexpensive (<$1/ea) and will run at 1000MHz I2C.
 
Maybe you could post your corrected code so the next person using these NVRAM can benefit from what you learned?
 
The only correction was to use proper address spacing. For a byte, I used a spacing of 8 bits, a float 64 bits, and a double 128 bits.

Code:
const unsigned int doubleVal = (sizeof(double) * 8);
const unsigned int floatVal = (sizeof(float) * 8);
const unsigned int intVal = (sizeof(int) * 8);
const unsigned int shortVal = (sizeof(short) * 8);
const unsigned int byteVal = (sizeof(byte) * 8);

const int NVRAM_I2C_ADDR = 0x53;               // NVRAM address on the I2C bus
const unsigned int NVRAM_ADDR = 0;                      // NVRAM register start address 
const unsigned int TRIPA_ADDR = NVRAM_ADDR;             // Tripmeter A - float
const unsigned int TRIPB_ADDR = TRIPA_ADDR + floatVal;  // Tripmeter B - float
const unsigned int LAT_ADDR = TRIPB_ADDR + floatVal;    // Latitude - double
const unsigned int LON_ADDR = LAT_ADDR + doubleVal;        // Longitude - double
const unsigned int valA_ADDR = LON_ADDR + doubleVal; 
const unsigned int valB_ADDR = valA_ADDR + floatVal;
const unsigned int valC_ADDR = valB_ADDR + floatVal;
const unsigned int valD_ADDR = valC_ADDR + floatVal;
 
Last edited:
Status
Not open for further replies.
Back
Top