;****************************************************
;EE 476 - Final Project



.include "c:\windows\desktop\projects\8515def.inc"	;Uses the 8535 chip

;******************
;Register Defs
.def	AnaLo	=r4		;ADC convert values
.def	past	=r5
.def	past2 	=r6
.def	temp 	=r16		;temporary value register
.def	temp2	=r17
.def	effect	=r18		;current effect
.def	ADCFlag =r19		;Tells if the ADC is finished or not
.def    TXbusy  =r20  		;transmit busy flag
.def    RXchar  =r21  		;a received character
.def	parameterL=r22		;low byte of input parameter
.def	parameterH=r23		;high byte of input parameter


;EQUATES

;MACROS
.macro outi 			;out immediate macro
	ldi temp, @1
	out @0, temp
.endmacro


;timer schtuff
.equ	timskVal=0b01000000	;sets Timer1 Compare A match
.equ	t1cAVal	=0		;no timer1 Output Stuff
.equ	t1cBVal	=0b00001001	;clear on match, prescale = 1
.equ	t1oAVal	=666		;6kHz sampling rate
;.equ	t1oAVal	=1200		;300Hz sampling rate
;.equ	t1oAVal =2400		;Really Slow!!

;UART schtuff
.equ    baud96  =25     	;9600 baud constant for 4Mhz crystal

;Effects
.equ	wire		=0		;no effects
.equ	inversion 	=1		;inverting every other bit
.equ	swapping	=2		;reverse high order bits with low order
.equ	delay 		=3		;delay is effect 1
.equ	clipping	=4		;amplitude clipping
.equ	echo		=5		;echo effect
.equ	needsparameters	=3		;the lowest effect # that needs parameters

;port D bit definitions, outputs to ADC and input from it 
.equ    ADCSCLK =     5    ;ADC serial clock output 
.equ    ADCCS =       0    ;ADC chip select (active low) 
.equ    ADCDIN =      2    ;ADC serial data 
.equ    ADCDout =     3    ;ADC output 
.equ    ADCSTRB =     4    ;ADC STROBE output to signal end of conversion 

;other stuff
.equ	MaxDelay =15000
.equ	Ack	=0x55		;Acknowledgement String


;*******************
;Data
.dseg			
.org RAMEND+1
delayline: .byte 15000		;the delay line



;*******************
;Code
.cseg
.org $0000
        rjmp    RESET   ;reset entry vector
        reti            ;IRQ0
        reti		;IRQ1
	reti    	;Timer 1 Capture
        rjmp	TIMER1A	;Timer 1 CompareA
	reti		;Timer 1 CompareB
	reti		;Timer 1 Overflow
        reti		;timer0 overflow
        reti		;SPI TX Complete            
        rjmp	RXDONE	;UART RX Complete
        reti		;UDR Empty
        reti	;rjmp	TXDONE	;UART TX Complete
	reti		;Analog Compare


;**********RESET ISR
RESET:
	;RAM setup
	outi	SPL, LOW(RAMEND)
	outi	SPH, HIGH(RAMEND)

	outi	MCUCR, 0b10000000 ;use external RAM

	;Port setup
     	outi    DDRD, 0b000100100 ;set bits 2 & 5 to outputs and all 
     	outi    portd, 0x00 
	outi	DDRB, 0xFF	;make port B output
	outi	PORTB, 0xFF

	;Timer 1 Setup
	outi	TIMSK, timskVal
	outi	TCCR1A, t1cAVal
	outi	TCCR1B, t1cBVal
	outi	OCR1AH, HIGH(t1oAVal)
	outi	OCR1AL, LOW(t1oAVal)

        ;setup UART -- enable TXempty & RXdone int, and RX, TX pins
        outi     UCR, 0b10011000
        outi     UBRR, baud96    ;set baud rate to 9600



	;setup RAM Pointers
	ldi	ZL, LOW(delayline)
	ldi	ZH, HIGH(delayline)

	;Initial Effect conditions
	ldi	effect, wire
	ldi	YL, LOW(delayline)
	ldi	YH, HIGH(delayline)

	sei

MAIN:	
	tst	ADCFlag		;Has the ADC given us an input yet?
	breq	MAIN

;**************ADC Conversion
READADC: 
  
     cbi    portD, ADCSCLK     ;clear the clock line 
     cbi    portB, ADCCS       ;chip select the ADC 
     ldi    temp, 0b10001110  ;the ADC command word  
                     ;unipolar (channel1) single ended conversion 
                     ;with internal clocking 
                     ;Change this for different functions of the  
                     ;ADC such as bipolar conversion or external 
                     ;clocking.  
  
     ldi    temp2,8  ;the bit counter 
  
 ADC_SENDCOMMAND: 
     rol    temp            ;shift out the 8-bit command 
          .SET    _skipcc = PC+2 
     brcc    _skipcc 
 
     sbi    portD,ADCDin     ;set the bit in Din 
          .set    _skipcs = PC+2 
     brcs    _skipcs 
     cbi    portD, ADCDin    ;clear the bit in Din 
     sbi     PortD, ADCSCLK              ;SCLK high 
     .SET    _nextstep = PC+1            ;wait at least 200 nS 
     rjmp    _nextstep 
     .SET    _nextstep = PC+1 
     rjmp    _nextstep 
     cbi     PortD, ADCSCLK              ;SCLK low 
     dec     temp2 
     brne    ADC_SENDCOMMAND 


 _WAITLOOP:                               
     sbic    portD, ADCSTRB    ; wait until you receive a signal from strobe 
     rjmp    _WAITLOOP 
     clr     AnaLo             ;refresh Main 3 
     ldi     temp2, 10          ;shift in 8+2 bit result (2 leading 0's)
 
 ADC_RECEIVEDATA: 
     clc                ;first set the carry 
     sbi     PortD, ADCSCLK              ;SCLK high 
     .SET    _nextstep = PC+1            ;wait at least 200 nS 
     rjmp    _nextstep 
     .SET    _nextstep = PC+1 
     rjmp    _nextstep 
     cbi     PortD, ADCSCLK              ;SCLK low 
     sbis    PinD, ADCDOUT  ;if ADC data low is high, set carry 
     sec                    ;inverted since low turns led on 
     rol     AnaLo          ;shift carry into data buffer 
     dec     temp2 
     brne    ADC_RECEIVEDATA;repeat until all bits read 
     sbi     PortB, ADCCS   ;release ADC chip select 
  
     clr	ADCFlag


;+++++

	st	Z+, AnaLo	;save input value, increment pointer
	ldi	temp, HIGH(delayline+MaxDelay)	;if reached end of delayline, go back to begining
	cpi	ZL, LOW(delayline+MaxDelay)
	cpc	ZH, temp
	brne	_chooseEffects
	ldi	ZL, LOW(delayline)
	ldi	ZH, HIGH(delayline)


;--------------------Choose Effects----------------------
_chooseEffects:
	ld	r0, Y+		;load input value, increment value	
_selector:
	cpi	effect, wire
	breq	_output
	cpi	effect, inversion
	breq	_inversion
	cpi	effect, swapping
	breq	_swap
	cpi	effect, delay
	breq	_output
	cpi	effect, clipping
	breq	_clipping
	cpi	effect, echo
	breq	_echo
;--------------------------------------------------------
_output:
	ldi	temp, 1
	or	r0, temp
	out	PORTB, r0	;out to LEDs
	ldi	temp, HIGH(delayline+MaxDelay)	;if reached end of delayline, go back to begining
	cpi	YL, LOW(delayline+MaxDelay)
	cpc	YH, temp
	brne	_dojump
	ldi	YL, LOW(delayline)
	ldi	YH, HIGH(delayline)
	rjmp	_dojump

_dojump:
	rjmp 	MAIN

_inversion:

	sbrs	YL, 0
	com	r0		;inverts every other bit
	rjmp	_output

_swap:
	swap	r0
	rjmp	_output

_clipping:
	cp	r0, parameterL
	brlt	_lowclipping	;if below the low threshold, set value to threshold
	cp	r0, parameterH	;
	brge	_highclipping
	rjmp	_output

_lowclipping:
	mov	r0, parameterL
	rjmp	_output
_highclipping:
	mov	r0, parameterH
	rjmp	_output	
_echo:
	mov	XL, YL
	mov	XH, YH
	ldi	temp, 1
	ldi	temp2, 0
	sub	XL, temp
	sbc	XH, temp2
	mov	temp, parameterL
	mov	temp2, parameterH
	sub	XL, temp
	sbc	XH, temp2	

	ldi	temp, high(delayLine)	;check to see if X<0... if so, wrap around
	cpi	XL, low(delayLine)	
	cpc	XH, temp
	brge	_processEcho	
	ldi	temp, low(MaxDelay)	;if X<0, then add MaxDelay for wrap around
	ldi	temp2, high(MaxDelay)
	add	XL, temp
	adc	XH, temp2		
_processEcho:
	ld	past, X
	lsr	past
	mov	past2, past
	lsr	past2
	add	past, past2
	lsr	past
	lsr	r0
	add	r0, past		;this is the current sample plus 75% of a previous sample

_echostage2:
	mov	temp, parameterL
	mov	temp2, parameterH
	sub	XL, temp
	sbc	XH, temp2	

	ldi	temp, high(delayLine)	;check to see if X<0... if so, wrap around
	cpi	XL, low(delayLine)	
	cpc	XH, temp
	brge	_processEcho2	
	ldi	temp, low(MaxDelay)	;if X<0, then add MaxDelay for wrap around
	ldi	temp2, high(MaxDelay)
	add	XL, temp
	adc	XH, temp2		
_processEcho2:
	ld	past, X
	lsr	past
	lsr	past
	add	r0, past		;this is the current sample plus 75% of a previous sample + 50% of a previous sample
	rjmp	_output


	



;****************Timer 1 A Compare Match
TIMER1A:
	push	temp
	ser	ADCFlag
	;outi	ADCSR, 0b11001001	;Enable & Start ADC for one run at 2div prescale

	pop	temp
	reti

;****************ADC Complete
;ADCDONE:
;	ser	ADCFlag		;sets the ADC done flag
;	reti

;****************UART guys
; TX done -- buffer is empty
TXDONE: push	temp
	in	temp, SREG	;save processor status
	push	temp
	pop	temp
        out     SREG, temp	;restore proc status
	pop	temp
        reti                    ;back to pgm

; UART read a character
RXDONE: push	temp
	in	temp, SREG	;save processor status
	push	temp
	in      RXchar, UDR     ;get the character
;	out	UDR, RXchar	;echo character - for Hyperterminal only
;	subi	RXChar, 0x30	;convert to decimal -- NEEDS to be for HYPERTERM

	;Calculate effects
	mov	effect, RXchar

	mov	YL, ZL		;setup initial conditions for Y to current Z value
	mov	YH, ZH

	cpi	effect, needsparameters	;check to see if effect needs parameters
	brlt	InitEffects	;if no, skip parameter check.


;-------------------------Send/Receive Parameters--------------------
	ldi	temp, Ack	;acknowledgement string
	mov	RXChar,	temp	
	out	UDR, RXChar	;send acknowledgement
CharSent:
	sbis	USR, TXC	;check to see if transmit is complete
	rjmp	CharSent
	cbi	USR, TXC	;clear the transmit complete bit
ParamLRead:
	sbis	USR, RXC	;have we received the data yet?
	rjmp	ParamLRead
	cbi	USR, RXC	;clear the receive complete bit
	in	parameterL, UDR	;get the character
;	subi	parameterL, '0'
	out	PORTB, parameterL

	ldi	temp, Ack	;acknowledgement string
	mov	RXChar,	temp	
	out	UDR, RXChar	;send acknowledgement
NextCharSent:
	sbis	USR, TXC	;check to see if transmit is complete
	rjmp	NextCharSent
	cbi	USR, TXC	;clear the transmit complete bit
ParamHRead:
	sbis	USR, RXC	;have we received the data yet?
	rjmp	ParamHRead
	cbi	USR, RXC	;clear the receive complete bit
	in	parameterH, UDR	;get the character
;	subi	parameterH, '0'
	out	PORTB, parameterH
;-------------------------End of Send/Receive Parameters--------------------

InitEffects:
;wire?
	cpi	effect, wire
	brne	_inversionsetup	
	rjmp	_endcase

_inversionsetup:
	cpi	effect, inversion
	brne	_delay
	rjmp	_endcase


_delay:;delay?
	cpi	effect, delay
	brne	_amplitudeclipping

	sub	YL, parameterL		;subtract the delay offset
	sbc	YH, parameterH
	ldi	temp, high(delayLine)	;check to see if Y<0... if so, wrap around
	cpi	YL, low(delayLine)	
	cpc	YH, temp
	brge	_endcase	
	ldi	temp, low(MaxDelay)	;if Y<0, then add MaxDelay for wrap around
	ldi	temp2, high(MaxDelay)
	add	YL, temp
	adc	YH, temp2		
	rjmp	_endcase

_amplitudeclipping:
	cpi	effect, clipping
	brne	_echoEffect
	rjmp	_endcase


_echoEffect:
	cpi	effect, echo
	brne	_nexteffect
	rjmp	_endcase
_nexteffect:



_endcase:
	pop	temp
        out     SREG, temp	;restore proc status
	pop	temp
        reti                    ;back to program