BitMath - Converting Between Long and Bytes (Storing Data on EEPROM)

New question: Can someone help me figure out what I am doing wrong? I want to send a long to my external EEPROM. I store it as a string of bytes by using bitshift operators. Then I want to read these bytes back and reassemble them into a long. My math is not correct - I can reproduce 0 but the other values I generate are all over the place.

Specifically, here is a code snippet I was using to test my math. I take 4 values out of my 1D array of longs and put them into an array of 4 bytes using bit shift. I then try to undo what I did and print out the value.

 Serial.println("Data prepared!");
    for (i=0; i<4; i++){
      Time = TimeVector[i];
      
      Serial.println(Time); 
      
      Page[0] = (byte) Time;
      Page[1] = (byte) Time >> 8;
      Page[2] = (byte) Time >> 16;
      Page[3] = (byte) Time >> 24;
      
      Time = 0;
      Time = Time | Page[3];
      Time = Time << 8;
      Time = Time | Page[2];
      Time = Time << 8;
      Time = Time | Page[1];
      Time = Time << 8;
      Time = Time | Page[0];
      
      Serial.println("Reconstructed time: ");
      Serial.println(Time);
      Serial.println();

I am working with an Arduino DUE, which has two separate I2C buses. I’m using SCL1 and SDA1, both with external pull-up resistors.

I need to store a large amount of data on the EEPROM to be preserved between power cycles. I have an array of bytes whose total size is 4320 bytes and I have what I call a “vector” (not vector in C++ terms) that consists of a single dimensional array of 720 longs for a size 2880 bytes. The EEPROM is the typical 24LC256T and the functions I stole from the Arduino Playground tutorial on I2C EEPROM.

Previously, I posted here about problems with the amount of time it was taking to write to the EEPROM after doing nothing except removing a few Serial.print debugging statements. I’m still not sure what the problem was, but shortly there after the driver for the board disappeared and I couldn’t communicate. I rebooted my PC and re-installed the driver for the DUE and now everything is working like it should.

  #include <Wire.h> //I2C library
  
  byte dataArray[6][720];
  long TimeVector[720];
  int i = 0;
  int j = 0;
  int k = 0;
  int addr = 0;
  int address = 0;
  byte dataByte = 0;
  char timeStr[5];
  long Time = 0;
  byte Page[4];

  void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
    int rdata = data;
    Wire1.beginTransmission(deviceaddress);
    Wire1.write((int)(eeaddress >> 8)); // MSB
    Wire1.write((int)(eeaddress & 0xFF)); // LSB
    Wire1.write(rdata);
    Wire1.endTransmission();
  }

  // WARNING: address is a page address, 6-bit end will wrap around
  // also, data can be maximum of about 30 bytes, because the Wire1 library has a buffer of 32 bytes
  void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
    Wire1.beginTransmission(deviceaddress);
    Wire1.write((int)(eeaddresspage >> 8)); // MSB
    Wire1.write((int)(eeaddresspage & 0xFF)); // LSB
    byte c;
    for ( c = 0; c < length; c++)
      Wire1.write(data[c]);
    Wire1.endTransmission();
  }

  byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
    byte rdata = 0xFF;
    Wire1.beginTransmission(deviceaddress);
    Wire1.write((int)(eeaddress >> 8)); // MSB
    Wire1.write((int)(eeaddress & 0xFF)); // LSB
    Wire1.endTransmission();
    Wire1.requestFrom(deviceaddress,1);
    if (Wire1.available()) rdata = Wire1.read();
    return rdata;
  }

  // maybe let's not read more than 30 or 32 bytes at a time!
  void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
    Wire1.beginTransmission(deviceaddress);
    Wire1.write((int)(eeaddress >> 8)); // MSB
    Wire1.write((int)(eeaddress & 0xFF)); // LSB
    Wire1.endTransmission();
    Wire1.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ )
      if (Wire1.available()) buffer[c] = Wire1.read();
  }




  void setup() 
  {
    Wire1.begin(); // initialise the connection
    Serial.begin(9600);
    Serial.println("Preparing time data:");
    for (i=0; i<720; i++){
      TimeVector[i] = i*1000;
    }
    
    Serial.println("Data prepared!");
    for (i=0; i<4; i++){
      Time = TimeVector[i];
      
      Serial.println(Time); 
      
      Page[0] = (byte) Time;
      Page[1] = (byte) Time >> 8;
      Page[2] = (byte) Time >> 16;
      Page[3] = (byte) Time >> 24;
      
      Time = 0;
      Time = Time | Page[3];
      Time = Time << 8;
      Time = Time | Page[2];
      Time = Time << 8;
      Time = Time | Page[1];
      Time = Time << 8;
      Time = Time | Page[0];
      
      Serial.println("Reconstructed time: ");
      Serial.println(Time);
      Serial.println();
      
      address = 4*i;
      i2c_eeprom_write_page(0x50, address, Page, sizeof(Page)); // write to EEPROM 
      delay(4); //add a small delay
    }
    Serial.println("Memory written. Last address: ");
    Serial.print(address);
  }

  void loop() 
  {
    while (addr <= address)
    {
      Time = 0;
      for (i = 0; i < 4; ++i){
        dataByte = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
        Time = Time | dataByte;
        Time = Time << 8;
        addr++;
      }
      Serial.println(Time);
    }
    Serial.println(" ");
    delay(2000);

  }

Fixed it… this seems to work properly:

      Page[0] = Time;
      Page[1] = Time >> 8;
      Page[2] = Time >> 16;
      Page[3] = Time >> 24;
      
/*   DEBUGGING PRINT OUT
      Serial.println("Page bytes: ");
      for(j = 0; j < 4; ++j){
      Serial.println(Page[j], BIN);
      }
      Serial.println();
*/
      Time = 0;
      Time = Time | Page[3];
      Time = Time << 8;
      Time = Time | Page[2];
      Time = Time << 8;
      Time = Time | Page[1];
      Time = Time << 8;
      Time = Time | Page[0];

You -could- read the long directly from RAM as 4 bytes in a row using a byte pointer.

void setup() 
{
  Serial.begin(9600);

  long fourBytes = 0x12345678; // using hex instead of binary

  // note that:
  // as long as you put them back in the order you get the bytes
  // it doesn't matter what order you store them, but low to high
  // would make more sense as that is how the long is in RAM

  Serial.println( "Page bytes: " );
  // here printing the long in high byte to low byte order.
  byte *oneByte = ( byte * ) &fourBytes;  
  oneByte += 3; // points to the high byte first

  while ( oneByte >= ( byte * ) &fourBytes ) 
  {
    Serial.println( *( oneByte-- ), HEX ); 
  }
  Serial.println();
}

void loop() {
}

Definitely do the pointer thing. Also use sizeof(variable) if you want some flexibility.

Thanks, folks!