.nolist
;Copyright 2005 Dick Cappels, projects@cappels.org  www.projects.cappels.org
;Function/Sweep Generator Button interface
;Note: Expects to use AVR with about 1 MHz clock (AT90S1200A with on-chip clock.)
;In this case, an ATtiny2313 running with internal 8 MHz clock divided by 8.
;To use the AT90S1200, remove the stack initialiaztion right after "START:"
; and change the name of the include file below.
;******************************************************
.include "tn2313def.inc" ;"1200def.inc" <===only use one .inc file.
;******************************************************
;Version fsgen13060305A Added EEPROM write enable. NOT TESTED.
;Version fsgen13050527A Attiny2313 version. Use 8 MHz internal clock divided by 8.






.equ	waitL		= 0
.equ	waitH		= 18				;waitH is the number of 10 second increments. 24 = 4 minutes.

.def	temp 		= r16				;Scratch register.
.def	temp2		= r17				;Scratch register.
.def	delayone	= r18				;Used for button filtering delay.
.def	delaytwo	= r19				;Used for button filtering delay.
.def	Dreg		= r20				;PORTD data output buffer
.def	EEPROMpntr	= r21				;Pointer to EEPOROM location to be read/written. Bits zero 
										;through 6 indicate corresponding bit status. Bit 7 speficies the state of DDRD,0.
.def	flagreg		= r22				;Flags for firmware.
;Note: ZH,ZL used for EEPROM write delay.

;flagreg bit assignments
;0
;1
;2
;3
;4
;5
;6
;7	If set, data in dreg needs to be written to EEPROM.

.org $0000	
		rjmp	START
						
					
LowFreqMode:							;Set VCO input mux to accept Low Freuqency (FLOW) pot as control.
		andi	Dreg,	0b11111100
		ori		Dreg,	0b10000000
		rjmp	Buttonack


HighFreqMode:							;Set VCO input mux to accept High Freuqency (FHIGHH) pot as control.
		andi	Dreg,	0b11111101
		ori		Dreg,	0b10000001
		rjmp	Buttonack

START:

		ldi temp,RAMEND      			;ATtin2313 only -- Init Stack Pointer;
		out SPL,temp					;Omit this line and one above for AT90S1200A

		ldi 	temp,	00				;Set PORTD as output, set bits to initial value
		out 	PORTD,	temp
		ldi		temp,	$FF
		out		DDRD,	temp
	
		ldi		temp,	$FF				;Set PORTB as input with weak pullups.
		out 	PORTB,	temp
		ldi		temp,	$00
		out		DDRB,	temp	
		clr		flagreg
		ldi		ZL,		waitL
		ldi		ZH,		waitH
		rcall	ReadNextEE
		mov		dreg,temp

		ldi		temp,255
		rcall	Buzzloop

Loadbuttons:							;Main loop entry point.

		dec		ZL
		brne	noprog
		dec		ZH
		brne	noprog
		ldi		ZL,		waitL
		ldi		ZH,		waitH
		sbrs	flagreg,7	
		rjmp	noprog
		mov		temp2,	dreg		
		ori		temp2,	0b01000000
		rcall	WriteNextEE
		andi	flagreg,0b01111111
noprog:
		out		PORTD,	dreg			;Output PORTD data to the output port.
		sbrs	dreg,	7				;Set DDRD,0 according to dreg,7
		rjmp	D0Low				
		sbi		DDRD	,0			
		rjmp	D0Done
D0Low:
		cbi		DDRD,	0	
D0Done:
		in		temp	,PINB			;Get the button status.
		rcall	delay					;Wait debounce period.
		in		temp2,	pinB			;If button changed, start over
		cp		temp,	temp2
		brne	loadbuttons
		rcall	InterpretButtons
		rjmp 	loadbuttons

	

InterpretButtons:						;Interpret buttons routines called by this must terminate with ret instruction.
		cpi		temp,	0b11111110		;Low frequency pot button pressed.
		breq	LowFreqMode
		cpi		temp,	0b11111101		;Sweep button pressed.
		breq	sweepmode
		cpi		temp,	0b11111011		;High frequency pot button pressed.
		breq	HighFreqMode
		cpi		temp,	0b11110111		;Marker one button pressed.
		breq	MarkerOne
		cpi		temp,	0b11101111		;Marker two button pressed.
		breq	Markertwo
		cpi		temp,	0b11011111		;Marker mode button pressed.
		breq	MarkerModeOn
		cpi		temp,	0b10111111		;Show Marker button pressed.
		breq	ToggleShowMarker
		cpi		temp,	0b01111111		;Waveform change button is pressed.
		breq	ChangeWaveform
		cpi		temp,	0b10011111		;Waveform change and Show Marker buttons are pressed.
		breq	zeroEErelay				;Zero the EEPROM.
		ret


ToggleShowMarker:						;Toggle Marker On/Off signal
		sbrc	dreg,	5
		rjmp	MarkerIs1
		rcall	MarkerOff
		rjmp	Buttonack

MarkerIs1:
		Rcall	MarkerOn
		rjmp	Buttonack			

zeroEErelay:
		clr		temp2
		rjmp	zeroEE					;Relaying execution for branch that was out of reach.



ChangeWaveform:
										;flagreg	2				Change Wavefore bit A0
										;flagreg	3				Change Waveform bit A1
										;flagreg 	3	2
	
										;			1	X			Sine
										;			0	0			Square
										;			0	1			Triangle


		mov		temp,	dreg			;Check status of control bits and change to the next in sequence.
		andi	temp,	0b0001100
		cpi		temp,	0b0001000
		brne	Nosine
		rcall	SquareOut
		rjmp	Buttonack
Nosine:
		cpi		temp,	0b0000000
		brne	NoSquare
		rcall	TriangleOut
		rjmp	Buttonack
NoSquare:								;If its not a sine or square, it must be a triangle,
		rcall	SineOut					;so change it to a sinewave.
		rjmp	Buttonack

MarkerOne:								;Set marker mux to connect Marker1 pot.			
		ori	dreg,0b0010000
		rjmp	Buttonack


MarkerTwo:								;Set marker mux to connect Marker2 pot.
		cbr	dreg,0b0010000
		rjmp	Buttonack

	
MarkerOn:								;Enable Marker signals in signal output
		andi	dreg,0b11011111
		ret

MarkerOff:
		ori		dreg,0b00100000			;Inhibit Marker signals in signal output
		ret

MarkerModeOn:							;Set VCO input mux to use output of Marker mux.
		rcall	MarkerOff		
		andi	dreg,	0b11111110
		ori		dreg, 	0b10000010
		rjmp	Buttonack  

Sweepmode:								;Make PortD bit 0 into an input without an pullup so.
		andi	dreg,	0b01111100		;VCO input sees a sawtooth, set VCO input mux.
		rjmp	Buttonack

SineOut:								;Set A0 and A1 input of MAX038 so output is a sinewave.
		ori		dreg,	0b00001000
		andi	dreg,	0b11111011
		ret

SquareOut:								;Set A0 and A1 input of MAX038 so output is a squarewave.
		andi	dreg,	0b11110011		
		ret

TriangleOut:							;Set A0 and A1 input of MAX038 so output is a trianglewave.
		ori		dreg,	0b00000100
		andi	dreg,	0b11110111
		ret


delay:									;Delay for button debounce and noise filtering.
		ldi		delayone,50 			;Count of 50 for about 39 ms for electrical noise. 20 Was ok for button debounce.
outerloop:
		ldi		delaytwo,0	
innerloop:
		dec		delaytwo
		brne	innerloop

		dec		delayone
		brne	outerloop
		ret


WriteNextEE:							;Write data in temp2 into next available EEPROM location starting from zer0.
	
		ldi		EEPROMpntr,255			;Initialize pointer.
Nextwritloc:
		inc		EEPROMpntr
		rcall	EERead					;Check to see if empty
		cpi		temp,0
		breq	writenow				;Write to first empty location you find.
		cpi		EEPROMpntr,63			;If we just read the last byte, the EEPROM is fill. Time to erase.
		brne	Nextwritloc				;If not full, go back and try the next location.

zeroEE:
		ldi		EEPROMpntr,63				;Write zeros throughout the EEPROM.
zeromore:
		clr		temp
zerobusy:
		sbic	EECR,EEWE				;if EEWE not clear
		rjmp	zerobusy				;Wait.
		out		EEAR,EEPROMpntr			;Output address
		out		EEDR,temp				;Output data	
		sbi		EECR,EEWE				;Set EEPROM Write strobe
		dec		EEPROMpntr
		cpi		EEPROMpntr,$FF			;Keep going until after location 0 is zeroed.
		brne	zeromore	
		rjmp	WriteNextEE

writenow:								;Write data in temp2 to location EEPROMpntr points to.
		sbic	EECR,EEWE				;If EEWE not clear,
		rjmp	writenow				;Wait.
		out		EEAR,EEPROMpntr			;Output address
		out		EEDR,temp2				;Output data	
		sbi 	EECR,EEMWE 				;Set master write enable. *** This line of code not tested.
		sbi		EECR,EEWE				;Set EEPROM Write strobe
		ldi		temp,75
		rcall	Buzzloop
		ret


ReadNextEE:								;Read first nonzero EEPROM byte found starting from byte 63, scanning down, to temp.
		LDI		EEPROMpntr,64
readmore:
		dec		EEPROMpntr
		rcall	EERead
		cpi		temp,		0
		breq	noData
		ret
NoData:
		cpi		EEPROMpntr,	0			;If at the bottom of memory,and still no data, then load zero into temp and return.
		brne	readmore
		clr		temp
		ret		

EERead:									;Read from EERPOM. Enter with address in EEPROMpntr. Returns with data in temp..
		sbic	EECR,EEWE				;If EEWE not clear
		rjmp	EERead					;Wait more
		out		EEAR,EEPROMpntr			;Output address
		sbi		EECR,EERE				;Set EEPROM Read strobe
		in		temp,EEDR				;Get data
		ret




Buttonack:								;Emit a keyclick, set EEPROM write flag & timer, output PORTD, then wait for button up.

		ldi		ZL,		waitL			;Set waiting time until programming the EEPROM			
		ldi		ZH,		waitH			
		ori		flagreg,0b10000000		;Set flag to write to EEPROM after time is up.
		ldi		temp,6					;;;;;;start keyclick code.
Buzzloop:								;Emit a tone out of D6, the number of cycles = contents of temp.	
		sbi		PORTD,6
		rcall	delay2
		cbi		PORTD,6
		rcall	delay2
		dec		temp
		brne	Buzzloop				;;;;;;end keyclick code.
		out		PORTD,	dreg			;Output PORTD data to the output port.
		sbrs	dreg,	7				;Set DDRD,0 according to dreg,7
		rjmp	D0Low2				
		sbi		DDRD	,0			
		rjmp	D0Done2
D0Low2:
		cbi		DDRD,	0	
D0Done2:
Wait4ButtonsUp:
		in		temp,	PINB			;Wait for all buttons to be up before proceeding.
		rcall	delay					;Debounce
		in		temp2,	PINB
		cp		temp,	temp2
		brne	Wait4ButtonsUp
		cpi		temp,0b11111111			;All up?
		brne	Wait4ButtonsUp;
		ret


delay2:								
		ldi		delayone,1 				;Delay for 1/2 cycle of button click.
outerloop2:
		ldi		delaytwo,0	
innerloop2:
		dec		delaytwo
		brne	innerloop2

		dec		delayone
		brne	outerloop2
		ret

.exit



