;ATmega644A.asm
;version 3.0 Jan 17, 2013
;author: W8DIZ Dieter (Diz) Gentzow

; cd ~/Desktop/www/kitsandparts.com/DDS_VFO/DDS-3/

; avra ATmega644A.asm

; avrdude -P usb -p m644 -c avrispv2 -U ATmega644A.hex -F

; avrdude -P usb -p m644 -c avrispv2 -U flash:w:ATmega644A.hex -U eeprom:w:ATmega328.v2.eep.hex

; avrdude -P usb -p m644 -c avrispv2  -U eeprom:r:eeprom:i

; avrdude -P usb -p m644 -c avrispv2 -U lfuse:w:0xD7:m -F ; default is 0x62 - clock stuff
; avrdude -P usb -p m644 -c avrispv2 -U hfuse:w:0xD1:m -F ; default is 0x99 - EEPROM preserved
; avrdude -P usb -p m644 -c avrispv2 -U efuse:w:0xFC:m -F ; default is 0xFF - brownout detection

.include "m644Adef.inc"

.equ LED		=	PB0
.equ FC_IN =	PB1
.equ LCD_DRS=	PB2
.equ LCD_E	=	PB3
.equ LCD_CP	=	PB4

.equ DDSenable = PB5
.equ DDSclock  = PB6
.equ DDSdata   = PB7

.equ PHASE = PD1
.equ BUTTON = PD2
.equ STATE = PD3

.equ FREQ0 = $40
.equ FREQ1 = $80

.def mx0 = r2
.def mx1 = r3
.def mx2 = r4
.def mx3 = r5
.def mz0 = r6
.def mz1 = r7
.def mz2 = r8
.def mz3 = r9
.def mz4 = r10
.def mz5 = r11
.def mz6 = r12
.def mz7 = r13
.def press = r14
.def encoder =r15
.def temp1 =r16
.def temp2 =r17
.def temp3 =r18
.def temp4 =r19
.def temp5 =r20
.def delay =r21
.def my0 = r22
.def my1 = r23
.def my2 = r24
.def my3 = r25
.def XL = r26
.def XH = r27
.def YL = r28
.def YH = r29
.def ZL	= r30
.def ZH	= r31

.eseg
.org 0
magic_number_eeprom: .db $2A,$F3,$1D,$C4,$61,$18,$73,$BF
frequency_memory_0: .db "12345678"
frequency_memory_1: .db "12345678"
frequency_memory_2: .db "12345678"
frequency_memory_3: .db "12345678"
frequency_memory_4: .db "12345678"
frequency_memory_5: .db "12345678"
frequency_memory_6: .db "12345678"
frequency_memory_7: .db "12345678"
frequency_memory_8: .db "12345678"
frequency_memory_9: .db "12345678"
cursor_number_eeprom: .db $03

.dseg
.org SRAM_START
test_buffer: .byte 8; buffer for displaying memory data
frequency: .byte 8; ascii displayed frequency
freq_hex: .byte 4 ; 32 bit Hex frequency
freq_DDS: .byte 4 ; 28 bit DDS frequency
cursor_number_sram: .byte 1

.cseg
.org 0
 jmp RESET
 jmp EXT_INT0 ; External Interrupt Request 0
 jmp EXT_INT1 ; External Interrupt Request 1
 jmp NOT_USED ; External Interrupt Request 2
 jmp NOT_USED	; Pin Change Interrupt Request 0
 jmp NOT_USED	; Pin Change Interrupt Request 1
 jmp NOT_USED	; Pin Change Interrupt Request 2
 jmp NOT_USED	; Pin Change Interrupt Request 3
 jmp NOT_USED	; Watchdog Time-out Interrupt
 jmp NOT_USED	; Timer/Counter2 Compare Match A
 jmp NOT_USED	; Timer/Counter2 Compare Match B
 jmp NOT_USED	; Timer/Counter2 Overflow
 jmp NOT_USED	; Timer/Counter1 Capture Event
 jmp NOT_USED	; Timer/Counter1 Compare Match A
 jmp NOT_USED	; Timer/Counter1 Compare Match B
 jmp NOT_USED	; Timer/Counter1 Overflow
 jmp NOT_USED	; Timer/Counter0 Compare Match A
 jmp NOT_USED	; Timer/Counter0 Compare Match B
 jmp OVF0 ; Timer/Couner0 Overflow
 jmp NOT_USED	; SPI Serial Transfer Complete
 jmp NOT_USED	; USART0, Rx Complete
 jmp NOT_USED	; USART0 Data register Empty
 jmp NOT_USED	; USART0, Tx Complete
 jmp NOT_USED	; Analog Comparator
 jmp NOT_USED	; ADC Conversion Complete
 jmp NOT_USED	; EEPROM Ready
 jmp NOT_USED	; 2-wire Serial Interface
 jmp NOT_USED	; Store Program Memory Read
 jmp NOT_USED	; USART1 RX complete
 jmp NOT_USED	; USART1 Data Register Empty
 jmp NOT_USED	; USART1 TX complete

NOT_USED:
 reti
 
RESET: ;init everything here
	ldi		temp1,low(RAMEND)
	out		SPL,temp1			; Set stack pointer to last internal RAM location
	ldi		temp1,high(RAMEND)
	out		SPH,temp1
	
;init ports
	ldi		temp1,$00
	out		DDRA,temp1		;make PA0-7 pins all inputs
	ldi		temp1,$FF			;set pullup resistors on PA0-7
	out		PORTA,temp1 	;
	
	ldi		temp1,$FD
	out		DDRB,temp1		;make PB0,PB2,PB3,PB4,PB5,PB6,PB7 pins an output
	ldi		temp1,$FF			;set pullup resistors on PB1
	out		PORTB,temp1 	;and make PB0,PB2-PB7 high

	cbi		PORTB,LCD_E		;set LCD_E low
 	cbi		PORTB,LCD_CP	;set LCD_CP low
	sbi		PORTB,LED			;turn LED off	
	
	ldi		temp1,$FF
	out		DDRC,temp1		;make all pins an output
	
	ldi		temp1,$F0
	out		DDRD,temp1		;make PD4-7 outputs
	ldi		temp1,$01 		;set pullup resistors PD0
	out		PORTD,temp1 	;and make PD4-7 high

;init misc
	clr		encoder				;clear encoder interrupt counts
	clr		press         ;clear the BUTTON counter
	ldi		temp1,$05			;set timer0 prescale divisor to 1024
	out		TCCR0B,temp1	;using 20.48 XTAL = 50uS
	
	ldi		temp1,$01
	sts		TIMSK0,temp1	;enable TIMER0 overflow interrupts
	
	;sbi		EIMSK,0 ;enable int0 interrupts - press
	sbi		EIMSK,1 ;enable int1 interrupts - encoder
	
	ldi		temp1,0b00001100	; int1 on rising edge
	sbic	PIND,STATE				; test state of encoder
	ldi		temp1,0b00001000	; int1 on falling edge
	sts		EICRA,temp1


;****  CHECK MAGIC NUMBER IN EEPROM ****
 ldi YH,high(magic_number_eeprom)
 ldi YL,low(magic_number_eeprom)
 rcall EEPROM_READ
 cpi temp1,$2A
 breq MAGIC_NUMBER_IN_EEPROM_OK
 rcall MOVE_MAGIC_NUMBER_TO_EEPROM
MAGIC_NUMBER_IN_EEPROM_OK:


 ldi YH,high(cursor_number_eeprom)
 ldi YL,low(cursor_number_eeprom)
 rcall EEPROM_READ
 tst temp1
 breq MOVE_DEFAULT_CURSOR_TO_EEPROM
 cpi temp1,$09
 brlo CURSOR_NUMBER_IN_EEPROM_OK
MOVE_DEFAULT_CURSOR_TO_EEPROM:
 ldi temp1,3
 rcall EEPROM_WRITE
CURSOR_NUMBER_IN_EEPROM_OK:
 ld temp1,Y
 ldi XH,high(cursor_number_sram)
 ldi XL,low(cursor_number_sram)
 st X,temp1

	sei ;global all interrupt enable

MSG_PORK:
;    1234567890123456789012345678901234567890
.db " The Porkalyzer ",0,0
MSG_CMD:
;    1234567890123456789012345678901234567890
.db "     Ready!     ",0,0
PORK:	
 rcall INIT_LCD
 ldi ZH,high(2*MSG_PORK)
 ldi ZL,low(2*MSG_PORK)
 ldi temp2,$80				;display on line 1
 rcall LCDCMD
 rcall DISPLAY_LINE
 ldi temp1,3 ;blink LED 3x to show system is working
 rcall BLINK_LED ; has effect of a delay 1.5 seconds
 rcall load_last_entered_frequency
 rcall ShowFreq
 rcall INIT_DDS
 call ASCII8_HEX4
 
MENU:
 ldi		ZH,high(2*MSG_CMD)
 ldi		ZL,low(2*MSG_CMD)
 ldi		temp2,$C0				;display on line 2
 rcall	LCDCMD
 rcall	DISPLAY_LINE
GET_CMD:
CMD025:
 tst encoder
 breq CMD050
 jmp process_encoder
CMD050:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq GET_CMD
CMD100:
 cpi temp1,'1'
 brne CMD200
 rjmp enter_frequency
CMD200:
 cpi temp1,'2'
 brne CMD300
 rjmp save_to_memory
CMD300:
 cpi temp1,'3'
 brne CMD400
 rjmp load_from_memory
CMD400:
 cpi temp1,'4'
 brne CMD500
 rjmp set_default_cursor
CMD500:
 cpi temp1,'5'
 brne CMD600
 rjmp span_frequency
CMD600:
CMD700:
CMD800:
CMD900:
CMD999:
 rjmp GET_CMD

MSG_CURSOR:
;    1234567890123456789012345678901234567890
.db " Cursor Loc: 1  ",0,0
set_default_cursor:
 ldi		ZH,high(2*MSG_CURSOR)
 ldi		ZL,low(2*MSG_CURSOR)
 ldi		temp2,$C0				;display on line 1
 rcall	LCDCMD
 rcall	DISPLAY_LINE
 ldi XH,high(cursor_number_sram)
 ldi XL,low(cursor_number_sram)
 ld temp3,X ; default cursor value
 ori temp3,$30
SC103: 
 ldi temp2,$CD ; set CURSOR
 rcall LCDCMD
SC105:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq SC105
 cpi temp1,'0' ; '0' is illegal
 breq SC105
 cpi temp1,'#' ; enter key
 breq SC120 ; all done with keypad entry
 cpi temp1,'*' ; enter key
 breq SC999 ; Escape key (*)
 cpi temp1,$39 ; disregard keys 9,A,B,C,D
 brge SC105
 mov temp3,temp1
 rcall LCDCHR
 rjmp SC103
SC120:
 ldi YH,high(cursor_number_eeprom)
 ldi YL,low(cursor_number_eeprom)
 subi temp3,$30
 st X,temp3
 mov temp1,temp3
 rcall EEPROM_WRITE
SC999:
 rjmp MENU
  
MSG_SF:
;    1234567890123456789012345678901234567890
.db " Enter Span: 1  ",0,0
span_frequency:
 ldi		ZH,high(2*MSG_SF)
 ldi		ZL,low(2*MSG_SF)
 ldi		temp2,$C0				;display on line 1
 rcall	LCDCMD
 rcall	DISPLAY_LINE
 ldi temp3,$31 ; default span number
SF103: 
 ldi temp2,$CD ; set CURSOR
 rcall LCDCMD
SF105:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq SF105
 cpi temp1,'#' ; enter key
 breq SF120 ; all done with keypad entry
 cpi temp1,'*' ; Escape key
 brne SF110 ; Escape key (*)
 rjmp MENU
SF110:
 cpi temp1,$3A ; disregard keys A,B,C
 brge SF105
 mov temp3,temp1 ; temp3 = span
 rcall LCDCHR
 rjmp SF103
 
SF120:

 ;ldi ZH,$F0 ; span resolution 4000
 ;ldi ZL,$60 ; span resolution 4000
 ;ldi ZH,$F8 ; span resolution 2000
 ;ldi ZL,$30 ; span resolution 2000
 ldi ZH,$FC ; span resolution 1000
 ldi ZL,$18 ; span resolution 1000
 
 ldi XL,$00
 ldi XH,$00

 ldi YH,high(freq_hex)
 ldi YL,low(freq_hex)
 ld mx3,Y+
 ld mx2,Y+
 ld mx1,Y+
 ld mx0,Y+
  
SF130:

;$2A,$F3,$1D,$C4,$61,$18,$73,$BF

;temp3 contains the span number

 ldi my0,$05 ; 2 Hz resolution
 ldi my1,$00
 ldi my2,$00
 ldi my3,$00
 
 add mx0,my0
 adc mx1,my1
 adc mx2,my2
 adc mx3,my3

 ldi YH,high(magic_number_eeprom)
 ldi YL,low(magic_number_eeprom)
 rcall EEPROM_READ
 mov my3,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ 
 mov my2,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ  
 mov my1,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ   
 mov my0,temp1

 clr	temp1
 mul	my0,mx0
 movw	mz0,R0
 clr	mz2
 clr	mz3
 movw mz4,mz2
 movw mz6,mz2
 mul	my1,mx0
 add	mz1,R0
 adc	mz2,R1
 mul	my2,mx0
 add	mz2,R0
 adc	mz3,R1
 mul	my3,mx0
 add	mz3,R0
 adc	mz4,R1

 mul	my0,mx1
 add	mz1,R0
 adc	mz2,R1
 adc	mz3,temp1
 adc	mz4,temp1
 adc	mz5,temp1
 mul	my1,mx1
 add	mz2,R0
 adc	mz3,R1
 adc	mz4,temp1
 adc	mz5,temp1
 mul	my2,mx1
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 mul	my3,mx1
 add	mz4,R0
 adc	mz5,R1

 mul	my0,mx2
 add	mz2,R0
 adc	mz3,R1
 adc	mz4,temp1
 adc	mz5,temp1
 adc	mz6,temp1
 mul	my1,mx2
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 adc	mz6,temp1
 mul	my2,mx2
 add	mz4,R0
 adc	mz5,R1
 adc	mz6,temp1
 mul	my3,mx2
 add	mz5,R0
 adc	mz6,R1

 mul	my0,mx3
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 adc	mz6,temp1
 adc	mz7,temp1
 mul	my1,mx3
 add	mz4,R0
 adc	mz5,R1
 adc	mz6,temp1
 adc	mz7,temp1
 mul	my2,mx3
 add	mz5,R0
 adc	mz6,R1
 adc	mz7,temp1
 mul	my3,mx3
 add	mz6,R0
 adc	mz7,R1

 ;ldi temp1,$10 ;28 bits FREQ0 to AD9834
 ;ldi temp2,$20
 ;rcall SHIFT_16 ;output to DDS chip
 
 mov temp4,mz6
 mov temp3,mz5
 mov temp2,mz4
 mov temp1,mz3
 
 ldi temp5,FREQ0
 rcall FREQ_OUT10
 
 adwi XL,1
 

 adiw ZL,1
 breq SF140
 rjmp SF130
SF140:
 rcall get_keypad ; return character in temp1
 cpi temp1,'*' ; escape key
 breq SF150 ; all done with scan
 rjmp SF120
SF150:
 call ASCII8_HEX4
 rjmp MENU
 
MSG_LM:
;    1234567890123456789012345678901234567890
.db "Load from Mem: 1",0,0
load_from_memory:
 ldi		ZH,high(2*MSG_LM)
 ldi		ZL,low(2*MSG_LM)
 ldi		temp2,$C0				;display on line 1
 rcall	LCDCMD
 rcall	DISPLAY_LINE
 ldi temp3,$31 ; default save memory number
LM103: 
 ldi temp2,$CF ; set CURSOR
 rcall LCDCMD
LM105:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq LM105
 cpi temp1,'#' ; enter key
 breq LM120 ; all done with keypad entry
 cpi temp1,'*' ; escape key
 breq LM999 ; Escape key (*)
 cpi temp1,$3A ; disregard keys A,B,C
 brge LM105
 mov temp3,temp1
 rcall LCDCHR
 rjmp LM103
LM120:
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ldi YH,high(frequency_memory_0)
 ldi YL,low(frequency_memory_0)
 subi temp3,$30
 breq LM140
LM130:
 adiw YL,8 ; move EEPROM memory pointer to next frequency memory
 dec temp3
 brne LM130
LM140:
 ldi my3,8
LM150:
 rcall EEPROM_READ
 st Z+,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 dec my3
 brne LM150
 call ASCII8_HEX4
LM999:
 rjmp MENU

load_last_entered_frequency:
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ldi YH,high(frequency_memory_0)
 ldi YL,low(frequency_memory_0)
 ldi my3,8
LLEF5:
 rcall EEPROM_READ
 st Z+,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 dec my3
 brne LLEF5
 ret
 
MSG_SM:
;    1234567890123456789012345678901234567890
.db " Save to Mem: 1 ",0,0
save_to_memory:
 ldi		ZH,high(2*MSG_SM)
 ldi		ZL,low(2*MSG_SM)
 ldi		temp2,$C0				;display on line 1
 rcall	LCDCMD
 rcall	DISPLAY_LINE
 ldi temp3,$31 ; default save memory number
SM103: 
 ldi temp2,$CE ; set CURSOR
 rcall LCDCMD
SM105:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq SM105
 cpi temp1,'#' ; enter key
 breq SM120 ; all done with keypad entry
 cpi temp1,'*' ; enter key
 breq SM999 ; Escape key (*)
 cpi temp1,$3A ; disregard keys A,B,C
 brge SM105
 mov temp3,temp1
 rcall LCDCHR
 rjmp SM103
SM120:
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ldi YH,high(frequency_memory_0)
 ldi YL,low(frequency_memory_0)
 subi temp3,$30
 breq SM140
SM130:
 adiw YL,8 ; move EEPROM memory pointer to next frequency memory
 dec temp3
 brne SM130
SM140:
 ldi my3,8
SM150:
 ld temp1,Z+
 rcall EEPROM_WRITE
 adiw YL,1 ; increment EEPROM memory pointer
 dec my3
 brne SM150
SM999:
 rjmp MENU

MSG_EF:
;    1234567890123456789012345678901234567890
.db "Freq:",0
enter_frequency:
 ldi ZH,high(2*MSG_EF)
 ldi ZL,low(2*MSG_EF)
 ldi temp2,$C0				;display on line 1
 rcall LCDCMD
 rcall DISPLAY_LINE
 ldi temp1,' ' ; space
 ldi ZH,high(frequency)
 ldi ZL,low(frequency) ; clear frequency buffer
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z+,temp1
 ldi temp1,' '
 st Z,temp1
EF100:
 ldi temp2,$C5 ; set CURSOR
 rcall LCDCMD 
 rcall display_freq_buffer
EF103: 
 ldi temp2,$CE ; set CURSOR
 rcall LCDCMD
EF105:
 rcall get_keypad ; return character in temp1
 tst temp1
 breq EF105
 cpi temp1,'*' ; backspace key
 brne EF108
; *** start update_freq_buffer_right ***
 ldi ZH,high(frequency+7) 
 ldi ZL,low(frequency+7)
 ld temp2,Z+
 cpi temp2,' '
 brne EF106
 rjmp MENU
EF106:
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,2
 ld temp2,Z+
 st Z,temp2
 sbiw ZL,1
 ldi temp2,' '
 st Z,temp2
; *** end of update_freq_buffer_right ***
 ldi temp2,$C5 ; set CURSOR
 rcall LCDCMD 
 rcall display_freq_buffer
 rjmp EF103
EF108:
 cpi temp1,'#' ; enter key
 breq EF115 ; all done with keypad entry
 cpi temp1,$3A ; disregard keys A,B,C,D
 brge EF103
EF110:
 rcall update_freq_buffer_left
 ldi temp2,$C5 ; set CURSOR
 rcall LCDCMD 
 rcall display_freq_buffer
 rjmp EF103
EF115:
 rcall ASCII8_HEX4
 rcall save_last_entered_frequency
EF999:
 rjmp MENU
 
ASCII8_HEX4: ; convert ascii freq to 4 byte hex
 ldi ZH,high(freq_hex)
 ldi ZL,low(freq_hex)
 clr temp1
 st Z+,temp1 ; clear freq_hex
 st Z+,temp1
 st Z+,temp1
 st Z,temp1
 ldi temp2,8 ; convert 8 ascii freq bytes to 4 hex bytes
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
EF122:
 ld temp1,Z+
 cpi temp1,' '
 breq EF123
 subi temp1,$30
 rcall multiply_freq_hex_by_10_and_add
EF123:
 dec temp2
 brne EF122
EF130: ;convert 4 byte freq_hex to freq_DDS
 rcall MULTIPLY32X32 ; save result in freq_DDS
 rcall ShowFreq
 ldi temp5,FREQ0
 rcall FREQ_OUT
EF140:
 ret

save_last_entered_frequency:
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ldi YH,high(frequency_memory_0)
 ldi YL,low(frequency_memory_0)
 ldi my3,8
SLEF5:
 ld temp1,Z+
 rcall EEPROM_WRITE
 adiw YL,1 ; increment EEPROM memory pointer
 dec my3
 brne SLEF5
 ret

FREQ_OUT: ; temp5=$40 for FREQ0, $80 for FREQ1
 ldi YH,high(freq_DDS)
 ldi YL,low(freq_DDS)
 ld temp4,Y+   ;MSB
 ld temp3,Y+   ;
 ld temp2,Y+   ;
 ld temp1,Y+   ;LSB

FREQ_OUT10:

 lsr temp4			;MSB-high
 ror temp3			;MSB-low
 ror temp2			;LSB-high
 ror temp1			;LSB-low
 lsr temp4			;MSB-high
 ror temp3			;MSB-low
 ror temp2			;LSB-high
 ror temp1			;LSB-low
 lsr temp4			;MSB-high
 ror temp3			;MSB-low
 ror temp2			;LSB-high
 ror temp1			;LSB-low
 lsr temp4			;MSB-high
 ror temp3			;MSB-low
 ror temp2			;LSB-high
 ror temp1			;LSB-low

 lsl temp2
 rol temp3
 rol temp4
 lsl temp2
 rol temp3
 rol temp4
 
 lsr temp2
 lsr temp2

 push temp1
 push temp2
 ldi temp1,$00
 ldi temp2,$20
 rcall SHIFT_16 ;output to DDS chip
 pop temp2
 pop temp1
 
 or temp2,temp5
 rcall SHIFT_16		;send 14 bits
 
 mov temp1,temp3
 mov temp2,temp4 
 or temp2,temp5
 rcall SHIFT_16		;send 14 bits
 
 ret

;**********************************
;* SHIFT_16 - send data to AD9834
;* 16 bit serial out msb first in temp2, then lsb in temp1 
;*********************************** 
SHIFT_16:
 cbi PORTB,DDSenable	;FSYNC goes LOW
 ldi YL,16						;16 bits bit counter
shift8:
 sbi PORTB,DDSdata		;set port bit
 rol temp2						;shift dds address byte
 brcs clockit				  ;check for 1/0
 cbi PORTB,DDSdata		;clear port bit
clockit:
 nop
 cbi PORTB,DDSclock		;clock dds
 nop
 sbi PORTB,DDSclock
 dec YL							;decrement bit counter
 breq sox							;exit if done
 cpi YL,8						;check byte counter
 brne shift8					;output more bits
 mov temp2,temp1			;get lsb
 rjmp shift8					;write data bits
sox:
 sbi PORTB,DDSenable 	;FSYNC goes HIGH
 ret

;**********************************
;* ShowFreq
;* uses temp1 & temp2
;***********************************
ShowFreq: ;display freq on LCD
 ldi temp2,$80
 rcall LCDCMD
 ldi temp1,' '
 rcall LCDCHR
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 cpi temp1,' '
 breq ShowFreq3
 ldi temp1,','
ShowFreq3:
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 cpi temp1,' '
 breq ShowFreq5
 ldi temp1,','
ShowFreq5:
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ldi temp1,' '
 rcall LCDCHR
 ldi temp1,'H'
 rcall LCDCHR
 ldi temp1,'z'
 rcall LCDCHR
 ldi temp1,' '
 rcall LCDCHR
 ret

;************ multiply 32 x 32 ***************
;*  R29:R26 x R5:R2 -> R15:R8
;*  86 cycles + 4 (RET) = 90 Cycles
;*  2A F3 1D C4
MULTIPLY32X32:

 ldi YH,high(freq_hex)
 ldi YL,low(freq_hex)
 ld mx3,Y+
 ld mx2,Y+
 ld mx1,Y+
 ld mx0,Y+

 ldi YH,high(magic_number_eeprom)
 ldi YL,low(magic_number_eeprom)
 rcall EEPROM_READ
 mov my3,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ 
 mov my2,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ  
 mov my1,temp1
 adiw YL,1 ; increment EEPROM memory pointer
 rcall EEPROM_READ   
 mov my0,temp1

 clr	temp1
 mul	my0,mx0
 movw	mz0,R0
 clr	mz2
 clr	mz3
 movw mz4,mz2
 movw mz6,mz2
 mul	my1,mx0
 add	mz1,R0
 adc	mz2,R1
 mul	my2,mx0
 add	mz2,R0
 adc	mz3,R1
 mul	my3,mx0
 add	mz3,R0
 adc	mz4,R1

 mul	my0,mx1
 add	mz1,R0
 adc	mz2,R1
 adc	mz3,temp1
 adc	mz4,temp1
 adc	mz5,temp1
 mul	my1,mx1
 add	mz2,R0
 adc	mz3,R1
 adc	mz4,temp1
 adc	mz5,temp1
 mul	my2,mx1
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 mul	my3,mx1
 add	mz4,R0
 adc	mz5,R1

 mul	my0,mx2
 add	mz2,R0
 adc	mz3,R1
 adc	mz4,temp1
 adc	mz5,temp1
 adc	mz6,temp1
 mul	my1,mx2
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 adc	mz6,temp1
 mul	my2,mx2
 add	mz4,R0
 adc	mz5,R1
 adc	mz6,temp1
 mul	my3,mx2
 add	mz5,R0
 adc	mz6,R1

 mul	my0,mx3
 add	mz3,R0
 adc	mz4,R1
 adc	mz5,temp1
 adc	mz6,temp1
 adc	mz7,temp1
 mul	my1,mx3
 add	mz4,R0
 adc	mz5,R1
 adc	mz6,temp1
 adc	mz7,temp1
 mul	my2,mx3
 add	mz5,R0
 adc	mz6,R1
 adc	mz7,temp1
 mul	my3,mx3
 add	mz6,R0
 adc	mz7,R1
 
 ldi YH,high(freq_DDS)
 ldi YL,low(freq_DDS)
 st Y+,mz6
 st Y+,mz5
 st Y+,mz4
 st Y+,mz3
 ret

multiply_freq_hex_by_10_and_add:
 push ZL
 push ZH

 push temp1
 ldi ZH,high(freq_hex)
 ldi ZL,low(freq_hex)
 ld mx3,Z+
 mov my3,mx3
 ld mx2,Z+
 mov my2,mx2
 ld mx1,Z+
 mov my1,mx1
 ld mx0,Z+
 mov my0,mx0

 lsl mx0
 rol mx1
 rol mx2
 rol mx3
 
 lsl mx0
 rol mx1
 rol mx2
 rol mx3 
 
 lsl mx0
 rol mx1
 rol mx2
 rol mx3

 add mx0,my0
 adc mx1,my1
 adc mx2,my2
 adc mx3,my3
 
 add mx0,my0
 adc mx1,my1
 adc mx2,my2
 adc mx3,my3

 pop temp1
 clr my0
 add mx0,temp1
 st -Z,mx0
 adc mx1,my0
 st -Z,mx1
 adc mx2,my0
 st -Z,mx2
 adc mx3,my0
 st -Z,mx3

 pop ZH
 pop ZL
 ret

update_freq_buffer_left:
 ldi ZH,high(frequency+1)
 ldi ZL,low(frequency+1)
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,2
 ld temp2,Z
 st -Z,temp2 
 adiw ZL,1
 st Z,temp1
 ret

display_freq_buffer:
 ldi ZH,high(frequency)
 ldi ZL,low(frequency)
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 cpi temp1,' '
 breq dfb10
 ldi temp1,','
dfb10:
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 cpi temp1,' '
 breq dfb20
 ldi temp1,','
dfb20:
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z+
 rcall LCDCHR
 ld temp1,Z
 mov temp3,temp1 ; save last character
 rcall LCDCHR
 ret
 
get_keypad:
 sbi DDRA,0 ; make PA0 an output
 cbi PORTA,0 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'1'
 sbis PINA,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'2'
 sbis PINA,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'3'
 sbis PINA,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ;ldi temp1,'A'
 ;sbis PINA,7 ; Skip if Bit in I/O Register is Set
 ;rjmp grk_exit
 sbi PORTA,0 ; Set Bit in I/O Register
 cbi DDRA,0 ; make PA0 an input
 
 sbi DDRA,1 ; make PA1 an output
 cbi PORTA,1 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'4'
 sbis PINA,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'5'
 sbis PINA,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'6'
 sbis PINA,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ;ldi temp1,'B'
 ;sbis PINA,7 ; Skip if Bit in I/O Register is Set
 ;rjmp grk_exit
 sbi PORTA,1 ; Set Bit in I/O Register
 cbi DDRA,1 ; make PA1 an input
 
 sbi DDRA,2 ; make PA2 an output
 cbi PORTA,2 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop
 ldi temp1,'7'
 sbis PINA,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'8'
 sbis PINA,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'9'
 sbis PINA,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ;ldi temp1,'C'
 ;sbis PINA,7 ; Skip if Bit in I/O Register is Set
 ;rjmp grk_exit
 sbi PORTA,2 ; Set Bit in I/O Register
 cbi DDRA,2 ; make PA2 an input
 
 sbi DDRA,3 ; make PA3 an output
 cbi PORTA,3 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'*'
 sbis PINA,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'0'
 sbis PINA,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'#'
 sbis PINA,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ;ldi temp1,'D'
 ;sbis PINA,7 ; Skip if Bit in I/O Register is Set
 ;rjmp grk_exit
 sbi PORTA,3 ; Set Bit in I/O Register
 cbi DDRA,3 ; make PA3 an input
 
 clr temp1
 rjmp grk_exit2
grk_exit:
 ldi delay,250 ; wait 250 milliseconds to remove bounce
 rcall WAIT
grk_exit2:
 sbi PORTA,0 ; Set Bit in I/O Register
 sbi PORTA,1 ; Set Bit in I/O Register
 sbi PORTA,2 ; Set Bit in I/O Register
 sbi PORTA,3 ; Set Bit in I/O Register
 cbi DDRA,0 ; make PA0 an input
 cbi DDRA,1 ; make PA1 an input
 cbi DDRA,2 ; make PA2 an input
 cbi DDRA,3 ; make PA3 an input
 ret
	
DISPLAY_LINE:
	lpm		temp1,Z+
	tst		temp1
	breq	DISPLAY_LINE_FINIS
	rcall	LCDCHR
	rjmp	DISPLAY_LINE
DISPLAY_LINE_FINIS:
 ldi XH,high(cursor_number_sram)
 ldi XL,low(cursor_number_sram)
 ld temp2,X
 cpi temp2,4
 brlo cursor9
 inc temp2
 cpi temp2,8
 brlo cursor9
 inc temp2
cursor9:
 ldi temp1,$8B
 sub temp1,temp2
 mov temp2,temp1
 rcall LCDCMD
 ret
 
;************************************
;* WAIT
;* temp1 = WAIT time in milliseconds
;************************************
WAIT:
	tst		delay
	brne	WAIT
	ret

;************************************
;* BLINK_LED
;* temp1 = number of times LED BLINKS
;************************************
BLINK_LED:
	cbi		PORTB,LED				;turn LED on
	ldi		delay,250				;250 mSec
	rcall WAIT
	sbi		PORTB,LED				;turn LED off		
	ldi		delay,250				;250 mSec
	rcall	WAIT
	dec		temp1
	brne	BLINK_LED
	ret
	
;************************************
;* LCDCMD - Send a command to the LCD
;* temp2 = cmd
;*****************************************
;* LCDCHR - Display a character on the LCD
;* temp1 = data
;************************************
LCDCMD:
  push temp1
  mov temp1,temp2
	rcall	SENDBYTE
	cbi		PORTB,LCD_DRS			;set RS low
	rjmp	LCDEXEC
LCDCHR:
  push temp1
	rcall	SENDBYTE
	sbi		PORTB,LCD_DRS			;set RS High
LCDEXEC:
	sbi		PORTB,LCD_E				;E clocks on rising edge
	ldi		delay,2				;wait 2 milliseconds
	cbi		PORTB,LCD_E				;set E low
	rcall	WAIT
	pop temp1
	ret
	
;**********************************
;* SENDBYTE clock byte into 74hc164
;* temp1 = data
;* temp2 = bitcounter
;***********************************
SENDBYTE:
  push temp1
	push	temp2
	ldi		temp2,8					;bit counter
ShiftBits:
	cbi		PORTB,LCD_DRS   ;set LCD Data bit to 0
	lsl		temp1						;shift bits in AReg into carry
	brcc	ClockBit				;if zero, clock it out
	sbi		PORTB,LCD_DRS   ;if 1, set LCD Data bit to 1
ClockBit: 
	sbi		PORTB,LCD_CP		;bit clocks on rising edge
	cbi		PORTB,LCD_CP		;bring clock back to 0
	dec		temp2						;shift out 8 bits
	brne	ShiftBits
	pop		temp2
	pop temp1
	ret
    	
EXT_INT0:
 push temp1
 in temp1,SREG
 inc press
 out SREG,temp1
 pop  temp1
 reti

EXT_INT1:
	push	temp1 ;save temp1 register
	in		temp1,SREG ;save the status register
	push	temp1
	lds		temp1,EICRA
	cpi		temp1,0b00001000	; test falling edge
	breq	int15
	ldi		temp1,0b00001000	; set int1 on falling edge
	sts		EICRA,temp1
	sbis	PIND,PHASE ; test PHASE
	rjmp	int11
	dec		encoder
	rjmp	int19
int11:
	inc		encoder
	rjmp	int19
int15:
	ldi		temp1,0b00001100	; set int1 for rising edge
	sts		EICRA,temp1
	sbis	PIND,PHASE ; test PHASE
	rjmp	int16
	inc		encoder
	rjmp	int19
int16:
	dec		encoder
int19:
	pop		temp1
	out		SREG,temp1 ;restore the status register
	pop		temp1   ;restore temp1 register
	reti

;**********************************
;* Timer 0 Overflow
;* gets here every 1 millisecond
;* decrements the DELAY counter
;***********************************     	
OVF0:
	push	temp1
	in		temp1,SREG
	push	temp1
	ldi		temp1,256-20		;1 ms using a 20.48 MHz Xtal
	out		TCNT0,temp1			;set for next overflow
	tst		delay
	breq	OVF_EXIT
	dec		delay
OVF_EXIT:
	pop		temp1
	out		SREG,temp1
	pop		temp1
	reti

;**********************************
;* SHOWHEX_LINE
;* display HEX bytes from non-program memory on line 2
;* byte count in temp2
;*********************************** 
SHOWHEX_LINE:
	ldi		temp2,8			;display 8 hex bytes
SHOWHEX_LINE_2:
	ld		temp1,Z+		;get display byte
;preserves temp1 and temp2 values
	push	temp1
	push	temp2
	push	temp1
	swap	temp1
	andi	temp1,$0F
	ori		temp1,$30
	cpi		temp1,$3A
	brlo	SHOWHEX2
	ldi		temp2,$07
	add		temp1,temp2
SHOWHEX2:
	rcall	LCDCHR
	pop		temp1
	andi	temp1,$0F
	ori		temp1,$30
	cpi		temp1,$3A
	brlo	SHOWHEX3
	ldi		temp2,$07
	add		temp1,temp2
SHOWHEX3:
	rcall	LCDCHR
	pop		temp2
	pop		temp1
	dec		temp2
	brne	SHOWHEX_LINE_2
	ret

INIT_DDS:
 ldi		temp2,$21 ;reset AD9834 and init all registers
 ldi		temp1,$00
 rcall	SHIFT_16 ;output to DDS chip

 ldi		temp2,$40 ;freq0 ls 14 bits
 ldi		temp1,$00
 rcall	SHIFT_16

 ldi		temp2,$40 ;freq0 ms 14 bits
 ldi		temp1,$00
 rcall	SHIFT_16
 
 ldi		temp2,$80 ;freq1 ls 14 bits
 ldi		temp1,$00
 rcall	SHIFT_16

 ldi		temp2,$80 ;freq1 ms 14 bits
 ldi		temp1,$00
 rcall	SHIFT_16

 ldi		temp2,$C0 ;clear phase0
 ldi		temp1,$00
 rcall	SHIFT_16

 ldi		temp2,$E0 ;clear phase1
 ldi		temp1,$00
 rcall	SHIFT_16

 ldi		temp2,$20 ;enable output
 ldi		temp1,$00
 rcall	SHIFT_16
 ret
 
EEPROM_READ:
 cli
 sbic EECR,EEPE
 rjmp EEPROM_READ ; Wait for completion of previous write
 out EEARH,YH ; Set up address register
 out EEARL,YL
 sbi EECR,EERE ; Start eeprom read by writing EERE
 in temp1,EEDR ; Read data from data register
 sei
 ret

EEPROM_WRITE:
 cli
 sbic EECR,EEPE
 rjmp EEPROM_WRITE; Wait for completion of previous write
 ldi temp2,0 ; Set Programming mode
 out EECR,temp2
 out EEARH,YH ; Set up address register
 out EEARL,YL
 out EEDR,temp1 ; Write data temp1 to data register
 sbi EECR,EEMPE ; Write logical one to EEMPE
 sbi EECR,EEPE ; Start eeprom write by setting EEPE
 sei
 ret

;************************************
INIT_LCD:
;* uses temp2 
;************************************
	ldi		delay,20			;wait 20 milliseconds for system to stabilize
	rcall	WAIT
	ldi		temp2,$30
	rcall LCDCMD
	ldi		delay,4				;wait 4 milliseconds
	rcall	WAIT	
	ldi		temp2,$38			;set for 8 bits, 2 lines, default font
	rcall LCDCMD
	ldi		temp2,$01			;Clear screen, CURSOR home
	rcall LCDCMD
	ldi		temp2,$0E			;Display on, CURSOR on, blink off
	rcall LCDCMD
	ret

MOVE_MAGIC_NUMBER_TO_EEPROM:
 ldi YH,high(magic_number_eeprom)
 ldi YL,low(magic_number_eeprom)
 ldi ZH,high(magic_number_flash*2)
 ldi ZL,low(magic_number_flash*2)
 lpm temp1,Z+
 rcall EEPROM_WRITE
 adiw YL,1 ; increment EEPROM memory pointer
 lpm temp1,Z+
 rcall EEPROM_WRITE
 adiw YL,1 ; increment EEPROM memory pointer
 lpm temp1,Z+
 rcall EEPROM_WRITE
 adiw YL,1 ; increment EEPROM memory pointer
 lpm temp1,Z+
 rcall EEPROM_WRITE
 ret

process_encoder:
 ldi XH,high(cursor_number_sram)
 ldi XL,low(cursor_number_sram)
 sbic PIND,button ; Skip if Bit in I/O Register is Cleared
 rjmp PE050
 ld temp2,X
 tst encoder
 brpl cursor_right
 inc temp2
 cpi temp2,9
 brlo cursor_exit
 ldi temp2,1
 rjmp cursor_exit
cursor_right:
 dec temp2
 brne cursor_exit
 ldi temp2,8
cursor_exit:
 st X,temp2
 clr encoder
 rcall ShowFreq
 rjmp MENU 
PE050:
 ldi ZH,high(frequency+8)
 ldi ZL,low(frequency+8)
 ld temp1,X ; get cursor
 ldi temp2,8
 sub temp2,temp1
PE100:
 sbiw ZL,1
 dec temp1
 brne PE100
 tst encoder
 brpl freq_positive
freq_negative:
 ld temp1,Z
 dec temp1
 cpi temp1,$30
 brsh SP200
 ldi temp1,$39
 st Z,temp1
 sbiw ZL,1
 rjmp freq_negative
 rjmp SP200
freq_positive:
 ld temp1,Z
 inc temp1
 cpi temp1,$3A
 brlo SP200
 ldi temp1,$30
 st Z,temp1
 sbiw ZL,1
 rjmp freq_positive
SP200:
 st Z,temp1
 call ASCII8_HEX4
PE999:
 clr encoder
 jmp MENU
 
magic_number_flash:
.db $2A,$F3,$1D,$C4,$61,$18,$73,$BF

; ldi ZH,high(freq_DDS)
; ldi ZL,low(freq_DDS)
; st Z+,temp4   ;MSB
; st Z+,temp3   ;
; st Z+,temp2   ;
; st Z+,temp1   ;LSB
 
;ldi ZH,high(freq_DDS)
;ldi ZL,low(freq_DDS)
;ldi temp2,$80		;display on line 1
;rcall LCDCMD
;rcall SHOWHEX_LINE
;loop1: rjmp loop1
