I²C (Part 1) - Building an I²C slave + Theory

Author: Sébastien Lelong | Jallib Group

i2c is a nice protocol: it is quite fast, reliable, and most importantly, it's addressable. This means that on a single 2-wire bus, you'll be able to plug up to 128 devices using 7bits addresses, and even 1024 using 10bits address. Far enough for most usage... I won't cover i2c in depth, as there are plenty resources on the Web (and I personally like this page).

A few words before getting our hands dirty...

i2c is found in many chips and many modules. Most of the time, you create a master, like when accessing an EEPROM chip. This time, in this three parts tutorial, we're going to build a slave, which will thus respond to master's requests.

The slave side is somewhat more difficult (as you may have guess from the name...) because, as it does not initiate the talk, it has to listen to "events", and be as responsive as possible. You've guessed, we'll use interrupts. I'll only cover i2c hardware slave, that is using SSP peripheral1. Implementing an i2c software slave may be very difficult (and I even wonder if it's reasonable...).

There are different way implementing an i2c slave, but one seems to be quite common: defining a finite state machine. This implementation is well described in Microchip AppNote AN734. It is highly recommended that you read this appnote, and the i2c sections of your favorite PIC datasheet as well (I swear it's quite easy to read, and well explained).

Basically, during an i2c communication, there can be 5 distinct states:
  1. Master writes, and last byte was an address: to sum up, master wants to talk to a specific slave, identified by the address, it wants to send data (write)
  2. Master writes, and last byte was data: this time, master sends data to the slave
  3. Master read, and last byte was an address: almost the same as 1., but this time, master wants to read something from the salve
  4. Master read, and last byte was data: just the continuation of state 3., master has started to read data, and still wants to read more data
  5. Master sends a NACK: basically, master doesn't want to talk to the slave anymore, it hangs up...
Note: in the i2c protocol, one slave has actually two distinct addresses. One is for read operations, and it ends with bit 1. Another is for write operations, and it ends with bit 0.

Example: consider the following address (8-bits long, last bit is for operation type)

0x5C => 0b_0101_1100 => write operation

The same address for read operation will be:

0x93 => 0b_0101_1101 => read operation

Note: jallib currently supports up to 128 devices on a i2c bus, using 7-bits long addresses (without the 8th R/W bits). There's currently no support for 10-bits addresses, which would give 1024 devices on the same bus. If you need it, please let us know, we'll modify libraries as needed !

OK, enough for now. Next time, we'll see how two PICs must be connected for i2c communication, and we'll check the i2c bus is fully working, before diving into the implementation.

1 some PICs have MSSP, this means they can also be used as i2c hardware Master