Module 3 : Introduction to PIC Microcontrollers

Lecture 27 : Software for I 2C Communication

Software for  I2 C  Communication

The data transfer in I2C mode is not automatically controlled by hardware unlike UART. The Master has to be programmmed by suitable software to generate 'Start' / 'Stop' conditions, various data bits from sending / receving , acknowledgement bit and clock signal. Here, we will discuss some examples of I2C software.

Since SDA (RC4) and SCL (RC3) are both open drain pins, they can be configured either as an output or as an input. When a PIC Processor is configured is I2C master, the SCL pin will function as open drain output while the SDA pin can be either an input or an open drain output. Hence, the software I 2C will repeatedly access TRISC, the data direction register for PORT C. However, TRISC is located in bank-1 at an address 87H, which cannot be accessed by direct addressing without changing RP0 bit to 1 as given in the following instruction.


Then required bit of TRISC can be changed followed by clearing RP0 and reverting back to Bank-0.


Alternately, the indirect pointer FSR can have the address of TRISC and the required bit setting and bit clearing can be done indirectly.

Consider  the following definitions.

SCL equ 3
SDA equ 4

The instruction bsf INDF, SDA will release the SDA line(as RC4/SDA pin is configured as an input, hence tristated), letting the external pullup resister pull it high or some I 2C Slave device/Chip pull it low.

When FSR is used for indirect addressing, care should be taken to restore FSR value when subroutine is completed and the program returns to the main line program.

I 2 C Subroutine

SDA equ 4
SCL equ 3

The following subroutine DATA_OUT transfers out three bytes, i.e., ADDRDEV, ADDR8, and DATAWRTE

DATA_OUT:                    call START                   ; Generate start condition
                                          movf ADDRDEV, W    ; Sends 7-bit peripheral address with R/ =0
                                          call TRBYTE                ; Transmit
                                          movf ADDR8, W          ; Send 8-bit internal address
                                          call TRBYTE
                                          movf DATAWRTE, W  ; Send data to be written
                                          call TRBYTE
                                          call STOP                     ; Generate Stop condition

The DATA_IN subroutine, which is given below transfers out ADDRDEV (with R/ =0) and ADDR8, restarts and transfers out ADDRDEV (with R/ =1) and read one byte back into RAM variable DATARD.

DATA_IN:                       call START                              
                                        movf ADDRDEV, W              ;  Send 7-bit peripheral address R/ =0
                                        call TRBYTE                              
                                        movf ADDR8, W                    ;  Send int. address
                                        call TRBYTE
                                        call START1                          ; Restart
                                        movf ADDRDEV, W             ;  Send 7-bit peripheral address R/ =1
                                        iorlwl  01H
                                        call TRBYTE
                                        bsf  TRBUF, 7                      ; Generate NO ACK
                                        call RCVBYTE
                                        movwf DATARD
                                        call STOP

The 'START' subroutine initializes I2C bus and then generates START condition on the I 2C bus. START1 bypasses the initialization of I 2C.

START:                          movlw 3BH                           ;enables I2C  master mode by programming SSPCON
                                        movwf SSPCON
                                        bcf PORTC, SDA                  ; drive SDA low when it is an o/p
                                        movlw TRISC                        ;set indirect pointer to TRISC
                                        movwf FSR
                                        bsf INDF, SDA                      ; SDA=1
                                        bsf INDF , SCL                     ; SCL=1                                        
                                        call DELAY                            ; Generates a suitable delay
                                        bcf INDF, SDA                      ; SDA=0
                                        call DELAY                            ; Generate a suitable delay
                                        bcf INDF, SCL                       ;SCL=0
                                        bcf INDF, SDA                       ;SDA=0
                                        bsf INDF, SCL                       ; SCL=1
                                        call DELAY                             ; Generate a suitable delay                    
                                        bsf INDF, SDA                       ;SDA=1

The subroutine 'TRBYTE' send out the byte available in w. It returns with Z=1 if ACK occurs. It returns with Z=0 if NOACK occurs.
TRBUF is an 8-bit RAM variable used for temporary storage. The bits are shifted to carry flag (C) and the carry bit transmitted successively. Data transfer is complete when all 8-bits are transmitted. Setting C = 1 initially sets an index for 8-bits to be transferred. C is rotated through TRBUF. After transmitting C, C-bit is cleared. When TRBUF is completely cleared, all 8-bis are transmitted.


movwf    TRBUF
bsf          STATUS,C


rlf         TRBUF, F
movf    RBUF,F
btfss   STATUS, Z
call      out_bit              ; Send a bit available in C
btfss    STATUS, Z
goto     TR_1
call       in_bit               ; Get the ACK bit in RCBUF<0>
movlw  01H                 ;
andwf  RCBUF, W      ; Store the complement of ACK bit in Z flag

The RCVBYTE subroutine receives a byte from I2 C into W using a RAM variable RCBUF buffer.

Call RCVBYTE with bit 7 of TRBUF clear for ACK
Call RCVBYTE with bit 7 of TRBUF set for NOACK
RCBUF is an 8-bit RAM variable used for recieving the data. the bit is recieved in the RCBUF<0> and is rotated successively through RCBUF as shown. The reception ends when all 8-bits are recieved.


movlw    01H
movwf    RCBUF           ; Keep an index for 8-bits to be recieved.


rlf        RCBUF, F
call     In_bit
btfss  STATUS, C
goto   RCV_1
rlf       TRBUF, F
call    Out_bit
movf  RCBUF,w

The out_bit subroutine transmits carry bit, then clears the carry bit.


bcf      INDF, SDA
btfsc  STATUS, C
bsf     INDF, SDA             ; Send carry bit
bsf     INDF, SCL
call     DELAY
bcf      INDF, SCL
bcf      STATUS,C             ; Clear carry bit

The in_bit subroutine receives one bit into bit-0 of RCBUF.

bsf      INDF,SDA
bsf      INDF, SCL
bcf      RCBUF, 0
btfsc   PORTC, SDA          ; Check SDA line for data bit
bsf      RCBUF, 0
bcf      INDF, SCL

Example of I 2 C interfacing
DAC interfacing on I 2 C bus:

MAX518 is a dual 8-bit Digital to Analog Converter (DAC) with I2C interface. The address of the device is selectable through two pins AD1 and AD0 . This device works in I2C slave mode. The connection diagram is shown as follows.

Fig 27.1     I2C Interface for DAC
The 7-bit device address is given as

For the present connection AD1 = 0 and AD0 = 1
The device address is 010 1101
Three bytes are sent to output an analog voltage.

First byte   (Address of the DAC and R/ bit )
Second byte  (DAC Configuration)
Third byte           (The 8-bit digital data(B) to be converted to analog voltage)

Analog output voltage = V DD x B/256