
;-----------------------------------------------------------------
; Name:			I2C.asm
; Description:	ATMega128 Two Wire Interface (IC2) Test Program
;				Interfaces SRF09 Sonar Range Finder to IC2 Bus

; Author:		Max Koessick
; Class:		EEL5666C, Intelligent Machine Design Lab
; Date:			June 28, 2003
; Revision		1.a
; Changes to Date:
;				7/1/03 First Revision
;-----------------------------------------------------------------

.nolist								; Do not include in .lst file
.include "m128def.inc"				; Standard ATMega128 Include File
.list
; Interrupt service vectors

.org $0000
	rjmp Reset						; Reset vector
;.org INT0addr
;	rjmp IntV0						; INT0 vector (ext. interrupt from pin D0)	
;.org INT1addr	
;	rjmp IntV1						; INT1 vector (ext. interrupt from pin D1)
;.org INT2addr		
;	rjmp IntV2						; INT2 vector (ext. interrupt from pin D2)


	
;-----------------------------------------------------------------
; Register defines for main loop
;-----------------------------------------------------------------


.def		mpr		=r16			; defines multipurpose register
.def		mpr2	=r17			; multipurpose register 2
.def		ECHOL	=r18
.def		ECHOH	=r19
.def		ErrorReg=r20
.def		mpr3	=r21


; Equate statements
.equ		start		= $08		; Start Condition 
.equ		Rep_start	= $10		; Repeated Start Condition Message
.equ		MT_SLA_ACK	= $18		; Master Transmitter Slave Address Acknowledge
.equ		MT_DATA_ACK = $28		; Master Transmitter Data Acknowledge
.equ		MT_DATA_NACK= $30		; Master Transmitter Data Not Acknowledge
.equ		MR_SLA_ACK	= $40		; Master Receiver Slave Address Acknowledge
.equ		MR_SLA_NACK	= $48		; Master Receiver Slave Address Acknowledge
.equ		MR_DATA_ACK = $50		; Master Receiver Data Acknowlede
.equ		MR_DATA_NACK= $58		; Master Receiver Data Not Acknowledge
.equ		W			= 0			; Write Bit
.equ		R			= 1			; Read Bit
.equ		SLA			= $E0		; Slave Address of Sonar Ranger SRF08
.equ		Inches		= $50		; Return result in Inches
.equ		CommandReg	= $00		; SRF08 Command Register
;-----------------------------------------------------------------
; Reset vector
;-----------------------------------------------------------------

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-----------------------------------------
	ser		mpr						; Set TEMP to $FF to...

	out 	DDRC,mpr
	ser		mpr
	out		PORTC,mpr				; Lights off

	ser		mpr
;	ldi		mpr2,(1<<PD0)|(1<<PD1)
									; Define pull ups on the input pins of PORTD
	out 	DDRD,mpr				; Set 'D' as input
;	out		PORTD,mpr2
;-----------------------------------------------------------------

	clr 	ErrorReg
	

; Set TWIBitRate for fclk=16Mhz

	ldi		mpr,12					;400Khz=16MHz/(16+2*12) See Datasheet Pg202
	sts		TWBR,mpr

	ldi		mpr,(0<<TWPS1)|(0<<TWPS0)
	sts		TWSR,mpr

; Initialize TWCR Register

	ldi 		MPR, (1<<TWINT)|(1<<TWEA) | (1<<TWEN);
	sts	 		TWCR,MPR 			; Send START condition
	sei								; set interrupts active
			
; **MASTER TRANSMITTER*****

; The Slave being addressed has address 0xE0. 
Check:
	lds			mpr,TWCR
	andi		mpr,0b00010000		; Check to see that no transmission is going on
	brne		Check
;	call		test
	ldi 		MPR, (1<<TWINT)|(1<<TWSTA) | (1<<TWEN);
	sts	 		TWCR,MPR 				; Send START condition


WAIT1: 
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; the START condition has been transmitted
	rjmp 		WAIT1

	lds 		MPR,TWSR 			; Check value of TWI Status Register.
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,START 			; If status different from START go to ERROR
	breq		NEXT1
	jmp			ERROR1
		
;***SLAVE ADDRESS***

NEXT1:
	ldi 		MPR,SLA+W			; Load SLA+W into TWDR Register
	sts	 		TWDR,MPR
	ldi 		MPR,(1<<TWINT) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of address
WAIT2: 
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; SLA+W has been transmitted, and ACK/NACK has
	rjmp 		WAIT2 				; been received

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MT_SLA_ACK 		; different from MT_SLA_ACK, go to ERROR
	breq		NEXT2
	jmp			ERROR2

;***COMMAND REGISTER***

NEXT2:
	ldi 		MPR,CommandReg 		; Load data (CommandReg Address) into TWDR
									; Register
	sts 		TWDR,MPR
	ldi 		MPR,(1<<TWINT) | (1<<TWEN)
	sts 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of data
WAIT3: 

	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; data has been transmitted, and ACK/NACK has
	rjmp 		WAIT3 				; been received

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MT_DATA_ACK 	; different from MT_DATA_ACK, go to ERROR
	breq		NEXT3
	jmp			ERROR3

;***Start Ranging in Inches***
NEXT3:
	ldi			MPR,Inches 			; Load data (Inches = $50) into TWDR
									; Register
	sts	 		TWDR,MPR

	ldi 		MPR,(1<<TWINT) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of data
WAIT4: 
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; data has been transmitted, and ACK/NACK has
	rjmp 		WAIT4 				; been received

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MT_DATA_ACK 	; different from MT_DATA_ACK, go to ERROR
	breq 		NEXT4
	jmp			ERROR4

	call		delay65ms

;Issue Stop
NEXT4:
	ldi 		mpr,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
	sts			TWCR,mpr
;Wait for last transmission to end

Check1:
	lds			mpr,TWCR
	andi		mpr,0b00010000		; Check to see that no transmission is going on
	brne		Check1

;Issue New Start Condition
	ldi 		mpr,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
	sts			TWCR,mpr
WAIT5: 
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; the START condition has been transmitted
	rjmp 		WAIT5
		
	lds 		MPR,TWSR 			; Check value of TWI Status Register.
									; If status different from START go to ERROR
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,START 			
	breq		NEXT5
	jmp			ERROR5

;Send Slave Address + Write Condition
NEXT5:
	ldi			MPR,SLA+W 			; Load data (Register 2, Echo 1, low byte) into TWDR
									; Register
	sts	 		TWDR,MPR
	ldi 		MPR,(1<<TWINT) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of data
WAIT6:
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; data has been transmitted, and ACK/NACK has
	rjmp 		wait6				; been received

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
									; different from MT_SLA_ACK, go to ERROR
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MT_SLA_ACK 	
	breq 		NEXT6
	jmp			ERROR6

;Send Sonar Register Address 0x02
NEXT6:
	ldi			mpr,$02
	sts			TWDR,MPR			; Load Data into TW Data Register

	ldi 		MPR,(1<<TWINT) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of data
WAIT7: 
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; data has been transmitted, and ACK/NACK has
	rjmp 		WAIT7 				; been received

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
									; different from MT_DATA_ACK, go to ERROR
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MT_DATA_ACK 	
	breq 		NEXT7
	jmp			ERROR7

;Send Repeated Start
NEXT7:
	ldi 		MPR,(1<<TWINT) | (1<<TWSTA) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Send REP_START condition
WAIT8:
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; the START condition has been transmitted
	rjmp 		WAIT8
	
	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
									; different from START, go to ERROR
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,REP_START 		
	breq 		NEXT8
	JMP			ERROR8


;***SLAVE ADDRESS+READ***
NEXT8:
	ldi 		MPR,SLA+R 			; Load SLA+R into TWDR Register

	sts	 		TWDR,MPR
	ldi 		MPR,(1<<TWINT) | (1<<TWEN)| (1<<TWEA)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start transmission
									; of SLA+R
WAIT9:
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; SLA+R has been transmitted, and ACK/NACK has
	rjmp 		WAIT9 				; been received

	lds 		MPR,TWSR			; Check value of TWI Status Register. If status
									; different from MR_SLA_ACK, go to ERROR
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MR_SLA_ACK 		
	brne 		ERROR9

;Start Reading DATA
	ldi 		MPR,(1<<TWINT) | (1<<TWEA) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start reception of
									; data. Setting TWEA causes ACK to be returned
									; after reception of data byte
WAIT10:
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs		MPR,TWINT 			; data has been received and ACK returned
	rjmp 		WAIT10

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MR_DATA_ACK 	; different from MR_DATA_ACK, go to ERROR
	brne 		ERROR10

	lds 		ECHOH,TWDR 			; Input received data from TWDR.

;Get last data Byte

	ldi			MPR,(1<<TWINT) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Clear TWINT bit in TWCR to start reception of
									; data. Not setting TWEA causes NACK to be
									; returned after reception of next data byte
									; receive last data byte. Signal this to Slave
									; by returning NACK
WAIT11:
	lds 		MPR,TWCR			; Wait for TWINT Flag set. This indicates that
	sbrs 		MPR,TWINT 			; data has been received and NACK returned
	rjmp 		WAIT11

	lds 		MPR,TWSR 			; Check value of TWI Status Register. If status
	andi		MPR,$F8				; Mask Prescaler Bits
	cpi 		MPR,MR_DATA_NACK 	; different from MR_DATA_NACK, go to ERROR
	brne 		ERROR11

	lds			ECHOL,TWDR 			; Input received data from TWDR.

;Issue Stop 

	ldi 		MPR,(1<<TWINT) | (1<<TWSTO) | (1<<TWEN)
	sts	 		TWCR,MPR 			; Send STOP signal


mainloop:
	com			ECHOL
	out			PORTC,ECHOL
	rjmp		mainloop

ERROR1:
	ldi			ErrorReg,$01
	rjmp		output
ERROR2:
	ldi			ErrorReg,$02
	rjmp		output
ERROR3:
	ldi			ErrorReg,$03
	rjmp		output
ERROR4:
	ldi			ErrorReg,$04
	rjmp		output
ERROR5:
	ldi			ErrorReg,$05
	rjmp		output
ERROR6:
	ldi			ErrorReg,$06
	rjmp		output
ERROR7:
	ldi			ErrorReg,$07
	rjmp		output
ERROR8:
	ldi			ErrorReg,$08
	RJMP		output
ERROR9:
	ldi			ErrorReg,$09
	RJMP		output
ERROR10:
	ldi			ErrorReg,$0A
	RJMP		output
ERROR11:
	ldi			ErrorReg,$0B
	RJMP		output
Output:

; Load Contents of TWI Status Register and display on Port C (LEDs)

	lds 		mpr2,TWSR			; Load the TWSR for Error display
	or			mpr2,errorreg
	com			mpr2				; Change to active low LEDs
;	out			PORTC,MPR2 
LOOP1:
	rjmp		loop1
; *** 65ms delay while Sonar process data
;---------------------------------------------------------------------
Delay65ms:

	push  		XH
	push		XL
	push		mpr2

	ldi			XH,$ff
	ldi			XL,$ff
	ldi			mpr2,$ff

loop:
	sbiw		XH:XL,1
	brne		loop
	dec			mpr2
	brne		loop

	pop 		mpr2

	pop			XL
	pop			XH

	ret

Test:
	ldi		mpr3,$00
	out		portc,mpr3
loop2:
	rjmp	loop2
	ret