I2CU! I2C updates and search for devices

03 Sep 2009 . Edited: 03 Sep 2009

A few people seem to be playing with I2C, and hitting common problems, so I did some I2C updates this afternoon:

  1. Move to specifiying address as 8-bit rather than 7-bit
  2. Return success from read/write (ACK)
  3. Wrote a simple program to find I2C devices on a bus, and list their addresses

Here are the details:

1) I2C addresses are 7-bit, sent as the top bits of a byte with the bottom bit saying whether it is a read or write. However, most datasheets actually list the address already aligned to the top bits (shifted left by one) i.e. 8-bit, and some even list two addresses; the write and the read address (write | 1).

+----------------------+
|  7-bit address | R/W |  
+----------------------+

As such, the majority of first uses of I2C have tried the wrong address :(

So rather than fight the flow, i've updated the library to use what seems more conventional. You specify the address as 8-bit, and the library will force the bottom bit to 0 for a write, and 1 for a read. This should make things more in line with how things seem to be documented.

2) The library used to die if a transaction failed, for any reason, including a NACK. This was more a quick fix when I first played with getting the library working. However, for some devices (RAM/PROM), it is required to be able to detect the NACK, as that is how you detect whether e.g. the device is still busy.

Whilst not ideal, for now the I2C read/write functions return 0 if everything went ok (ACK), and non-0 if not (NACK). It still needs a proper think and reworking, but this gets some additional functionality working straight away. In particular, it lets you see if a device responds, which leads to:

3) I2CU is a quick program I wrote to go through all the I2C addresses on a bus, and see if anything responds. It lists the devices it hears from, and hence should be a good way to see if your bus is up and running, and whether devices are on it. The basic idea is:

for (int address=0; address<256; address+=2) {
    if (!i2c.write(address, NULL, 0)) { // 0 returned is ok
        printf(" - I2C device found at address 0x%02X\n", address);
    }
}

The full program can be imported from http://mbed.org/users/simon/published/7250cc082e343d0dba3ee345cfcf0cf2/I2CU.zip

Hopefully this will be ideal for a first test step before worrying about device addresses and command structures etc. It could be improved to diagnose the exact faults better, but for now it is limited by the I2C library functionality; i'll aim to update both when some of our I2C test parts come in.

If you are having trouble with your I2C bus or devices, run this first!

Simon

04 Sep 2009

Hello,

Simon

I2C could not find slave address, in your code , you do not connect slave. so address is 0x00, your code can execute. I download your code , it can execute ,but when I connect slave ,it could not execute. It could not slave address .

You change address to 8 bits,so I use address 0xC4 .

I don't konw why it could not execute .

Please tell me!

Thanks!

zhenjiang

04 Sep 2009 . Edited: 04 Sep 2009

Hi zhenjiang,

I download your code , it can execute ,but when I connect slave ,it could not execute.

If it stops executing, that suggests the bus is not wired up correctly.

To help diagnose this, can you explicitly answer each of the following questions in this forum thread:

  1. How is the TDA7541 getting power? From the mbed 3.3v VOUT/GND pins?
  2. Have you got any indication the chip is running?
  3. What value pull up resistors are you using on the I2C sda and scl lines?
  4. Are the pull-up resistors connected to 3.3v (can you confirm this with a voltmeter)
  5. If you have only the pull-up resistors connected (not the TDA part), what is the output of the test program (paste the whole output, rather than paraphrase)
  6. If you have the pull-ups and TDA connected, what is the output of the test program (paste the whole output again)

Please answer each of these questions. Then we can help you track it down.

Simon
04 Sep 2009 . Edited: 04 Sep 2009

Hello Simon,

I want to tell you something about my TDA7541 , my TDA7541 chip is in HK830 radio module , and in the radio module have a EEPROM chip also, it's write address is 0xA0. I write data to TDA7541 , and when powner off save to EEPROM . Hardware engineer connect the circuit . It is correct .

Hk830 pin

Could you give me the I2C.H and I2C.cpp documentation .

Thanks !

zhenjiang

04 Sep 2009

Hi Zhenjiang,

If you'd like us to try and help, you really need to explicitly answer each of the following questions:

  1. How is the TDA7541 getting power? From the mbed 3.3v VOUT/GND pins?
  2. Have you got any indication the chip is running?
  3. What value pull up resistors are you using on the I2C sda and scl lines?
  4. Are the pull-up resistors connected to 3.3v (can you confirm this with a voltmeter)
  5. If you have only the pull-up resistors connected (not the TDA part), what is the output of the test program (paste the whole output, rather than paraphrase)
  6. If you have the pull-ups and TDA connected, what is the output of the test program (paste the whole output again)

Please can you go through these methodically and respond with the answer to each question.

Thanks!
Simon

05 Sep 2009 . Edited: 05 Sep 2009

Hello Simon,

I am very sorry, because one of my negligence, resulting in the circuit the wrong connection.
I modified the circuit ,and I can write data in TDA7541 now . I am very glad . Thank you for your help !
I want to know how to read data from EEPROM subaddress,
EEPROM address is 0xA0 ,it's subaddress is from 0x00 to 0x66.
This is read data from EEPROM code:
char read_data[103];
read(0xA0, read_data, 103);  // when I read data from EEPROM , is it the address auto increament in
                                          //  the EEPROM?
I don't known how parameters are defined .
Could you tell me about it ?
Thanks
zhenjiang
10 Nov 2010

Not worth starting a new topic and this seems to be as goddd a place as any:).

The I2C bock read and write seem to have 0 as the ACK and a simple write byte has 1 as the ACK. Is this a misprint in the documentation?

Thanks

Greg

11 Dec 2011

Hi,

I have tried the above code from Simon, but seems it hangs when no I2C device is connected. Any idea? Thanks.

11 Dec 2011

The code should not hang. Just make sure that you have the I2C pull-up resistors installed. The I2C engine will hang when the pull-ups are missing.

11 Dec 2011

I see, that's the thing...the pull-up resistors are built into the I2C device, so when it's detached, the resistors are, too. So I guess this setup isn't supported by mbed then. I know there is a workaround (e.g. connect any DigitalIn to VU as flag pin representing the presence of the I2C device), but that isn't a pretty solution as it blocks a pin that might be needed for smth else.

11 Dec 2011

It should be possible to use internal pull up resistors, Possibly just enough to stop it locking.

Ceri

12 Dec 2011

Thanks for the reply Ceri, but how is that supposed to work :P