29 September 2012

Tutorial 20a: Introducing I2C

The SPI protocol is a simple and useful system, but is not without its disadvantages. In the example we looked at, we noted that at any given time, despite the ability to exchange messages simultaneously, only the master or the slave was sending any meaningful data. The system is capable of linking multiple devices together, but the technique is much like an old switchboard operator: each devices gets its own unique and private line, and the master selects which device it is talking to at any given moment. In the mean time, lines not being used are taking up space and resources that could be allocated to other tasks. This technique is not the only way to communicate, however. What if instead of a switchboard model, we looked more to radio communication: if you tune in to a specific frequency, anything transmitted can be heard by all, and (at least at some frequencies) all can transmit at any time. This type of system is far more conducive to linking multiple devices together as it greatly simplifies the connections, both physically and conceptually.

In electrical systems, we call any line that links multiple parts together a "bus". In the sense of serial communication, a bus is a line on which devices can watch for signals, or generate signals of their own. A bus-type system reduces the number of connections needed between components and links multiple systems together in potentially complex ways. One of the most popular implementations of a true serial communications bus was developed in the 1980's by Philips Semiconductors: the Inter-integrated Circuit Bus, or I2C.

Problems With a Serial Bus

As you might expect if you've ever heard radio interference, some significant issues come up when rather than each device getting its own, private communication line they have to share a line. Much like a crowded household of entitled teenagers (at least before cell phones), a crowded bus in an electrical system needs to lay down rules for who can talk and when.

Problem 1: Since multiple devices control the same line, what happens when one device actively pulls the line low, while another actively pulls the line high? This creates a short between the low and high states, likely causing irreparable damage to the system. To get around this, the I2C specification requires devices to only actively pull a line low. The line is tied with a resistor to Vcc, so if no device is active it defaults to a high state. (This reason is similar to the need for the resistor(s) in the SPI example.) In terms of the MSP430 GPIO, think of it as setting the output of a pin to 0, then toggling whether the pin is an output (pulling the line low) or an input (allowing the line to be pulled high). In fact, if you ever find yourself required to bit-bang I2C, this is exactly the technique you'll have to use to prevent any damage to the systems involved.

Problem 2: As a result of the use of resistors to pull the line state high, we are limited on the speed at which we can communicate with I2C. Any capacitance in the line, combined with the resistor, will lengthen the amount of rise time in the line.  Too much resistance, and the line doesn't pull high soon enough to get the right message sent. Too little resistance, and you draw far too much power through the resistor when the line is pulled low. The standard specification for I2C limits transmission speeds to a 100 kHz clock. For the 3 V power used on many MSP430 designs, a resistance between 1 and 10 kΩ is typical; if you're concerned about speed, aim for the 1 kΩ end. Other specifications allow for clock speeds of up to 400 kHz (fast mode), or 1 MHz (fast mode plus). These modes will require smaller resistors, and inherently use more power than standard mode.

Problem 3: Since all devices are listening in on the same line, if the master asks for a data value to be reported, which device responds? I2C assigns a call sign, of sorts, to each device in the form of a 7-bit address. (An 8th bit is added to specify if the master wants to read from or write to the device.) This address is usually hard-coded into the device, and reading its datasheet will give the information needed to address it correctly. Some devices hard code some of the bits, allowing the user to select the specific address by setting the other bits accordingly. This technique allows the use of more than one of the same device in a system.

Problem 4: In addition to knowing who needs to respond, devices (including the master) need to know when they can send signals; if the line is tied up by another device, other devices must hold on their own messages until the line is signaled as being free. This coordination is effected in I2C by the timing of changes in the data line compared to the clock line. Communication in I2C is initiated by a falling edge in the data line, and marked complete by a rising edge in the data line, much like the use of the chip select in the SPI example we did. Since this is the same line where data is transmitted, I2C specifies that a "start condition" occurs when the data line is pulled low while the clock is high. A "stop condition" occurs when the line is pulled high while the clock is high. Data transmission occurs between these two conditions.

Data is sent after signaling a start condition by changing the line state while the clock is low, and the listening device reading the state while the clock is high. (Note that this is essentially equivalent to Mode 3 for SPI.) It is essential that devices sending messages do not change the state of the data line while the clock is high unless marking a start or stop condition. Other devices need to be aware of start and stop conditions to avoid sending messages of their own at the same time. If a device sees a start condition, it will listen for the address. If not its own, it must wait until the line is freed up by a stop condition before sending its message.

I2C in Action

If after reading all of that you feel like I2C is really complicated, it's not. Well, it's certainly more complicated than SPI, but once you see how the protocol works it's not too difficult to understand. So let's look at a typical I2C transmission and analyze what's going on.


Look at this image of the first part of an I2C transmission-- this portion highlights the start condition and the addressing portions. Note that the state of the clock (bottom curve) is idling high. The clock does not start until after the master pulls SDA low. The start condition is signaled by the falling edge on SDA while SCL is high. The start signal is followed by 9 pulses of the clock on SCL. Remember: at this point, neither the master nor the slave changes the state of SDA while the clock is high. Notice that the changes in SDA sending the data occur between pulses-- you can read out the transmitted value at the points where the clock is high. In this example, the data reads 0b01000001. The first 7 bits of this value are the address of the slave (in this case, 0b0100000). These bits are followed by a final 1, which designates a read command. The following data will be sent by the slave, reporting the data it has ready to send.

Did you note that there were 9 pulses, but only 8 bits? The 9th clock is done for some basic handshaking, and is called the "acknowledge" bit. In this case, the master addresses the slave at the specified address and releases the line after sending the 8 bits. If the slave recognizes the call, it pulls the line low; the master reads the 9th bit to confirm that the slave has heard the instruction. What happens if the slave doesn't hear, or fails to acknowledge the signal? Since the line is tied high and the master has relinquished control, the line automatically pulls high. If the master reads the 9th bit and sees it high, it aborts the transmission. (Whether it tries again or not depends on how the master is built, of course.)

At this point (assuming the slave acknowledged the instruction), it is important that the master not signal a stop condition (by sending a rising edge on SDA while the clock is high) to give the slave the time to report back the data it was asked to read. The remainder of this example looks like this:
How we interpret the remainder of the instruction depends on the exact device being read. For simplicity, let's assume that we're dealing with a device that has a single, 2-byte register. No further addressing is necessary, so when the slave receives the instruction to read, it reports back the 16 bit value it has. Data is transmitted one byte at a time, with an acknowledge bit between bytes. In this example, we see the slave reporting back the two byte value corresponding to the ASCII characters "%%". After the first byte, the slave relinquishes SDA and watches for the master to acknowledge receiving the data (again, by holding SDA low). After the final byte, notice that the acknowledge bit is now high. On the last cycle, the master does not send an acknowledge bit, indicating that no more data is expected.

Finally, the master pulls SDA low again, then releases the clock so that SCL is high. The master then releases SDA to give a stop condition.  At this point, any other devices needing to start a transmission are free to do so; if between the start and stop any other device has a message to send, it must wait until it sees the stop condition before doing so.

Now that we've got a handle on some basic I2C formatting, we'll turn our attention to the USI module and how it's used in I2C in the next part of this tutorial.

Reader Exercise: Using the second image, identify which bits (including acknowledge bits) in the data stream on SDA are sent by the master, and which are sent by the slave, according to the description given in this tutorial. What is the slave doing while the master is sending data? What is the master doing while the slave is sending data? Who has control of SDA at what times?

3 comments:

Unknown said...

A while back you mentioned that you would do a tutorial on PWM for the MSP430g2231. I'm trying to use a shift register and PWM to cycle through the different colours of an RGB LED and I'm failing miserably...Any chance you could put up that tutorial on PWM?

Nabil Hanke said...

David,

I just found your blog and am starting at the beginning, so it may be a little while before I get to the subsequent posts to this i2c tread. However, what I've read thus far is well composed and, for me, totally on the mark.

I understand how regular updating can prove difficult. Let this be an added boost to see it through, your works here are very well appreciated.

Unknown said...

Gareth, I'll do my best to get to it. Obviously I've been delayed at finishing the I2C tutorial, but I will plan on doing a PWM example or two as soon as I finish it.