LIST P=16F74	
#INCLUDE "P16F74.INC"

CBLOCK	0X20
W_TMP
STA_TMP
Temp
KIOLVASOTT
ENDC

ORG	0
    goto    Startup ;
    nop             ; 0x0002
    nop             ; 0x0003
ORG	4
    goto    ISR     ; 0x0004



Startup
    call    Setup
Main 
    goto    Main 

ISR
BANKSEL	PORTC
BSF		PORTC,1
banksel SSPCON
MOVWF	W_TMP
MOVF	STATUS,W
BCF	STATUS,RP0
BCF	STATUS,RP1
MOVWF	STA_TMP
    banksel PIR1
    btfss   PIR1,SSPIF  ; Is this a SSP interrupt?
    goto    $           ; No, just trap here.
    bcf     PIR1,SSPIF
    call    SSP_Handler ; Yes, service SSP interrupt.
BCF	STATUS,RP0
BCF	STATUS,RP1
MOVF	STA_TMP,W
MOVWF	STATUS
SWAPF	W_TMP,F
SWAPF	W_TMP,W
RETFIE
;---------------------------------------------------------------------
Setup
	BANKSEL	TRISC
	CLRF	TRISC	
	BSF		TRISC,3
	BSF		TRISC,4
	BANKSEL	PIR1
    clrf    PIR1
	banksel SSPCON
    MOVLW	B'00101110'      ; Setup SSP module for 7-bit
    movwf   SSPCON      ; address, slave mode
    movlw   B'10100000'
    banksel SSPADD
    movwf   SSPADD
	banksel	SSPSTAT
    clrf    SSPSTAT
    banksel PIE1        ; Enable interrupts
    bsf     PIE1,SSPIE

	BANKSEL	INTCON
    bsf     INTCON,PEIE ; Enable all peripheral interrupts
    bsf     INTCON,GIE  ; Enable global interrupts
    bcf     STATUS,RP0
	BANKSEL	PORTC
	CLRF	PORTC

    return

SSP_Handler; Code is adapted from Microchip AN734A


	banksel	SSPSTAT
	movf	SSPSTAT,W		; Get the saved value of SSPSTAT
	andlw	b'00100101'	      ; Mask out unimportant bits in SSPSTAT. (WAS: 00101101 in AN734A!)
	banksel	Temp		; Put masked value in Temp
	movwf	Temp		      ; for comparision checking.

;										SPSTAT BITS: SMP | CKE | D_A | P | S | R_W | UA | BF

State1:				; Write operation, last byte was an
	movlw	b'00000001'	      ; address, buffer is full.			(WAS 00001001 in AN734A!)
	xorwf	Temp,W		; 							but works only if S bit is
	btfss	STATUS,Z	      ; Are we in State1?				discarded!
	goto	State2		; No, check for next state.....
	
	call	ReadI2C
		; Do a dummy read of the SSPBUF.
	return
	
State2:			; Write operation, last byte was data,
	movlw	b'00100001'	; buffer is full.						(WAS 00101001 in AN734A!)
	xorwf	Temp,W
	btfss	STATUS,Z	; Are we in State2?
	goto	State5	; No, check for next state.....
		
	call	ReadI2C	; Get the byte from the SSP.
	MOVWF	KIOLVASOTT	; save received byte

	return
	


State5:
	movlw	b'00100000'	; A NACK was received when transmitting (WAS 00101000 in AN734A!)
	xorwf	Temp,W	; data back from the master.  Slave logic
	btfss	STATUS,Z	; is reset in this case.  R_W = 0, D_A = 1
	goto	I2CErr	; and BF = 0
	banksel	SSPCON
	bsf	SSPCON, CKP ; Release clock (this is not from AN734A
	return		; but a tip I got from Robert Soubie and Alan B. Pearce)		

I2CErr				; If we aren’t in State5, then something is 
	banksel	PORTB		; wrong!  FLASH LED slowly
	clrf	PORTA
	clrf	PORTB
	bsf	PORTC,0
	call	WAIT_100MSEC
	bcf	PORTC,0
	CALL	WAIT_100MSEC
	goto	$-4
	
WAIT_100MSEC
	MOVLW	D'250'			;D'50'	
	MOVWF	0X7C		
RIDO2:	MOVLW	H'FF'			;D'256'	
	MOVWF	0X7D
RIDO1:	DECFSZ	0X7D,1			
	GOTO	RIDO1			;0X7D <> 0
	DECFSZ	0X7C,1
	GOTO	RIDO2			;0X7C <> 0
RETURN

;FFLED
;	banksel	PORTB		; Unknown interrupt!  FLASH LED fast
;	clrf	PORTA
;	clrf	PORTB
;	bsf	PORTA,3
;	call	WAIT_10MSEC
;	bcf	PORTA,3
;	CALL	WAIT_10MSEC
;	goto	$-4		
;---------------------------------------------------------------------
; WriteI2C
;---------------------------------------------------------------------

WriteI2C
	banksel	SSPSTAT
	btfsc	      SSPSTAT,BF	; Is the buffer full?
	goto	      WriteI2C	; Yes, keep waiting.
	banksel	SSPCON	; No, continue.
DoI2CWrite
	bcf		SSPCON,WCOL	; Clear the WCOL flag.
	movwf	      SSPBUF	; Write the byte in WREG
	btfsc	      SSPCON,WCOL	; Was there a write collision?
	goto	      DoI2CWrite
	NOP
	NOP
	NOP
	NOP
	NOP
	bsf	      SSPCON,CKP	; Release the clock.
	return

;---------------------------------------------------------------------
ReadI2C
;---------------------------------------------------------------------
	
	banksel	SSPBUF
	movf	SSPBUF,W	; Get the byte and put in W
	return

end