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).
i2c is found in many chips and many modules. Most of the time, you create a master, like when accessing an EEPROM. This time, in this tutorial, we're going to build a slave, which will thus respond to master's requests.
The slave side is somewhat more difficult 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 peripheral (note: some PICs have MSSP, this means they can also be used as i2c hardware Master). 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:
- 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)
- Master writes, and last byte was data : this time, master sends data to the slave
- Master read, and last byte was an address : almost the same as 1., but this time, master wants to read something from the salve
- 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
- Master sends a NACK : basically, master doesn't want to talk to the slave anymore, it hangs up...
Note: in 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.
Ex: 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
[EDIT: 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 today. 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.
Reading:
- Part 1: a few words before getting our hands dirty...
- Part 2: checking the hardware and the i2c bus...
- Part 3: implementing an i2c slave ISR
Sébastien Lelong
I notice that AN734 was revised in October of 2008. Which revision of AN734 did the author consult? Thank you. William
ReplyDeleteImplementing an I2C 'Slave' in software might be fun! I may give it a try some time, since I have some picmicro devices w/o SSP or MSSP.
ReplyDeleteA starting point might be the Atmel appnote AVR302.
I may 'cheat' and utilize the 'clock-stretching' feature of the I2C spec, which means I can slow down the bus to whatever speed I choose - of course this would reduce performance and thruput.
William
William, appnote version is AN734A, from 2000. I did have a very quick look, it seems newer 18F PICs are covered in the updated appnote. Did you notice any inconsistencies with what exposed here ?
ReplyDeleteSeb