; Rutina obsluhy externí EEPROM
; Krystal 4MHz
; Power by M.Supík 2011

LIST P=16F628A,R=DEC 
INCLUDE<P16F628A.INC>  

;------------------------------------------------------------------------------
; Definice registrů
;------------------------------------------------------------------------------

EEPROM_ADRESA_H		EQU		21h			; Horních 8 bitů adresy zápisu/čtení
EEPROM_ADRESA_L		EQU		22h			; Dolních 8 bitů adresy zápisu/čtení
EEPROM_DATA			EQU		23h			; Data pro zápis do EEPROM
I2C_ERR				EQU		24h			; NO ACK - pokud 1 = chyba zápisu

ZNAK				EQU		25h			; RS232 - Zobrazovaný znak 

TMP0				EQU		26h			; Čekací smyčka
TMP1				EQU		27h			; Čekací smyčka
TMP2				EQU		28h			; Čekací smyčka
TMP3				EQU		29h			; Čekací smyčka

;------------------------------------------------------------------------------
; !!! Musí být adresovány od adresy 70h !!!
; !!! Tyto adresy jsou zrcadleny v obou bankách !!!
;------------------------------------------------------------------------------

I2C_DATA			EQU		71h			; Data pro zápis na sběrnici
I2C_BITS			EQU		72h			; Počet odesílaných bitů ( počet opakování zápisu/čtení )

;------------------------------------------------------------------------------
; Definice portů
;------------------------------------------------------------------------------

#define	SDA			PORTA,6					; I2C - data - 1 vstup, 0 výstup
#define	SCL			PORTA,7					; I2C - hodiny - 1 vstup, 0 výstup

;------------------------------------------------------------------------------
; Direktivita ORG
;------------------------------------------------------------------------------

	ORG 	00h
	GOTO	INI_PIC

;------------------------------------------------------------------------------
; Inicializace procesoru
;------------------------------------------------------------------------------

INI_PIC
	CLRF	PORTA				; Porty do 0
	CLRF	PORTB

	MOVLW	b'00000111'			; Komparátor OFF
	MOVWF	CMCON 

	BSF		STATUS,RP0			; Banka 1
	MOVLW	b'11000000'			; TRISA - SDA, SCL - vstupy
	MOVWF	TRISA
	MOVLW	b'00000010'			; TRISB	- RB1=RX=1
	MOVWF	TRISB
	BCF		STATUS,RP0			; Banka 0

	CALL	CEK2s

	CALL	SET_RS232			; Inicializace RS232

	MOVLW	0
	MOVWF	EEPROM_ADRESA_H		; Horních 8 bitů adresy 
	MOVLW	5
	MOVWF	EEPROM_ADRESA_L		; Dolních 8 bitů adresy
	CALL	EEPROM_WRITE_PAGE

	MOVLW	5
	MOVWF	EEPROM_ADRESA_L		; Dolních 8 bitů adresy
	CALL	EEPROM_READ_PAGE

	MOVLW	0xFF
	MOVWF	EEPROM_ADRESA_L		; Dolních 8 bitů adresy
	MOVLW	0x00
	MOVWF	EEPROM_DATA
	CALL	EEPROM_WRITE
	MOVLW	0xFF
	MOVWF	EEPROM_ADRESA_L		; Dolních 8 bitů adresy
	CALL	EEPROM_READ
	
	NOP
	GOTO 	$-1

;------------------------------------------------------------------------------
; Obsluha I2C sběrnice - externí EEprom
;------------------------------------------------------------------------------

EEPROM_WRITE_PAGE				; Zápis více dat od určené adresy do EEprom
	CALL	I2C_START			; Podprogram START sekvence
	BCF		I2C_ERR,0			; Smazat záznam chyb - NO ACK 

	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END 	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

								; Zápis více dat od určené adresy. Data se zapisují hned po sobě - bez sekvence
								; !!! Maximální zápis 32 bytů najednou - určeno pamětí !!!
								; každý další zápis automaticky zvýší adresu o 1
								; Sekvence STOP se zapisuje až nakonec
	MOVLW	1				
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVLW	2
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVLW	3
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVLW	4
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVLW	5
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_STOP			; Podprogram sekvence STOP se zapisuje až nakonec
	RETURN

EEPROM_WRITE					; Zápis jednoho byte do EEprom
	CALL	I2C_START			; Podprogram START sekvence
	BCF		I2C_ERR,0			; Smazat záznam chyb - NO ACK 

	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END 	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP


	MOVFW	EEPROM_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_DATA			; Data do W				
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_STOP			; Podprogram sekvence STOP se zapisuje až nakonec
	RETURN

EEPROM_WRITE_END
	CALL	I2C_STOP			; Pošle se STOP byte ( po NO ACK musí následovat stop bit)
	MOVLW	45h
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK
	RETURN

I2C_WRITE
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; Hodiny = 0
	MOVWF	I2C_DATA			; Odesílaná data do I2C_DATA
	MOVLW	8					; Počet odesílaných bitů - 8
	MOVWF	I2C_BITS
I2C_WRITE_BITS
	BCF		SCL					; Hodiny = 0 - při prvním bite nemá smysl
	BCF		SDA					; Data = 0
	RLF		I2C_DATA,F			; Rotace I2C_DATA přes C doleva
	BTFSC	STATUS,C			; Otestujeme C, zda je jedna 
	BSF		SDA					; ANO, odešle 1
	BSF		SCL					; Hodiny = 1
	DECFSZ	I2C_BITS			; Počet odesílaných bitů -1 ( počet opakování zápisu jednoho bite)
	GOTO	I2C_WRITE_BITS		; Opakuj odesílání
	NOP							; Odesláno 8 bite
	NOP
	BCF		SCL					; Hodiny = 0
	BSF		SDA					; Data = vstup
	NOP							; Čekej 2 us
	NOP
	BSF		SCL					; Hodiny = 1
	BCF		STATUS,RP0			; Banka 0
I2C_WRITE_OTESTUJ_ACK
	INCF	I2C_BITS			; Po dobu 255 us testuj ACK
	BTFSC	STATUS,Z
	GOTO	I2C_ERROR			; Pokud do 255 us nepřišlo potvzení ACK, ukonči zápis
	BTFSC	SDA					; Otestuj ACK, zda je 0
	GOTO	I2C_WRITE_OTESTUJ_ACK	; NE, opakuj testování
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; ANO, Hodiny = 0
	BCF		STATUS,RP0			; Banka 0
	RETURN

;------------------------------------------------------------------------------
; Podprogram čtení z externí EEprom
;------------------------------------------------------------------------------

EEPROM_READ_PAGE				; Čtení více dat z EEprom
	CALL	I2C_START			; Podprogram START sekvence
	BCF		I2C_ERR,0			; Smazat záznam chyb - NO ACK 

	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
								; !!! R/W = 0 !!! Zápis adresy
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_START			; Opakuj sekvenci START

	MOVLW	b'10100001'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
								; !!! R/W = 1 !!! Teď už čtení
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_READ			; Čtení více dat od určené adresy. Data se čtou hned po sobě s potvrzením ACK
								; Přečtená data jsou v EEPROM_DATA
								; !!! Čtení posledního byte se nepotvrzuje ACK !!!
								; Může se najednou přečíst celá EEprom
	CALL	I2C_WRITE_ACK		; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	CEK15m

	CALL	I2C_READ		
	CALL	I2C_WRITE_ACK		; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)	
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	CEK15m

	CALL	I2C_READ		
	CALL	I2C_WRITE_ACK		; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)	
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	CEK15m

	CALL	I2C_READ		
	CALL	I2C_WRITE_ACK		; Odeslání ACK bitu - 0 = pokračuj v čtení na další adrese (adresa + 1)	
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	CEK15m

	CALL	I2C_READ			; !!! Poslední čtený byte - neodesílá se ACK !!!
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	CEK15m
	
	CALL	I2C_STOP
	RETURN

EEPROM_READ						; Čtení jednoho byte z EEprom
	CALL	I2C_START			; Podprogram START sekvence
	BCF		I2C_ERR,0			; Smazat záznam chyb - NO ACK 

	MOVLW	b'10100000'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
								; !!! R/W = 0 !!! Zápis adresy
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_H		; Horních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	MOVFW	EEPROM_ADRESA_L		; Dolních 8 bitů adresy zápisu/čtení do W
	CALL	I2C_WRITE			; Odešle 1 byte
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_START			; Opakuj sekvenci START

	MOVLW	b'10100001'			; Definuje: typ zařízení XXXX0000 ( 24C64 )
								; počet zařízení 0000XXX0, ( A1, A2, A3)
								; R/W bit - 0000000X - zapis - 0, čtení - 1  
								; !!! R/W = 1 !!! Teď už čtení
	CALL	I2C_WRITE			; Odešle 1 byte na sběrnici
	BTFSC	I2C_ERR,0			; Otestuje, zda bylo odeslání byte v pořádku
	GOTO	EEPROM_WRITE_END	; Ne, ukonči zápis sekvencí STOP

	CALL	I2C_READ			; Čtení jednoho byte z EEprom do EEPROM_DATA - neodesílá se ACK !!!
	MOVFW	EEPROM_DATA
	MOVWF	ZNAK
	CALL	VYSILANI_ZNAK

	CALL	I2C_STOP
	RETURN

I2C_READ
	BSF		STATUS,RP0			; Banka 1
	BCF		SCL					; Hodiny = 0
	BSF		SDA					; Data = vstup
	MOVLW	8
	MOVWF	I2C_BITS			; Počet přijímaných bite
I2C_READ_BITS	
	BSF		SCL					; Hodiny = 1
	BCF		STATUS,RP0			; Banka 0
	RLF		EEPROM_DATA,F		; Rotace EEPROM_DATA přes C doleva
	BCF		EEPROM_DATA,0		; Vynuluje bit, přes který se bude rolovat
	BTFSC	SDA					; Otestuj SDA, zda je ve vysoké úrovni ( přijímaný bit = 1 )
	BSF		EEPROM_DATA,0		; ANO, zapiš 1 do C ( přijímaný bit = 1)
	BSF		STATUS,RP0			; Ne, v C je 0	( přijímaný bit = 0)
	BCF		SCL					; Hodiny = 0
	DECFSZ	I2C_BITS			; Odecteme 1 od čítače a pokud neni nula
	GOTO	I2C_READ_BITS		; Počet přijímaných bitů -1 - počet opakování příjmu 1 bitu - 8x
	BCF		STATUS,RP0			; Banka 0
	RETURN

;------------------------------------------------------------------------------
; Podprogram I2C
;------------------------------------------------------------------------------

I2C_START
	BSF		STATUS,RP0			; Banka 1
	BSF		SDA					; Data = 1
	BSF		SCL					; Hodiny = 1
	NOP							; Čekej 1us
	BCF		SDA					; Data = 0
	NOP							; Čekej 1us
	BCF		STATUS,RP0			; Banka 0
	BCF		SDA					; Data, hodiny do nuly 
	BCF		SCL
	RETURN
	
I2C_STOP
	BSF		STATUS,RP0			; Banka 1
	BCF		SDA					; Data = 0
	BSF		SCL					; Hodiny = 1
	NOP							; Čekej 1us
	BSF		SDA					; Data = 1
	BCF		STATUS,RP0			; Banka 0
	CALL	CEK15m
	RETURN

I2C_WRITE_ACK					; Zápis ACK po čtení byte z EEprom
	BSF		STATUS,RP0			; Banka 1
	BCF		SDA					; Data = 1
	BSF		SCL					; Hodiny = 1
	NOP					
	NOP							; Čekej 3us
	NOP
	BCF		SCL					; Hodiny = 0
	BCF		STATUS,RP0			; Banka 0
	RETURN
	
I2C_ERROR
	BSF		I2C_ERR,0			; Chyba zápisu/čtení - vyslat STOP sekvenci
	RETURN

;------------------------------------------------------------------------------
; Obsluha seriové linky
;------------------------------------------------------------------------------

SET_RS232	
	bsf		STATUS,RP0			; Banka 1
	movlw	25					; 9600b, krystal 4,00MHz, HighSpeed
	movwf	SPBRG
	movlw	b'00100110'			; 8bit, vysílání povoleno, asynchroní mod, vysoká rychlost
	movwf	TXSTA				; Nastavení vysílání !!!
	bcf		STATUS,RP0			; Banka 0

	movlw	b'10010000'			; povolen sériový port, 8bit, asynchroní mod
	movwf	RCSTA				; Nastavení příjmu !!!

	RETURN

;	bsf		TXSTA,BRGH			; BRGH=1 HighSpeed, BRGH=0 LowSpeed
;	bsf		TXSTA,TXEN			; 1=povoleno vysílání, 0=zakázáno vysílání
;	bsf		RCSTA,SPEN			; 1=povolena komunikace po RS232 (příjem i vysílání)
;	bsf		RCSTA,CREN			; 1=povolen pokračující příjem

VYSILANI_ZNAK
	btfss	PIR1,TXIF			; Testuj, zda se může vysílat
	goto	$-1					; =0, 0=buffer je plny, 1=buffer je prazdny
	MOVFW	ZNAK				; Znak do W
	movwf	TXREG				; W -> do TX registru
	RETURN

PRIJEM_ZNAK
	btfss	PIR1,RCIF			; Testuj, zda je co přijmout
	goto	$-1					; =0, 0=buffer je prazdny, 1=buffer je plny
	movf	RCREG,W				; prijmuta data -> do W
	movwf	ZNAK				; Prijmuta data do ZNAK
	RETURN

;------------------------------------------------------------------------------
; Časové smyčky
;------------------------------------------------------------------------------

CEK2s	
	movlw	20					; TMP2 = 20  cekej 2 sekundu
	movwf	TMP3
	goto	SMYCKA2

CEK100m	
	movlw	0CFh				; cas = 100,009 ms
	movwf	TMP0
	movlw	0A0h
	movwf	TMP1
	goto	SMYCKA

CEK15m	
	movlw	0ABh				; cas = 15,002 ms
	movwf	TMP0
	movlw	01Dh
	movwf	TMP1
	goto	SMYCKA

CEK4m	
	movlw	0A5h				; cas = 4,001 ms
	movwf	TMP0
	movlw	008h
	movwf	TMP1
	goto	SMYCKA

CEK1m6	
	movlw	041h				; cas = 1,601 ms
	movwf	TMP0
	movlw	008h
	movwf	TMP1
	goto	SMYCKA

SMYCKA2	
	call	CEK100m
	decfsz	TMP3,F				; nejvetsi smycka
	goto	SMYCKA2
	retlw	00h

SMYCKA	
	movf	TMP0,W
	movwf	TMP2

SMYCKA1	
	decfsz	TMP2,1				; mala smycka
	goto	SMYCKA1

	decfsz	TMP1,1				; velka smycka
	goto	SMYCKA
	retlw	00h

;------------------------------------------------------------------------------
; KONEC
;------------------------------------------------------------------------------

	END