AT24C256 issue

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, I’m making a database type system… sort of, anyway, I’m using the first 128 bytes to keep track of addresses for each item (each gets 256 bytes of data with the rest of the space left over for other variables). So, I can easily write and read these two byte addresses starting at 0. Going up to 127. 
However, I can’t write anything passed 127. No matter what I do I can’t write passed 127. I’m doing it byte by byte by the way. I’ve tried everything. I just have a jumble of test code now but I know it works because I can write a byte to anything under 128 but anything passed that is a no go. It doesn’t make sense. Do I need to address a page or something? I can’t find anything online about this because it always brings me to “writing data array to page” well, I don’t want that, I just want to select an address past 127 and read and write to it. What am I missing? Any ideas? I can show you the code but it really is just basic and as I said if I use an address under 128 it works fine.

This topic has a solution.
Last Edited: Sun. Apr 10, 2022 - 04:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please, do post your code. It must be something with 1st and 2nd Word Address.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok but it’s going to be like all over because it’s a test project 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

//Modes
unsigned int Mode;
unsigned long lastMil;
int nDevices;

#define logoMode 0
#define titleMode 1
#define chipSelectMode 2

#define btnEnter PIN_PA7
#define romWrite PIN_PA1
#define romCLK PIN_PA3
#define romDATA PIN_PA2
#define ADDR_ROM 0x50
byte address;

U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ PIN_PB0, /* data=*/ PIN_PB1, /* cs=*/ PIN_PB2, /* dc=*/ PIN_PB3, /* reset=*/ PIN_PB4);  // Nokia 5110 Display (U8G2_R0, /* clock=*/ PIN_PA5, /* data=*/ PIN_PA6, /* cs=*/ PIN_PA3, /* dc=*/ PIN_PA4, /* reset=*/ PIN_PA2);  // Nokia 5110 Display

void u8g2_prepare(void) {
  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
}

void writePosText(int posX, int posY, String str)
{
  u8g2.setCursor(posX, posY);
  u8g2.print(str);
}


void writeI2CByte(byte i2cAddr, int dAddr, byte data)
{

  Wire.beginTransmission(i2cAddr);
  Wire.write((int)(dAddr >> 8)); // MSB
  Wire.write((int)(dAddr & 0xFF)); // LSB
  delay(5); 
  Wire.write(data);
  Wire.endTransmission();
  delay(1);
}

byte readI2CByte(byte i2cAddr, int dAddr){
  byte data = NULL;
  
  Wire.beginTransmission(i2cAddr); //writing the address to be read
  //Wire.write(dataAddr1);
  //Wire.write(dataAddr2);
  Wire.write((int)(dAddr >> 7)); // MSB
  Wire.write((int)(dAddr & 0xFF)); // LSB
  Wire.endTransmission();
  delay(10);
  Wire.requestFrom(i2cAddr, 1);
  while(Wire.available())
   {
    data = Wire.read();
   }
  Wire.endTransmission();
  return data;
}

void setup(void) 
{
  Wire.begin();
  Mode = logoMode;
  u8g2.begin();
  pinMode(btnEnter, OUTPUT);
  digitalWrite(btnEnter, HIGH);
  pinMode(romWrite, OUTPUT);
  digitalWrite(romWrite, LOW);
  lastMil = millis();
}

void WriteText(long BYTE_ADDR, String txt)
{
  int len = sizeof(txt);
  for(int i = 0; i < len; i++)
  {
    writeI2CByte(ADDR_ROM, BYTE_ADDR + i, txt.charAt(i));
    delay(10);
  }
}


void WriteLocationBytes()
{

int startLoc = 128;
int result;

  //goes up 255 bytes each time
  for(int i = 0; i < 128; i+=2){
     u8g2.clearBuffer();
     u8g2_prepare();
  
     writeI2CByte(ADDR_ROM, i, startLoc >> 8);
     delay(100);
     writeI2CByte(ADDR_ROM, i + 1, startLoc);
     delay(100);
   
    writePosText(0, 0, String(startLoc >> 8, HEX) + " & " + String(startLoc, HEX));

    u8g2.sendBuffer();
    startLoc += 255;
    delay(100);
  }

  u8g2.clearBuffer();
  u8g2_prepare();
  writePosText(0, 0, "DONE");
  u8g2.sendBuffer();
    //locations: first = 128 or 0x80, second = 128 + 255 = 383 or 0x17F, 3rd = 638 or 0x027E, etc. basically adding FF each time
}

void readLocationBytes()
{
 int result;
  for(int i = 0; i < 128; i+=2)
  {
  u8g2.clearBuffer();
  u8g2_prepare();
      result = 0;
      result |= ((int)readI2CByte(ADDR_ROM, i)) << 8;
      result |= ((int)readI2CByte(ADDR_ROM, i + 1));
    writePosText(0, 0, "Loc:" + String(i) + " = " + String((int)result));
    u8g2.sendBuffer();
    delay(100);
  }
  
u8g2.clearBuffer();
u8g2_prepare();
writePosText(0, 0, "DONE!");
u8g2.sendBuffer();

}

void getChipName(int chipNum)
{
  char tmp;
  int chipAddr;
  String tmpName;
  
  chipAddr = getChipAddr(chipNum);
  //for(int i = 0; i < 20; i++)
  //{
    tmp = readI2CByte(ADDR_ROM, 128);// + i);
    //tmpName += String(tmp, HEX);
    u8g2.clearBuffer();
  u8g2_prepare();
   writePosText(0, 0, String(tmp, HEX));
  u8g2.sendBuffer();
    delay(1000);
  //}
 
}

int getChipAddr(int chipNum)
{
  int result = 0;
  result |= ((int)readI2CByte(ADDR_ROM, chipNum)) << 8;
  result |= ((int)readI2CByte(ADDR_ROM, chipNum + 1));
  return result;
}

void ReadText(int len)
{
  char tmp;
  u8g2.clearBuffer();
  u8g2_prepare();
  for(int i = 0; i < len; i++)
  {
    tmp = readI2CByte(ADDR_ROM, i);
    u8g2.print(tmp);
  }
  
  u8g2.sendBuffer();
  delay(1000);
}

void writeChipName(int chipNum, String chipName)
{
  //always 20 characters
  //chip num = 0, 2, 4 , 6...etc to 126
  u8g2.clearBuffer();
  u8g2_prepare();
  
  int nameAddr;
  char tmpChar;
 
  nameAddr = getChipAddr(chipNum);
  writePosText(0,0, String(nameAddr));
  
  //for(int i = 0; i < chipName.length(); i++)
   //{
    //tmpChar = chipName.charAt(i);
      writeI2CByte(ADDR_ROM, 700, 0xAB);
     // delay(1000);
     //u8g2.clearBuffer();
     delay(50);
  //u8g2_prepare();
  byte tmp;
   tmp = readI2CByte(ADDR_ROM, 700);
   writePosText(0,10, String(tmp));
  u8g2.sendBuffer();
     delay(1000);
    
  // }
  
}

void deleteEeprom()
{
  for(int i = 0; i < 32000; i++)
  {
    u8g2.clearBuffer();
    u8g2_prepare();
    writeI2CByte(ADDR_ROM, i, 0x00);
    writePosText(0,0, String(i));
    delay(1);
    u8g2.sendBuffer();
  }
  u8g2.clearBuffer();
    writePosText(0,0, "Done!");
    delay(2);
    u8g2.sendBuffer();
}

void loop(void) 
{
  //start at byte zero for two byte chip info addresses, 0&1 == chip 1, 2&3 == chip 2, etc.
  
      digitalWrite(romWrite, LOW);
  
   if(digitalRead(btnEnter) == LOW)
         {
             //WriteLocationBytes();
             //readLocationBytes();
              //writeChipName(0, "4116 Ram");
           // getChipName(0);
            //deleteEeprom();
         }
  
  delay(100);
}

 

Some of it might be all over the place because I've taken some stuff out and added stuff to try different things and to debug using the LCD. Anyway, I've been messing with the read and writeChipName, but it doesn't matter. No matter what I do, I've made small real quick functions and no address over 127 will write.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why, it can be easy: adapt any 24C32 or 24C64 library to your device.

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DLXXV wrote:
Some of it might be all over the place

Agreed !

 

My suspicion lies here:

  Wire.write((int)(dAddr >> 7)); // MSB

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

N.Winterbottom wrote:

DLXXV wrote:
Some of it might be all over the place

Agreed !

 

My suspicion lies here:

  Wire.write((int)(dAddr >> 7)); // MSB

 

that section is only for putting the two byte address into an address that is below 128. It has nothing to do with the reason I can’t write to an address above 127. 
As I said, if I just do something simple like 

writeI2CByte(ADDR_ROM, 300, 0xAA); or any other variation of it it will read zero. However, if I were to use 0-127 it works fine. It’s only if I try to put it at an address higher than that that it doesn’t work.

 

edit:

that’s reason I’m confused. Why is the pertinent  code, writeI2CByte working with addresses from 0-127 and nothing above that? It’s weird 

Last Edited: Sat. Apr 9, 2022 - 04:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read the 24C256 datasheet.   It has 64-byte pages.  Each page-write takes a typical 3ms. 

The chip does not ACK its Slave address when it is busy doing a page-write.

 

So you can erase the 32768 bytes by writing 0xFF to each of the 64-byte pages.   i.e. typical 1.5 seconds for all 512 pages.

 

Likewise,  you can write multiple bytes as long as they don't cross a page boundary.

You can always read multiple bytes.   The chip looks after the page boundaries.

 

Reading and writing one byte at a time is very SLOW.

Erasing the whole chip one byte at a time will wear out the EEPROM.  e.g. 30 chip-erases will be 1 million page-writes.

 

David.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I figured it was something to do with page boundaries but I never saw anything about full page writes when accessing writing a single byte nor anything about pages when accessing single bytes from the datasheet. It’s specifically says you can’t cross page boundaries in a single write but it doesn’t say anything like that for single byte writing. It’s pretty short and vague on byte writing. Unless I missed something. 

 

I honestly was unaware that it was doing a full page write for every single byte entry and I’ll change the erase chip code to page write. Yes it’s slow but this isn’t really an end-user program, this is just to get the info onto the chip, the erase is just there for me to try some things. I’ve also intentionally made some things slow so that I can see it on the display. That still doesn’t explain why I can’t write to an address above 127.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read the docs for Wire.h

 

Especially read about write() variants.

 

And read carefully about what happens when you shift signed variables.   e.g. sign-extension.

 

But one of the most important things is learning how to write functions that return values.  And how to use the return value.

 

void functions were invented by the Devil.

 

Hint.  Life is generally easier when you use unsigned variables.

 

David.

Last Edited: Sat. Apr 9, 2022 - 04:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, everything you said is true and in my final code it would have all been cleaned up. This is just a rudimentary testing thing. To quickly get things working and tested before doing cleanup. That’s just how I work. It was why I was hesitant to post the code in the first place. I know it looks like dookie because my early code always does.  
And thank you, I will read the docs… and are you saying because I forgot to unsign my address variables that is the problem? I can definitely see that but how would that effect a low number address? Eh anyway, I’m going to change all my vars to unsigned, read the doc and do some more testing. I’ll get back to ya about the results. Thanks for the push to the hopefully right direction. 
-kelvin 

edit: aaaah the signing bit perhaps throws it off without it being unsigned. That sounds plausible 

Last Edited: Sat. Apr 9, 2022 - 05:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
// always return something.  addresses are always unsigned
int writeI2CByte(byte i2cAddr, uint16_t dAddr, byte data) 
{
  int ret;
  Wire.beginTransmission(i2cAddr);
  Wire.write((byte)(dAddr >> 8)); // MSB 
  Wire.write((byte)(dAddr & 0xFF)); // LSB
  //delay(5);                     // no point in delay here
  Wire.write(data);               // these write() calls only fill a buffer
  ret = Wire.endTransmission();   // this actually starts the I2C traffic
  delay(5);                       // typical 3ms but guaranteed 5ms page-write
  return ret;                     // report success, failure, problem, ...
}

The cast in the write() is not really necessary.   But it does ensure that you get the correct overloaded function.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup, I think I’m seeing it now. Thanks a lot. I’m not used to casting signed and unsigned in my normal programming life so doing so is an after thought to me and usually only comes up if I’m working in Swift or on an avr and even then only if I need to be aware of it. But yeah, I get it. Thanks a lot. I’ll reply later with the results. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DLXXV wrote:
in my final code it would have all been cleaned up.

 

It is always worth the extra tea-bag.   Design a universal function.   Write once, use many times.

 

Personally,  I would pass a buffer pointer and length as arguments.

Then you can write a single byte or multiple bytes.    The function can handle page boundaries.   Return the number of bytes written.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You’ve been a big help. Thank you. I WILL reply later with results.

-Kelvin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Double check any of your /funny/ Read and Write delays.

 

Write delay must be higher than a read one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Will do. Once I sit down to work I’ll be in the zone for a while and go over everything and take your suggestions into my rework

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is my ASM for a light reading.

Both subroutines sTWICDataRead and sTWICDataStore are 'universal', for one or multi bytes. Also, they have an option: to do it real (with true SCL/SDA) or using two simulated pins. Care on boundaries- do not cross 64B in a single write, or else- you will rewrite data.

 

sC32_Read:  ; in:  X= Read addr
            ;       XH= 255: Read addr position in XL
            ;       XH< 255: Read addr position in XHXL
            ;      w3= Number of data to read
            ; out: w3= Number of withhold data, or zero
            ;      vTWICData
    lds     w0, vQ24DevAddr   ; (24C32 Write addr)
    ldi     YL, low(vTWICData)
    ldi     YH, high(vTWICData)
    rcall   sTWICDataRead
    ret

 

sC32_Write: ; in:  X= Write addr
            ;       XH= 255: Write addr position in XL
            ;       XH< 255: Write addr position in XHXL
            ;      w3= Number of data to write
            ; out: w3= Number of withhold data, or zero
    ldi     YH, high(vTWICData)
    ldi     YL, low(vTWICData)
    lds     w0, vQ24DevAddr
    rcall   sTWICDataStore
    call    sQD5ms
    ret

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for that. Right now I’m using megacoreX on arduino because I am on Mac and it’s just easier. I bought a used windows laptop I am converting to an all in one desktop so I could program some CPLD and fpga and I put AVR Studio on it as well. I haven’t used AVR studio in a long time but I’m sure I’ll get back into the swing of it easy enough. I’ll look into your code once I get my rebuild done and back into ASM. Thanks. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mr. (or Ms.?) Winterbottom was correct. I didn't notice the 7 on my main read function. I thought he was talking about the other function. Thanks for all the help everyone. It's working now. I'm still going to refer back to this page and heed your advice. Thanks a ton for all your time.