Recent changes
SerialPC
Creating a program
Downloading a program
Setup guide
Exporting to Code Red
Exporting to uVision
Order
tag order
From the mbed microcontroller Handbook.  

I2C

/media/uploads/mbedofficial/i2c_interfaces.png

The I2C interface provides I2C Master functionality.

This interface can be used for communication with a I2C devices, such as serial memories, sensors and other modules or integrated circuits.

Hello World!

Reading range data from the SRF05 Ultrasonic Range Finder

#include "mbed.h"

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

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

int main() {
    char cmd[2];
    while(1) {
        cmd[0] = 0x0;            // pointer to command register
        cmd[1] = 0x51;           // Start ranging, results in cm
        i2c.write(addr, cmd, 2); // Send command string

        wait(0.07);              // Could also poll, 65ms is typical

        // Set pointer to location 2 (first echo)
        cmd[0] = 0x2;
        i2c.write(addr, cmd, 1);
        i2c.read(addr, cmd, 2); // read the two-byte echo result

        // print the ranging data to the screen
        float echo = 0.01 * ((cmd[0] << 8) + cmd[1]);
        pc.printf("Range = %.2f\n", echo);
        wait(0.1);
    }
}

Warning

Remember, you will need a pull-up resistor on sda and scl.

All drivers on the I2C bus are required to be open collector, and so it is necessary for pull up resistors to be used on the two signals. A typical value for the pullup resistors is around 2.2k ohms, connected between the pin and 3v3.

API

I2CAn I2C Master, used for communicating with I2C slave devices
Functions
I2CCreate an I2C Master interface, connected to the specified pins
frequencySet the frequency of the I2C interface
readRead from an I2C slave
readRead a single byte from the I2C bus
writeWrite to an I2C slave
writeWrite single byte out on the I2C bus
startCreates a start condition on the I2C bus
stopCreates a stop condition on the I2C bus
class I2C : public Base
An I2C Master, used for communicating with I2C slave devices
I2C(PinName sda,  
PinName scl,  
const char *name =  NULL)
Create an I2C Master interface, connected to the specified pins
void frequency(int hz)
Set the frequency of the I2C interface
int read(int address,  
char *data,  
int length,  
bool repeated =  false)
Read from an I2C slave
int write(int address,  
const char *data,  
int length,  
bool repeated =  false)
Write to an I2C slave
void start(void)
Creates a start condition on the I2C bus
void stop(void)
Creates a stop condition on the I2C bus

Details

The I2C Interface can be used on mbed pins p9/p10 and p28/p27

The default frequency of the I2C interface is 100KHz.

I2C is a two wire serial protocol that allows an I2C Master exchange data with an I2C Slave. The I2C protocol support upto 127 devices per bus. The I2C interface can be used for writing data words out of the I2C port, returning the data recieved back from I2C slave. The I2C clock frequency can be configured.

References




calendar Page history
Last modified 07 Dec 2010, by   user Simon Ford   tag No tags | 21 comments      

21 comments on I2C:

27 Oct 2010

Thanks for adding default freq Simon Lerche

11 Nov 2010

Could you, please, explain what the arguments in the i2c.write and i2c.read commands mean. What is the general structure of the read and write commands for the I2C interface?

Thanks LL

11 Nov 2010

As a follow-up to my previous question, what would the code look like in order to put characters in an I2C display such as the EA T123-I2C?

13 Dec 2010

I posted a comment a couple of days ago, including an image of a diagram giving the complete sequence of pulses on the SDA and SCL lines for a data transfer. Is it still waiting for approval, is it unsuitable, or did it not get through? Please let me know, thanks. I am harryweston@btinernet.com

13 Dec 2010

Well, that one appeared instantly so the problem was mine not understanding the system. I apologise for the unnecessary posting.

Here is a diagram I devised for myself when I was programming a PIC to read the bearing from a CMP03, in two formats, both binary numbers, one a single byte in the range 0-255 for 0-360 degrees and the other a two byte value giving the angle in tenths of a degree as 0-2599. It is reading the latter from the CMP03 that is shown here.

There are two lines, SDA which carries the data, and SCL which is a clock. SDA can only be changed while SCL is low, and SDA is read on the rising edge of SCL. This allows the extra codes for START and STOP shown at the left. Note that any device can hold either line low to gain time for processing when SCL is held low for this purpose it is known as 'clock stretching' as in the centre of the sketch. I hope this helps and I will answer any queries.

/media/uploads/ColonelPewter/i2c_001004.gif

15 Jun 2011

Sorry but the "SRF05 Ultrasonic Range Finder" haven't i²C bus. May be it's about the SRF08... please be careful...

28 Oct 2011

Are there no internal Pullups available? Maybe by using DigitalInput at the same Pin?

09 Dec 2011

How does one send the Slave address and a specific Register address for read and write? The IC I'm using requires both.

09 Dec 2011

The way to select a specific register for reading and writing is usually as follows: First send a start condition, then send the device slave address with the 'write' bit set, followed by the register address. The register has then been selected internally in the device. When you want to write a value to this register, just continue and send the data to be written. Normally the register addresses will automatically increment. You can continue writing databytes, they will be written to sequential register addresses (or memory addresses when the device is an EEPROM or RAM). When you are done writing, send a Stop condition. The selected slave device should acknowledge each byte as it is written.

When you wish to read a register, proceed as follows: First sends a start condition, then send the device slave address with the 'write' bit set, followed by the register address. The register has then been selected internally in the device. Then send a Stop condition. Now start a new I2C transaction to read from the selected register. First sends a start condition, then send the device slave address with the 'read' bit set. The previously selected register is still selected internally in the device. Now read the value from the device. The register addresses will again auto increment. You can continue reading until you are done. Then send a Stop condition. The master should acknowledge each byte as it is received.

You can use the mbed I2C lib to achieve this:

i2c.write(slave_address, data, nr_bytes) The first byte in array data should be the registeraddress, remaining bytes are the register contents.

i2c.write(slave_address, data, 1) The first byte in array data should be the registeraddress you want to select. i2c.read(slave_address, data, nr_bytes) Read nr_bytes starting from the selected register

09 Dec 2011

Hello RT and Wim Huiskamp. Wim's comments all correct, but I think that the master should also send a "Nack" at the end to signal the end of the data transmission. All this is on the chart I posted a year ago, 10th December 2010, it is at five comments earlier than this one in the set I got when I typed I2C in the "Search wikis" box. A very good slide show giving the sequence for an EEP rom, among other things is at "http://ww1.microchip.com/downloads/en/devicedoc/i2c.pdf"

11 Dec 2011

Hey wim and harry,

I tried implementing this and I haven't been able to read yet, I think I need to go over my circuit and values for errors, although I don't see any at the moment. But in case I have a coding problem, I was hoping you guys could take a quick look.

Code

#include "mbed.h"

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

int main() 
    {
    const int iDACadd = 0x98; // define the DAC I2C Address
    int iI2Cfreq = 100000; // bus frequency in Hz
    i2c.frequency (iI2Cfreq); //set I2C frequency
    char cWdata [7] = {0}; // 7 bytes of write data
    char cRdata [7] = {0}; // 7 bytes of read data
    char cRegisterAdd [1] = {0x90}; //first byte is register address
    printf("\nHELLO\n");
    printf ("\nINIT\nStarting Register Address %X\nRegister 16 %X\nRegister 17 %X\nRegister 18 %X\nRegister 19 %X\nRegister 20 %X\nRegister 21 %X\nRegister 22 %X\n" , cRegisterAdd [0], cRdata[0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    i2c.write(iDACadd, cRegisterAdd, 1);
    i2c.read(iDACadd, cRdata, 7);
    wait(0.75);//wait for read data
    printf ("\nREAD\nStarting Register Address %X\nRegister 16 %X\nRegister 17 %X\nRegister 18 %X\nRegister 19 %X\nRegister 20 %X\nRegister 21 %X\nRegister 22 %X\n" , cRegisterAdd [0], cRdata[0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    //i2c.write(iDACadd, cWdata, 2); // Send write command
    //printf ("\nWrite\nRegister 16 %X\nRegister 17 %X\nRegister 18 %X\nRegister 19 %X\nRegister 20 %X\nRegister 21 %X\nRegister 22 %X\n" , cRdata [0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    }

I have the detailed read and write operations from the data sheet, Harry is right in that the end of the Read operation requires a NACK then a stop command from the master. I'm not sure if the Mbed lib does this. I suppose I may have to get more in depth on the code and set those conditions, as I don't fully understand exactly what is happening with the i2c commands.

I've heard that sometimes the given slave address is wrong so I will try the debug program tomorrow.

Thanks Ryan,

PS. The IC is the DSD1793 if you need to check the data sheet.

11 Dec 2011

Hey I had a few more minutes and tried this.

Code

#include "mbed.h"

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

int main() 
    {
    const int iDACadd = 0x98; // define the DAC I2C Address
    int iI2Cfreq = 100000; // bus frequency in Hz
    i2c.frequency (iI2Cfreq); //set I2C frequency
    //char cWdata [7] = {0}; // 7 bytes of write data
    //char cRdata [7] = {0}; // 7 bytes of read data
    //char cRegisterAdd [1] = {0x90}; //first byte is register address
    int iRegisterAdd = 0x90;
    int iData[6] = {0};
    printf("\nHELLO\n");
    printf("\nINIT\nData1 %X\nData2 %X\nData3 %X\n", iData[0], iData[1], iData[2]);  
    i2c.start();
    i2c.write(0x98);
    i2c.write(iRegisterAdd);
    i2c.start();
    i2c.write(0x99);
    iData[0]=i2c.read(1);
    iData[1]=i2c.read(1);
    iData[2]=i2c.read(0);
    i2c.stop();
    printf("\nData1 %X\nData2 %X\nData3 %X\n", iData[0], iData[1], iData[2]);  
    }

Code

Result:

HELLO

INIT
Data1 0
Data2 0
Data3 0

Data1 FF
Data2 FF
Data3 FF

The first two register values are correct, the third is not the correct default value... hmmm. Some progress at least! Unless I made some code error that will always make it FF.

Ryan.

12 Dec 2011

Ok, some comments:

  • Yes, the I2C master (mbed) needs to NAck when he has received the last byte and wants to stop. I left that out as a simplification since there is no need to do that yourself when you use the mbed libs for reading multiple bytes. That is done by the lib. However, you do need to take care of that Nack when you use the atomic lib functions for start, read, stop.
  • I assume your DSD1793 has ADR0 and ADR1 pins connected to 'logic 0'. That would result in a I2C slave address of 0x98. This is used in your code.
  • The DSD1793 datasheet is a bit confusing. Tables 4 and the other tables that show the register definitions use 16 bits. That makes no sense for I2C. All transactions are 8 bit. Anyhow, the significant bits for the registers are bit0-7. The bits 8-15 are hardcoded in the tables. I assume that bit0-7 is what you get or set using I2C communications.
  • The DSD1793 is also confusing wrt to the valid register addresses. Table 4 mentions registers 16-22. Page 21 mentions that valid register indexes are between 0x10 and 0x1F. This leads to the conclusion that the values 16-22 are in fact hexadecimal numbers 0x10 - 0x16. In your code I find that you use 0x90 as the initial address. That would not work. You will get random values in return, probably 0xFF. Any value outside the range 0x10-0x16 will be undefined.

Try this:

Code

#include "mbed.h"

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

int main() 
    {
    const int iDACadd = 0x98; // define the DAC I2C Address
    int iI2Cfreq = 100000; // bus frequency in Hz
    i2c.frequency (iI2Cfreq); //set I2C frequency
    char cWdata [7] = {0}; // 7 bytes of write data
    char cRdata [7] = {0}; // 7 bytes of read data
    char cRegisterAdd [1] = {0x10}; //first byte is register address
    printf("\nHELLO\n");
    printf ("\nINIT\nStarting Register Address %X\nRegister 0x10 %X\nRegister 0x11 %X\nRegister 0x12 %X\nRegister 0x13 %X\nRegister 0x14 %X\nRegister 0x15 %X\nRegister 0x16 %X\n" , cRegisterAdd [0], cRdata[0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    i2c.write(iDACadd, cRegisterAdd, 1);
    i2c.read(iDACadd, cRdata, 7);
    wait(0.75);//wait for read data
    printf ("\nREAD\nStarting Register Address %X\nRegister 0x10 %X\nRegister 0x11 %X\nRegister 0x12 %X\nRegister 0x13 %X\nRegister 0x14 %X\nRegister 0x15 %X\nRegister 0x16 %X\n" , cRegisterAdd [0], cRdata[0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    //i2c.write(iDACadd, cWdata, 2); // Send write command
    //printf ("\nWrite\nRegister 16 %X\nRegister 17 %X\nRegister 18 %X\nRegister 19 %X\nRegister 20 %X\nRegister 21 %X\nRegister 22 %X\n" , cRdata [0], cRdata[1], cRdata[2], cRdata[3], cRdata[4], cRdata[5], cRdata[6]);
    }
13 Dec 2011

Hey wim,

I got it working today, sorry I didn't get to this sooner. After using the real term debug program I found that the device wasn't responding at all yet.

After re reading the 56 page data sheet again (for the nth time)I found that if SCK isn't receiving a proper clock signal the device isn't operational and you can't read/write to it. SO after applying that, I can read it fine with the first bit of code I posted above. The second code wasn't functional.

That datasheet is pretty confusing huh! When it mentions 0x10 - 0x1F, it's referring to the write address and not the read address, so 0x90 is correct for read.

Thanks for all your help.

1 week, 5 days ago

Is there any way to register a function to be called when data is received?

23 hours, 17 minutes ago

Hi,

Anyone know the maximum frequency i can set. I have an i/o expander, MCP23017, which claims to work up to 1.7MHz.

22 hours, 46 minutes ago

I think the max frequency for I2C is 400kHz

22 hours, 39 minutes ago

Try going higher, see what happens :D Nothing bad should happen. Notice: SHOULD, I can't be sure, but I would just tell it to go to max :D

Lerche

19 hours, 7 minutes ago

Hi, I intended to ask what the maximum speed the mbed can run the i2c clock rather than the maximum frequency defined by the i2c bus standard. I have tried increasing it, the i/o expander chip continues to respond up until 700kHz. This is what prompted me to ask the question. The i/o expander datasheet says it has a high speed i2c bus which works up to 1.7MHz. If the mbed is capable of this then i must assume the input expander datasheet is wrong. If someone happened to know that the mbed was not capable of this speed then i would know it is a limitation of the mbed device. Thanks for the replies

19 hours, 3 minutes ago

I can't see why the expander shouldn't be able to do it. It must be mbed...

Lerche

15 hours, 43 minutes ago

Check the LPC1768 datasheet (chapter 19). The I2C engine on I2C ports 1 and 2 run in fast mode (max 400Kz) and standard mode (100 kHz). The I2C port 0 is a Fastmode Plus port and can go upto 1 MHz. However that port is not available through the mbed pins. Not sure what the mbed libs do, they might limit the bitrate to 400KHz. The actual bitrates you can achieve depend on bus wiring and capacitive load.

Please login to post comments.