I2C - Problem communicating with IC

10 Aug 2012

I am new to Mbed and having a problem communicating with an I2C IC. The program is very basic and compiles ok. For a start I wanted to read from one of the registers back to the uC. I am monitoring with a scope on the sda line on the uC side of a level converter I built using the recommended mosfets. I see no activity whatsoever. I did make a mistake when assembling the project board I am working with. I forgot to cut all the tracks between the two rows of pins, before switching on. I corrected the mistake and tested again. It seems to be ok, but leaves me in doubt looking at the probelm I am having with the I2C comms. Further to that I made a direct connection between it and the IC operating at 5V. That is the sda and scl lines with the required pull up resistors. I could have created further problems for myself. I did however do some reading beforehand and came to the conclusion that the mbed is 5v tolerant after reading a blog or two. Now I am not sure.

If I can get some answers I can hopefully make some progress.

The device I am trying to communicate with has 5 registers containing 7 bytes each. My code below.

The device is hardwired for address 0x1 "The command register is offset from address0xE0" - straight from the spec sheet

Please help.

  1. include "mbed.h"

I2C i2c(p9, p10); sda, scl Serial pc(USBTX, USBRX); tx, rx

const int addr = 0x10; define the I2C Address

int main() { char cmd[1]; char reg0data[7]; while (1) { cmd[0] = 0xE0; i2c.start(); i2c.write(addr, cmd, 1); i2c.read(addr, reg0data, 7); i2c.stop();

wait (0.07);

print the data to the screen float reg0byte1 = reg0data[1]; pc.printf("Register 0 Byte 1 = %.2f\r\n", reg0byte1); wait(5); } }

10 Aug 2012

It is easier to read when code tags are used :)

Anyway mbed is indeed 5V tolerant, so using pull-up resistors to 5V should work fine. You still see no activity at all on SDA lines? Which level are they, they should idle be at 5V.

Then looking at your code

#include "mbed.h"

I2C i2c(p9, p10);        // sda, scl
Serial pc(USBTX, USBRX); // tx, rx

const int addr = 0x10; // define the I2C Address    

int main() 
{
    char cmd[1];
    char reg0data[7];
    while (1) 
    {
        cmd[0] = 0xE0;
        i2c.start();
        i2c.write(addr, cmd, 1);
        i2c.read(addr, reg0data, 7);
        i2c.stop();
        
        wait (0.07);

        // print the data to the screen
        float reg0byte1 = reg0data[1];
        pc.printf("Register 0  Byte 1 = %.2f\r\n", reg0byte1);
        wait(5);
    }
}

Which I2C device are you using? Is 0x10 the 7 or 8 bit address? Mbed uses 8bit address, which is the 7 bit address shifted one position left. The 8-bit address includes the R/W bit, the 7-bit address doesnt.

You dont have to manually to start and stop conditions on I2C, they are included in the read/write commands (I have no clue why they made those functions available in the first place), so just remove them. If you need to do a repeated start after writing the register address, use:

i2c.write(addr, cmd, 1, true);

Is the printf function executed? If yes, which value does it return?

Edit: it is also useful for debugging to assing the return value of i2c.write to a variable and send that to your PC. It should be zero.

11 Aug 2012

The device is a SM72445. It's an alternate energy IC which does Maximum Power Point Tracking on a solar system. You can find the spec sheet on Texas Instruments website.

As far as the address goes. It is hardwired via resistor settings. The IC has three address pin which means that up to 7 different addresses can be configured. Seeing as though there are three pins, I guess it has a 7 bit address. The range according to a table in the documentation is between 0x1 and 0x7. Must I add the R/W bit to it making it either 0x10 or 0x11, depending on whether I am writing to or reading from the device. You say the mbed works with 8 bit address. Will the IC understand? If the Sm72445 is 7 bit and mbed 8 bit, how do I get around this?

The printf function does execute. It returns a value, but established that it does not matter whether the SM 72445 in on or not, so not getting it via I2C.

The edit you speak of - i2c.writes return value. This I guess would indicate that the write was successful? Like I said, I am monitoring with a scope and there is no activity on either the sda or scl lines. As far as the voltage goes. It looks correct. 3.3v on mbed side of level shifter via 10k pull ups. And 5v on Sm72445 side, also via 10k pull ups.

I'll add the tags as you suggest. I know what you mean. It's difficult to try to figure out what someone else means without some insight.

Thanks for the reply

11 Aug 2012

I added tags and made some changes. Here it is.

  1. include "mbed.h"

I2C i2c(p9, p10); sda, scl Serial pc(USBTX, USBRX); tx, rx

const int addr = 0x11; define the I2C Address - 7 bit address plus 1 on right. This taken from sequence diagram provided. Always seems to be 1 whether R/W. Not sure though

int main() { char cmd[1]; command register char reg0data[7]; register to hold Register 0 - 7 bytes of info while (1) { cmd[0] = 0xE0; command register - 0xE0 is base address i2c.write(addr, cmd, 1); adrress the SM72445, send the reister address i2c.read(addr, reg0data, 7); read register contents from SM72445 into reg0data array

wait (0.07); default time suggested

print the data to the screen - register 0 byte1 just to test establishment of comms float reg0byte1 = reg0data[1]; first byte of register 0 pc.printf("Register 0 Byte 1 = %.2f\r\n", reg0byte1); wait(5); } }

11 Aug 2012

With tags I meant the code tags used by these forums: <<code>> and <</code>> (they need to be on a newline to work). It marks up the code such as in my previous post.

Few things:

Quote:

You say the mbed works with 8 bit address. Will the IC understand? If the Sm72445 is 7 bit and mbed 8 bit, how do I get around this?

The only thing you need to do is multiply the address by 2, the R/W bit is still set by the mbed. In this case the address itself isnt the 0x10 you entered, but 0x01. I have to admit that it is quite bad the datasheet calls it 0x1 instead of 0x01. This is the 7-bit address, so you need to enter 0x02 as address (mulitplied by 2, equivalent to shifting one to the left).

Edit: The difference is in bits:

7 bit address: A6 - A5 - A4 - A3 - A2 - A1 - A0

8 bit address: A6 - A5 - A4 - A3 - A2 - A1 - A0 - R/W bit

The R/W bit is in the end set/cleared by the mbed functions, but the address must be given including that location, so the normal address shifted one position to the left.

Quote:

The edit you speak of - i2c.writes return value. This I guess would indicate that the write was successful? Like I said, I am monitoring with a scope and there is no activity on either the sda or scl lines. As far as the voltage goes. It looks correct. 3.3v on mbed side of level shifter via 10k pull ups. And 5v on Sm72445 side, also via 10k pull ups.

Indeed it shows if it was succesfull, to be precise if you receive an ACK from the device.

But it is weird you dont see anything on a scope. Only two thinks I can think of atm, with one a bit unlikely. I dont know how good (/expensive) your scope is, but can it be you are missing the communication simply because it is too short? If you remove all wait statements and also the printf it should send alot more, so much smaller chance you could miss it (it will probably depend on your scope if you could miss it in the first place).

And because you never know, you are 100% sure you connected the correct pins?

11 Aug 2012

I did think of the fact that I could be missing the communication. Been playing around with different timebase settings with no luck. The scope I am using is a Tektronix THS730A. It's a 200Mhz unit. Should be good enough.

I am pretty sure I connected the pins correctly. Something strange. Seeing as I am in doubt of the condition of my uC. I tried moving over to pins 27 and 28. I also tried 2k2 pull ups, just to make a change. When I load the program, the test leds on the board flash. Not all at once. 1 & 4 then 2 & 3 alternating.

I will work on your suggestion above, regards addressing.

On a humorous note. You can see a newby, seeing as I don't even catch your "tags" suggestion.

I will try it in future.

Thanks

11 Aug 2012

Moving it to pin 27-28 is probably a good idea for testing. What you see (the leds blinking) is the error function being called, first guess would be that you got the pinnumbers for SDA/SCL mixed up.

But while trying the alternate port is a good idea, the LPC1768 can handle quite a bit of abuse. Once I connected -7V to both an input and an output pin, and the mbed survived that (apparently when they say something uses RS232 they also mean RS232 signal levels :P )

Btw you can also check with your scope what happens when you do connect pull-up resistors, but not the sensor unit. If you see communication then.

11 Aug 2012

Slave address should be 0x02. According to the datasheet, you have to read 8 bytes from a selected register. The first byte is a dummy length value of 0x07. That byte is followed by the 7 actual databytes. Something similar happens when writing data: start with a length byte, followed by the actual data. First make sure that the wiring is ok and that there is i2c communication visible on the pins.

11 Aug 2012

To expel doubt I wrote a short program test P9 and 10 as digitalouts. Now I can see it on the scope, but admit that the freq is way lower as I just used a wait command at 0.2 secs. Anyway, it seems the electronics are ok. I also checked the level converter I built (also when I was doubting the ability of the mbed - 5v tolerant?). It seems to be working fine.

I just started writing a reply and something told me to check one more time. It seems the digitalout test seems to have woken it up. I now see data and clock pulses on the scope. Eventually. And I didn't change anything in the code. I also changed back to P27 and 28 and error has gone.

Now I need to get the two talking.

I will work on the advice you have given so far.

Thanks a ton so far. I am sure I will have further questions though.

Cheers

11 Aug 2012

OK. Two and a half days later and it appears I have the two talking. Thank goodness.

Can you please enlighten me. If the command register is offset from base address 0xE0. Is this the first data byte in register 0? How will I address the rest (7 bytes of 8 data bits in each of the 5 registers 0,1,3,4,5). I incremented the 0xE0 to 0xE1 and the IC returned a different value. I haven't started to manipulate or format the data so it doesn't mean anything to me yet. Just the fact the when I switch off the IC then the value I am outputting to terminal changes to 0. When i switch back on it returns a different value. When I increment the command register it changes again. Looks positive.

Cheers

11 Aug 2012

That should indeed be the correct way to address it, you send the register address, 0xE0 for register 0, 0xE1 for register 1, etc, then receive 7 bytes. Because apparently everyone who makes an I2C IC needs to do it slightly different to keep the users on their toes. Really, who thought it was a good idea to make 56 bit registers?

11 Aug 2012

Hi Erik

Thanks for the reply. I managed to come right through trial and error. I am now trying to make one int out of data byte 1 and the first 4 bits of data byte 2. Being new I am having to learn everything from scratch.

Thanks for the help so far.