I2C, it's a standard that's been around for around 20 years and has found uses in nearly every corner of the electronics universe. It's an incredibly useful technology for us microcontroller hobbyists but can seem daunting for new users. This tutorial will solve that problem, first by reviewing what I2C is and how it works, then by going in-depth on how to implement I2C in Atmel's ATTiny USI (Universal Serial Interface) hardware.
I2C is commonly used in GPIO expanders, EEPROM/Flash memory chips, temperature sensors, real-time clocks, LED drivers, and tons of other components. If you spend much time looking for new, cool parts you'll probably wind up with several I2C parts. Fortunately it is a protocol that is available on most microcontrollers, though it is a bit more complex than others. Learning it is tough at first, but once you know I2C it is a powerful tool.
I2C Tools of Interest:
Before you dig too deep into I2C communications, you'll want to have some things on hand that will make your learning experience easier.
1. Various I2C-compatible parts - Anything goes, as long as it's I2C. If you're writing a master driver you need some things to talk to. I like Texas Instruments' TMP100 temperature sensor as it's cheap (free if you sample) and has a simple protocol (just send an I2C read command to get temp values). I more recently purchased some Microchip MCP23017 GPIO expanders which give you 16 bits of additional GPIO over the I2C bus.
2. Something that has a working I2C master - You'll want something to test/compare against if possible. An Arduino with the Wire library will work, but more recently I prefer my Raspberry Pi with the Linux i2ctools package. i2cdetect, i2cset, i2cget, and i2cdump are invaluable when writing code, especially slave-mode code.
3. Oscilloscope. I know this is a big one, but if you can work with one (either own one, borrow one, or go to a lab where you can use one) it's a super amazing help. I2C uses two wires, so a two-channel scope works great. I used my Rigol DS1052E (100Mhz modded) and it helped a TON. Of course, I did most of the work with it and am telling you what I learned, so hopefully it'll be easier for you.
Step 1: What Is I2C - 1
I2C (Inter-Integrated Circuit bus), originally developed by Phillips (now NXP Semiconductor) and also commonly known as TWI (Two Wire Interface) by Atmel and other companies who don't want to get into trademark issues, is a two-wire synchronous serial bus. Let's take a look at what each of those words means:
Two wire - This one's easy, I2C uses two wires (in addition to ground, of course!) They're called SDA (serial data) and SCL (serial clock). These are wired in an open-drain configuration, which means that the outputs of all connected devices cannot directly output a logic-level 1 (high) and instead can only pull low (connect to ground, outputting a 0). To make the line go high, all devices release their pull on the line and a pull-up resistor between the line and the positive rail pulls the voltage up. A good pull-up resistor is 1-10K ohms, low enough that the signal can be seen as a high level by all devices but high enough that it can easily be shorted out (pulled down) and not cause damage or significant power usage. There is one pull-up resistor on SDA and one on SCL.
Synchronous - This means that data transfer is synchronized via a clock signal that is present to all connected devices. This is generated by the master. To contrast, an asynchronous serial system does not have a clock signal. Instead, it uses a pre-determined time-base, or baud rate. An example of asynchronous serial is RS-232 (the common serial port on many computers).
Serial - Data transferred serially means that one single bit is transferred at a time over a single wire. To contrast, parallel data transfer has multiple wires, each carrying one bit, which are all sampled at once to transfer multiple bits in parallel.
Bus - A bus is a system which allows many devices to communicate to each other over a single set of wires. While it may be called a bus, USB is not a true bus at the hardware level, as connecting multiple devices requires a hub. A bus such as I2C allows new devices to be added simply by attaching their SDA and SCL connections to the existing line. Busses (I2C, USB, PCI, etc) all use an addressing system, in which each device has a unique address. An address in this case is simply a binary number, and all messages to that device must be sent with that address.