When 30 is an odd number???  

Page 1 / 2
  RSS

Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-06 9:01 am  

In this case for non-native English speakers "odd" means "strange"!

I turned my attention to I2C EEPROM modules that have been lying around in my drawer for a few months and started putting some test code together before adding these modules to my sensor project.

So I ran the following code snippet, to store 30 random numbers to the EEPROM and read back the stored values to the serial monitor:

// Include the I2C Wire Library
#include "Wire.h"

// EEPROM I2C Address
#define i2c_eeprom 0x50

byte mByte[0x1d]; //0x1d = 30

void setup() {

Serial.begin(9600);
Wire.begin();
randomSeed(analogRead(0));

}

void loop() {
  int address = 0;
  Wire.beginTransmission(i2c_eeprom);
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Serial.println("Values to be stored in EEPROM:");
  for(int i = 0; i < 0x1d; i++){
    int randomNumber = random(255);
    Wire.write(randomNumber);
    Serial.print(randomNumber);
    Serial.print(",");
  }
  Wire.endTransmission();
  
  Serial.println();

  delay(5);

  address = 0;
  
  Wire.beginTransmission (i2c_eeprom);
  // Set device to start read reg 0
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Wire.endTransmission ();  

  Wire.requestFrom(i2c_eeprom, 0x1d);

  int idx = 0;
  
  // read the bytes into an array
  while(Wire.available()) {
    
    mByte[idx] = Wire.read(); // read each byte from the register and store in the array
    idx++;
  }
  Serial.println("Values returned from EEPROM");
  for (int i = 0; i < 0x1d; i++){
    Serial.print(mByte[i]);
    Serial.print(",");
    }
  
  Serial.println();
  Serial.println("Done");
  while(1);
}


And this was the result:

Values to be stored in EEPROM:
41,100,62,107,159,92,215,26,56,9,225,154,70,22,60,82,9,93,65,135,240,33,183,240,124,72,178,184,221,
Values returned from EEPROM
41,100,62,107,159,92,215,26,56,9,225,154,70,22,60,82,9,93,65,135,240,33,183,240,124,72,178,184,221,
Done

But when I tried to increase the number of stored values to 32 with this code snippet:

// Include the I2C Wire Library
#include "Wire.h"

// EEPROM I2C Address
#define i2c_eeprom 0x50

byte mByte[0x20]; //0x20 = 32

void setup() {

Serial.begin(9600);
Wire.begin();
randomSeed(analogRead(0));

}

void loop() {
  int address = 0;
  Wire.beginTransmission(i2c_eeprom);
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Serial.println("Values to be stored in EEPROM:");
  for(int i = 0; i < 0x20; i++){
    int randomNumber = random(255);
    Wire.write(randomNumber);
    Serial.print(randomNumber);
    Serial.print(",");
  }
  Wire.endTransmission();
  
  Serial.println();

  delay(5);

  address = 0;
  
  Wire.beginTransmission (i2c_eeprom);
  // Set device to start read reg 0
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Wire.endTransmission ();  

  Wire.requestFrom(i2c_eeprom, 0x20);

  int idx = 0;
  
  // read the bytes into an array
  while(Wire.available()) {
    
    mByte[idx] = Wire.read(); // read each byte from the register and store in the array
    idx++;
  }
  Serial.println("Values returned from EEPROM");
  for (int i = 0; i < 0x20; i++){
    Serial.print(mByte[i]);
    Serial.print(",");
    }
  
  Serial.println();
  Serial.println("Done");
  while(1);
}


This was the result:

Values to be stored in EEPROM:
110,43,97,120,143,138,128,76,1,191,247,168,145,136,9,35,92,111,222,234,103,170,223,15,168,17,121,69,0,195,164,98,
Values returned from EEPROM
110,43,97,120,143,138,128,76,1,191,247,168,145,136,9,35,92,111,222,234,103,170,223,15,168,17,121,69,0,195,0,0,
Done

The last two values were not being stored in EEPROM.

I have browsed through the at24c256 datasheet and found no mention of this 30 byte storage limit.

Coming back to the thread title, I consider 30 as an odd number in a world of multiples of two, 32 would have made a lot more sense, I guess!!

SteveC - Topple Rudd Poltman


Quote
Topic Tags
frogandtoad
(@frogandtoad)
Reputable Member
Joined: 10 months ago
Posts: 384
2020-02-06 12:14 pm  

@pugwash

Posted by: @pugwash

byte mByte[0x1d]; //0x1d = 30

Umm..., 0x1D == 29 stored numbers, not 30...

Not sure about the rest without some careful study 🙂

 

 

 


ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-06 2:39 pm  

@frogandtoad

I meant "0x1e" = 30!

Have double checked the code and 0x1e returns the first 30 values stored in EEPROM, and so does 0x1f and 0x20.

I have searched the internet, but come up blank why there seems to be a 30 byte limit! 

SteveC - Topple Rudd Poltman


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-06 5:35 pm  

What is the value of idx when it escapes the While loop, at line 53? Has the "while(Wire.available())" actually read anything from those ram locations? Maybe the two zero values were defaulted in the array "mByte[]" when it was initialized. 

You description of the problem and what you've found to date makes me question the wire library. 

 

Just my two cents. 

--
Dale


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-06 9:37 pm  

I just dug up an LC version of your RAM chip (24LC256), and I'll try to duplicate your issue tonight. 

I've gone over the code and the data sheet and can not find anything obvious. Of course it will be quite obvious once we find it 🙂

--
Dale


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-07 3:19 am  

OK, I've duplicated the fault. Sorta. My first observation was that the last two bytes were fixed. However in my case, they were both 255.  Not 0, as you found. I then messed about with making sure the counter were counting properly, Which of course they were. I then made a few changes to your code.  See below. This allowed me to see what happened when I wrote smaller blocks, starting at different addresses. Long story short, when I wrote less than 32 bytes, but wrote on the last two bytes (bytes 31 and 32) the bytes were correctly updated. When I did a 32 byte write, the last two bytes remained as previously set. 

Example:

Starting address: 0
Block size: 32
Values to be stored in EEPROM:
3,212,80,81,61,234,105,237,50,72,144,21,191,17,36,170,54,30,166,106,5,143,86,76,176,147,204,247,84,87,177,56,
Values returned from EEPROM
3,212,80,81,61,234,105,237,50,72,144,21,191,17,36,170,54,30,166,106,5,143,86,76,176,147,204,247,84,87,255,255,
Done

Starting address: 2
Block size: 30
Values to be stored in EEPROM:189,213
212,250,14,157,29,118,78,119,44,36,129,54,141,111,240,74,84,188,104,210,139,9,187,141,62,56,72,239,189,213,
Values returned from EEPROM
212,250,14,157,29,118,78,119,44,36,129,54,141,111,240,74,84,188,104,210,139,9,187,141,62,56,72,239,189,213,
Done

Starting address: 0
Block size: 32
Values to be stored in EEPROM:
189,14,45,68,77,188,192,187,105,18,122,134,116,158,87,217,226,12,137,7,142,6,46,46,5,74,6,107,178,148,154,225,
Values returned from EEPROM
189,14,45,68,77,188,192,187,105,18,122,134,116,158,87,217,226,12,137,7,142,6,46,46,5,74,6,107,178,148,189,213,
Done

Starting address: 30
Block size: 2
Values to be stored in EEPROM:
3,212,
Values returned from EEPROM
3,212,
Done

Starting address: 0
Block size: 32
Values to be stored in EEPROM:
212,250,14,157,29,118,78,119,44,36,129,54,141,111,240,74,84,188,104,210,139,9,187,141,62,56,72,239,189,213,162,41,
Values returned from EEPROM
212,250,14,157,29,118,78,119,44,36,129,54,141,111,240,74,84,188,104,210,139,9,187,141,62,56,72,239,189,213,3,212,
Done

So there's the data, but I haven't found a reason behind it. 

// Include the I2C Wire Library
#include "Wire.h"

// EEPROM I2C Address
#define i2c_eeprom 0x50

#define SIZE 32
#define START_ADDRESS 0

byte mByte[SIZE];

void setup() {

Serial.begin(9600);2
Wire.begin();
randomSeed(analogRead(0));

}

void loop() {
Serial.print("Starting address: ");
Serial.println(START_ADDRESS);
Serial.print("Block size: ");
Serial.println(SIZE);
int address = START_ADDRESS;
Wire.beginTransmission(i2c_eeprom);
Wire.write((int)(address >> 8)); // MSB
Wire.write((int)(address & 0xFF)); // LSB
Serial.println("Values to be stored in EEPROM:");
for(int i = 0; i < SIZE; i++){
int randomNumber = random(255);
Wire.write(randomNumber);
Serial.print(randomNumber);
Serial.print(",");
}
Wire.endTransmission();

Serial.println();

delay(5);

address = START_ADDRESS;

Wire.beginTransmission (i2c_eeprom);
// Set device to start read reg 0
Wire.write((int)(address >> 8)); // MSB
Wire.write((int)(address & 0xFF)); // LSB
Wire.endTransmission ();

Wire.requestFrom(i2c_eeprom, SIZE);

int idx = 0;

// read the bytes into an array
while(Wire.available()) {

mByte[idx] = Wire.read(); // read each byte from the register and store in the array
idx++;
}

Serial.println("Values returned from EEPROM");
for (int i = 0; i < SIZE; i++){
Serial.print(mByte[i]);
Serial.print(",");
}

Serial.println();
Serial.println("Done");
while(1);
}

 

 

--
Dale


ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-07 8:31 am  

@dale

In your first test result block, the last two values of 255 each are because the EEPROM has never before been used, the factory settings for EEPROM are 255. Mine were already zero because I had set the first 120 bytes previously to zero, after previous experimentation with these chips.

In the last block, bytes 31 and 32 had not been overwritten during the while/write loop.

I think you would have to dig deep into the wire.h library and possibly other dependent libraries, to find out if they were responsible for this 30 byte write limit!

SteveC - Topple Rudd Poltman


ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-07 8:54 am  

@dale

What is also interesting is that according to the datasheet attached, it is possible to write 64-byte data blocks to the registers. In the datasheet, they are called "pages".

I am sure that wire.h does not support this method. After looking at the wire.h library, this library is not responsible for read or write actions, I think they are handled by TwoWire.h or stream.h.

It is now getting beyond me ? 

SteveC - Topple Rudd Poltman


ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-07 12:45 pm  

Another thing I have discovered is that if you try to write 30 bytes starting at address 60, only the first 4 bytes are written to registers 60, 61, 62 & 63.

Can you confirm this??

SteveC - Topple Rudd Poltman


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-07 1:08 pm  

I can try to reproduce a little later. However, that is probably correct operation, as the memory is organized in 64 byte blocks. 

--
Dale


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-08 2:09 am  

Problem identified. Solution to follow? I found this tonight...

http://www.hobbytronics.co.uk/eeprom-page-write

This page Identifies the Oddity of "30" as being an issue with the Wire library.  It claims that the buffer in the library is only 32 bytes long, and then when doing a "page write," two of those buffer bytes hold the address data. Hence,  only 30 bytes of data are able to be sent. I've not confirmed it, but my money is on Wire sending a stop after the buffer is empty. I suppose hacking the Wire lib would be the best way to fix it, but that is out of my pay grade. As is writing a compliant I2C driver. Easiest solution may be to have a subroutine that repackages byte blocks longer than 30 bytes and sends Wire the smaller, compliant chunks. 

@pugwash As to your last post...

if you try to write 30 bytes starting at address 60, only the first 4 bytes are written to registers 60, 61, 62 & 63.

The article go on to discuss the issue of writing past page boarders.

 

Hope this helps. 

 

PS: maybe the "chunker" routine could also manage data across these boundries.

This post was modified 2 months ago by NewburyPi

--
Dale


Pugwash liked
ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-08 11:27 am  

@dale

Problem identified. Solution to follow? I found this tonight...

http://www.hobbytronics.co.uk/eeprom-page-write

Read it, and it does explain some of the odd things that were happening when using the write() function.

As I mentioned above, I don't think that altering the Wire.h library will have any effect. I believe that the write() function is in one of the underlying libraries invoked by Wire.h, probably stream.h.

These are the functions of the Wire.h library listed in the KEYWORDS file.

begin
setClock
beginTransmission
endTransmission
requestFrom
onReceive
onRequest

If I knew where the Arduino IDE is hiding the stream.h library, I may be able to confirm it!

SteveC - Topple Rudd Poltman


ReplyQuote
Pugwash
(@pugwash)
Prominent Member
Joined: 10 months ago
Posts: 970
2020-02-08 3:34 pm  

I took the simplest example from the website:

// Include the I2C Wire Library
#include "Wire.h"

// EEPROM I2C Address
#define i2c_eeprom 0x50
#define READ_DATA 64
#define START_ADDRESS 0

byte mByte[READ_DATA];

void setup() {

Serial.begin(9600);
Wire.begin();
randomSeed(64);

}

void loop() {
  
  for(int i = 0; i < 64; i++){
    byte seed = random(255);
    writeEEPROM(i2c_eeprom, i, seed ); 
  }

  delay(5);

// display section****************************
  
  Wire.beginTransmission (i2c_eeprom);
  // Set device to start read reg 0
  Wire.write((int)(START_ADDRESS >> 8));   // MSB
  Wire.write((int)(START_ADDRESS & 0xFF)); // LSB
  Wire.endTransmission ();  

  Wire.requestFrom(i2c_eeprom, READ_DATA);

  int idx = 0;
  
  // read the bytes into an array
  while(Wire.available()) {
    
    mByte[idx] = Wire.read(); // read each byte from the register and store in the array
    idx++;
  }
  Serial.println("\nValues returned from EEPROM");
  Serial.println("Register , Value\n");
  
  for (int i = 0; i < READ_DATA; i++){
    Serial.print(i);
    Serial.print(" , ");
    Serial.println(mByte[i]);
    
    }
  
  Serial.println();
  Serial.println("Done");
  while(1);
}

//write one single byte of data

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
 
  delay(5);
}

And can't figure out why the above code only writes to 32 registers!

SteveC - Topple Rudd Poltman


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-08 4:50 pm  

@pugwash

Are you getting back all 32 bytes correctly now, or are you having the exact same response.  Just guessing now and will have to run this code later, but...   if all 32 bytes are correct you may be running into the Wire buffer problem again, except this time on the wire.read end.

You could try repeating the section between "// display section****" and the end of the for loop. The second time through set START_ADDRESS to 32. If the write is working properly you should see the remainder of the bytes in the second read part.

Off to do a VV run and some groceries.

--
Dale


ReplyQuote
NewburyPi
(@dale)
Trusted Member
Joined: 10 months ago
Posts: 88
2020-02-09 1:44 am  

@pugwash

Yep! looks like the 32 byte buffer strikes again. I changed the wire.right part to output incremental data. Then split the wire.read part to first read just the first 32 bytes, then repeat the read on the second 32 bytes. (code below)

Values returned from EEPROM
Register , Value

1 *** , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 *** 8
9 *** , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 *** 16
17 *** , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 *** 24
25 *** , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 *** 32

Values returned from EEPROM
Register , Value

33 *** , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 *** 40
41 *** , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 *** 48
49 *** , 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 *** 56
57 *** , 56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 *** 64

Done

 

// Include the I2C Wire Library
#include "Wire.h"

// EEPROM I2C Address
#define i2c_eeprom 0x50
#define READ_DATA 32
#define START_ADDRESS 0

byte mByte[READ_DATA];

void setup() {

Serial.begin(9600);
Wire.begin();
randomSeed(64);

}

void loop() {

for(int i = 0; i < 64; i++){
byte seed = random(255);
writeEEPROM(i2c_eeprom, i, i );
}

delay(5);

// display section****************************

Wire.beginTransmission (i2c_eeprom);
// Set device to start read reg 0
Wire.write((int)(START_ADDRESS >> 8)); // MSB
Wire.write((int)(START_ADDRESS & 0xFF)); // LSB
Wire.endTransmission ();

Wire.requestFrom(i2c_eeprom, READ_DATA);

int idx = 0;

// read the bytes into an array
// while(Wire.available()) {
for (int i = 0; i < READ_DATA; i++){
mByte[idx] = Wire.read(); // read each byte from the register and store in the array
idx++;
}
Serial.println("\nValues returned from EEPROM");
Serial.println("Register , Value\n");

for (int i = 0; i < READ_DATA; i++){
if ((i)%8 == 0) {
Serial.print(i+1+START_ADDRESS);
Serial.print(" *** ");
}
// Serial.print(i);
Serial.print(" , ");
Serial.print(mByte[i]);
if ((i+1)%8 == 0) {
Serial.print(" *** ");
Serial.println(i+1+START_ADDRESS);
}

}
// second display section****************************

Wire.beginTransmission (i2c_eeprom);
// Set device to start read reg 0
Wire.write((int)((START_ADDRESS+32) >> 8)); // MSB
Wire.write((int)((START_ADDRESS+32) & 0xFF)); // LSB
Wire.endTransmission ();

Wire.requestFrom(i2c_eeprom, READ_DATA);

idx = 0;

// read the bytes into an array
// while(Wire.available()) {
for (int i = 0; i < READ_DATA; i++){
mByte[idx] = Wire.read(); // read each byte from the register and store in the array
idx++;
}
Serial.println("\nValues returned from EEPROM");
Serial.println("Register , Value\n");

for (int i = 0; i < READ_DATA; i++){
if ((i)%8 == 0) {
Serial.print(i+1+START_ADDRESS+READ_DATA);
Serial.print(" *** ");
}
// Serial.print(i);
Serial.print(" , ");
Serial.print(mByte[i]);
if ((i+1)%8 == 0) {
Serial.print(" *** ");
Serial.println(i+1+START_ADDRESS+READ_DATA);
}
}
Serial.println();
Serial.println("Done");
while(1);
}

//write one single byte of data

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(data);
Wire.endTransmission();

delay(5);
}

 

--
Dale


ReplyQuote
Page 1 / 2

Please Login or Register