
;******************************************************
.include "2313def.inc"
;******************************************************

; User timer 1 to make a 4 khz interrupt and put a square wave sampling pulse on pin 16.
; Firmware expects a 4 Mhz AT90S2313
; Keep other I/O pins low, except when outpulse is greater than $C0, hold reset pin high

.def	chargecount	= r2	;Value of measuered charge in integrator
.def	counterlow	= r3	;Lower byte of the preload for 4 kHz interrupt. Usaed for programmability
.def	oldchargecount	= r4	;Value of charge on prior measurement
.def	quarterycles	= r5	;Value to change timer low
.def	meascount	= r6	;Count of measurements modulus 256. Used for alternative meas output

.def	temp		=r16	;Scratch register
.def	temp2		=r17	;Second scratch register 
.def	outpulse	=r18	;Interrupt counter
.def	datab		=r19	;Temporary data for PORTB, to be output every interrupt time (only 4 lsb available).	
;.def	resetcounter	=r20	;Counter to determine reset time
.def	flagreg		=r21	;Flags stored here
.def	H		= r22	;Used to send decimal ascii
.def	T		= r23	;Used to send decimal ascii
.def	U		= r24	;Used to send decimal ascii
;NOTE: Y register is used as integration timer


;definition of I/O
;B0	COMPARITOR NONINVERTING
;B1	COMPARITOR INVERTING
;B2	
;B3	SAMPLE CLOCK PHASE 1 ON EVEN MEASUREMENTS
;B4	SAMPLE CLOCK PHASE 1
;B5	SAMPLE CLOCK PHASE 2
;B6	SAMPLE CLOCK PHASE 3
;B7	SAMPLE CLOCK PHASE 4


;D0	USED FOR UART RECEIVE
;D1	USED FOR UART TRANSMIT
;D2
;D3	LED - SIGNAL ABOVE THRESOLD
;D4	CLAMP INTEGRATOR TO ZERO
;D5	MEASURE
;D6
;D7

;definition of flagreg bit assignments
.equ	meastaken	=0	;Set after new measurement taken. Cleared by servo 
;1
;2
;3
;4
;5
;6
;7

.equ	counterhigh	=$03	;High byte of the perolaod for 4 kHz interrupt
.equ	measuretime	=$E7	;Point detector cycle that measurement takes place
.equ	measuretimeH	=$03
.equ	resettime	=$E8
.equ	resettimeH	=$03
.equ	detthreshold	=$40	;Threshold above which a signal is said to have been detected
.equ	outpulsepattern =0b00110011 ;Note: As used here, the high and low nybble are used sequentially,and
;repeats every two cycles. For odd and even cycles to be identicle, both nybbles should be identicle.
;The pattern "0b00110011 would result in a 50% duty cycle at 1 kHz.


	;UART baud rate calculation
.equ	clock = 4000000	;clock frequency
.equ	baudrate = 9600		;choose a baudrate
.equ	baudconstant = (clock/(16*baudrate))-1
 


.cseg		; Main program entry point on reset
.ORG $0000
	rjmp start
.ORG $0004 
	rjmp timerservice	;Timer/counter compare interrupt handler
	
start:
   
	ldi	r16,RAMEND	;Init Stack Pointer
	out	spl,r16

 	ldi     temp,baudconstant     
 	out     ubrr,temp     		;Load baudrate.
 ;	sbi	ucr,rxen		;Enable WAUT receive ;Uart receive not used so not enabled bere.
 	sbi	ucr,txen		;Enable UART Transmit


	ldi	outpulse,outpulsepattern ;Initial pulse ouput pattern 
	ldi	flagreg, 0b00000000	;Initialize all flags	
	
	clr	YL			;Initialize integration cycle counter
	clr	YH

	ldi	temp,$04	;Initialize quarter cycle counter
	mov	quarterycles,temp

	ldi	temp,$E8	;Initialize the variable for interrupt timer
	mov	counterlow,temp 

	ldi	temp,$00	;Set data on PORTD and PORTB low.
	out	PORTD,temp
	out	PORTB,temp
	

	ldi	temp,0b11111100	;Make pins on PORTB, except comparitor pins, ouputs.
	out	DDRB,temp
	ldi	temp,0b11111111	;Make all pins on PORTD
	out	DDRD,temp

	ldi	temp,$09	;Set timer 1 to reset 0000 after compare match. Prescaler = 1X
	out	TCCR1B,temp

	ldi	temp,counterhigh;Set compare register to $03E8 for 4 khZ interrupt
	out	OCR1AH,temp
	mov	temp,counterlow
	out	OCR1AL,temp	

	ldi	temp,$40	;Enable interrupt on compare match
	out	TIMSK,temp
	
	sei			;Enable interrupts
	rjmp	Main		;Go to main loop and wait for interrupt



locklight:

	mov	temp,chargecount
	cpi	temp,detthreshold
	brmi	ledoff
	sbi	PORTD,3
	ret 

ledoff: cbi	PORTD,3
	ret	
	



servo:	
	sbrs	flagreg,meastaken
	ret				;Return if this is not first call after signal measurement
	andi	flagreg,$FE

	mov	temp,chargecount	;Send the latest measuremnet followed by a CR and LF.
	rcall	sendnumber		
	rcall	crlf			

	rcall	locklight
	ret
	
	;Code below is not executed
	mov	temp,chargecount
	cpi	temp,$10
	brpl	nosignal
	inc	counterlow
	ldi	temp,counterhigh	;Set compare register 
	out	OCR1AH,temp
	mov	temp,counterlow
	out	OCR1AL,temp
	
nosignal:
	ret		
		
	
		
Main: 	
	rcall	servo
	rjmp	Main



	

 sendnumber:	;Enter with value to be sent in temp, sends as three digit ascii 
 		;via serial port.
 	mov	U,temp			;Enter with 8 bit value in U, Exits with numerals in H,T,U
 	clr	H			;(Hundreds, Tens, and Units).
 	clr	T
 anotherh:
 	subi 	U,100			;Find out how many hundreds in U.
 	brcs	hdone
 	inc	H
 	rjmp	anotherh
 hdone:
 	subi	U,-100			;Subtracted one too many -add back.
 anothert:
 	subi	U,10
 	brcs	tdone
 	inc	T
 	rjmp	anotherT
 tdone:
 	subi	U,-10		
 	cpi	H,0		
 	breq	dontsendh
 	subi	H,-48
 	mov	temp,H
 	rcall	emitchar
 	cpi	t,0
 	brne	dontsendh
 	ldi	temp,$30		;If U=0 then don't emit this zero
 	rcall	emitchar
 dontsendh:	
 	cpi	t,0
 	breq	dontsendt
 	subi	T,-48
 	mov	temp,T
 	rcall	emitchar
 dontsendt:
 	subi	U,-48	
 	mov	temp,U
 	rcall	emitchar
 	ret
 	
 	
 crlf:			;Send return and linefeed 
 	ldi	temp,$0A		;Send return and line feed
 	rcall	emitchar
 	ldi	temp,$0D
 	rcall	emitchar
 	ret	
 


emitchar:	;Send character contained in temp with two stop bits.
 	sbis	usr,udre  		;wait until the register is cleared.
 	rjmp	emitchar     
 	cbi	ucr,0			;Set 9th bit to zero (second stop bit).
 	sbi	ucr,2			;Set to send 9 data bits.
 	out	udr,temp		;send the character.
 	ret


measurecharge:			;Measure time it takes to zero integrator. Output range is $80 to $00,
	ldi	temp,$81	;which is later adjusted to 0 to $127 in timerservice and sendnumber.
	mov	chargecount,temp;Set chargevalue to $81 so it will only spend 127 cycles in this routine.	
	ori	flagreg,1	;Set meastaken flag.
	cbi	PORTB,4		;Make both phase 1 and phase 3 low during the measurement	
	cbi	PORTB,6		;so incoming signals don't affect measurement accuracy.
	sbi	PORTD,5		;Turn on discharge resistor.				;(Discharge resistor turned off after return).
	sbic	acsr,aco	;If comparitor is high, then charge is zero or negative. In this case.
	ret			;skip measurement and go on to discharge capacitor.
morch:
	inc	chargecount	;Stay in a counting loop until the comparitor goes high.
	breq	saturated
	sbis	acsr,aco
	rjmp	morch
saturated:
	ret			;(Discharge resistor turned off after return)	


writeportb:	;Output outpulse combined with datab lower 4 bits to PORTB
	mov	temp,datab
	andi	temp,$0F
	mov	temp2,outpulse
	andi	temp2,$F0
	or	temp,temp2
	out	PORTB,temp
	ret

timerservice:		;Timer 1 interrupt service

	push	temp
	push	temp2
	clc
	rol	outpulse		;Rotate bit image and output to PORTB.
	brcc	B1			;If carry set, set bit 0.
	ori	outpulse,$01		
B1:
					;If meascount is even, copy PORTB bit 4 to PORTB bit 3
					;so that pulses are sent from B3 on alternate measurements
	mov	temp,meascount
	andi	temp,0b00000001
	brne	noclockout		;If meascount lsb is not zero, skip to noclockout
					;If meascount is zero, then copy outputle bit 4 into datab bit 3
	mov	temp,datab
	andi	temp,0b11110111
	mov	datab,temp
	mov	temp,outpulse
	lsr	temp
	andi	temp,0b00001000
	or	datab,temp

noclockout:
	rcall	writeportb

	dec	quarterycles		;If four quarter cycles haven't passed, then don't
	brne	notfullcycle		;increment resetcounter or see if its time to measure charge.
	ldi	temp,$04
	mov	quarterycles,temp	

	
	adiw	YL,1			;There will be a glitch on D4 during resets.
	mov	temp,YL
	mov	temp2,YH
	subi	temp,measuretime
	sbci	temp2,measuretimeH

;	cpi	resetcounter,measuretime	;See if its time to measure charge and reset the integrator.
	brcs	noreset
	brne	nomeasure		;If this is the first time through, measure the charge (250 us).
	rcall	measurecharge		;First time is when resercounter = measuretime.
	inc	meascount		;Increment measurement count
	mov	temp,chargecount	;After measuring charge, adjust offset and save previoius charge
	subi	temp,$81		;for possible future use.
	mov	oldchargecount,chargecount;Save old charge value before replacing.
	mov	chargecount,temp	;Remove offset from count.
nomeasure:

	mov	temp,YL
	mov	temp2,YH
	subi	temp,resettime
	sbci	temp2,resettimeH
	brne	nozeroY
	clr	YL
	clr	YH
nozeroY:
	cbi	PORTD,5			;Turn off discharge resistor.
	sbi	PORTD,4			;Turn on dump resistor.
	rcall	writeportb		;Restore PORTB
	rjmp	finishedinterupt	
noreset:
	cbi	PORTD,4			;Turn off dump resistor.
		
	
notfullcycle:				;Skip to here if this is not at the end of a full cycle.
	
finishedinterupt:
	pop	temp2
	pop	temp
	reti





.exit				;don't assemble past here.
