; I2CM.ASM ;*************************************************************************** ;* Listing du 09/05/2002 * ;* Permet au PIC16F84 de communiquer sur un bus i2c en tant que composant * ;* Maitre * ;* * ;* m6m * ;* (o o) * ;* <======oOO==(_)==OOo======> * ;* * ;*************************************************************************** List P=16c84 Include p16c84.inc ;--------------- Equivalents utilis‚s pour la transmition i2c ------------- ;_I2CM_sda EQU 0 ;Ligne RB0/INT , ligne de donnée du bus I2C ;_I2CM_scl EQU 1 ;Ligne RB1 , Ligne d'horloge du bus I2C ;ifndef INDF ; #include "pic16F876" ;endif IFNDEF _RAM vars equ 0ch _RAM equ vars _RAM1 equ vars+1 _RAM2 equ vars+2 _RAM3 equ vars+3 _RAM4 equ vars+4 _RAM5 equ vars+5 _RAM6 equ vars+6 _RAM7 equ vars+7 _FLAGS equ vars+8 ENDIF _I2CM_Control equ _RAM ; Port number (0-2). _I2CM_EEADRH equ _RAM1 ; Port number (0-2). _I2CM_EEADRL equ _RAM2 ; Port number (0-2). _I2CM_EEDATA equ _RAM3 ; Port number (0-2). _I2CM_pin_sda equ _RAM4 ; Pin number (0-7). _I2CM_pin_scl equ _RAM5 ; Pin number (0-7). _I2CM_port equ _RAM6 ; Port number (0-2). _I2CM_RCVSTAT equ 7 ; _Flags last byt rx/tx _I2CM_R/W equ 6 ; _Flags R/W _I2CM_ACQ equ 4 ; _Flags Acquit _I2CM_INIT bcf STATUS,RP1 ; bank 0 bcf STATUS,RP0 ; bank 0 bcf _FLAGS, _I2CM_RCVSTAT ; dele last byte flag MOVF _I2CM_pin_scl,w ANDLW 7 CALL _Pinz ; Get bit mask from the table. MOVWF _I2CM_pin_scl ; Put the mask into pin. MOVF _I2CM_pin_sda,w ANDLW 7 CALL _Pinz ; Get bit mask from the table. MOVWF _I2CM_pin_sda ; Put the mask into pin. MOVLW 5h ; Add offset for port RA. ADDWF _I2CM_port,f movf _I2CM_port,w ; suprimer car sur le 876 OPTION_REG est en bank1 ; movwf FSR ; sublw 6 ; test if Portb ; btfsc STATUS,z ; if yes then ; bcf OPTION_REG,7 ; make sure weak pull-up is on movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) comf _I2CM_pin_scl,w ; make scl as an output andwf INDF,f movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) return ; ; - read modified to do sequential read ; ;###################################################### ; EEPROM READ/WRITE ROUTINE ;###################################################### ; Used reg: EEADRL, EEDATA,RCVSTAT,W ; IN : W= READ ADRESS ; OUT : W= BYTE _I2CM_R/W_EE MOVWF _I2CM_EEADRL ; store byte in reg EEADR movf _I2CM_port,w movwf FSR _I2CM_R/W_EE_DIR CALL _I2CM_BSTART ; generate start bit BCF STATUS,CY ; WRITE SEQUENCE CALL _I2CM_CONTROL_BYT ; CALC CONTROL BYTE AND TRANSMIT ; 24C16 ou PCF8583 ; MOVF _I2CM_EEADRH,W ;GET WORD high ADRESS ; CALL _I2CM_TX ;WRITE @ ADRESS COUNTER MOVF _I2CM_EEADRL,W ; get word low address.... _I2CM_R/W_EE1 CALL _I2CM_TX ; and send it ; btfsc _FLAGS,_I2CM_RCVSTAT ;if lastbyte then ; GOTO _I2CM_BSTOP ; END READ SEQUENCE return _I2CM_R/W_CURRENT CALL _I2CM_BSTART ; generate start bit BSF STATUS,CY ; READ SEQUENCE btfss _FLAGS,_I2CM_R/W ; Test if R or W BCF STATUS,CY ; Write SEQUENCE CALL _I2CM_CONTROL_BYT ; CALC CONTROL BYTE AND TRANSMIT btfsc _FLAGS,_I2CM_R/W ; Test if R or W GOTO _I2CM_RX ; read 1 byte from serial EE GOTO _I2CM_TX ; write 1 byte to serial EE ; ;********************************************** ; GENERATE CONTROL BYTE ;********************************************** _I2CM_CONTROL_BYT movf _I2CM_port,w movwf FSR RLF _I2CM_EEADRH,W ; => CY=1 ANDLW B'00000001' ; Keep just R/W bit IORWF _I2CM_control,w ; Complet with control ; ANDLW B'00001111' ;MASK OUT UPPER NIBBLE ; IORLW B'10100000' ;COMPLETE BYTE 1010AAAD ;A=ADRESS D=DIRECTION ;SEND CONTROL BYTE ;********************************************** ; TRANSMIT DATA SUBROUTINE ;********************************************** _I2CM_TX MOVWF _I2CM_EEDATA ;STORE BYTE TO TX _I2CM_TX2 movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) comf _I2CM_pin_sda,w ; sda = 0 andwf INDF,f ; set data,clock as outputs movlw 07fh ; set bank 0 (Indexed Mode) andwf FSR,f CALL _I2CM_TX4 ;TRANSMIT 8 TIMES CALL _I2CM_TX4 call _I2CM_BItAcq ; _I2CM_BITIN return _I2CM_TX4 CALL _I2CM_TXLP CALL _I2CM_TXLP CALL _I2CM_TXLP _I2CM_TXLP RLF _I2CM_EEDATA,F ; ROTATE BIT TO CARRY goto _I2CM_BITOUT_R ; send the bit to serial EE ;********************************************** ; RECEIVE DATA SUBROUTINE ;********************************************** _I2CM_RX movf _I2CM_port,w _I2CM_RX2 movwf FSR movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) MOVF _I2CM_pin_sda,w ; Get the pin mask. IORWF INDF,f ; make SDATA an input line/SCLK = OU movlw 07fh ; set bank 0 (Indexed Mode) andwf FSR,f CALL _I2CM_RX4 CALL _I2CM_RX4 ; btfss _FLAGs,_I2CM_RCVSTAT ; if not last byte then bcf STATUS,CY ; set Ack=0 btfsc _FLAGs,_I2CM_RCVSTAT ; else BSF STATUS,CY ; SET ACK BIT=0 Ack OK GOTO _I2CM_BITOUT ; TO FINISH TRANSMISSION _I2CM_RX4 CALL _I2CM_RXLP CALL _I2CM_RXLP CALL _I2CM_RXLP _I2CM_RXLP CALL _I2CM_BITIN_R ; READ A BIT RLF _I2CM_EEDATA,F ; SHIFT CARRY TO BYTE RETURN ;********************************************* ; START BIT SUBROUTINE ;********************************************* _I2CM_BSTART movf _I2CM_port,w movwf FSR MOVF _I2CM_pin_sda,w ; Get the pin mask. IORWF INDF,f ; make sure data is high comf _I2CM_pin_sda,w ; sda = 0 IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) andwf INDF,f ; set data and clock lines for output movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) MOVF _I2CM_pin_scl,w ; Get the pin mask. IORWF INDF,f ; set clock high comf _I2CM_pin_sda,w andwf INDF,f ; data line goes low during IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF GOTO _I2CM_BC_END ; high clock for start bit ;********************************************** ; STOP BIT SUBROUTINE ;********************************************** _I2CM_BSTOP comf _I2CM_pin_sda,w andwf INDF,f ; make sure data line is low IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) comf _I2CM_pin_sda,w andwf INDF,f ; set data/clock lines as outputs movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) MOVF _I2CM_pin_scl,w ; Get the pin mask. IORWF INDF,f ; set clock line high IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF MOVF _I2CM_pin_sda,w ; Get the pin mask. IORWF INDF,f ; data goes high while clock high ; for stop bit _I2CM_B_END IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF ; NOP _I2CM_BC_END comf _I2CM_pin_scl,w andwf INDF,f ; set clock low again IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF RETURN ;********************************************** ; BITOUT ROUTINE , SEND BIT WHEN CARRY SET ;********************************************** _I2CM_BITOUT movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) comf _I2CM_pin_sda,w ; sda =0 andwf INDF,f ; set data,clock as outputs IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) _I2CM_BITOUT_R BTFSc STATUS,CY ; check for state of data bit to xmit goto _I2CM_BITOUT_R1 comf _I2CM_pin_sda,w ; SDA = 0 andwf INDF,f ; set data line low goto _I2CM_CLKOUT _I2CM_BITOUT_R1 MOVF _I2CM_pin_sda,w ; Get the pin clk mask. IORWF INDF,f ; high? set data line high _I2CM_CLKOUT MOVF _I2CM_pin_scl,w ; Get the pin clk mask. IORWF INDF,f ; set bit. IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF GOTO _I2CM_B_END ;********************************************** ; BITIN ROUTINE ;********************************************** _I2CM_BITIN movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) movf _I2CM_pin_sda,w ; make SDATA an input line/SCLK = OUT iorwf INDF,f IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) _I2CM_BITIN_R MOVF _I2CM_pin_scl,w ; Get the pin clk mask. IORWF INDF,f ; set clock line high IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movf INDF,w ; read the port ANDWF _I2CM_pin_sda ; mask the data bit BSF STATUS,CY ; assume input bit is high BTFSc STATUS,z ; Test if the data bit = 0 BCF STATUS,CY ; Yes, input bit was low ,clear CARRY GOTO _I2CM_BC_END ;********************************************** ; BITAcq ROUTINE ;********************************************** _I2CM_BItAcq clrf _I2CM_EEADRH ; 255 loop for test Ack OK movlw 080h iorwf FSR,f ; set bank 1 (Indexed Mode) movf _I2CM_pin_sda,w ; make SDATA an input line/SCLK = OUT iorwf INDF,f IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF movlw 07fh andwf FSR,f ; set bank 0 (Indexed Mode) _I2CM_BITIN_R MOVF _I2CM_pin_scl,w ; Get the pin clk mask. IORWF INDF,f ; set clock line high movf INDF,w ; read the port ANDWF _I2CM_pin_sda ; mask the data bit BSF STATUS,CY ; assume input bit is high BTFSc STATUS,z ; Test if the data bit = 0 goto _I2CM_ACKOK IFDEF X20MHZ call Wait_10 ENDIF IFNDEF X20MHZ call Wait_04 ENDIF decf _I2CM_EEADRH,f btfss status,Z goto _I2CM_BITIN_R _I2CM_NoACK BSF STATUS,CY ; Yes, input bit was low ,clear CARRY GOTO _I2CM_BC_END _I2CM_ACKOK BCF STATUS,CY ; Yes, input bit was low ,clear CARRY GOTO _I2CM_BC_END Wait_10 ; pour 4Mhz ; nop ; nop call Wait_02 ; pour 20Mhz goto Wait_08 Wait_08 call Wait_04 goto Wait_04 Wait_06 call Wait_02 goto Wait_04 Wait_04 ; return ; pour 4Mhz nop nop ;nop ;nop ;nop ;nop ;nop ;nop ;nop ;nop Wait_02 ;nop ;nop ;nop ;nop ;nop nop return