LIST P=16F74
#INCLUDE "P16F74.INC"

CBLOCK	0X20
	KIOLVASOTT
ENDC

CBLOCK	0X70
	W_TMP			; Must be in common ram
	STA_TMP
	Temp
	Delay1
	Delay2
ENDC

ORG	0
	nop
    goto    Startup ;
    nop             ; 0x0002
    nop             ; 0x0003

ORG	4
ISR
	MOVWF	W_TMP
	swapf	STATUS,W
	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.

	swapf	STA_TMP,W
	MOVWF	STATUS
	SWAPF	W_TMP,F
	SWAPF	W_TMP,W
	RETFIE



Startup
    call    Setup
Main
    goto    Main

;---------------------------------------------------------------------
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

    banksel SSPADD
    movlw   B'10100000'
    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

	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 discarded!
	btfss	STATUS,Z	    ; Are we in State1?
	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.
	banksel KIOLVASOTT
	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'250'
	MOVWF	Delay2
RIDO2:
	MOVLW	H'FF'			;D'255'
	MOVWF	Delay1
RIDO1:
	DECFSZ	Delay1,f
	GOTO	RIDO1			;Delay1 <> 0
	DECFSZ	Delay2,f
	GOTO	RIDO2			;Delay2 <> 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
;---------------------------------------------------------------------

ReadI2C
	banksel	SSPBUF
	movf	SSPBUF,W	; Get the byte and put in W
	return

end