<pre>
;***************************************************************************
;
; File Name		:'twi.asm"
; Title			: I2C (TWI) Hardware
; Date			:2003.04.29.	Lastmod.:[2003.04.29.]
; Version		:1.0.0
; Support telephone	:+36-70-333-4034,  Old: +36-30-9541-658 VFX
; Support fax		:
; Support Email		:info@vfx.hu
; Target MCU		:ATmaga8
;
;***************************************************************************
;	D E S C R I P T I O N
;
;
;
;***************************************************************************
;	M O D I F I C A T I O N   H I S T O R Y
;
;
;       rev.      date      who		why
;	----	----------  ---		--------------------------------------------
;	0.01	2003.04.29  VFX		Creation
;
;***************************************************************************
;
;
;
;Hardware
;***************************************************************************
;*


;**************************************************************************
;* Const Def
;
;Bit Rate Generator in Master Mode
;TWBR = Value of the TWI Bit Rate Register
;TWPS = Value of the prescaler bits in the TWI Status Register
;
;Note: TWBR should be 10 or higher if the TWI operates in Master mode.
; If TWBR is lower than 10, the master may produce an incorrect output on SDA
; and SCL for the reminder of the byte.
;
; SCL = SYSCLK/(16+2*TWBR*4^TWPS)  , TWPS= 0..3, TWBR= 0..255
;
; we use 100kHz I2C Bus & TWPS = 0, always for LOW Power

.EQU	SCL_Freq	 = 100000	;Hz
.EQU	TWI_SlaveAddress = 0xFE		;Slave Address is FECO :)


.equ	TWI_WriteByte = 0x00		;Send Byte
.equ	TWI_WriteRAW = 0x01		;Send Blokk of data
.equ	TWI_ReadByte = 0x02		;Read Byte
.equ	TWI_ReadRAW = 0x03		;Read Block of data


;***************************************************************************
.DSEG

TWI_CTL:	.byte 2		;Address of TWI IO Control Blokk
TWI_Count:	.byte 1		;Byte counter for TWI
TWI_Slave:	.byte 1 	;Slave Address
TWI_ADR:	.byte 1		;Slave internal Address
TWI_Flag:	.byte 1		;0. = 1 TWI in use
TWI_SADR:	.byte 2		;TWI State Machin Address



;*************************************************************************
;*  Code
;*
.CSEG

;*************************************************************************
;*  Init TWI Device, Clear TWI_CTL
;
TWI_Init:
		ldi	R16,Low(TWIRET)
		sts	TWI_SADR+0,R16
		ldi	R16,High(TWIRET)
		sts	TWI_SADR+1,R16

		ldi	R16,SYSCLK/(2*SCL_Freq)-8	;TWI Bit Rate Register - TWBR
		out	TWBR,R16
		ldi	R16,0b00000101	 		;TWI Control Register &#8211; TWCR
		out	TWCR,R16			;7 &#8211; TWINT: TWI Interrupt Flag
							;6 &#8211; TWEA: TWI Enable Acknowledge
							;5 &#8211; TWSTA: TWI START Condition
							;4 &#8211; TWSTO: TWI STOP Condition
							;3 - TWWC: TWI Write Collision Flag
							;2 &#8211; TWEN: TWI Enable
							;1 &#8211; Res: Reserved Bit
							;0 &#8211; TWIE: TWI Interrupt Enable

		ldi	R16,0b11111000			;TWI Status Register &#8211; TWSR
		out	TWSR,R16			;7..3 &#8211; TWS: TWI Status
							;2 &#8211; Res: Reserved Bit
							;1..0 &#8211; TWPS: TWI Prescaler Bits

		ldi	R16,TWI_SlaveAddress		;TWI (Slave) Address Register
		out     TWAR,R16
		clr	R16
		sts	TWI_Flag,R16
		ret


;*************************************************************************
;*  Start TWI Comunication in Master Mode
; In:	X - Address of IO_CTR Block
;
;	R17 - count of byte
;	R18 - Slave Address
;	R19 - Internal Address of Slave
; Out:	c = 1 error
;
TWI_StartRead:
			rcall	WaitToTWI
			ldi	R16,Low(RBlock0)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock0)
       			sts	TWI_SADR+1,R16
TWI_Common:
			sts	TWI_CTL+0,XL
			sts	TWI_CTL+1,XH
			sts	TWI_Count,R17
			sts	TWI_Slave,R18
			sts	TWI_ADR,R19

			lds	R16,TWI_Flag
			ori	R16,1	   		;TWI in use!
			andi	R16,0b11111101		;TWI no error
			sts	TWI_Flag,R16

			ldi	R16,0b11100101
			out	TWCR,R16		;7 &#8211; TWINT: TWI Interrupt Flag
							;6 &#8211; TWEA: TWI Enable Acknowledge
					      		;5 &#8211; TWSTA: TWI START Condition
					     		;4 &#8211; TWSTO: TWI STOP Condition
					      		;3 &#8211; TWWC: TWI Write Collision
					       		;2 &#8211; TWEN: TWI Enable
					       		;1 &#8211; Res: Reserved
					       		;0 &#8211; TWIE: TWI Interrupt Enable
TWIRET:
			ret

;*************************************************************************
;*  Start TWI Comunication in Master Mode - Write!
; In:	X - Address of IO_CTR Block
;	R17 - count of byte
;	R18 - Slave Address
;	R19 - Internal Address of Slave
; Out:	c = 1 error
;
TWI_StartWrite:
			rcall	WaitToTWI

			ldi	R16,Low(WBlock0)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(WBlock0)
       			sts	TWI_SADR+1,R16
			rjmp	TWI_Common




;*************************************************************************
;*  TWI interrupt
;*
TWI:					; Two-wire Serial Interface Interrupt Handler
		push	ZL
		push	ZH
		in	ZL,SREG			;preserve main OS status reg.
		push	ZL
		push	R16
		push	R0
		push	R17


;		cbi	GreenLED_PORT,GreenLED 		;LED


		in	R16,TWSR			;Load TWI Status
		andi	R16,0b11111000			;csak a status marad

		lds	ZL,TWI_SADR+0
       		lds	ZH,TWI_SADR+1
		icall

		pop	R17
		POP	R0
		POP	R16
		POP	ZL
		OUT	SREG,ZL
		POP	ZH
		POP	ZL
		RETI


;************************************************************************************************************
;*** R E A D  B L O C K
;***
;
;***********************
; Read Block of data - State 0
; Start bit sended
RBlock0:
       			cpi	R16,0x08			;A START condition has been transmitted
       			breq	Rbl0
       			cpi	R16,0x10			;A Repeated START condition has been transmitted
       			breq	Rbl0
			rjmp	TWI_ReadError
Rbl0:
			lds	R16,TWI_Slave
			andi	R16,0b11111110			;Write SLA
			out	TWDR,R16			;Send Slave Address

			ldi	R16,Low(RBlock1)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock1)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret

;***********************
; Read Block of data - State 1
; Slave Address sended -> Send slave internal address
RBlock1:
      			cpi	R16,0x18			;SLA+W has been transmitted
       			breq	RBl1
			rjmp	TWI_ReadError
RBl1:
			lds	R16,TWI_ADR
	       		out	TWDR,R16			;Send Slave Internal Address

			ldi	R16,Low(RBlock2)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock2)
       			sts	TWI_SADR+1,R16
	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16

			ret


;***********************
; Read Block of data - State 2
; Slave addres send -> Repeated Satrt send
RBlock2:
			cpi	R16,0x28			;SlaveAddress sended + ACK received
       			breq	Rbl21
			rjmp	TWI_ReadError
Rbl21:
			ldi	R16,Low(RBlock3)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock3)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE) | (1<<TWSTA)
	   		out	TWCR,R16
			ret

;***********************
; Read Block of data - State 3
; Repeated Start sended -> Send SLA+R
RBlock3:
			cpi	R16,0x10			;Repeated Start sended + ACK received
       			breq	RBl31
			rjmp	TWI_ReadError
RBl31:
			lds	R16,TWI_Slave
			ori	R16,1		       		;Write SLA+R
	       		out	TWDR,R16			;Send Slave Address

			ldi	R16,Low(RBlock4)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock4)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret

;***********************
; Read Block of data - State 4
; SLA+R sended -> Read data byte
RBlock4:
			cpi	R16,0x40			;SLA+R send + ACK received
       			brne	TWI_ReadError

			lds	R16,TWI_Count
			cpi	R16,1
			breq	TWILAstByte

			ldi	R16,Low(RBlock5)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(RBlock5)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret

TWILAstByte:						       ;Last byte alesz NACK
		        ldi	R16,Low(TWI_ReadLast)
			sts	TWI_SADR+0,R16
	       		ldi	R16,High(TWI_ReadLast)
	       		sts	TWI_SADR+1,R16

			ldi	R16,(1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret

;***********************
; Read Block of data - State 5
; Read data byte
RBlock5:
			cpi	R16,0x50			;data received + ACK send
       			brne	TWI_ReadError

			in	R0,TWDR				;Received data byte
			lds	ZL,TWI_CTL+0
			lds	ZH,TWI_CTL+1
			st	Z+,R0
			sts	TWI_CTL+0,ZL
			sts	TWI_CTL+1,ZH
			lds	R16,TWI_Count
			dec	R16
			sts	TWI_Count,R16
			cpi	R16,1
			breq	TWILAstByte

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret
;*********************************
;** Read Last byte and response NACK
;
TWI_ReadLast:
			cpi	R16,0x58			;data received + NACK send
       			brne	TWI_ReadError

			in	R0,TWDR				;Received data byte
			lds	ZL,TWI_CTL+0
			lds	ZH,TWI_CTL+1
			st	Z+,R0
			rjmp	TWISendStop
TWI_WriteError:
TWI_ReadError:
			lds	R16,TWI_Flag
			ori	R16,0b00000010	   		;TWI error
     			sts	TWI_Flag,R16

TWISendStop:
       			ldi	R16,Low(TWIRET)
			sts	TWI_SADR+0,R16
	       		ldi	R16,High(TWIRET)
	       		sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE) | (1<<TWSTO)
	   		out	TWCR,R16

			lds	R16,TWI_Flag
			andi	R16,0b11111110	   		;TWI free
     			sts	TWI_Flag,R16
			ret

;************************************************************************************************************
;*** W R I T E   B L O C K
;***
;
;***********************
; Write Block of data - State 0
; Start bit sended
WBlock0:
       			cpi	R16,0x08			;A START condition has been transmitted
       			breq	Wbl0
       			cpi	R16,0x10			;A Repeated START has been transmitted
       			breq	Wbl0
			rjmp	TWI_WriteError
Wbl0:
			lds	R16,TWI_Slave
			andi	R16,0b11111110			;Write SLA
			out	TWDR,R16			;Send Slave Address

			ldi	R16,Low(WBlock1)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(WBlock1)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret


;***********************
; Write Block of data - State 1
; Slave Address sended -> Send slave internal address
WBlock1:
      			cpi	R16,0x18			;SLA+W has been transmitted
       			breq	WBl1
			rjmp	TWI_WriteError
WBl1:
			lds	R16,TWI_ADR
	       		out	TWDR,R16			;Send Slave Internal Address

			ldi	R16,Low(WBlock2)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(WBlock2)
       			sts	TWI_SADR+1,R16
	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
			ret

;***********************
; Write Block of data - State 2
; Send slave internal address -> Write data
WBlock2:
			cpi	R16,0x28			;Data byte has been transmitted + ACK received
			breq	WB12
			rjmp	TWI_WriteError
WB12:								;Send data byte continous
			lds	ZL,TWI_CTL+0
			lds	ZH,TWI_CTL+1
			ld	R0,Z+
			out	TWDR,R0				;next data byte
			sts	TWI_CTL+0,ZL
			sts	TWI_CTL+1,ZH

			lds	R16,TWI_Count
			cpi	R16,1
			breq	TWI_WriteLastByte
			dec	R16
			sts	TWI_Count,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret

TWI_WriteLastByte:
			ldi	R16,Low(TWISendStop)
       			sts	TWI_SADR+0,R16
       			ldi	R16,High(TWISendStop)
       			sts	TWI_SADR+1,R16

	      		ldi	R16,(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
	   		out	TWCR,R16
	      		ret


;****************************
; Wait to TWI Ready and check Error
; Out:
; c = 1 TWI Error and Ready
; c = 0 TWI No Error and Ready
WaitToTWI:
			push	R16
			push	XL
			push	XH
			clr	XL
			clr	XH
WaitToTWI0:
			adiw	XL,1
			brcs	WaitToTWI1
	    		lds	R16,TWI_Flag
	       		andi	R16,1		   		;TWI free
	       		brne	WaitToTWI0
			lds	R16,TWI_Flag
			ror	R16		   		;TWI error
			ror	R16
WaitToTWI1:
			pop	XH
			pop	XL
			pop	R16
	       		ret

