;***********************************************************************

; compact I2C eeprom access code V1.0
; (C) Mike Harrison 1998
; example code for PIC12C508
;------------------------------------------------------- workspace
cnt equ 08   	; byte count register
flags equ 09 	; flags and bit count :
read equ 0 	; 1 to read bytes, 0 to write
addr equ 1 	; 0 to send eeprom address byte
rden equ 2 	; 1 to enable read next cycle
           	; b5-7 used as bit counter

temp equ 0a  	; read/write data byte
eeadr equ 0b 	; eeprom address

iiport equ gpio  	; port address
sclbit equ 4 		; SCL port pin (no pullup required)
sdabit equ 5 		; SDA port pin (10K pullup to Vdd required)

lotris equ b'00101'	; TRIS setting with SCL and SDA outputs, other bits as required by application

hitris equ lotris+(1<<sdabit)


; calling examples :
;to read 3 bytes from eeprom addr 10..12 to registers 14..16 
; movlw 10
; movwf eeadr
; readee 3,14 

;to write 5 bytes from registers 19..1d to eeprom address 0
; clrf eeadr
; writeee 5,19


;--------------------------------------------------- calling macros

; to simplify parameter set-up, you can call the code using the following macros

readee macro bytes,address
 ; usage : readee <no. of bytes to read>, <RAM address to read to>
 
 movlw address-3 ; FSR offset due to unconditional increment
 movwf fsr
 movlw 0ef - bytes ; 2 writes (control, address) + n+1 reads (control,data) 
 call do_iic
 endm
 
writeee macro bytes,address
 ; usage : writeee <no. of bytes to write>, <RAM address to write from>

 movlw address-1 
 movwf fsr
 movlw 0e0 - (bytes <<4) ; n+2 writes (control,address,data), no reads
 call do_iic
 endm

;-----------------------------------------------------------do_iic
do_iic ; read/write byte(s) to I2C EEPROM
       ; W & FSR to be setup as follows : 
       ; read  : EF - nbytes      FSR = RAM address-1 
       ; write : E0 - (nbytes<<4) FSR = RAM address-3 
       ; eeadr holds eeprom address (preserved on exit)
       ; on exit, FSR points to the byte after the last one read/written
       ; nbytes can be up to 14, but eeprom write cache may limit this
       
 movwf cnt
retry_iic
 clrf flags ; initialise flags and bit count
phaseloop
  movlw hitris 
  tris iiport 		; ensure SDA high
  bsf iiport,sclbit  	; SCL high
  bcf iiport,sdabit 	; ensure SDA o/p reg low
  movlw lotris
  goto $+1			; ensure Tsu:sta - can be omitted in fast mode
  tris iiport 			; sda low - start condition


  movlw iiadr 			; IIC control byte (write)
  btfsc flags,rden
  movlw iiadr+1 		; .. or read control byte if read pending
  movwf temp    		; IIC control byte 
  bcf iiport,sclbit     ; scl low - code above ensures Thd:sta


byteloop        		;
								; start of byte read/write section
    movlw lotris  
    btfss flags,read 			; set SDA high (tri-state) if reading
    btfsc temp,7     			; set SDA low only if writing and data bit = 0
    movlw hitris     			; (sda o/p register bit will be low)
    tris iiport     
    goto $+1          					; wait set-up time          
    bsf iiport,sclbit 					; clock high (may set SDA o/p reg bit high)
    clc									; used later - done here for timing
    movlw 0ff^(1<<sclbit)^(1<<sdabit)  	; mask to clear SDA and SCL, "   "
    btfsc iiport,sdabit        			; test SDA input for read
    sec					      
    andwf iiport						; SCL low, SDA o/p reg bit low
    rlf temp 							; shift read data in or write data out    
    movlw 020
    addwf flags 						; increment bitcount in b5-7
    skpc
    goto byteloop						; do 8 bits
   movlw 0f0
   xorwf cnt,w				; last byte of read ? Z set if so
   movlw lotris				; ack low if reading to send ack to eeprom
   skpz					; ..but no ack on last byte of read
   btfss flags,read			;
   movlw hitris				; ack high for write to test ack from eeprom
   tris iiport
   bsf iiport,sclbit    		; clock high to get or send ack bit
   goto $+1 				; wait ack pull-up time
   movlw 0ff^(1<<sclbit)^(1<<sdabit) 	; SDA/SCL low mask, done here to add delay
   skpz					; last byte of read - skip retry  
   btfss iiport,sdabit  		; read ack bit state 
   goto no_retry_iic			
   goto retry_iic			; retry if ack high (will be forced low on reads, except last byte)
no_retry _iic
   andwf iiport				; set scl and sda o/p register bit low
  ;.....................  end of byte read/write section
   movf temp,w
   btfsc flags,read
   movwf indf 			; store data if reading
   movf indf,w			; get write data
   incf fsr 			; increment RAM pointer
   
   btfss flags,addr
   movf eeadr,w			; load eeprom address if not disabled 
   movwf temp			; byte to send next loop - address or data
   bsf flags,addr       ; disable address flag
   btfsc flags,rden		; read mode pending?
   bsf flags,read		; set read mode
   
   movlw 010
   addwf cnt			; increment byte counter in B4..7
   skpnz               
   goto done  			; both nibbles zero - all done
   skpc				; c set if b7-4 now clear - write phase done
   goto byteloop
   bsf flags,rden       ; set 'read pending' flag
   swapf cnt            ; load byte counter with read byte count
   goto phaseloop		; do second phase of command

done 
						; do stop condition				
  movlw lotris			; (SDA o/p bit will be low)
  tris iiport 			; set SDA low
  bsf iiport,sclbit		; scl high
  goto $+1				; ensure Tsu:sto
  goto $+1				; both these can be omitted for fast mode
  movlw hitris			
  tris iiport			; sda high
  retlw 0

