Main Site Documentation

Problem with I2C EEprom


#1

Hello all !

I’m currently testing a 24LC256 EEprom (I2C device) and have a big problem : I can’t read or write to it :-[

In fact, I don’t know if I really write to it but can’t read or if the write has failed (so that the value I read is not the one expected).

Here’s the (little) I2C code that deals with it :

public class PandaEEprom
    {
        private static I2CDevice.Configuration EEpromConfig;
        private static I2CDevice.Configuration LCDConfig;
        private static I2CDevice I2C;

        public PandaEEprom(byte DeviceAddress, int ClockRate)
        {
            EEpromConfig = new I2CDevice.Configuration((ushort)(0x50 >> 1), 400);  // 400 KHz, A0-A2 shorted to ground = 0x50
            LCDConfig = new I2CDevice.Configuration((ushort)(0xC6 >> 1),91);   // Devantech LCD, for testing I2C
            I2C = new I2CDevice(EEpromConfig);
        }

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

        public void WriteLCD(byte data)
        {
            I2C.Config = LCDConfig;
            var xActions = new I2CDevice.I2CTransaction[1];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0, data });
            I2C.Execute(xActions, 1000);
        }

        public byte Read(byte Address)
        {
            I2C.Config = EEpromConfig;
            var Data = new byte[1];
            var xActions = new I2CDevice.I2CTransaction[2];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (byte)(Address >> 8), (byte)(Address & 0xFF) });
            xActions[1] = I2CDevice.CreateReadTransaction(Data);
            I2C.Execute(xActions, 1000);

            return Data[0];
        }
    }

Pretty simple, isn’t it ?

Now the code for testing :

static PandaEEprom MyEeeprom = new PandaEEprom(0x50,400);
        static OutputPort Led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED,false);

        public static void Main()
        {
            Led.Write(true);

            MyEeeprom.WriteLCD(19);   // Backlight ON. This works.
            //MyEeeprom.WriteLCD(20);   // Backlight OFF. This works.

            MyEeeprom.Write(1, 19);   // Does this work ?
            var MyVar = MyEeeprom.Read(1);   // MyVar is always 0 :-(

             Thread.Sleep(Timeout.Infinite);
        }

Of course, the WP pin is grounded :wink:

I know that I2C is working because the LCD is doing what I want. So, there’s something wrong elsewhere, but where ? :-[

Is it so obvious that I can’t see it ?

I’ve also had a look at Arduino code and it is almost the same. I thought at addresses bytes order and tried both (MSB/LSB and LSB/MSB), but to no avail.

I’m stuck. If anyone has an idea or any clue to solve this, he will have my eternal gratitude. :hand:


#2

I think the eeprom address is" 0xA0 >> 1" not " 0x50 >> 1" all the eeproms I have used are addressed like this , also ground A0,A1 and A3 on the device…

Also make sure its a 400kHz part as well.

Cheers Ian


#3

Well, I’ve also checked with address “0xA0”, but got the same results. Btw, if I understand the datasheet correctly, it should be 0x50 : 1010/A2/A1/A0 with A2=A1=A0=0 if grounded, which is the case. So I get 1010000=0x50.

I haven’t thought at this one :think: I will try to check. Do you know 24LC256 that don’t run at 400KHz ?
Here again, the datasheet says that the DIP8 package is 400KHz.


#4

Yes! 0xA0 >> 1 is equal to 0x50 but then you shift it again!

You can set it like this… ( 0xA0 >> 1 )
or like this …( 0x50 )

But not like this ( 0x50 >> 1 ) this has an extra shift!!

Cheers Ian

P.S. are we looking at the same thing here… Your driver is selecting address 0x24 by default even though your passing 0x50 in your main…

Also looking through code from others you might want to use this to identify which routine is failing

     
 if (I2C.Execute(xaction, 1000) == 0)      
     {  
     new Exception("I2C Transaction Failed "); 
     } 


#5

I understand what you say about extra-shifting, but… if I take the Devantech LCD03 device, its address (reported on screen when powered on) is 0xC6. I then shift this address when initializing the I2C stuff.

Do you mean that the 0x50 address (obtained by grounding the A0-A2 pins and the formula given in the datasheet) should be kept as-is, without shifting ? Or, in other words, that I should left-shift it before passing it to my routine (because it’s right-shifting its parameter), hence giving 0xA0 ?
This sounds consistent, since I don’t know if devices can have addresses as low as 0x50… :think:

Anyway, this doesn’t work either :wall:

I have tried with two different chips and got the same (bad) results. I will have to investigate this further.

I’ve also looked at different datasheets sources and all report a 400 KHz clock rate (for the DIP8 version, that is), so I think I’m safe by assuming it’s the right frequency.

What puzzle me here is that I can drive the LCD flawlessly, which is also I2C, and that I can’t use this fu*** bast** of eeprom :-[

Let’s pause, have a drink (or better : two or three), calm down and see later…

Thanks for your support :hand:


#6

I’ll be at work tomorrow and I will put one together and test it… I’ve had three drinks already. so its time for night night… I don’t know where you are in the world… but here in England it’s midnight…

Cheers Ian


#7

At first glance I don’t see any delay added after a write which is 5ms. When you have that read immediately after the write without a delay then it probably doesn’t have time to complete the write cycle. Even when it seems to work, without a delay the writing could be sporadic.


#8

[title]We have a winner !!![/title] :clap:

I’ve added a 5ms delay (max write cycle time) after each Write transaction and now it’s working. This was in the datasheet, though not clearly stated as mandatory delay. But I understand that there should be a delay, anyway.

Btw, the correct address is indeed 0xA0, which I also understand, but then it means that the Devantech LCD03 is reporting an already-left-shifted address whern it says “I2C mode at address 0xC6”.

Thanks to both of you :slight_smile:

It’s also showing that having one or more drinks and have a sleep after that does indeed help seeing things differently :-[


#9

Sorry I missed that as well… I thought with a transaction delay command of 1000 it was built in.

Savitch… Still impressing me… ( not that I want to start choosing curtains )

Glad its sorted and you have working code…

Cheers Ian


#10

I’ve overlooked that type of delay myself so it’s at the top of my checklist. It keeps running normally without error or timeout whether it writes or not which makes it easy to assume the problem is somewhere else.


#11

It was not that obvious, unless you’re already used to that :wink:

I’ve made some tests and it appears that the delay should be put after each byte is written.
If I send a sequence of bytes in the transaction, then nothing is written. If I split this sequence in single byte chuncks and add the 5ms delay between each write, then it’s ok.

So… 1 byte written = 5ms delay. A whiplash for each omission. :whistle:

Once you know what’s happening, everything becomes more clear.

About the 1000 timeout, it’s a timeout, not a delay :wink:


#12

It’s been added to Fezzer.com : http://www.fezzer.com/project/167/i2c-eeprom/

This code is part of a bigger code (that will also be published when done) that will drive my “PandaMotor board” that is discussed here : http://www.tinyclr.com/forum/7/1180/#/1/

I should receive the PCB this week, so I hope to have it working in the next week. Some short nights coming ???


#13

I want to see the board when you receive it. Probably in a video too :smiley:


#14

I’m now confident that at least the EEprom will work :-[ For the other parts, that’s another story… :whistle:

But of course, I will take some pictures “before”, “during” and “after” complete soldering and then make a small video showing the board working (as expected, if possible ??? ).

Then the driver(s) will be posted on Fezzer along with a demo program.


#15

Please let me know what is wrong here.
I think the read is wrong. Because we have to set the R/W bit of the EEPROM. How is that done

        public static void EEPROMTest()
        {
            Int32 ReplyLen = 0;

            byte[] I2C_Add = new byte[2];
            byte[] I2C_Data = new byte[1];

            I2C_Add[0] = 0x1;
            I2C_Add[1] = 0x2;

            I2C_Data[0] = 0xAA;

            ReplyLen = EEPROMWrite(I2C_Add, I2C_Data);

            if (ReplyLen == 0)
            {
                DispPrint("EEPROMWrite Error");
            }

            ReplyLen = EEPROMRead(I2C_Add, I2C_Data);

            if (ReplyLen == 0)
            {
                DispPrint("EEPROMRead Error");
            }
        }

        public static Int32 EEPROMWrite(byte[] I2C_Add, byte[] I2C_Data)
        {
            Int32 ReplyLen = 0;

            I2CPort.I2C_Port.Config = new I2CDevice.Configuration(I2CPort.I2C_EEPROM, 100);
            I2CDevice.I2CTransaction[] I2C_Transaction = new I2CDevice.I2CTransaction[1];

 #if MF_FRAMEWORK_VERSION_V4_1	
            I2C_Transaction[0] = I2CDevice.CreateWriteTransaction(I2C_Add);
 #else
            I2C_Transaction[0] = I2CPort.I2C_Port.CreateWriteTransaction(I2C_Add);
 #endif
            ReplyLen = I2CPort.I2C_Port.Execute(I2C_Transaction, 1000); //100ms time out

            Thread.Sleep(10);

            return ReplyLen;
        }

        public static Int32 EEPROMRead(byte[] I2C_Add, byte[] I2C_Data)
        {
            Int32 ReplyLen = 0;

            I2CPort.I2C_Port.Config = new I2CDevice.Configuration(I2CPort.I2C_EEPROM, 100);
            I2CDevice.I2CTransaction[] I2C_Transaction = new I2CDevice.I2CTransaction[2];

 #if MF_FRAMEWORK_VERSION_V4_1
            I2C_Transaction[0] = I2CDevice.CreateWriteTransaction(I2C_Cmd);
            I2C_Transaction[1] = I2CDevice.CreateReadTransaction(I2C_Read_Data);
 #else
            I2C_Transaction[0] = I2CPort.I2C_Port.CreateWriteTransaction(I2C_Add);
            I2C_Transaction[1] = I2CPort.I2C_Port.CreateReadTransaction(I2C_Data);
 #endif
            ReplyLen = I2CPort.I2C_Port.Execute(I2C_Transaction, 1000); //100ms time out

            return ReplyLen;
        }

#16

Should the read have
I2CPort.I2C_Port.Config = new I2CDevice.Configuration(I2CPort.I2C_EEPROM & 0x1, 100);


#17

http://wiki.tinyclr.com/index.php?title=I2C_-_EEPROM

The address that you set in the configuration is the actual 7-bit address. Whats your device, and whats the device’s 7-bit address?


#18

Hi,

Your write to the eeprom only writes the address, never any data…

This should contain data too:

I2C_Transaction[0] = I2CDevice.CreateWriteTransaction(I2C_Add);


#19

There is still something wrong. I get random bad data when I read it back. I looked on the scope and the wave form looks good.
I has the 24L16 powered by+5v, then I changed it to 3.3V. Still no luck

I write only 1 byte at a time. Then I read I read 4 or 16 bytes at a time.

        
        public const byte I2C_EEPROM = 0x50;

static void EEPROMWrite(byte[] I2C_Add, byte[] I2C_Data)
        {
            Int32 ReplyLen = 0;

            I2CPort.I2C_Port.Config = new I2CDevice.Configuration(I2CPort.I2C_EEPROM, 100);
            I2CDevice.I2CTransaction[] I2C_Transaction = new I2CDevice.I2CTransaction[1];

            byte[] I2C_Add_Data = new byte[I2C_Add.Length + I2C_Data.Length];

            Array.Copy(I2C_Add, I2C_Add_Data, I2C_Add.Length);
            Array.Copy(I2C_Data, 0, I2C_Add_Data, I2C_Add.Length, I2C_Data.Length);

 #if MF_FRAMEWORK_VERSION_V4_1	
            I2C_Transaction[0] = I2CPort.I2CDevice.CreateWriteTransaction(I2C_Add_Data);
 #else
            I2C_Transaction[0] = I2CPort.I2C_Port.CreateWriteTransaction(I2C_Add_Data);
 #endif
            ReplyLen = I2CPort.I2C_Port.Execute(I2C_Transaction, 1000); //100ms time out

            if (ReplyLen == 0)
            {
                DispPrint("EEPROMWrite Error");
            }

            Thread.Sleep(20);    //5 or 20 ms delay
        }

        static void EEPROMRead(byte[] I2C_Add, byte[] I2C_Data)
        {
            Int32 ReplyLen = 0;

            I2CPort.I2C_Port.Config = new I2CDevice.Configuration(I2CPort.I2C_EEPROM, 100);
            I2CDevice.I2CTransaction[] I2C_Transaction = new I2CDevice.I2CTransaction[2];

 #if MF_FRAMEWORK_VERSION_V4_1
            I2C_Transaction[0] = I2CPort.I2CDevice.CreateWriteTransaction(I2C_Cmd);
            I2C_Transaction[1] = I2CPort.I2CDevice.CreateReadTransaction(I2C_Read_Data);
 #else
            I2C_Transaction[0] = I2CPort.I2C_Port.CreateWriteTransaction(I2C_Add);
            I2C_Transaction[1] = I2CPort.I2C_Port.CreateReadTransaction(I2C_Data);
 #endif
            ReplyLen = I2CPort.I2C_Port.Execute(I2C_Transaction, 1000); //100ms time out

            if (ReplyLen == 0)
            {
                DispPrint("EEPROMRead Error");
            }
        }

#20

Should I use

EEPROMRead((new byte[] { (byte)(tID &0xFF ), (byte)(tID >> 8) }));

or

EEPROMRead((new byte[] { (byte)(tID >> 8 ), (byte)(tID & 0xFF) }));

Which is first MSB or LSB byte