;I2C EEPROM 105.9 - ASM

;Jiří Čech (CEC128) LB351  Po 12:30

; Program přečte externí paměť EEPROM.V ní je jednoznačné identifikační 2bytové číslo,
; které zobrazí na 4-místném multiplexovaném displeji v hex. soustavě.


	list		p=16F877A,	R=DEC
	include		"p16f877a.inc"

	__config _BODEN_OFF & _CP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC & _DEBUG_ON & _CPD_OFF & _LVP_OFF
	errorlevel 1, -306

#define Misto		PORTA
#define Displej		PORTD
;#define ISDA		PORTC,4
;#define ISCL		PORTC,3
#define Tlacitko	PORTB,4



	cblock	0x20
	Znaky	
	Znaky1
	Znaky2
	Znaky3
	
	Pozice
	Pozice2
	
	Cekani
	Count
	Bity
	Cas
	I2CHodn
  	endc


#define I2CStarted	Bity,0
#define I2CError	Bity,1
;NASTAV KMITOCET A RYCHLOST
; base frequency
XTAL_FREQ	EQU	20000000	; OSC freq in Hz
; used for I2C calculations
#define  I2CClock    D'100000'           ; define I2C bite rate
#define  I2C_ClockValue  (((XTAL_FREQ/I2CClock)/4) -1) ; 
  	org	0h
	GOTO	Start

VratZnak:	
;	RLNCF	WREG,f,ACCESS	; 16 bitové PC, takže musíme vynásobit dvěma
  	ANDLW	0x1E		; Pozice se omezí na 30 (bezpečnostní ochrana) {0,2,4,...,30}
  	ADDWF	PCL,f	; K Program Counteru se přidá tato pozice
	RETLW	B'11000000'	; 0
	RETLW	B'11111001'	; 1
	RETLW	B'10100100'	; 2
	RETLW	B'10110000'	; 3
	RETLW	B'10011001'	; 4
	RETLW	B'10010010'	; 5
	RETLW	B'10000010'	; 6
	RETLW	B'11111000'	; 7
	RETLW	B'10000000'	; 8
	RETLW	B'10010000'	; 9
	RETLW	B'10001000'	; A
	RETLW	B'10000011'	; b
	RETLW	B'11000110'	; C
	RETLW	B'10100001'	; d
	RETLW	B'10000110'	; E
	RETLW	B'10001110'	; F

Start:	
	banksel	ADCON1		; banka registru 1
	movlw	b'00000110'	; A/D input OFF
	movwf	ADCON1
	banksel	TRISA
	MOVLW	0xC3		; PORTA má výstup RA2-RA5
	MOVWF	TRISA
	CLRF	TRISD		; PORTD jako výstupní
	MOVLW	B'10111111'
	MOVWF	TRISC

	banksel	Znaky
	MOVLW	B'11000000'	; nic
	MOVWF	Znaky
	MOVWF	Znaky+1
	MOVWF	Znaky+2
	MOVWF	Znaky+3
	CLRF	Pozice
	CLRF	Pozice+1

	CALL	I2CSetup		; Zapnout I2C


	CALL	ReadMemory		; Přečte první 2byty z i2c paměti

Opakuj:	BTFSC	Tlacitko
	GOTO	Opakuj
	
	MOVF	Pozice,W
	CALL	VratZnak
    MOVWF	Znaky
	SWAPF	Pozice,W
	CALL	VratZnak
	MOVWF	Znaky+1
	MOVF	Pozice+1,W
	CALL	VratZnak
    MOVWF	Znaky+2
	SWAPF	Pozice+1,W
	CALL	VratZnak
	MOVWF	Znaky+3
    CALL	Opakuj2
Op1:	
	MOVLW	0xFF
	CALL	Delay
;	BTFSC	Tlacitko
;	GOTO	Opakuj
;	GOTO	Op1
;---------------------------Zápis na Multiplexovaný displej-----------------------------------------------------

Opakuj2:
 	CLRF	Pozice
Opakuj3:	

	MOVLW	Znaky	; Načíst adresu proměnných
  	MOVWF	FSR	; Uložit ji do FSR1, který slouží kao ukazovátko (pointer)
	MOVF	Pozice,W
  	ADDWF	FSR	; A přičíst aktuální pozici zobrazovaného znaku

  				; Zhasnout displej,
  	movlw	0xFF
	movwf	Misto
;	SETF	Misto	; aby bylo možno měnit znaky a nedošlo k jejich překrytí

	MOVLW	0x20		; Čekání
	MOVWF	Cekani	; až se vybijou zbytkové kapacity
Cek1:
	DECFSZ	Cekani,f
	GOTO	Cek1

	MOVF	INDF,W	; Načíst znak z místa, na který se odkazujeme pomocí FSR1
	MOVWF	PORTD	; Tento znak vyslat na displej
	CALL	GetDis		; Zjisti, co je třeba vyslat na PORTA, podle toho, na které jsme pozici
	MOVWF	Misto	; Vyslat na PORTA a tím rozsvítit znak

	INCF	Pozice,f	; Zvětšit pozici, tedy jsme na dalším znaku
  	MOVLW	0x03		; Celkem 4 místa (0-3)
	ANDWF	Pozice,f	; Proto postačí AND

Cek2:
	DECFSZ	Cekani,f	; Chvilku čekat, aby měl znak dostatečnou dobu ke svícení
	GOTO	Cek2
	GOTO	Opakuj3		; Pak skočit na Opakuj 
	RETURN

GetDis:				; Tato funkce vrací hodnotu potřebnou pro rozsvícení jednoho znaku
;	RLNCF	Pozice,W,ACCESS	; 16 bitové PC, takže musíme vynásobit dvěma
  	ANDLW	0x06		; Pozice se omezí na 6 (bezpečnostní ochrana) {0,2,4,6}
  	ADDWF	PCL,f		; K Program Counteru se přidá tato pozice
  	RETLW	B'00111000'		; A podle toho se skočí na první až čtvrtou instrukci,
  	RETLW	B'00110100'		; která je návratová a vrací potřebnou hodnotu
  	RETLW	B'00101100'		; Šlo by to sice udělat přes rotace,
  	RETLW	B'00011100'		; ale takhle je to jednodušší

;--------------------------------------------------------------------------------------------------
; Zpožďovací smyčka
Delay:	MOVWF	Cas
Delay01:	
	DECFSZ	Cas,f
	GOTO	Delay01
	RETURN

; Čekání na dokončení operace I2C sběrnice
I2CWait:	
	banksel	PIR1
	BTFSS	PIR1,SSPIF	; Pokud je příznak skončení operace nastaven,
	GOTO	I2CWait		; přeskoč tuto instrukci
	BCF		PIR1,SSPIF	; Vynuluj příznak dokončení operace I2C
	RETURN

; Zapne a nakonfiguruje I2C sběrnici na 100kHz
I2CSetup:
;**************************************************************************
;I2C init
;**************************************************************************
Init_I2C
	; make sure pins are setup before calling this routine

	; setup MSSP adress register
	MOVLW	SSPADD	; get adress for synch serial port status reg
	MOVWF	FSR	; setup fsr
	MOVLW	I2C_ClockValue ; setup clock rate
	MOVWF	INDF	; and store it


	; setup MSSP status reg
	MOVLW	SSPSTAT	; get adress for synch serial port status reg
	MOVWF	FSR	; setup fsr
	MOVLW	(1<<SMP) ; enable slowrate control
	MOVWF	INDF	; and store it

	; setup MSSP control reg
	MOVLW	SSPCON	; get adress for synch serial port control reg
	MOVWF	FSR	; setup fsr
	MOVLW	((1<<SSPEN)|(1<<CKP)|(1<<SSPM3)); enable syncronous port, enable clock ,
						; I2C master mode clock = OSC/(4*(SSPADD)+1)
	MOVWF	INDF	; and set it

;	; enable MSSP interrupt
;	MOVLW	PIE1	; get adress for periphial irq's
;	MOVWF	FSR	; setup fsr
;	BSF	INDF,SSPIE  ; enable MSSP irq
;	BSF	INTCON,PEIE ; and periphial irq must also be enabled (if not already )

;	banksel	SSPCON2
;	bsf		SSPCON2,RCEN
	RETURN


; Provede podmínku START na sběrnici
I2CStart
	banksel	PIR1
	bcf		PIR1,SSPIF
	banksel	SSPCON2
	bsf		SSPCON2,SEN	;send i2c START [S] bit
	banksel	PIR1
	btfsS	PIR1,SSPIF	;start bit cycle complete?
	goto	$-1
	return	

; Provede podmínku STOP na sběrnici
I2CStop:	
	banksel	PIR1
	bcf		PIR1,SSPIF
	banksel	SSPCON2
	bsf		SSPCON2,PEN	;send i2c STOP [P] bit
	banksel	PIR1
	btfsS	PIR1,SSPIF	;start bit cycle complete?
	goto	$-1
	return	


; Vyšle byte na sběrnici
I2COut:	
	banksel	SSPBUF
	MOVWF	SSPBUF		; Vyšli W
	GOTO	I2CWait		; Čekej a konec

; Přečte byte se sběrnice
I2CIn:	
	banksel	SSPCON2
	BSF		SSPCON2,RCEN	; Enable recieve mode
	CALL	I2CWait
	MOVF	SSPBUF,W		; Přečti data z I2C do W
	MOVWF	I2CHodn			; a ulož je do I2CHodn
	BCF		SSPCON2,ACKEN	; ACK
;	CALL	I2CWait		; Čekej
	MOVF	I2CHodn,W		; I2CHodn do W (aby byl lépe zpracovatelný výsledek)
   	RETURN

; Přečte z paměti 24c08 první dva byty
ReadMemory:
	CALL	I2CStart		; I2C Start
	MOVLW	0A0h		; control byte A0h,zapis adresy
 	CALL	I2COut
	MOVLW	00h		; čtení adr 00
 	CALL	I2COut
	CALL	I2CStart	; I2C Start
	MOVLW	0A1h		; control byte A1h,čtení dat
 	CALL	I2COut
	CALL	I2CIn
	MOVWF	Pozice+1
	CALL	I2CStop

	CALL	I2CStart		; I2C Start
	MOVLW	0A0h		; control byte A0h,zapis adresy
 	CALL	I2COut
	MOVLW	01h		; čtení adr 01
 	CALL	I2COut
	CALL	I2CStart	; I2C Start
	MOVLW	0A1h		; control byte A1h,čtení dat
 	CALL	I2COut
	CALL	I2CIn
	MOVWF	Pozice
		CALL	I2CStop
	
	RETURN

  	END
