;**** A P P L I C A T I O N   N O T E   A V R 3 0 0 ************************
;*
;* Title		: TWI (Single) Master Implementation
;* Version		: 1.0
;* Last updated		: 2002.05.03
;* Target		: AT90Sxxxx (any AVR device)
;*
;* Support email	: avr@atmel.com
;*
;* DESCRIPTION
;* 	Basic routines for communicating with TWI slave devices. This
;*	"single" master implementation is limited to one bus master on the
;*	TWI bus. Most applications do not need the multimaster ability
;*	the TWI bus provides. A single master implementation uses, by far,
;*	less resources and is less XTAL frequency dependent.
;*
;*	Some features :
;*	* All interrupts are free, and can be used for other activities.
;*	* Supports normal and fast mode.
;*	* Supports both 7-bit and 10-bit addressing.
;*	* Supports the entire AVR microcontroller family.
;*
;*	Main TWI functions :
;*	'TWI_start' -		Issues a start condition and sends address
;*				and transfer direction.
;*	'TWI_rep_start' -	Issues a repeated start condition and sends
;*				address and transfer direction.
;*	'TWI_do_transfer' -	Sends or receives data depending on
;*				direction given in address/dir byte.
;*	'TWI_stop' -		Terminates the data transfer by issue a
;*				stop condition.
;*
;* USAGE
;*	Transfer formats is described in the AVR300 documentation.
;*	(An example is shown in the 'main' code).	
;*
;* NOTES
;*	The TWI routines can be called either from non-interrupt or
;*	interrupt routines, not both.
;*
;* STATISTICS
;*	Code Size	: 81 words (maximum)
;*	Register Usage	: 4 High, 0 Low
;*	Interrupt Usage	: None
;*	Other Usage	: Uses two I/O pins on port D
;*	XTAL Range	: N/A
;*
;***************************************************************************

;**** Includes ****
.nolist
.include "m128def.inc"			; change if an other device is used
.list
;**** Global TWI Constants ****

.equ	SCLP	= 0			; SCL Pin number (port D)
.equ	SDAP	= 1			; SDA Pin number (port D)

.equ	b_dir	= 0			; transfer direction bit in TWIadr

.equ	TWIrd	= 1
.equ	TWIwr	= 0

;**** Global Register Variables ****

.def	TWIdelay= r16			; Delay loop variable
.def	TWIdata	= r17			; TWI data transfer register
.def	TWIadr	= r18			; TWI address and direction register
.def	TWIstat	= r19			; TWI bus status register
.def		mpr	= r20			; Multipurpose register
;**** Interrupt Vectors ****

	rjmp	RESET			; Reset handle
;	( rjmp	EXT_INT0 )		; ( IRQ0 handle )
;	( rjmp	TIM0_OVF )		; ( Timer 0 overflow handle )
;	( rjmp	ANA_COMP )		; ( Analog comparator handle )


;***************************************************************************
;*
;* FUNCTION
;*	TWI_hp_delay
;*	TWI_qp_delay
;*
;* DESCRIPTION
;*	hp - half TWI clock period delay (normal: 5.0us / fast: 1.3us)
;*	qp - quarter TWI clock period delay (normal: 2.5us / fast: 0.6us)
;*
;*	SEE DOCUMENTATION !!!
;*
;* USAGE
;*	no parameters
;*
;* RETURN
;*	none
;*
;***************************************************************************

TWI_hp_delay:
	ldi			TWIdelay,1+(18-7)/3
TWI_hp_delay_loop:
	dec			TWIdelay
	brne		TWI_hp_delay_loop
	ret

TWI_qp_delay:
	ldi			TWIdelay,1+(9-7)/3	
TWI_qp_delay_loop:
	dec			TWIdelay
	brne		TWI_qp_delay_loop
	ret


;***************************************************************************
;*
;* FUNCTION
;*	TWI_rep_start
;*
;* DESCRIPTION
;*	Assert repeated start condition and sends slave address.
;*
;* USAGE
;*	TWIadr - Contains the slave address and transfer direction.
;*
;* RETURN
;*	Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;*	IMPORTANT! : This funtion must be directly followed by TWI_start.
;*
;***************************************************************************

TWI_rep_start:
	sbi			DDRD,SCLP			; force SCL low
	cbi			DDRD,SDAP			; release SDA
	rcall		TWI_hp_delay		; half period delay
	cbi			DDRD,SCLP			; release SCL
	rcall		TWI_qp_delay		; quarter period delay


;***************************************************************************
;*
;* FUNCTION
;*	TWI_start
;*
;* DESCRIPTION
;*	Generates start condition and sends slave address.
;*
;* USAGE
;*	TWIadr - Contains the slave address and transfer direction.
;*
;* RETURN
;*	Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;*	IMPORTANT! : This funtion must be directly followed by TWI_write.
;*
;***************************************************************************

TWI_start:				
	mov			TWIdata,TWIadr		; copy address to transmit register
	sbi			DDRD,SDAP			; force SDA low
	rcall		TWI_qp_delay		; quarter period delay


;***************************************************************************
;*
;* FUNCTION
;*	TWI_write
;*
;* DESCRIPTION
;*	Writes data (one byte) to the TWI bus. Also used for sending
;*	the address.
;*
;* USAGE
;*	TWIdata - Contains data to be transmitted.
;*
;* RETURN
;*	Carry flag - Set if the slave respond transfer.
;*
;* NOTE
;*	IMPORTANT! : This funtion must be directly followed by TWI_get_ack.
;*
;***************************************************************************

TWI_write:
	sec								; set carry flag
	rol			TWIdata				; shift in carry and out bit one
	rjmp		TWI_write_first
TWI_write_bit:
	lsl			TWIdata				; if transmit register empty
TWI_write_first:
	breq		TWI_get_ack			;	goto get acknowledge
	sbi			DDRD,SCLP			; force SCL low

	brcc		TWI_write_low		; if bit high
	nop								;	(equalize number of cycles)
	cbi			DDRD,SDAP			;	release SDA
	rjmp		TWI_write_high
TWI_write_low:						; else
	sbi			DDRD,SDAP			;	force SDA low
	rjmp		TWI_write_high		;	(equalize number of cycles)
TWI_write_high:
	rcall		TWI_hp_delay		; half period delay
	cbi			DDRD,SCLP			; release SCL
	rcall		TWI_hp_delay		; half period delay

	rjmp		TWI_write_bit


;***************************************************************************
;*
;* FUNCTION
;*	TWI_get_ack
;*
;* DESCRIPTION
;*	Get slave acknowledge response.
;*
;* USAGE
;*	(used only by TWI_write in this version)
;*
;* RETURN
;*	Carry flag - Cleared if a slave responds to a request.
;*
;***************************************************************************

TWI_get_ack:
	sbi			DDRD,SCLP			; force SCL low
	cbi			DDRD,SDAP			; release SDA
	rcall		TWI_hp_delay		; half period delay
	cbi			DDRD,SCLP			; release SCL

TWI_get_ack_wait:
	sbis		PIND,SCLP			; wait SCL high 
										;(In case wait states are inserted)
	rjmp		TWI_get_ack_wait

	clc								; clear carry flag
	sbic		PIND,SDAP			; if SDA is high
	sec								;	set carry flag
	rcall	TWI_hp_delay			; half period delay
	ret


;***************************************************************************
;*
;* FUNCTION
;*	TWI_do_transfer
;*
;* DESCRIPTION
;*	Executes a transfer on bus. This is only a combination of TWI_read
;*	and TWI_write for convenience.
;*
;* USAGE
;*	TWIadr - Must have the same direction as when TWI_start was called.
;*	see TWI_read and TWI_write for more information.
;*
;* RETURN
;*	(depends on type of transfer, read or write)
;*
;* NOTE
;*	IMPORTANT! : This funtion must be directly followed by TWI_read.
;*
;***************************************************************************

TWI_do_transfer:
	sbrs		TWIadr,b_dir		; if dir = write
	rjmp		TWI_write			;	goto write data


;***************************************************************************
;*
;* FUNCTION
;*	TWI_read
;*
;* DESCRIPTION
;*	Reads data (one byte) from the TWI bus.
;*
;* USAGE
;*	Carry flag - 	If set no acknowledge is given to the slave
;*			indicating last read operation before a STOP.
;*			If cleared acknowledge is given to the slave
;*			indicating more data.
;*
;* RETURN
;*	TWIdata - Contains received data.
;*
;* NOTE
;*	IMPORTANT! : This funtion must be directly followed by TWI_put_ack.
;*
;***************************************************************************

TWI_read:
	rol			TWIstat					; store acknowledge
										; (used by TWI_put_ack)
	ldi			TWIdata,0x01			; data = 0x01
TWI_read_bit:							; do
	sbi			DDRD,SCLP				; 	force SCL low
	rcall		TWI_hp_delay			;	half period delay

	cbi			DDRD,SCLP				;	release SCL
	rcall		TWI_hp_delay			;	half period delay

	clc									;	clear carry flag
	sbic		PIND,SDAP				;	if SDA is high
	sec									;		set carry flag

	rol			TWIdata					; 	store data bit
	brcc		TWI_read_bit			; while receive register not full


;***************************************************************************
;*
;* FUNCTION
;*	TWI_put_ack
;*
;* DESCRIPTION
;*	Put acknowledge.
;*
;* USAGE
;*	(used only by TWI_read in this version)
;*
;* RETURN
;*	none
;*
;***************************************************************************

TWI_put_ack:
	sbi	DDRD,SCLP		; force SCL low

	ror	TWIstat			; get status bit
	brcc	TWI_put_ack_low		; if bit low goto assert low
	cbi	DDRD,SDAP		;	release SDA
	rjmp	TWI_put_ack_high
TWI_put_ack_low:			; else
	sbi	DDRD,SDAP		;	force SDA low
TWI_put_ack_high:

	rcall	TWI_hp_delay		; half period delay
	cbi	DDRD,SCLP		; release SCL
TWI_put_ack_wait:
	sbis	PIND,SCLP		; wait SCL high
	rjmp	TWI_put_ack_wait
	rcall	TWI_hp_delay		; half period delay
	ret


;***************************************************************************
;*
;* FUNCTION
;*	TWI_stop
;*
;* DESCRIPTION
;*	Assert stop condition.
;*
;* USAGE
;*	No parameters.
;*
;* RETURN
;*	None.
;*
;***************************************************************************

TWI_stop:
	sbi	DDRD,SCLP		; force SCL low
	sbi	DDRD,SDAP		; force SDA low
	rcall	TWI_hp_delay		; half period delay
	cbi	DDRD,SCLP		; release SCL
	rcall	TWI_qp_delay		; quarter period delay
	cbi	DDRD,SDAP		; release SDA
	rcall	TWI_hp_delay		; half period delay
	ret


;***************************************************************************
;*
;* FUNCTION
;*	TWI_init
;*
;* DESCRIPTION
;*	Initialization of the TWI bus interface.
;*
;* USAGE
;*	Call this function once to initialize the TWI bus. No parameters
;*	are required.
;*
;* RETURN
;*	None
;*
;* NOTE
;*	PORTD and DDRD pins not used by the TWI bus interface will be
;*	set to Hi-Z (!).
;*
;* COMMENT
;*	This function can be combined with other PORTD initializations.
;*
;***************************************************************************

TWI_init:
	clr	TWIstat				; clear TWI status register (used
								; as a temporary register)
	out	PORTD,TWIstat		; set TWI pins to open collector
	out	DDRD,TWIstat

	ser	mpr
	out	DDRC,mpr			; Set Port C as output
	ret


;***************************************************************************
;*
;* PROGRAM
;*	main - Test of TWI master implementation
;*
;* DESCRIPTION
;*	Initializes TWI interface and shows an example of using it.
;*
;***************************************************************************

RESET:


;-----Setting Stackpointer--------------------------------------------
	ldi		MPR,low(RAMEND)			; Set stackptr to ram end
	out		SPL,MPR
	ldi 	MPR, high(RAMEND)
	out 	SPH, MPR

;-----Set Port Directions---------------------------------------------
	
	rcall	TWI_init			; initialize TWI interface


;**** Write data => Adr(E0) = 0x50 **** Device 1, Echo Register 1

	ldi		TWIadr,$E0+TWIwr	; Set device address and write


	rcall	TWI_start			; Send start condition and address

	ldi		TWIdata,$00			; Write word address (0x00)-> Command Register

	rcall	TWI_do_transfer		; Execute transfer

	ldi		TWIdata,$50			; Set write data to $50->send data back in inches
	rcall	TWI_do_transfer		; Execute transfer

	rcall	TWI_stop			; Send stop condition

	ldi		XL,$ff				; Wait 65ms for Sonar to Process data 
	ldi		XH,$ff				;		Before reading register
	ldi		r21,$1
loop1:
	sbiw	XH:Xl,1
	brne	loop1
	dec		r21
	brne	loop1


;**** Read data => TWIdata = Adr(00) ****
main:
	ldi		TWIadr,$E0+TWIwr	; Set device address and write
	
	rcall	TWI_start			; Send start condition and address

	ldi		TWIdata,$05		; Write word address Echo Register 1

	rcall	TWI_do_transfer		; Execute transfer

	ldi		TWIadr,$E0+TWIrd	; Set device address and read
	rcall	TWI_rep_start		; Send repeated start condition and address

	sec							; Set no acknowledge (read is followed by a stop condition)
	rcall	TWI_do_transfer		; Execute transfer (read)


	rcall	TWI_stop			; Send stop condition - releases bus

	mov		mpr,TWIdata
	com		mpr
	out		PORTC,mpr


;	ldi		XL,$ff
;	ldi		XH,$10
;	ldi		r21,$ff
;loop1:
;	sbiw	XH:Xl,1
;	brne	loop1
;	dec		r21
;	brne	loop1

here:
	rjmp	main				; Loop forewer
	
;**** End of File ****



