;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ě.


#include p18F452.inc

#define Misto		PORTA
#define Displej		PORTD
#define ISDA		PORTC,4
#define ISCL		PORTC,3
#define Tlacitko	PORTB,4



	cblock	0x00
  Znaky:4
  Pozice:2
  Cekani
  Count
  Bity
  Cas
  I2CHodn
  	endc


#define I2CStarted	Bity,0
#define I2CError	Bity,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,ACCESS	; 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:	MOVLW	0x07		; PORTA bude digitální
	MOVWF	ADCON1,ACCESS
	MOVLW	0xC3		; PORTA má výstup RA2-RA5
	MOVWF	TRISA,ACCESS
	CLRF	TRISD,ACCESS	; PORTD jako výstupní
	MOVLW	B'10111111'
	MOVWF	TRISC,ACCESS

	MOVLW	B'11000000'	; nic
	MOVWF	Znaky,ACCESS
	MOVWF	Znaky+1,ACCESS
	MOVWF	Znaky+2,ACCESS
	MOVWF	Znaky+3,ACCESS
	CLRF	Pozice,ACCESS
	CLRF	Pozice+1,ACCESS

	CALL	I2CSetup		; Zapnout I2C


	CALL	ReadMemory		; Přečte první 2byty z i2c paměti

Opakuj:	BTFSC	Tlacitko,ACCESS
	GOTO	Opakuj
	
	MOVF	Pozice,W,ACCESS
	CALL	VratZnak
          MOVWF	Znaky,ACCESS
	SWAPF	Pozice,W,ACCESS
	CALL	VratZnak
	MOVWF	Znaky+1,ACCESS
	MOVF	Pozice+1,W,ACCESS
	CALL	VratZnak
          MOVWF	Znaky+2,ACCESS
	SWAPF	Pozice+1,W,ACCESS
	CALL	VratZnak
	MOVWF	Znaky+3,ACCESS
          CALL	Opakuj2
Op1:	MOVLW	0xFF
	CALL	Delay
;	BTFSC	Tlacitko
;	GOTO	Opakuj
;	GOTO	Op1
;---------------------------Zápis na Multiplexovaný displej-----------------------------------------------------

Opakuj2:
 	CLRF	Pozice,ACCESS
Opakuj3:	MOVLW	Znaky	; Načíst adresu proměnných
  	MOVWF	FSR1L,ACCESS	; Uložit ji do FSR1, který slouží kao ukazovátko (pointer)
	CLRF	FSR1H,ACCESS
	MOVF	Pozice,W,ACCESS
  	ADDWF	FSR1L,f,ACCESS	; A přičíst aktuální pozici zobrazovaného znaku

  				; Zhasnout displej,
  	SETF	Misto,ACCESS	; aby bylo možno měnit znaky a nedošlo k jejich překrytí

	MOVLW	0x20		; Čekání
	MOVWF	Cekani,ACCESS	; až se vybijou zbytkové kapacity
Cek1:	DECFSZ	Cekani,f,ACCESS
	GOTO	Cek1

	MOVF	INDF1,W,ACCESS	; Načíst znak z místa, na který se odkazujeme pomocí FSR1
	MOVWF	PORTD,ACCESS	; Tento znak vyslat na displej
	CALL	GetDis		; Zjisti, co je třeba vyslat na PORTA, podle toho, na které jsme pozici
	MOVWF	Misto,ACCESS	; Vyslat na PORTA a tím rozsvítit znak

	INCF	Pozice,f,ACCESS	; Zvětšit pozici, tedy jsme na dalším znaku
  	MOVLW	0x03		; Celkem 4 místa (0-3)
	ANDWF	Pozice,f,ACCESS	; Proto postačí AND

Cek2:	DECFSZ	Cekani,f,ACCESS	; 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,ACCESS	; 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,ACCESS
Delay01:	DECFSZ	Cas,f,ACCESS
	GOTO	Delay01
	RETURN

; Čekání na dokončení operace I2C sběrnice
I2CWait:	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:	MOVLW	38h		; Not ACK, ACK enable, I2C enable
	MOVWF	SSPCON1,ACCESS
	BCF	I2CStarted,ACCESS	; Ještě není zapnutá I2C
	BCF	I2CError,ACCESS	; Nebyla chyba
	MOVLW	80h		; 100kHz hodiny, disable SMBus
	MOVWF	SSPSTAT,ACCESS
	CLRF	SSPCON2,ACCESS	; Vše vynulovat
	MOVLW	2Dh		; Rychlost 100kHz
	MOVWF	SSPADD,ACCESS
	BTFSC	ISDA,ACCESS	; Je-li sběrnice volná,
	RETURN			; pak konec
	MOVLW	0E7h		; Jinak zrušit I2C
	ANDWF	PORTC,f,ACCESS	; a porty nakonfigurovat jako výstupní
	BCF	SSPCON1,SSPEN,ACCESS
	MOVLW	09h		; 9 krát blikneme hodinami
	MOVWF	Count,ACCESS	; A tak se pokusíme uvolnit zablokovanou sběrnici
I2CSet01:	BCF	TRISC,3,ACCESS	; TRISC - ISCL do nuly, tím se zapojí výstup
	MOVLW	D'240'		; Chvilku počkat (5ms)
	CALL	Delay
	BSF	TRISC,3,ACCESS	; Uvolnit sběrnici ISCL
	MOVWF	D'240'
	CALL	Delay
	BTFSC	ISDA,ACCESS	; Je-li sběrnice volná
	GOTO	I2CSet02		; Skoč na její zapnutí
	DECFSZ	Count,f,ACCESS	; To zkus znovu (9x maximálně)
	GOTO	I2CSet01
I2CSet02:	BSF	SSPCON1,SSPEN,ACCESS; Zapni I2C
	RETURN			; Konec

; Provede podmínku START na sběrnici
I2CStart:	BTFSS	I2CStarted,ACCESS	; Jestli nejsme nastartovaný
	GOTO	I2CSta01		; Skok na start
	BSF	SSPCON2,RSEN,ACCESS	; Udělej podmínku "ReStart"
	GOTO	I2CSta02		; Pokračuj
I2CSta01:	BTFSS	ISDA,ACCESS	; Pokud je sběrnice obsazená
	GOTO	I2CSta03		; Odskok
	BTFSS	ISCL,ACCESS
	GOTO	I2CSta03
	BSF	SSPCON2,SEN,ACCESS	; Udělej podmínku "Start"
I2CSta02:	BSF	I2CStarted,ACCESS	; Nastav informaci, že jsme nyní nastartovali
	GOTO	I2CWait		; Čekej na dokončení operace a navrať se
I2CSta03:	BSF	I2CError,ACCESS	; Došlo k I2C chybě
	RETURN			; Konec

; Provede podmínku STOP na sběrnici
I2CStop:	BSF	SSPCON2,PEN,ACCESS	; Podmínka "Stop"
	BCF	I2CStarted,ACCESS	; Zastaveno
	GOTO	I2CWait		; Čekej a konec

; Vyšle byte na sběrnici
I2COut:	MOVWF	SSPBUF,ACCESS	; Vyšli W
	GOTO	I2CWait		; Čekej a konec

; Přečte byte se sběrnice
I2CIn:	BSF	SSPCON2,RCEN,ACCESS	; Enable recieve mode
	CALL	I2CWait
	MOVF	SSPBUF,W,ACCESS	; Přečti data z I2C do W
	MOVWF	I2CHodn,ACCESS	; a ulož je do I2CHodn
	BCF	SSPCON2,ACKEN,ACCESS; ACK
;	CALL	I2CWait		; Čekej
	MOVF	I2CHodn,W,ACCESS	; 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
