
$NOMOD51
$INCLUDE (REG515.INC)
NAME    I2C                                     ;name of the program module
;FILE NAME - I2C.A51

;-----------------------------------------------------------------------------
;  THIS MODULE CONTAINS THE I2C DRIVER ROUTINES                              
;  27/08/98,07/12/98                                                        
;-----------------------------------------------------------------------------
?PR?ReadWriteI2c?I2C SEGMENT CODE             ;segment for program code
?DT?ReadWriteI2c?I2C SEGMENT DATA OVERLAYABLE ;segment for local variables
?BI?ReadWriteI2c?I2C SEGMENT BIT  OVERLAYABLE ;segment for local bit var 

PUBLIC  _ReadWriteI2c                           ;public symbols
PUBLIC  ?_ReadWriteI2c?BYTE                   ;for 'C'            
PUBLIC  ?_ReadWriteI2c?BIT                    ;function calls

        RSEG    ?DT?ReadWriteI2c?I2C          ;segment for local variables
?_ReadWriteI2c?BYTE:                          ;start of parameter passing
                                                ;segment
i2c_slave_address:      ds      1               
i2c_register_address:   ds      1
write_i2c_data:         ds      1

        RSEG    ?BI?ReadWriteI2c?I2C          ;segment for local bit var
?_ReadWriteI2c?BIT:                           ;start of parameter passing
                                                ;segment
read_write_flag:        dbit    1



;----------------------------------------------------------------------------
;       I2C PORT PIN DEFINITIONS                                  
;----------------------------------------------------------------------------

SDA                     EQU     P3.6                                    
SCL                     EQU     P3.7                                    

        RSEG    ?PR?ReadWriteI2c?I2C
        USING   0
            
_ReadWriteI2c:
;----------------------------------------------------------------------------
;       08/12/98
;       CHECK WHETHER READ OR WRITE
;       IF CY = 1 THEN IT IS READ, IF CY = 0 THEN IT IS WRITE
;----------------------------------------------------------------------------
        JB      CY, READ_I2C_REGISTER
        JMP     WRITE_I2C_REGISTER


;----------------------------------------------------------------------------
;       LOW LEVEL I2C MACROS
;----------------------------------------------------------------------------
SET_SCL         MACRO
                SETB    SCL
                JNB     SCL,$
                BIT_DELAY
                ENDM

CLEAR_SCL       MACRO
                CLR     SCL                
                BIT_DELAY
                ENDM

EMIT_CLOCK      MACRO
                SET_SCL
                CLEAR_SCL
                ENDM

START           MACRO
                SETB    SDA
                SET_SCL
                CLR     SDA
                BIT_DELAY
                CLEAR_SCL
                ENDM

STOP            MACRO
                CLR     SDA
                SET_SCL
                SETB    SDA
                BIT_DELAY
                ENDM

BIT_DELAY       MACRO
                NOP
                NOP
                ;NOP     ;04/02/2003 for 24Mhz
                ENDM 
        
;----------------------------------------------------------------------------
;       I2C SUBROUTINES
;----------------------------------------------------------------------------

XMIT_BYTE:

        ;ACC CONTAINS BYTE TO TRANSMIT
        ;CY= 0 IF SEQUENCE COMPLETES
        ;CY= 1 IF UNABLE TO TRANSMIT
        

        MOV     R1,#8                           ;8 BITS TO SEND

XB1:
        RLC     A                                                                               
        MOV     SDA, C                          ;PUT BIT ON PIN
        EMIT_CLOCK                              ;EMIT CLOCK PULSE
        DJNZ    R1,XB1                          ;LOOP UNTIL DONE

        ;SETUP TO ACK FROM SLAVE DEVICE

        SETB    SDA                             ;RELEASE DATA PIN
        SET_SCL                                 ;SCL HIGH
        JNB     SDA,XB2                         ;JUMP IF ACK SEEN
        CLEAR_SCL                               ;DROP SCL
        SETB    C                               ;SET ERROR CODE
        RET

XB2:
        CLEAR_SCL                               ;DROP SCL
        CLR     C                               ;SET COMPLETION CODE
        RET
;----------------------------------------------------------------------------

REC_BYTE:

        ;RECEIVE A BYTE OVER THE I2C BUS
        ;ACC CONTAINS RECEIVED BYTE
        ;CY IS DUMMIED UP WITH A 0

        MOV     R1,#8                           ;8 BITS TO RECEIVE

RB1:
        SET_SCL                                 ;SCL HIGH
        MOV     C,SDA                           ;PICK BIT OFF A PIN
        RLC     A
        CLEAR_SCL                                 ;SCL LOW
        DJNZ    R1,RB1                          ;MORE BITS TO RECEIVE?
        CLR     C                               ;MUST COMPLETE OK
        RET
                                                        
;----------------------------------------------------------------------------
;       TRANMIT ADDRESS AND DATA REGISTERED BYTE OVER I2C BUS
;       R7 CONTAINS SLAVE ADDRESS
;       R5 CONTAINS REGISTER ADDRESS
;       R3 CONTAINS DATA BYTE
;       CY = 0 IF SEQUENCE COMPLETES
;       CY = 1 IF UNABLE TO TRANSMIT
;----------------------------------------------------------------------------

XD_FAULT:                                       ;BUS FAULTL

        SETB    C                               ;SET ERROR CODE            
        RET

WRITE_I2C_REGISTER:

        JNB     SCL,XD_FAULT
        JNB     SDA,XD_FAULT                    ;JUMP IF BUS FAULT
        MOV     A,R7                            ;SETUP SLAVE ADDRESS
        CLR     ACC.0                           ;INDICATE WRITE OPERATION
        START                                   ;SET START CONDITION
        ACALL   XMIT_BYTE                       ;SEND SLAVE ADDRESS
        JC      XD2                             ;JUMP ON ERROR
        MOV     A,R5                            ;SETUP REGISTER ADDRESS
        ACALL   XMIT_BYTE                       ;SEND REGISTER ADDRESS
        JC      XD2                             ;JUMP ON ERROR
        MOV     A,R3                            ;SETUP DATA BYTE
        ACALL   XMIT_BYTE                       ;GO SEND

;       SET STOP CONDITION, RETURN CODE IS ALREADY IN CY

XD2:     
        STOP                                    ;SET STOP CONDITION
        RET
;----------------------------------------------------------------------------
;       TRANSMIT ADDRESS AND RECEIVE REGISTERED DATA BYTE OVER I2C BUS
;       R7      CONTAINS SLAVE ADDRESS
;       R5      CONTAINS REGISTER ADDRESS
;       CY      = 0 IF SEQUENCE COMPLETES
;       CY      = 1 IF UNABLE TO RECEIVE
;       R3      CONTAINS RECEIVED BYTE IF CY = 0
;----------------------------------------------------------------------------

RD_FAULT:

        SETB    C                               ;SET ERROR CONDITION
        RET

READ_I2C_REGISTER:

        JNB     SCL,RD_FAULT
        JNB     SDA,RD_FAULT                    ;JUMP IF BUS FAULT
        MOV     A,R7                            ;SETUP SLAVE ADDRESS
        CLR     ACC.0                           ;INDICATE READ OPERATION
        START
        PUSH    ACC
        ACALL   XMIT_BYTE                       ;SEND SLAVE ADDRESS
        POP     ACC
        JC      RD3                             ;JUMP ON ERROR
        XCH     A,R5                            ;SET UP REGISTER ADDRESS
        ACALL   XMIT_BYTE                       ;SEND REGISTER ADDRESS
        JC      RD3                             ;JUMP ON ERROR
        START                                   ;SET REPEATED START
        MOV     A,R7                            ;SETUP SLAVE ADDRESS
        SETB    ACC.0                           ;INDICATE READ OPERATION
        ACALL   XMIT_BYTE                       ;SEND SLAVE ADDRESS AGAIN
        JC      RD3                             ;JUMP ON ERROR

RD1:    
        ACALL   REC_BYTE                        ;GO RECEIVE
        MOV     R7,A                            ;STORE DATE BYTE 

;SEQUENCE COMPLETE, RETURN CODE IS ALREADY IN CY

RD2:
        SETB    SDA                             ;SET SDA IDLE
        EMIT_CLOCK                              ;EMIT CLOCK PULSE

RD3:
        STOP                                    ;SET STOP CONDITION
        RET

        END
