Shopping Cart
Your Cart is Empty
Quantity:
Subtotal
Taxes
Shipping
Total
There was an error with PayPalClick here to try again
CelebrateThank you for your business!You should be receiving an order confirmation from Paypal shortly.Exit Shopping Cart

Lennard Electronics Ltd

How I2C works, and code examples for 8051, Arduino, Basic Stamp, and Raspberry Pi (using Xojo)

I2C (Inter-Integrated Circuits), as it's name suggests, is a bus standard for allowing IC's to talk to each other.

I2C is not very difficult to implement at all. Some Micro Controllers have I2C support built in, and it's a simple matter of calling the appropriate built in commands. But others (like the BS2) do not have native support for I2C, so you need to "bit bash" a solution. Before we get in to the sample circuits and software, here's how I2C works.

The Protocol:

I2C is a two wire protocol, and requires the following basic elements:

  • A Start condition
  • Start is identified by a falling edge of SDA while SCL is High.
  • A byte indicating the type of I2C device you are addressing (DAC, ADC, EEPROM, etc.), and the address of that IC. Example 10100001 indicates an EEPROM (1010) with address 000 and that you want to read from it (1).
  • A Stop condition
  • Stop is identified by a rising edge of SDA while SCL is High.
  • Acknowledge signaling
  • Used to indicate a successful byte transfer. The bus transmitter (whether it be a bus master or slave device) releases SDA after sending eight bits of data. During the 9th clock pulse, the receiver pulls SDA low to acknowledge the receipt of the eight data bits.
  • The actual data you wish to transfer.
  • For correct operation, SDA must be stable during the rising edge of SCL, and the SDA signal must change only when SCL is low.
  • Bytes are sent MSB first.

So, for example, to write to an EEPROM:

To write an "A" to address 0 of an EEPROM who's device address is 011, the protocol would be as follows:

  • Start
  • Device ID and address of the device you want to talk to (byte would be 1010-011-0)
  • Acknowledge from the addressed device
  • Address in EEPROM to store the byte (00000000)
  • Acknowledge from the addressed device
  • Byte to store (01000001 which is the binary ASCII value for "A").
  • Acknowledge from the addressed device
  • Stop

The above is represented in the figure below.

To read from address 0 of the EEPROM:

The protocol is a little different to writing.

  • Start
  • "Dummy Write" Device ID and address of the device you want to talk to (byte would be 1010-011-0)
  • Acknowledge from the addressed device
  • Address in EEPROM to read the byte (00000000)
  • Acknowledge from the addressed device
  • Start
  • Device ID and address of the device you want to talk to (byte would be 1010-011-1)
  • Acknowledge from the addressed device
  • Data out
  • NO Acknowledge*
  • Stop

The above is represented in the figure below

*Reading multiple bytes is a little different. If reading multiple bytes, Acknowledge all bytes except the last byte, then finish with a Stop condition.

Bus Arbitration

In a multi-master system, we need a way of ensuring that only one Master is transmitting on the bus at any time. If two masters initiate an I2C command at the same time, an arbitration procedure determines which master wins and can continue with its transmission.

I2C bus devices use an open drain, or open collector arrangement on their output drive circuitry. So, when multiple devices are connected on the bus, this leads to a “wired AND” configuration. This makes it easy for a device to check if it has control of the bus or not.

If a Master puts a logic 1 on SDA but sees that SDA is at logic 0, then it knows that another device is using the bus, therefore it backs off and waits until it sees a stop condition.

EXAMPLE CIRCUITS AND SOFTWARE:

Connecting an EEPROM to a BS2:

As you can see, it's very easy to wire up an I2C device. Pins 1 to 3 of the 24LC02 (2kb EEPROM - 256Bytes) determine the IC's address. Then there is SCL and SDA (Serial Clock and Serial Data). /WR isn't used in this case, but if it is high it will prevent accidental writes to the Chip (unwired, it is held low internally). To add more I2C devices (eg - more EEPROM), simply tie them to SDA and SCL, and set the address pins to a different address. The Outputs of I2C chips are open drain, so you will need the pull up resistors. Also, although not shown above, you should connect a 220R resistor in series with P14 and P15 if using a Basic Stamp.

The Code:

           The code is approached in two parts. The first program stores the message "Lennard Electronics www.lennard.net.nz" in the EEPROM.

           There are a few debug routines so we can see what is happening (eg - Acknowledges, and to check that the bytes are converted to serial               data correctly).

          The second program reads the EEPROM, and displays the message in the debug window. Again, there are a few debug routines so we can            see what is going on.

Program 1: Write to the EEPROM

Some notes:

The code is a simple demonstration of getting I2C to work. Ideally, code should be added to act upon a NO Acknowledge condition (example, the eeprom may be busy writing internal data to it's memory cells, and the Master may therefore have to resend a byte). At this point in time, though, a pause for 10 milliseconds works fine as that is the longest time it takes for the eeprom to write to all it's cells.

Here is the code.

Screen shot of debug screen:

SIPO EXAMPLE:

Serial to Parallel conversion using a PCF8574A.

The 74HC245 is a bidirectional buffer. I use the buffer circuit to monitor the ports on my bread board prototypes, without loading them. You can connect the LEDs directly to the PCF8574A, but you will need to make sure total power dissipation of the PCF8574A is no more than 400mW.

The code simply displays the byte sent to the PCF8574A on 8 LEDs. Starting from 00000000 to 11111111. Also note that you should put a resistor in series with each LED rather than just have the one resistor, as shown. 220R should be enough.

Here is the code.

8051 examples:

ADC.c

DAC_SINEWAVE.c

EEPROM_READ.c

EEPROM_WRITE.c

Parallel_port_READ.c

Parallel_Port_WRITE.c

RTC.c

Arduino examples:

ADC

DAC

DAC_sinewave

EEPROM_Read

EEPROM_Write

Parallel_Port_READ

Parallel_Port_WRITE

RTC

I2C experimenter's board:

Coming soon, we have developed an experimenter's board that will be available on our shopping page. You'll be able to try out the above programs, and your own ideas with the board.