Writing Data to EEPROM Register Address

I think I have a 24LC256 around here somewhere but I can’t lay my hands on it to do a benchmark test to compare - I’m still searching (but if you saw my bench you’d understand that it’s non trivial :slight_smile: )

So can you please point out WHY you did that? Have you un-done it? From the Microchip datasheet for 24XX256 I can see 400khz maximum is fine for 2.5v to 5.5v, so going to 2v is out of spec. http://ww1.microchip.com/downloads/en/DeviceDoc/20001203U.pdf

edit: I see you have the FC part. That does nemtion having a 1.7v to 2.5v power for 400khz (max) so I assume that you can still power with 3.3v where the max is listed as 1000khz, and run it at 400khz which is below the maximum…

and can you confirm what you did with the WP pin? Tied to GND or VCC?

Unless you’ve changed the code from what you posted up above, there’s a whole heap of duplicated I2C Transaction Execute calls… worse, you’ve mashed reading in writing and all kinds of bad… hard to understand what you did or why. Where is the original source you referred to when you were creating this example code?

Here’s a snippet in my MAIN that I have successfully tested on an 24LC256.

Test harness device is a 24LC256 on a breadboard with a Fez Panda 3 running netmf 4.3.

Firmware (TinyCLR) version information:
4.3.8.1 on this computer.
4.3.8.1 on this device.

Wiring is A0, A1, A2, and WP all connected to GND. VCC connected to 3v3 on Panda. GND connected to GND on Panda. SDA to pin D2 on Panda. SCL to pin D3 on Panda. No pullups / pulldowns.

        // from MAIN
        EEPROM memory = new EEPROM(0x50, 400);
        int loopctr = 0;


        while (true)
        {
            /* 
            // omit - display status
            Thread.Sleep(500);
            lcd.ClearScreen();
            lcd.DrawString(x_pos, y_pos, "Starting Write " + loopctr.ToString(), 0xFF00, font);
            */
            memory.Write(loopctr, (byte)(loopctr));
            if (loopctr==10)
            {
                Debug.Print(memory.Read(1).ToString());
                Debug.Print(memory.Read(2).ToString());
                Debug.Print(memory.Read(3).ToString());
                Debug.Print(memory.Read(4).ToString());
                Debug.Print(memory.Read(5).ToString());
                Debug.Print(memory.Read(6).ToString());
                Debug.Print(memory.Read(7).ToString());
                Debug.Print(memory.Read(8).ToString());
                Debug.Print(memory.Read(9).ToString());
                Debug.Print(memory.Read(10).ToString());
                Thread.Sleep(Timeout.Infinite);
            }
            loopctr++;
        }

I have simplified the write and read code… proper error handling is a task for the reader :slight_smile:

public class EEPROM
{
private static I2CDevice.Configuration I2CConfig;
private static I2CDevice I2C;

/// <summary>
/// Initializes a new instance of the <see cref="EEPROM"/> class.
/// </summary>
public EEPROM(byte Address, int ClockRateKHz)
{
    I2CConfig = new I2CDevice.Configuration((ushort)(Address), ClockRateKHz);  // 400 KHz, A0-A2 shorted to ground (by design) = 0x50
    I2C = new I2CDevice(I2CConfig);
}

/// <summary>
/// Writes a one byte data at the specified address.
/// </summary>
/// <param name="Address">The address to write to.</param>
/// <param name="data">The byte to write</param>
public void Write(int Address, byte data)
{
    var xActions = new I2CDevice.I2CTransaction[1];
    xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address & 0xFF), data });
 
    if (I2C.Execute(xActions, 1000) == 0)
    {
        Debug.Print("Failed to perform I2C transaction");
    }
    
  
}

/// <summary>
/// Writes the string Text at the specified address.
/// </summary>
/// <param name="Address">The starting address to write to</param>
/// <param name="Text">The text to write to EEprom</param>
public void Write(int Address, string Text)
{
    var xActions = new I2CDevice.I2CTransaction[1];
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes("00" + Text);  // the "00" string reserves the room for the 2 bytes address that follows
    buffer[0] = (byte)(Address >> 8);
    buffer[1] = (byte)(Address & 0xFF);
    xActions[0] = I2CDevice.CreateWriteTransaction(buffer);
    if (I2C.Execute(xActions, 1000) == 0)
    {
        Debug.Print("Failed to perform I2C transaction");
    }

}
/// <summary>
/// Reads the specified address.
/// </summary>
/// <param name="Address">The address to be read</param>
/// <returns>One byte from the EEprom</returns>
public byte Read(int Address)
{
    var Data = new byte[1];
    var xActions = new I2CDevice.I2CTransaction[1];
    xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address & 0xFF) });

    if (I2C.Execute(xActions, 1000) == 0)
    {
        Debug.Print("Failed to perform I2C transaction");
    }
    else
    {
        xActions[0] = I2CDevice.CreateReadTransaction(Data);
        Thread.Sleep(5);   // Mandatory after each Write transaction !!!
        if (I2C.Execute(xActions, 1000) == 0)
        {
            Debug.Print("Failed to perform I2C transaction");
        }
        else
        {
            Debug.Print("Register value: " + Data[0].ToString());
            return Data[0];
        }
        
    }
    return 0;
}

}

Then, there’s the output to prove it works…

Creating Eeprom
Register value: 1
1
Register value: 2
2
Register value: 3
3
Register value: 4
4
Register value: 5
5
Register value: 6
6
Register value: 7
7
Register value: 8
8
Register value: 9
9
Register value: 10
10
The program ‘[11] Micro Framework application: Managed’ has exited with code 0 (0x0).

I have A0-A2 and WP tied to GND. Datasheet says to have a 2k ohm pullup on SDA for clock frequency of 400kHz. The code I posted has been heavily edited from a codeshare post in an attempt to get it working. I put a read inside of write just for testing purposes.

Thank you I will try out your way. Was also thinking of lowering clock speed.

Ah you are a lifesaver! You missed a few Thread.Sleep(5); after 2 or 3 executes - after I inserted that it started working but not before.

Got it working perfect now, can copy all 50+ Int32’s to the EEPROM and convert back after reading to my buffer (: now on to programming the FT232 and my GPIB circuit I made that replicates a GPIB to Serial converter

Thread.Sleep(5) is almost not relevant, depending on how your app behaves. In my use case, there were enough delays like the debug.print statements, that I would never need to include a wait like that.

Pullups are installed on Panda, which is why I don’t need to bother.

The code you have above is not efficient, given that your page lifetime is the main factor with the EEPROM life. I’d try to batch up 64 byte writes to address that

I have a pull up on SDA and it literally did not work until I added the delay so I would say it is definitely relevant to my case. No other changes were made to software or hardware to get it working. When this process occurs in my program, nothing else is happening so there are no other delays.

Can you elaborate on the 64 byte write part? I only need to write 51 integers one time then everything else will be recall them. So are you saying don’t write all 51 integers at once since thats 200 bytes?

1 Like

Sure, let me read the datasheet for you…

http://ww1.microchip.com/downloads/en/DeviceDoc/20001203U.pdf
Section 6.1, Byte Write. Boxed note. When doing a write of less than 64 bytes, the whole 64-byte page is refreshed, and that counts as a write cycle. Your part is warranted for a specific write cycle count (notionally 1mil in the Microchip part). If you write 64 bytes as 64 individual operations, that’s 64 writes - if you can do a single write of 64 bytes instead, that only counts as one write.

There’s another codeshare example https://old.ghielectronics.com/community/codeshare/entry/162 that implements more overloads and helps manage this - if you have very specific read and write patterns you should look to implement some of this and manage page life more effectively.

But if your write operation is once, and once only (set, and never re-set them) then it doesn’t really matter, since you’re only consuming 204 operations (4xbytes per INT, times 51). If that is per-restart of your app, then you need to think about it more :slight_smile: Create 4x 64-byte byte arrays and flush them at once

I am not sure how to modify this write method to accept a byte array because of the bit shifting that is occurring.

public void Write(int Address, byte data)
 {
var xActions = new I2CDevice.I2CTransaction[1];
xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address & 0xFF), data });

if (I2C.Execute(xActions, 1000) == 0)
{
    Debug.Print("Failed to perform I2C transaction");
}


}

read the datasheet. section 6.2.

The bit shifting is the START address in a page, and does not affect the byte array, your data. Create one transaction with the data array so the data will be transferred in one chunk.

I read the datasheet at least 5 times. The wording is quite confusing…like can you send 64 bytes of data or 63 bytes? Do address and control bytes not count to the page limit?

sorry dude, I’m calling bullshit - the wording can’t be clearer.


6.2 Page Write.
The write control byte, word address and the first data byte are transmitted to the 24XX256 in much the same
way as in a byte write. The exception is that instead of generating a Stop condition, the master transmits up to 63 additional bytes, which are temporarily stored in the on-chip page buffer, and will be written into memory once the master has transmitted a Stop condition. Upon receipt of each word, the six lower Address Pointer bits are internally incremented by one.

…“and the first data byte”… and “up to 63 additional bytes”.

Think of the sequence of data on the I2C bus itself in this way.

The Control byte tells the I2C bus and the receiving device what to do (R/W) and that you’re talking to it (I2C address)

The Address byte is an “instruction” byte for the I2C device, and just tells it where to start writing or reading data.

The data payload comes from the 4th byte on the I2C transaction (figure 6.1) or is allowed to run from “byte 0” to “byte 63” (figure 6.2). Also clearly 64 bytes.

No need to be a dick. I was not the only one confused by that part, someone with 40 years of hardware experience made the same wrong assumptions as I did.

1 Like

I am hardly being a dick :slight_smile: I am just saying that the doco is pretty damn clear so I call bullshit. I still even gave you a nice explanation as to why. Plus, I got you where you are. You’re welcome :slight_smile:

And seriously - I am not taking offence, even if I should. I dug out a sample chip, wired it up, wrote a test harness, rewrote the driver, all for someone I’ve never met in person who I wanted to help get a project done. I could have not done any or all of that. I chose to help. Remember, you’re the one coming here with a bucket full of problems looking for help, it might be worth a touch of deference when your next hurdle becomes known

2 Likes

I definitely appreciate the help, I am just saying you come off harsh on just about every post you help me on. I lost count of how many times you have told me to read the data sheet after I already had multiple times. Keep in mind I have never in my life programmed registers or microcontollers or any IC (before this project). What seems simple and clear to you is like ancient Sumerian to me. I have had many a professor tell me how easy this fluid mechanics or that thermodynamics problem is, just to have it kick my ass for days. My understanding is bullshit, yes. Not my questions/attempts to understand.

Thanks again though, got the page writes working…all 204 bytes in 4 writes.

1 Like

I’ll take this opportunity to point out the page boundary conditions - @hwalker_MIWV your scenario is perfect because you can control what you write at once, but for anyone else reading along after the fact, your page write MUST take into account the actual page boundary, you can only write 64 bytes if you’re starting from the start of a page boundary. Say you start at address 9, and need to write 70 bytes. You need to write (pagesize-9, 64-9, =55) bytes first, then the remaining bytes in the next page.

2 Likes

One thing to note is once you fill up a page, the address for reading keeps increasing past 64. But if you go over then restart back at address 0 and you rewrite over your data. Apparently that’s what “increment lower internal register,” means.