;********** i2c rutava karina ***********
RANDOM_WRITE: ; write DAT_VAL to 16-bit address ADR_HI and ADR_LO
CALL START
BCF STATUS, C ; send address byte
RLF DEV_ADR, W
IORLW h'A0'
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
MOVF ADR_HI, W ; send high byte of address
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
MOVF ADR_LO, W ; send low byte of address
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
MOVF DAT_VAL, W ; send the actual data
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
CALL STOP
RETURN
RANDOM_READ: ; reads data at location specified in ADR_HI & ADR_LO
; returns result in W .. i u I_BYTE
CALL START
BCF STATUS, C ; send address byte - write
RLF DEV_ADR, W
IORLW h'A0'
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
;MOVF ADR_HI, W ; send high and low bytes of address
;MOVWF O_BYTE
;CALL OUT_BYTE
;CALL NACK
MOVF ADR_LO, W
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
CALL START ; note there is no STOP
BCF STATUS, C
RLF DEV_ADR, W
IORLW h'A1' ; R/W set to one for read operation
MOVWF O_BYTE
CALL OUT_BYTE
CALL NACK
CALL IN_BYTE ; fetch the byte
CALL NACK
CALL STOP
;TRAX: ionako mi treba da ostane u I_BYTE! - i need it to stay in i_byte varijable
;MOVF I_BYTE, W ; return the byte in W
RETURN
; The following routines are low level I2C routines applicable to most
; interfaces with I2C devices.
IN_BYTE ; read byte on i2c bus
CLRF I_BYTE
MOVLW d'8'
MOVWF _N ; set index to 8
CALL HIGH_SDA ; be sure SDA is configured as input
IN_BIT
CALL HIGH_SCL ; clock high
BTFSS PORTA, SDA ; test SDA bit
GOTO IN_ZERO
GOTO IN_ONE
IN_ZERO
BCF STATUS, C ; clear any carry
RLF I_BYTE, F ; i_byte = i_byte << 1 | 0
GOTO CONT_IN
IN_ONE
BCF STATUS, C ; clear any carry
RLF I_BYTE, F
INCF I_BYTE, F ; i_byte = (i_byte << 1) | 1
GOTO CONT_IN
CONT_IN
CALL LOW_SCL ; bring clock low
DECFSZ _N, F ; decrement index
GOTO IN_BIT
RETURN
;;;;;;
OUT_BYTE: ; send o_byte on I2C bus
MOVLW d'8'
MOVWF _N
OUT_BIT:
BCF STATUS,C ; clear carry
RLF O_BYTE, F ; left shift, most sig bit is now in carry
BTFSS STATUS, C ; if one, send a one
GOTO OUT_ZERO
GOTO OUT_ONE
OUT_ZERO:
CALL LOW_SDA ; SDA at zero
CALL CLOCK_PULSE
CALL HIGH_SDA
GOTO OUT_CONT
OUT_ONE:
CALL HIGH_SDA ; SDA at logic one
CALL CLOCK_PULSE
GOTO OUT_CONT
OUT_CONT:
DECFSZ _N, F ; decrement index
GOTO OUT_BIT
RETURN
;;;;;;
NACK: ; bring SDA high and clock
CALL HIGH_SDA
CALL CLOCK_PULSE
RETURN
ACK:
CALL LOW_SDA
CALL CLOCK_PULSE
RETURN
START:
CALL LOW_SCL
CALL HIGH_SDA
CALL HIGH_SCL
CALL LOW_SDA ; bring SDA low while SCL is high
CALL LOW_SCL
RETURN
STOP:
CALL LOW_SCL
CALL LOW_SDA
CALL HIGH_SCL
CALL HIGH_SDA ; bring SDA high while SCL is high
CALL LOW_SCL
RETURN
CLOCK_PULSE: ; SCL momentarily to logic one
CALL HIGH_SCL
CALL LOW_SCL
RETURN
HIGH_SDA: ; high impedance by making SDA an input
BSF STATUS, RP0 ; bank 1
BSF TRISA, SDA ; make SDA pin an input
BCF STATUS, RP0 ; back to bank 0
CALL DELAY_SHORT
RETURN
LOW_SDA:
BCF PORTA, SDA
BSF STATUS, RP0 ; bank 1
BCF TRISA, SDA ; make SDA pin an output
BCF STATUS, RP0 ; back to bank 0
CALL DELAY_SHORT
RETURN
HIGH_SCL:
BSF STATUS, RP0 ; bank 1
BSF TRISA, SCL ; make SCL pin an input
BCF STATUS, RP0 ; back to bank 0
CALL DELAY_SHORT
RETURN
LOW_SCL:
BCF PORTA, SCL
BSF STATUS, RP0 ; bank 1
BCF TRISA, SCL ; make SCL pin an output
BCF STATUS, RP0 ; back to bank 0
CALL DELAY_SHORT
RETURN
;**** Pauze i2c
DELAY_SHORT: ; provides nominal 25 usec delay
MOVLW d'5'
MOVWF LOOP2
DELAY_SHORT_1:
NOP
DECFSZ LOOP2, F
GOTO DELAY_SHORT_1
RETURN
DELAY_LONG:
MOVLW d'250' ; 250 msec delay
DELAY_N_MS:
MOVWF LOOP1
OUTTER:
MOVLW d'110' ; close to 1.0 msec delay when set to .110
MOVWF LOOP2
INNER:
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ LOOP2, F ; decrement and leave result in LOOP2
; skip next statement if zero
GOTO INNER
DECFSZ LOOP1, F
GOTO OUTTER
RETURN