Writing to and reading from RAM via I2C

05 Sep 2012

Hi,

I'm having some problems writing to and reading from a RAM in an I2C device.

My code is as follows:

void RAMw() // I2C RAM write routine
{
    pc.printf("I2C: - write to RAM\r\n");
    char cmdw[3];
    cmdw[0] = 0x8f;         // Set cmd to HEX 8f to write to RAM address 0f
    cmdw[1] = 0x62;        // Set cmd[1] to HEX 62 (=98 dec) as second data byte for 0f
    cmdw[2] = 0x4a;         // Set cmd[2] to HEX 4a (=74 dec) as first data byte for 0f
    i2c.write(RAMaddw, cmdw, 3);      // addr + 2 byte cmd = f08f624a
    i2c.stop();
    wait(0.1);
}

void RAMr1() // I2C RAM read routine
{
    char cmdr[3];
    pc.printf("Read back from RAM\r\n");
    cmdr[0] = 0x1F;              // Set cmd to HEX 1F to read from RAM address 0f to SIF
    i2c.write(RAMaddr, cmdr, 3);      // addr + 1 byte cmd = f01F
    i2c.stop();
    wait(0.1);
    val = i2c.read(0x0f);           // read from SIF to I2C
    val2 = val;
    pc.printf("RAM address 0f: %04x hex, ",val2);
    pc.printf("dec = %d\r\n",val2);
    if (val == data){pass4 = true;};
}

When I look at the I2C with a scope, I see the write data is F08F - when I would expect to see F08F624A. I know the I2C address is correct otherwise I would not get an acknowledge back from the device. During the read stage I see F01F62 on the scope trace! But val in the above comes out as value of cmdw[1] x 2 (in this case c4 hex = 196 dec).

Are my write and/or read routines at fault? The device in question is a ZSC31050 sensor conditioner from ZMD.

I've looked through the forum post which have helped me get this far. Any pointers to help me make progress would be most useful. Thanks in advance.

Chris

05 Sep 2012

First you say your I2C address is correct since you see ACK on the scope, good. But it does not write all data apparently, however do you see ACKs after each data byte on the scope? The most logical reason it does not send everything is because it does not get an ACK back (which would be weird, if the address is correct).

Then you have several times i2c.stop() commands, that is not needed, the i2c.write/read commands will send a stop command in the end (unless you add ",true" at the end of the command, then it will transmit a restart instead).

In your read function you first write three bytes, however only one is initialized, the other two are randomly what used to be in that register address. The next read it is better to just use the 'normal' read command: i2c.read(RAMaddr, [pointer to wherever you want to store results], [number of bytes to read]); How you used the i2c read command isn't valid, and will for sure not give you what you will expect.

Hopefully that will get you further.

05 Sep 2012

Erik,

Thank you for your input. When sending the data in the format: address, command, databyte1, databyte2 it is the 'data byte 2' that I do not see on the scope. Instead I get:

start-address-ack-command-ack-databyte1-noack-stop

This may be a command issue so I'll keep experimenting.

I added the i2c.stop() commands after seeing them in another forum thread - they didn't appear to make any difference - thanks for the clarification.

The I2C device I'm using requires that I write to it first to get the content of the required RAM address into a Serial Interface (SIF), hence the write routine in the read section. I've tried the command structure as suggested - so far I just get 'ff' back for each byte I try to read. I'll keep trying and let you know.

Chris

05 Sep 2012

Hello,

Since you get a NACK back after the first databyte, my guess would be that indeed it is a command issue.

And most I2C devices require you to first write data to them before you can read (the correct data). That makes perfect sense, however the problem is that you define an array with length 3, you send those 3 bytes, but nowhere do you define the 2nd and 3rd byte of that array, only the first byte is initialized to a value. If you want to send only one byte with the write function, you have to change your last number to '1'. (And defining an array with length 3 wouldnt be needed).

If it is indeed 1 byte you have to write, and you want to read one byte, the code would be something like:

char cmdr = 0x1F;
char received;
i2c.write(RAMaddr, &cmdr, 1);      // addr + 1 byte cmd = f01F
i2c.read(RAMaddr, &received, 1);   
10 Sep 2012

Thanks,

The following write routine worked:

const int DEVadd = 0xf0;        // define the I2C Address

char cmdw[3];
cmdw[0] = 0x8f;                 // 8f is the command to write to RAM address 0f
cmdw[1] = 0x62;                 // first data byte
cmdw[2] = 0x4a;                 // second data byte
i2c.write(DEVadd, cmdw, 3);     // DEVadd (f0) + 3 byte command = f08f624a
wait(0.1);                      // delay for good measure to allow write

The scope displayed:

Start-f0-ack-8f-ack-62-ack-4a-ack-stop

However, if the I2C was subsequently exercised and left powered up the above didn’t work – which explained why it appeared not to work before.

The error in my previous read routine was the incorrect definition of the array of length 3. What worked was as follows:

    cmdr[0] = 0x1F;                 // cmd to HEX 1F to read RAM address 0f to SIF
    i2c.write(DEVadd, cmdr, 1);     // addr + 1 byte cmd = f01F
    wait(0.1);
    char RAMread[2];
    i2c.read(DEVadd, RAMread, 2);   // read 2 bytes from SIF to I2C

This first instructs the RAM data in address 0f to be read to the SIF, then the i2c.read enables the 2 bytes of data to be read from the SIF.

It seems very easy now, thanks again for your help, hopefully this will be of use to another reader.

09 Jul 2014

Hello Chris, After seeing some of your posts on mbed.org i realize that you used the signal conditioner ZSC31050 from ZDMI which i'm using in a course project. Currently i'm facing some problems with the I2C communication with the device. I Will try to explain my problems: - Each time i send the address to the device i'm not getting any acknowledgment. I have almost certain that the address is 0xF0 (8 bit). - In the document "ZSC31050_FunctionalDescription_Rev_1_11_2013-11-04.pdf" at page 17, are referred: "Note that the ZSC31050 also does not send acknowledges in non-configured mode if I²C communication is used." So my question is how can i configure the device for I2C communication using the same I2C? - Another question is regarding the first command that must be sent for the device. On the datasheet they refered the 0x72. Did you send this command on first too? I hope you can help me on this. Thanks in advance...

Best Regards Pedro