Inter-Integrated Circuit, originally developed by Phillips semiconductor, is a 2 wired half-duplex communication protocol. It uses 2 lines for communication and can achieve data rates up to several khz. Typically, In a microcontroller, the two pins for I2C communication are denoted by SDA and SCL i.e Serial data and Serial clock. Data transmission and reception takes place through SDA line whereas SCL line outputs clock pulses for required communication.
I2C is a multi-master, multi-slave communication protocol. On an I2C bus, one can have more than 1 Master and multiple slaves. Originally in I2C, slave address was restricted to 7 bits which give 128 unique addresses out of which 16 are reserved. Thus allowing 112 different addresses on the bus. Later on, 10-bit addressing for I2C was introduced, increasing the total number of devices that can be connected on an I2C bus.
In this article, we will be looking at I2C in PIC microcontroller(PIC16F887) along with all the important registers involved. In the next article, we will be interfacing an RTC with PIC microcontroller and use I2C for communication between the two devices.
Communication Basics in I2C
- Communication in I2C is essentially carried out by a master. A master is responsible for initiating a read from a slave or a write to a slave. Well, how does a master do that? Before beginning a communication, the master always sends a start bit on the bus informing all the devices on the bus about the incoming address.
- The master then sends a 7-bit address of the device it wants to communicate with, along with an 8th bit which is the R/W bit.
- A ‘0’ on the 8th bit, i.e. ‘R/W bit’ indicates that the master wants to write data to the slave whereas a ‘1’ on the ‘R/W bit’ indicates that the master wants to read data from the slave.
- When an address match occurs, the slave sends an acknowledgment to the master indicating that the address on the bus has been matched and it is ready for data communication.
- Depending on the R/W bit, the master either reads data from the slave(Slave transmission) or the Master writes data to the slave(Slave reception).
- Acknowledgment bits are latched by the respective sides on successful communication.
- The master then terminates the communication by sending a Stop bit.
I2C in PIC16F887
PIC16f887 provides an MSSP(Master synchronous Serial port) module which can be configured to work either as SPI or an I2C. In all, there are 6 registers associated with the MSSP module including 2 control registers and 1 status register. These registers have individual bits for SPI as well as I2C, with certain bits having functions for both. However, In this tutorial, I’ll only stress on bits associated with I2C and keep the SPI part for another tutorial. So let us get into the details of I2C in pic microcontroller.
Control and status registers for I2C
The bits in the following registers marked with ‘*’ indicate that the bit has a dual function, both in SPI as well as I2C. In this article, I will only be focusing on bits involved in I2C operation, to make thing more clear and less confusing.
SSP status register
SMP – Sample bit
1 – Slew rate control disabled for standard speed mode(100Khz – 1MHz).
0 – Slew rate control enabled for high-speed mode.
D/Ā – Data/Address bit (I2C mode only)
0 – Indicates that the last byte received or transmitted was Address.
1 – Indicates that the last byte received or transmitted was data.
P – Stop Bit (I2C mode only)
1 – Indicates that a stop bit was detected last
0 – Stop bit was not detected last.
S- Start Bit (I2C mode only)
1 – Indicates that a start bit was detected last
0 – Start bit was not detected last.
R/w̅ – Read/write control information bit (I2C mode only)
In slave mode:-
This bit holds the read/write information after the last address match. After an address match this bit is updated. A ‘0’ indicates Write and a ‘1’ indicates a Read.
In master mode:-
0 – Transmit is not in progress.
1 – Transmit is in progress.
U/A – Update address bit(10 -bit I2C mode only)
This bit is used when 10-bit addressing is used for a slave.
1 – Indicates address needs to be updated.
0 – Address does not need to be updated.
BF – Buffer full bit
Transmit(I2C mode only)
1 – Transmit is in progress.
0 – Transmission completed. SSPBUF is empty.
Receive(SPI and I2C mode)
1 – Receive complete. SSPBUF is full.
0 – No data received yet. SPBUF is empty.
SSP Control register
WCOL – (Write collision bit)
1 – A write to SSPBUF when the conditions were not valid for a write.
0 – No collision
SSPOV: (Receive overflow indication bit)
1 – A write to SSPBUF occurs when SSPBUF is already holding a previous byte. This bit must be cleared in software. SSPOV is a don’t care bit in Transmit mode.
0 – No overflow.
SSPEN – (Synchronous serial port enable bit)
In I2C mode
1 – Enables and configures SDA and SCL pins as source of serial port pins.
0 – Disables Serial port and configures SDA and SCL pins as GPIO.
CKP – (Clock polarity select bit)
I2C slave mode.
1 – Releases clock.
0 – Holds the clock line low, to ensure enough setup time before the master starts using the bus again.
SSMP<3:0> Synchronous serial port mode select bits
0000 – 0101 Used for SPI
0110 – I2C slave mode with 7-bit address
0111 – I2C slave mode with 10-bit address
1000 – I2C master mode, clock = Fosc/(4*(SSPADD+1))
1001 – Load mast function
1010 – Reserved
1011 – I2C firmware controlled master mode (Slave idle)
1100 – Reserved
1101 – Reserved
1110 – I2C slave mode, 7-bit address, with start and stop bit interrupt enabled
1111 – I2C slave mode, 10-bit address, with start and stop bit interrupt enabled.
SSP control register 2
GCEN – General call enable bit(In I2C slave mode only)
The master can send a specific address, i.e. all address bits as ‘0’ along r/w bit as zero. This address is the general call address and is used by a master to address all the slaves on the bus.
When bit GCEN in a slave is set, Interrupt occurs when the general address is received. Setting this bit to 0 disables this feature.
ACKSTAT – Acknowledge status bit(I2C master mode only)
In Master transmit mode:
1 – No acknowledgment received from the slave.
0 – Acknowledgment received from the slave, after a successful address match or data communication.
ACKDT – Acknowledge data bit(I2C master mode only)
In master receive mode.
The value written in ACKDT is sent when bit ACKEN is set.
1 – Not acknowledge
0 – Acknowledge
ACKEN – Acknowledge sequence enable bit(I2C master mode only)
In master receive mode.
1 – Initiates an acknowledgment sequence on SDA and SCL line and sents content of ACKDT bit.
0 – Acknowledge sequence idle.
RCEN – Receive enable bit(I2C master mode only)
1 – Enable receive mode
0 – Receive idle
PEN – Stop condition enable bit(I2c master mode only)
1 – Initiate a stop condition on the bus.
0 – Stop condition idle
RSEN – Repeated start condition enable bit(I2C master mode only)
1 – Initiate a repeated start condition on the bus. RSEN is automatically cleared by the hardware.
0 – Repeated start condition idle.
SEN – Start condition enable bit.
1 – Initiate start condition on the bus.
0 – Start condition idle
1 – Clock stretching is enabled for both slave transmission and reception.
0 – Clock stretching disabled.
Slave mode in I2C
As mentioned above, on an I2C bus there can be multiple slaves limited by the address size. A pic device can be configured as a slave by selecting the appropriate slave mode using SSPM<3:0> bits in SSPCON register. Along with SSPM bits, the synchronous port must be enabled by setting the SSPEN bit in the same register. It is also important to note that the data direction for the two lines i.e. RC3/SCL and RC4/SDA must be set as input using TRISC register.
When pic microcontroller is configured as a slave, its address is to be written in SSPADD register. The Master begins the communication by sending the address with which it wants to communicate on the bus. This address is then compared by the slave with its stored address in SSPADD register. If a match occurs, it automatically generates an acknowledge bit and is sent to the Master. The address is then loaded into SSPBUF register and the buffer full bit BF is set. This bit is automatically cleared when the user reads SSPBUF register.
If the last bit of the received address byte is cleared, the slave understands it is about to receive data from the master. The received address is stored in SSPBUF and bit BF is set which is cleared automatically when SSPBUF is read. Interrupt occurs when enabled. Interrupt flag bit SSPIF in PIR1 register is set. Acknowledgment bit is generated by the hardware.
The data sent by the maser is then received by the slave and stored in SSPBUF register followed by an acknowledgment bit by the slave. BF bit is again set and is cleared when SSPBUF is read. MSSP interrupt occurs when enabled and flag bit SSPIF is set which must be cleared in software.
When the last bit of the received address byte is 1, a slave transmission is initiated. The received address is loaded into SSPBUF register and bit BF is set. It is automatically cleared when SSPBUF is read. Acknowledgment bit for the received address will be sent automatically to the master. The slave device must then load the data into SSPBUF register and bit CKP in SSPCON2 register must be set.
Data is transmitted to the master and the MSSP interrupt occurs when enabled. Bit SSPIF in PIR1 register is set and must be cleared in software. Acknowledge bit is then latched by the master. After transmission of the 8 data bits, if the SDA line remains high on the rising edge of the ninth clock pulse(Not ack sequence), the communication is complete and the slave logic is reset.
If the SDA line remains low on the rising edge of the ninth clock pulse(Ack sequence), the slave must again load data into SSPBUF register and set the bit CKP for another set of data transfer.
During address reception by the slave as well as data reception, if the SSPBUF register is already full and another set of data is received, an overflow condition occurs. In such a case bit SSPOV bit in SSPCON register is set indicating an overflow condition.
During all the above events, the SSP Status register SSPSTAT provides a status of Start bit, Stop bit, Buffer full bit, data/address bit etc.
Master Mode in I2C
As I mentioned earlier, a master is responsible for initiating communication on the bus. It starts the communication by sending a start bit followed by the address byte. After an address match, it either writes or reads from the slave depending on the R/W bit and then terminates the communication by sending a stop bit. Master is also responsible for outputting clock pulses for communication on the bus. Unlike in slave, the SSPADD register in a master does not hold an address, instead, it holds a value responsible for generating the baud rate for the clock.
Just like setting a slave, A Pic device can be configured as a master using the SSMP<3:0> bits in SSPCON register. The synchronous port must be enabled by setting SSPEN bit in the same register. Interrupt in a master when enabled occurs after a start bit, stop bit, data transmission/reception, acknowledge sequence as well as a repeated start condition.
A master begins its communication by initiating a start condition. A start condition is characterized by a high to low transition on the SDA line while SCL line is high. The start condition i.e. a start bit is automatically generated by the hardware when bit SEN is set. If the user tries to write into SSPBUF register while start condition is in progress, WOCL bit is set and the content of SSPBUF is not changed. This bit is cleared by the hardware when a start bit is successfully transmitted.
The Master then loads the address with its R/W bit as 0 in SSPBUF register. Bit BF is set. The address is shifted out on the bus and bit BF is cleared by the hardware. On an address match, the slave responds with an acknowledgment bit. The status of this acknowledgment bit is loaded into ACKSTAT. A ‘0’ indicates that an acknowledgment was received by the slave, whereas a ‘1’ indicates no acknowledgment was received. SSPIF is set and must be cleared in software.
Master then loads data into SSPBUF register. Data is shifted out on the bus. On a successful reception, the slave sends an acknowledgment and its status is updated in ACKSTAT. Master can then terminate the communication by sending a stop condition characterized by a low to high transition on SDA bus while SCL is high. Bit PEN in SSPCON2 register is set to initiate a stop condition. This bit is automatically cleared by the hardware. If the user writes to SSPBUF while transmission of the previous byte is in progress, WOCL bit is set and contents of the buffer are not changed.
Reception in a Master is enabled by setting the RCEN bit in the SSPCON2 register. The For a master to receive data, the master sends the address byte with its R/W bit as 1. On an address match, the slave acknowledges the master. Master will then set RCEN bit to enable reception. Received data bits are loaded into SSPBUF register and bit RCEN is automatically cleared. Buffer full bit and SSPIF flag are set.
To send an acknowledgment to the slave, Master has to set bit ACKEN in SSPCON2 register. Setting bit ACKEN to ‘1’ will initiate the Acknowledge sequence and will transmit the content of ACKDT as an acknowledgment. Confusing?
ACKDT is a read/write bit. A ‘1’ in ACKDT signifies Acknowledge and a ‘0’ signifies no acknowledgment.
The value in ACKDT is sent as an ‘Acknowledgment’ when bit ACKEN is set.
Now when a Master receives a byte of data, it can either send a ‘1’ through ACKDT indicating no acknowledgment or a ‘0’ indicating an acknowledgment. When ACKEN is set with ACKDT being 1, the slave understands that the communication is complete. Whereas, if a ‘0’ is sent through ACKDT, the slave has to again load data into SSPBUF and set CKP for another data byte. The master can then terminate the communication by initiating a stop condition by setting bit PEN.
This is essentially everything you need to know about I2C in general as well as in PIC16F887 microcontroller. In the next tutorial, we will interface an RTC with PIC16887 microcontroller using I2C and display data and time on a character LCD.