; ATmega328.108.asm Jan 29, 2021
;basic source file to make an Si5351A chip "sing" and
; using 16 bits as a tune register with full LCD frequency display
; with optical encoder tested
; and with push putton tested - change tune rate
; and with 4x4 keypad
; now using 8 bytes in static ram  to buffer/display the tune frequency
; added high and low frequency limits

; cd ~/Desktop/freddieneil.com/kitsandparts.com/tutorials/ATmega328/108/

; avra ATmega328.108.asm

; avrdude -P usb -p m328p -c avrispv2 -U ATmega328.108.hex
; avrdude -P usb -p m328p -c avrispv2 -U flash:w:ATmega328.108.hex -U eeprom:w:ATmega328.108.eep.hex
; avrdude -P usb -p m328p -c avrispv2 -U lfuse:w:0x62:m  -U hfuse:w:0xD9:m  -U efuse:w:0xFF:m

; define ATmega version
.equ  ATmega = 1   ; Declares the symbol ATmega328
;.equ  ATmega = 2   ; Declares the symbol ATmega644

;.equ  encoder_type  = 0 ; Declare no encoder in use
.equ  encoder_type  = 1 ; Declare encoder to mechanical type - uses EXT_INT1
;.equ  encoder_type  = 2 ; Declare encoder to optical type - uses EXT_INT0 & EXT_INT1

.nolist

; conditional assembly: .define .undef .if .ifdef .ifndef .else .elif .endif .error .warning .message 
.if    ATmega  ==  1
;  .include  "../../include/m328Pdef.inc"
  .message  "m328Pdef.inc selected"
.elif  ATmega  ==  2
  .include  "../../include/m644Adef.inc"
  .message  "m644Adef.inc selected"
.else
  .error  "include file not specified"
.endif

.list

.equ  lcd_drs   =	portc0    ; data line for 74HC164
.equ  lcd_e	    =	portc2    ; lcd Enable
.equ  lcd_cp	  =	portc1    ; clock line for 74HC164
.equ  tune_bit  = portc3    ; not used in 108.asm code
.equ  sda_bit   = portc4
.equ  scl_bit   = portc5
.equ  led_bit   = portd0
.equ  button    = portd1
.equ  output_a  = portd2
.equ  output_b  = portd3
.equ  si5351_i2cAddr  = 0xC0  ; si5351A address = 0x60 but needs to shift left 1 bit

; Define register names
; r0,r1 are used by Z-register and MUL

.def  temp0         = r0  ; used by MUL & SPM instructions and Z register pointer


.def  temp29  = r2  ; r29_VCOa P1[15:8]
.def  temp30  = r3  ; r30_VCOa P1[7:0]
.def  temp31  = r4  ; r31_VCOa P3[19:16]:P2[19:16]
.def  temp32  = r5  ; r32_VCOa P2[15:8]
.def  temp33  = r6  ; r33_VCOa P2[7:0]
.def  temp34  = r7  ; extra byte for finer inc/dec resolution
.def  keypad  = r8  ; stores last keypad push
.def  delay_1ms   = r9
.def  tune_rate   = r10
.def  tune_flag   = r11

.def  temp1           = r16 ; general register and used for si5351_regVal
.def  temp2           = r17 ; general register and used for si5351_regNum
.def  temp3           = r18 ; general register and used for i2cData
.def  temp4           = r19 ; general register
.def  temp5           = r20 ; general register
.def  temp6           = r21 ; general register
.def  temp7           = r22 ; general register
.def  temp8           = r23 ; general register
; r24-r31 used as 16 bit register pointers W, X, Y ,Z
            
.eseg
.org 0

.dseg
.org SRAM_START
F10M:   .byte 1 ; ascii displayed frequency
F1M:    .byte 1
F100K:  .byte 1
F10K:   .byte 1
F1K:    .byte 1
F100:   .byte 1
F10:    .byte 1
F1:     .byte 1

.cseg
.org 0
  jmp RESET
  jmp EXT_INT0  ; External Interrupt Request 0
  jmp EXT_INT1  ; External Interrupt Request 1
  jmp NOT_USED	; Pin Change Interrupt Request 0
  jmp NOT_USED	; Pin Change Interrupt Request 1
  jmp PCI2	; Pin Change Interrupt Request 2
  jmp NOT_USED	; Watchdog Time-out Interrupt
  jmp NOT_USED	; Timer/Counter2 Compare Match A
  jmp NOT_USED	; Timer/Counter2 Compare Match A
  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	; TimerCounter0 Compare Match A
  jmp NOT_USED	; TimerCounter0 Compare Match B
  jmp TIMER0_OVF  ; Timer/Counter0 Overflow
  jmp NOT_USED	; SPI Serial Transfer Complete
  jmp NOT_USED	; USART Rx Complete
  jmp NOT_USED	; USART, Data Register Empty
  jmp NOT_USED	; USART Tx Complete
  jmp NOT_USED	; ADC Conversion Complete
  jmp NOT_USED	; EEPROM Ready
  jmp NOT_USED	; ;Analog Comparator
  jmp NOT_USED	; Two-wire Serial Interface
  jmp NOT_USED	; Store Program Memory Read
NOT_USED: 
  reti
  
;The below parameters / constants are all derived from the script at http://kitsandparts.com/tutorials/5351/Si5351A_calc3.php

.equ  crystal = 25 ; input frequency to the 5351 chip

.if crystal  ==  16
;=================================================================================================================
; 4,000,000 Hz, A=25, D=100, XTAL=16 MHz
.equ REG29 = $0A
.equ REG30 = $80
.equ REG31 = $00
.equ REG32 = $00
.equ REG33 = $00
.equ REG34 = $00

CR4445FL: .db $00,$30 ; D = $30 = 48 = (100/2 - 2)

; actual values from Si5351A_calc2.php
STEP_1:     .db $16,$9F,$02,$00,$00,$00 ; actual values from Si5351A_calc2.php 1 Hz   : $00,$00,$02,$9F,$16,$87
STEP_10:    .db $E1,$36,$1A,$00,$00,$00 ; actual values from Si5351A_calc2.php 10 Hz  : $00,$00,$1A,$36,$E1,$48
STEP_100:   .db $CC,$24,$06,$01,$00,$00 ; actual values from Si5351A_calc2.php 100 Hz : $00,$01,$06,$24,$CC,$CD
STEP_1K:    .db $00,$70,$3D,$0A,$00,$00 ; actual values from Si5351A_calc2.php 1K Hz  : $00,$0A,$3D,$70,$0A,$D3
STEP_10K:   .db $66,$66,$66,$06,$06,$00 ; actual values from Si5351A_calc2.php 10K Hz : $00,$66,$66,$66,$66,$66
STEP_100K:  .db $00,$00,$00,$00,$40,$00 ; actual values from Si5351A_calc2.php 100KHz : $04,$00,$00,$00,$00,$00
STEP_1M:    .db $00,$00,$00,$00,$80,$02 ; actual values from Si5351A_calc2.php 1MHz   : $28,$00,$00,$00,$00,$00

FREQUENCY_INIT:.db $30,$34,$30,$30,$30,$30,$30,$30,$00,$00 ; 04,000,000 - check low frequency limit
FREQUENCY_MAX: .db $31,$32,$30,$30,$30,$30,$30,$30,$00,$00 ; 12,000,000 - check high frequency limit (usually 3x the low limit)
FREQUENCY_MIN:.db $30,$34,$30,$30,$30,$30,$30,$30,$00,$00 ; 04,000,000 - check low frequency limit (usually same as init)
;=================================================================================================================
.elif  crystal  ==  25
;=================================================================================================================
; 4,000,000 Hz, A=20, D=100, XTAL=20 MHz
.equ REG29 = $06
.equ REG30 = $00
.equ REG31 = $00
.equ REG32 = $00
.equ REG33 = $00
.equ REG34 = $00

CR4445FL: .db $00,$30 ; D = $30 = 48 = (100/2 - 2)

; actual values from Si5351A_calc2.php
STEP_1:     .db $16,$18,$00,$00,$00,$00 ; actual values from Si5351A_calc2.php 1 Hz   : $00,$00,$02,$9F,$16,$87
STEP_10:    .db $E1,$F8,$02,$00,$00,$00 ; actual values from Si5351A_calc2.php 10 Hz  : $00,$00,$1A,$36,$E1,$48
STEP_100:   .db $CC,$B7,$14,$00,$00,$00 ; actual values from Si5351A_calc2.php 100 Hz : $00,$01,$06,$24,$CC,$CD
STEP_1K:    .db $00,$26,$D1,$08,$00,$00 ; actual values from Si5351A_calc2.php 1K Hz  : $00,$0A,$3D,$70,$0A,$D3
STEP_10K:   .db $66,$85,$31,$01,$05,$00 ; actual values from Si5351A_calc2.php 10K Hz : $00,$66,$66,$66,$66,$66
STEP_100K:  .db $00,$33,$EB,$03,$33,$00 ; actual values from Si5351A_calc2.php 100KHz : $04,$00,$00,$00,$00,$00
STEP_1M:    .db $00,$00,$33,$00,$00,$02 ; actual values from Si5351A_calc2.php 1MHz   : $28,$00,$00,$00,$00,$00

FREQUENCY_INIT:.db $30,$34,$30,$30,$30,$30,$30,$30,$00,$00 ; 04,000,000 - check low frequency limit
FREQUENCY_MAX: .db $31,$32,$30,$30,$30,$30,$30,$30,$00,$00 ; 12,000,000 - check high frequency limit (usually 3x the low limit)
FREQUENCY_MIN:.db $30,$34,$30,$30,$30,$30,$30,$30,$00,$00 ; 04,000,000 - check low frequency limit (usually same as init)
;=================================================================================================================
.endif

RESET:
	ldi		temp1,  low(RAMEND)
	out   SPL,    temp1			    ; Set stack pointer to last internal RAM location
	ldi		temp1,  high(RAMEND)
	out		SPH,    temp1
	
init_frequency:
  ldi		ZH, high(2*FREQUENCY_INIT)
  ldi		ZL, low(2*FREQUENCY_INIT)
  ldi   YH, high(F10M)
  ldi   YL, low(F10M)
  ldi   temp2,8
init_frequency_10:
  lpm		temp1,  Z+    ; copy frequency start in program memory to static ram
  st    Y+,     temp1 ; to be used as dynamic frequency storage register
  dec temp2
  brne init_frequency_10

;init keypad
	ldi		temp1,$00
	out		DDRB,temp1		;make PA0-7 pins all inputs
	ldi		temp1,$FF			;set pullup resistors on PA0-7
	out		PORTB,temp1 	;
	ldi  temp1,  '?'
  mov  keypad,  temp1
	
;led_init
  ldi   temp1, 0b00000001 ; all PORTD is INPUT except portd0 which is the led_bit
  out   DDRD, temp1       ; all of portd is input	except PD0

;Pin Change Interrupt Request 2 init
  ldi   temp1,  0b00000100  ;  all PORTD is INPUT except portd0 which is the led_bit
  sts   PCICR, temp1        ; Any change on any enabled PCINT[23:16] pin will cause an interrupt
  ldi   temp1,  0b00000010  ; PCINT17 - portd1 - enable bit
  sts   PCMSK2, temp1       ; Pin Change Mask Register 2
  ldi   temp1,  $B6         ; initial default tune_rate == 0 with bit_7 set to trigger display of tune rate
  mov   tune_rate,  temp1

i2c_init:
	cbi   DDRC,   sda_bit ; make sda_bit an input - release Si5351A sda_bit i2c sda line - float high via pull up resistor
	cbi   DDRC,   scl_bit ; make scl_bit an input - release Si5351A scl_bit i2c scl line - float high via pull up resistor
	cbi   PORTC,  sda_bit ; clear sda_bit to logic "0" (when DDRC(sda_bit) changes to an output)
	cbi   PORTC,  scl_bit ; clear scl_bit to logic "0" (when DDRC(scl_bit) changes to an output)

; set System Clock Prescaler - system default clock is 8.0 MHz
  ldi   temp1,  0b10000000  ; init for prescaler change
  sts   CLKPR,  temp1       ; else out instruction to CLKPR will not take effect
; ldi   temp1,  0b00000000  ; prescaler / 1 - ( 8.0 MHz / 1) = 8.000 MHz = 125 nanoseconds
; ldi   temp1,  0b00000001  ; prescaler / 2 - ( 8.0 MHz / 2) = 4.000 MHz = 250 nanoseconds
; ldi   temp1,  0b00000010  ; prescaler / 4 - ( 8.0 MHz / 4) = 2.000 MHz = 500 nanoseconds
  ldi   temp1,  0b00000011  ; prescaler / 8 - factory default; set by Fuse Low Byte ( 8.0 MHz / 8 = 1.000 MHz = 1.000 microsecond)
; ldi   temp1,  0b00000100  ; prescaler / 16 - ( 8.0 MHz / 16) = 500 KHz = 2.000 microseconds
; the setting below disable reprogramming the uP - must use "-B 500" with AVRDUDE to fix
; ldi   temp1,  0b00000101  ; prescaler / 32 - ( 8.0 MHz / 32) = 250 KHz = 4.000 microseconds
; ldi   temp1,  0b00000110  ; prescaler / 64 - ( 8.0 MHz / 64) = 125 KHz = 8.000 microseconds
; ldi   temp1,  0b00000111  ; prescaler / 128 - ( 8.0 MHz / 128) = 62.5 KHz = 16.000 microseconds
; ldi   temp1,  0b00001000  ; prescaler / 256 - ( 8.0 MHz / 256) = 31250 Hz = 32.000 microseconds
  sts   CLKPR,  temp1

; with prescaler set to 8:
; ldi   temp1,  0b00000001  ; no prescaling
  ldi   temp1,  0b00000010  ; CLK 1/8 ( 1.0 MHz / 8 = 125 KHz = 8.000 microsecond)
; ldi   temp1,  0b00000011  ; CLK 1/64 ( 1.0 MHz / 64 = 15.625 KHz = 64.000 microsecond)
; ldi   temp1,  0b00000100  ; CLK 1/256
; ldi   temp1,  0b00000101  ; CLK 1/1024
  out   TCCR0B, temp1	      ; set timer prescaler
  
  ldi   temp1,  1           ; overflow interrupt enable bit
  sts   TIMSK0, temp1       ; enable TIMER0 overflow interrupts

	sbi		DDRC,lcd_e		; make lcd_e an output
	sbi		DDRC,lcd_drs  ; make lcd_drs an output
	sbi		DDRC,lcd_cp   ; make lcd_cp an output

	cbi		PORTC,lcd_e		;set lcd_e low
 	cbi		PORTC,lcd_cp	;set lcd_cp low
 	
  ldi   temp1,  REG29
  mov   temp29, temp1
  ldi   temp1,  REG30
  mov   temp30, temp1
  ldi   temp1,  REG31
  mov   temp31, temp1
  ldi   temp1,  REG32
  mov   temp32, temp1
  ldi   temp1,  REG33
  mov   temp33, temp1
  ldi   temp1,  REG34
  mov   temp34, temp1

.if encoder_type  ==  1

;===============================================================================================================
; the DETENT STEADY encoder output (A) is connected to PD2 / INT0
; If the logic level of output (A) is high, then the next 2 possible edge generated interupts are both falling edges
; so we configure INT0 to capture only falling edges, then enable INT0, or
; If the logic level of output (A) is low, the the next 2 possible edges generated interupts are both rising edges
; so we configure INT0 to capture only rising edges, then enable INT0
;===============================================================================================================

  sbis	PIND, output_a ; skip if bit is set - test PHASE
  rjmp	encoder_rising
encoder_falling:
  ldi		temp1,0b00000010	; set int0 on falling edge
  rjmp encoder_edge_set
encoder_rising:
  ldi		temp1,0b00000011	; set int0 on rising edge
encoder_edge_set:
	sts		EICRA,  temp1
	sbi		EIMSK,  0 ;enable INT0 interrupts
	
.elif encoder_type  ==  2

	ldi		temp1,0b00000101	; Any change of INT0 & INT1 generate an interrupt request
	sts		EICRA,  temp1
	sbi		EIMSK,  0 ;enable INT0 interrupts
  sbi		EIMSK,  1 ;enable INT1 interrupts
  
.endif	  

	clr tune_flag

	sei   ;global all interrupt enable

  rcall Si5351  ; init Si5351 chip to base frequency

  rcall lcd_init
  
  rjmp  main

MSG_1:
;    1234567890123456789012345678901234567890
.db "328 ASM Tutorial",0,0

main:   ; start of main program

  ;ldi ZH,high(2*MSG_1)
  ;ldi ZL,low(2*MSG_1)
  ;ldi temp2,$80				;display on line 1
  ;rcall LCDCMD
  ;rcall DISPLAY_LINE

  rcall	SHOW_FREQUENCY

main10:
  tst   tune_rate ; check if bit7 is set (negative) in tune_rate
  brpl  main15
  rcall	SHOW_RATE ; update tune_rate display
main15:  
  rcall   get_keypad ; return character in temp1
  cp      keypad,  temp1
  brne    main20
  rcall	  SHOW_KEYPAD
  
main20:

  tst   tune_flag
  breq  main10
  brpl  UP_STEP ; else DN_STEP
  
DN_STEP:
  inc   tune_flag
  rcall DECREMENT_FREQUENCY ; update packed BCD freqency buffer in RAM based on tune_rate

CHECK_LOW_FREQUENCY_LIMIT:
  ldi		ZH, high(2*FREQUENCY_MIN)
  ldi		ZL, low(2*FREQUENCY_MIN)
  ldi   YH, high(F10M) ; current updated frequency location
  ldi   YL, low(F10M) ; current updated frequency location
  ldi   temp3,  8
CHECK_LOW_FREQUENCY_LIMIT_LOOP:
  lpm		temp1,  Z+
  ld    temp2,  Y+
  cp    temp1, temp2 ; compare LOWEST freq to Actual Freq
  brlo  LOW_FREQUENCY_LIMIT_EXIT
  breq  LOW_FREQUENCY_LIMIT_NEXT
  rcall INCREMENT_FREQUENCY
  rjmp  main10
LOW_FREQUENCY_LIMIT_NEXT:
  dec   temp3
  brne  CHECK_LOW_FREQUENCY_LIMIT_LOOP
LOW_FREQUENCY_LIMIT_EXIT:

  rcall	SHOW_FREQUENCY ; display packed BCD freqency buffer in RAM
  rcall STEP_DN ; calculate the new 5351 chip register values
  rcall UPDATE_2930313233 ; update the 5351 chip register new values
  rjmp main10

UP_STEP:
  dec   tune_flag
  rcall INCREMENT_FREQUENCY ; update packed BCD freqency buffer in RAM based on tune_rate
CHECK_HIGH_FREQUENCY_LIMIT:
  ldi		ZH, high(2*FREQUENCY_MAX)
  ldi		ZL, low(2*FREQUENCY_MAX)
  ldi   YH, high(F10M) ; current updated frequency location
  ldi   YL, low(F10M) ; current updated frequency location
  ldi   temp3,  8
CHECK_HIGH_FREQUENCY_LIMIT_LOOP:
  lpm		temp1,  Z+
  ld    temp2,  Y+
  cp    temp2, temp1 ; compare MAX freq to Actual Freq
  brlo  HIGH_FREQUENCY_LIMIT_EXIT
  breq  HIGH_FREQUENCY_LIMIT_NEXT
  rcall DECREMENT_FREQUENCY
  rjmp  main10
HIGH_FREQUENCY_LIMIT_NEXT:
  dec   temp3
  brne  CHECK_HIGH_FREQUENCY_LIMIT_LOOP
HIGH_FREQUENCY_LIMIT_EXIT:
  rcall	SHOW_FREQUENCY ; display packed BCD freqency buffer in RAM
  rcall STEP_UP; calculate the new 5351 chip register values
  rcall UPDATE_2930313233 ; update the 5351 chip register new values
  rjmp main10
  
INCREMENT_FREQUENCY:
  ldi		ZH,high(F1) ; point to lowest frequency byte in ram
  ldi		ZL,low(F1)  ; point to lowest frequency byte in ram
  mov   temp1,  tune_rate
  andi  temp1,  $7F ; mask off show tune rate bit
  ld 		temp3,  Z
IF00:  
  cpi   temp1,  $30 ; test for tune rate 0
  brne  IF10
  inc   temp3
  cpi   temp3,  $3A
  breq  IF05
  jmp   IFexit
IF05:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF12
IF10:
  sbiw  ZL, 1
  cpi   temp1,  $31 ; test for tune rate 1
  brne  IF20
  ld 		temp3,  Z
  inc   temp3
IF12:
  cpi   temp3,  $3A
  breq  IF15
  jmp   IFexit
IF15:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF22
IF20:
  sbiw  ZL, 1
  cpi   temp1,  $32 ; test for tune rate 2
  brne  IF30
  ld 		temp3,  Z
  inc   temp3
IF22:
  cpi   temp3,  $3A
  breq  IF25
  jmp   IFexit
IF25:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF32
IF30:
  sbiw  ZL, 1
  cpi   temp1,  $33 ; test for tune rate 3
  brne  IF40
  ld 		temp3,  Z
  inc   temp3
IF32:
  cpi   temp3,  $3A
  breq  IF35
  jmp   IFexit
IF35:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF42
IF40:
  sbiw  ZL, 1
  cpi   temp1,  $34 ; test for tune rate 4
  brne  IF50
  ld 		temp3,  Z
  inc   temp3
IF42:
  cpi   temp3,  $3A
  breq  IF45
  jmp   IFexit
IF45:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF52
IF50:
  sbiw  ZL, 1
  cpi   temp1,  $35 ; test for tune rate 5
  brne  IF60
  ld 		temp3,  Z
  inc   temp3
IF52:
  cpi   temp3,  $3A
  breq  IF55
  jmp   IFexit
IF55:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  rjmp  IF62
IF60:
  sbiw  ZL, 1
  cpi   temp1,  $36 ; test for tune rate 6
  brne  IFexit
  ld 		temp3,  Z
  inc   temp3
IF62:
  cpi   temp3,  $3A
  breq  IF65
  jmp   IFexit
IF65:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
  cpi   temp3,  $3A
  breq  IF75
  jmp   IFexit
IF75:
  ldi   temp3,  $30
  st 		Z,  temp3
  ld 		temp3,  -Z
  inc temp3
IFexit:
  st 		Z,  temp3
  ret

DECREMENT_FREQUENCY:
  ldi		ZH,high(F1) ; point to lowest frequency byte in ram
  ldi		ZL,low(F1)  ; point to lowest frequency byte in ram
  mov   temp1,  tune_rate
  andi  temp1,  $7F ; mask off show tune rate bit
  ld 		temp3,  Z
DF00:  
  cpi   temp1,  $30 ; test for tune rate 0
  brne  DF10
  dec   temp3
  cpi   temp3,  $2F
  breq  DF05
  jmp   DFexit
DF05:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF12
DF10:
  sbiw  ZL, 1
  cpi   temp1,  $31 ; test for tune rate 1
  brne  DF20
  ld 		temp3,  Z
  dec   temp3
DF12:
  cpi   temp3,  $2F
  breq  DF15
  jmp   DFexit
DF15:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF22
DF20:
  sbiw  ZL, 1
  cpi   temp1,  $32 ; test for tune rate 2
  brne  DF30
  ld 		temp3,  Z
  dec   temp3
DF22:
  cpi   temp3,  $2F
  breq  DF25
  jmp   DFexit
DF25:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF32
DF30:
  sbiw  ZL, 1
  cpi   temp1,  $33 ; test for tune rate 3
  brne  DF40
  ld 		temp3,  Z
  dec   temp3
DF32:
  cpi   temp3,  $2F
  breq  DF35
  jmp   DFexit
DF35:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF42
DF40:
  sbiw  ZL, 1
  cpi   temp1,  $34 ; test for tune rate 4
  brne  DF50
  ld 		temp3,  Z
  dec   temp3
DF42:
  cpi   temp3,  $2F
  breq  DF45
  jmp   DFexit
DF45:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF52
DF50:
  sbiw  ZL, 1
  cpi   temp1,  $35 ; test for tune rate 5
  brne  DF60
  ld 		temp3,  Z
  dec   temp3
DF52:
  cpi   temp3,  $2F
  breq  DF55
  jmp   DFexit
DF55:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  rjmp  DF62
DF60:
  sbiw  ZL, 1
  cpi   temp1,  $36 ; test for tune rate 6
  brne  DFexit
  ld 		temp3,  Z
  dec   temp3
DF62:
  cpi   temp3,  $2F
  breq  DF65
  jmp   DFexit
DF65:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
  cpi   temp3,  $2F
  breq  DF75
  jmp   DFexit
DF75:
  ldi   temp3,  $39
  st 		Z,  temp3
  ld 		temp3,  -Z
  dec   temp3
DFexit:
  st 		Z,  temp3
  ret

SHOW_RATE:
  push  temp1
  push  temp2
  ldi temp2,  $CE
  rcall LCDCMD
  mov   temp1,  tune_rate
  andi  temp1,  $7F ; mask off the show tune_rate bit
  mov   tune_rate,  temp1 ; and save tune_rate
  rcall LCDCHR
  pop   temp2
  pop   temp1
  ret

SHOW_KEYPAD:
  push  temp1
  push  temp2
  ldi temp2,  $CF
  rcall LCDCMD
  mov   temp1,  keypad
  rcall LCDCHR
  pop   temp2
  pop   temp1
  ret

SHOW_FREQUENCY: ; display freq_asci at beginning of line 2
  ldi		temp2,$C0				;display on line 2
  rcall	LCDCMD
  ldi		ZH,high(F10M)
  ldi		ZL,low(F10M)
	ld 		temp1,Z+
	cpi   temp1,'0'
	brne  SHOW_FREQUENCY_10
	ldi   temp1, ' '
SHOW_FREQUENCY_10:
	rcall	LCDCHR
	ld 		temp1,Z+
	rcall	LCDCHR
	ldi   temp1,','
	rcall	LCDCHR
	ld 		temp1,Z+
	rcall	LCDCHR
	ld		temp1,Z+
	rcall	LCDCHR
	ld		temp1,Z+
	rcall	LCDCHR
	ldi   temp1,','
	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
  ret

STEP_UP:  ; increment the 5351 chip frequency based on tune rate
  ldi temp1,  $30
  cp  tune_rate,  temp1
  breq    STEP_UP_1
  ldi temp1,  $31
  cp  tune_rate,  temp1
  breq    STEP_UP_10
  ldi temp1,  $32
  cp  tune_rate,  temp1
  breq    STEP_UP_100
  ldi temp1,  $33
  cp  tune_rate,  temp1
  breq    STEP_UP_1K
  ldi temp1,  $34
  cp  tune_rate,  temp1
  breq    STEP_UP_10K
  ldi temp1,  $35
  cp  tune_rate,  temp1
  breq    STEP_UP_100K
  ldi temp1,  $36
  cp  tune_rate,  temp1
  breq    STEP_UP_1M
      
STEP_UP_100:              ; default
  ldi ZH, high(2*STEP_100)
  ldi ZL, low(2*STEP_100)
  rjmp  STEP_UP_NOW
STEP_UP_1:
  ldi ZH, high(2*STEP_1)
  ldi ZL, low(2*STEP_1)
  rjmp  STEP_UP_NOW
STEP_UP_10:
  ldi ZH, high(2*STEP_10)
  ldi ZL, low(2*STEP_10)
  rjmp  STEP_UP_NOW
STEP_UP_1K:
  ldi ZH, high(2*STEP_1K)
  ldi ZL, low(2*STEP_1K)
  rjmp  STEP_UP_NOW  
STEP_UP_10K:
  ldi ZH, high(2*STEP_10K)
  ldi ZL, low(2*STEP_10K)
  rjmp  STEP_UP_NOW
STEP_UP_100K:
  ldi ZH, high(2*STEP_100K)
  ldi ZL, low(2*STEP_100K)
  rjmp  STEP_UP_NOW
STEP_UP_1M:
  ldi ZH, high(2*STEP_1M)
  ldi ZL, low(2*STEP_1M)
STEP_UP_NOW:  
  lpm		temp1,Z+
  add   temp34, temp1
  lpm		temp1,Z+
  adc   temp33, temp1
  lpm		temp1,Z+
  adc   temp32, temp1
  lpm		temp1,Z+
  adc   temp31, temp1
  lpm		temp1,Z+
  adc   temp30, temp1
  lpm		temp1,Z+
  adc   temp29, temp1
  ldi   temp1,  $F0
  or    temp31, temp1
  ret

STEP_DN:  ; decrement the 5351 chip frequency based on tune rate
  ldi temp1,  $30
  cp  tune_rate,  temp1
  breq    STEP_DN_1
  ldi temp1,  $31
  cp  tune_rate,  temp1
  breq    STEP_DN_10
  ldi temp1,  $32
  cp  tune_rate,  temp1
  breq    STEP_DN_100
  ldi temp1,  $33
  cp  tune_rate,  temp1
  breq    STEP_DN_1K
  ldi temp1,  $34
  cp  tune_rate,  temp1
  breq    STEP_DN_10K
  ldi temp1,  $35
  cp  tune_rate,  temp1
  breq    STEP_DN_100K
  ldi temp1,  $36
  cp  tune_rate,  temp1
  breq    STEP_DN_1M
STEP_DN_100:              ; default
  ldi ZH, high(2*STEP_100)
  ldi ZL, low(2*STEP_100)
  rjmp  STEP_DN_NOW
STEP_DN_1:
  ldi ZH, high(2*STEP_1)
  ldi ZL, low(2*STEP_1)
  rjmp  STEP_DN_NOW
STEP_DN_10:
  ldi ZH, high(2*STEP_10)
  ldi ZL, low(2*STEP_10)
  rjmp  STEP_DN_NOW
STEP_DN_1K:
  ldi ZH, high(2*STEP_1K)
  ldi ZL, low(2*STEP_1K)
  rjmp  STEP_DN_NOW  
STEP_DN_10K:
  ldi ZH, high(2*STEP_10K)
  ldi ZL, low(2*STEP_10K)
  rjmp  STEP_DN_NOW  
STEP_DN_100K:
  ldi ZH, high(2*STEP_100K)
  ldi ZL, low(2*STEP_100K)
  rjmp  STEP_DN_NOW 
STEP_DN_1M:
  ldi ZH, high(2*STEP_1M)
  ldi ZL, low(2*STEP_1M)
STEP_DN_NOW:
  ldi   temp1,  $0F
  and   temp31, temp1
  lpm		temp1,Z+
  sub   temp34, temp1
  lpm		temp1,Z+
  sbc   temp33, temp1
  lpm		temp1,Z+
  sbc   temp32, temp1
  lpm		temp1,Z+
  sbc   temp31, temp1
  lpm		temp1,Z+
  sbc   temp30, temp1
  lpm		temp1,Z+
  sbc   temp29, temp1
  ldi   temp1,  $F0
  or    temp31, temp1
  ret

;************************************
;* Si5351: Program the 5351 chip
;* temp1 = si5351_regVal
;* temp2 = si5351_regNum
;* temp3 = si5351_regData
;************************************
Si5351:  ; demo freq set for 7.000 MHz
  ldi temp2, 3; si5351_regNum
  ldi temp1, 0xFF ; si5351_regVal
  rcall i2cSend   ; disable all outputs

  ldi   temp2, 16 ; si5351_regNum
  ldi   temp1, 0x80 ; si5351_regVal
  rcall i2cSend   ; power down clock0

  ldi   temp2, 17 ; si5351_regNum
  ldi   temp1, 0x80 ; si5351_regVal
  rcall i2cSend   ; power down clock1

  ldi   temp2, 18 ; si5351_regNum
  ldi   temp1, 0x80 ; si5351_regVal
  rcall i2cSend   ; power down clock2

  ;ldi   temp2, 15 ; si5351_regNum
  ;ldi   temp1, 0x00   ; default is 0x00 - si5351_regVal
  ;rcall i2cSend   ; select PLLa,b source and use xtal input

  ;ldi   temp2, 24 ; si5351_regNum
  ;ldi   temp1, 0x00   ; default is 0x00 - si5351_regVal
  ;rcall i2cSend   ; clock disable state

  ldi temp2, 149 ; si5351_regNum
  ldi temp1, 0    ; disable spread spectrum on PLLa - si5351_regVal
  rcall i2cSend   ; reset both PLLs
  
; Output Multisynth0, e=0, f=1, MS0_P2 and MS0_P3
  ldi   temp2, 42 ; si5351_regNum
  ldi   temp1, 0 ; si5351_regVal
  rcall i2cSend   ; set MS0_P3[15:8]

  ldi   temp2, 43 ; si5351_regNum
  ldi   temp1, 1 ; si5351_regVal
  rcall i2cSend   ; set MS0_P3[7:0]
  
  ldi   temp2, 47 ; si5351_regNum
  ldi   temp1, 0 ; si5351_regVal
  rcall i2cSend   ; set MS0_P3[19:16] | MS0_P2[19:16]

  ldi   temp2, 48 ; si5351_regNum
  ldi   temp1, 0 ; si5351_regVal
  rcall i2cSend   ; set MS0_P2[15:8]

  ldi   temp2, 49 ; si5351_regNum
  ldi   temp1, 0 ; si5351_regVal
  rcall i2cSend   ; set MS0_P2:[7:0]
  
  ldi   temp2, 16 ; si5351_regNum
  ;ldi   si5351_regVal, 0x4C ; 2 mA - 144 ohms output Z (default)
  ;ldi   si5351_regVal, 0x4D ; 4 mA - 61 ohms output Z
  ;ldi   si5351_regVal, 0x4E ; 6 mA - 56 ohms output Z
  ldi   temp1, 0x4F ; 8 mA - 44 ohms output Z - si5351_regVal
  rcall i2cSend   ; power up clock0, MS0 in integer mode,  PLLa at 8 mA

  ;ldi temp2, 183 ; si5351_regNum
  ;ldi temp1, 0x52 ;$D2=default 10pF, $92=8pF, $52=6pF - si5351_regVal
  ;rcall i2cSend   ; reset both PLLs

  ldi temp2, 177 ; si5351_regNum
  ldi temp1, 0xA0 ; si5351_regVal
  rcall i2cSend   ; reset both PLLs
  
  ldi temp2, 3 ; si5351_regNum
  ldi temp1, 0xFE ; si5351_regVal
  rcall i2cSend   ; enable clock0 output only 
  
; Load PLLa Feedback Multisynth 26,27,28

  ldi   temp2,  26 ; si5351_regNum
  ldi   temp1,  0xff ; si5351_regVal
  rcall i2cSend   ; set MSNA_P3[15:8]

  ldi   temp2,  27 ; si5351_regNum
  ldi   temp1,  0xff ; si5351_regVal
  rcall i2cSend   ; set MSNA_P3[7:0]

  ldi   temp2,  28 ; si5351_regNum
  ldi   temp1,  0 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P1[17:16]
  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  rcall UPDATE_2930313233
   
; Load Output Multysynth with d (e and f already set during init and never changes) 44,45,46

  ldi ZH, high(2*CR4445FL)
  ldi ZL, low(2*CR4445FL)

  ldi   temp2,  44 ; si5351_regNum
  lpm		temp1,  Z+ ; si5351_regVal
  rcall i2cSend   ; set MS0_P1[17:16]

  ldi   temp2,  45 ; si5351_regNum
  lpm		temp1,  Z+ ; si5351_regVal
  rcall i2cSend   ; set MS0_P1[15:8]  
 

  ;ldi   temp2,  44 ; si5351_regNum
  ;ldi   temp1,  0 ; si5351_regVal
  ;rcall i2cSend   ; set MS0_P1[17:16]

  ;ldi   temp2,  45 ; si5351_regNum
  ;ldi   temp1,  0x30 ; si5351_regVal
  ;rcall i2cSend   ; set MS0_P1[15:8]

  ldi   temp2,  46 ; si5351_regNum
  ldi   temp1,  0 ; si5351_regVal
  rcall i2cSend   ; set MS0_P1[7:0]

  ldi temp2, 177 ; si5351_regNum
  ldi temp1, 0x20 ; si5351_regVal
  rcall i2cSend   ; reset PLLa only
  ret
  
UPDATE_2930313233: ; Load PLLa Feedback Multisynth 29,30,31,32,33
  ldi   temp2,  29 ; si5351_regNum
  mov   temp1,  temp29 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P1[15:8]
  
  ldi   temp2,  30 ; si5351_regNum
  mov   temp1,  temp30 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P1[7:0]
  
  ldi   temp2,  31 ; si5351_regNum
  mov   temp1,  temp31 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P3[19:16] | MSNA_P2[19:16]
  
  ldi   temp2,  32 ; si5351_regNum
  mov   temp1,  temp32 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P2[15:8]
  
  ldi   temp2,  33 ; si5351_regNum
  mov   temp1,  temp33 ; si5351_regVal
  rcall i2cSend   ; set MSNA_P2[7:0]
  ret

i2cSend: ; receives temp1 as si5351_regVal, receives temp2 as si5351_regNum, uses temp3 internally only
	rcall	i2c_start				  ; Send start condition and address
	mov		temp3,  temp2	; Write word address (0x00)
	rcall	i2c_write_8bits 	  ; Execute transfer
	mov		temp3,  temp1	; Set write data to 01010101b
	rcall	i2c_write_8bits 	  ; Execute transfer
	rcall	i2c_stop				  ; Send stop condition
	ret

i2c_start:
  ldi   temp3, si5351_i2cAddr   ; load i2c device address to transmit register - address = 0x60 but needs to shift left 1 bit
  sbi   DDRC,     sda_bit   ; force data line low by making DDRC an output
  rcall i2cDelay_6
  sbi   DDRC,     scl_bit   ; force clock line low by making DDRC an output
  rcall i2cDelay_6
i2c_write_8bits:
  sec                       ; set carry flag
  rol   temp3             ; shift in carry bit and out bit into carry bit
i2c_write_bit:
  breq  i2c_get_ack
  brcc  i2c_bit_write_low
clock_it_high:
  cbi   DDRC,   sda_bit     ; release sda_bit - float sda high
  rjmp  clock_it
i2c_bit_write_low:
  sbi   DDRC,   sda_bit     ; force sda line low
clock_it:
  rcall i2cDelay_6
  cbi   DDRC,   scl_bit     ; release scl_bit - float scl high
  rcall i2cDelay_6
  sbi   DDRC,   scl_bit     ; force scl_bit low
  rcall i2cDelay_6
next_i2c_byte:
  lsl temp3
  rjmp  i2c_write_bit
  
i2c_get_ack:
  cbi   DDRC,   sda_bit     ; release sda_bit - float sda high
  rcall i2cDelay_6
  cbi   DDRC,   scl_bit     ; release scl_bit - float scl high
  rcall i2cDelay_6
i2c_get_ack_wait:
  sbis  PINC,   scl_bit     ; wait sda_bit high
  rjmp  i2c_get_ack_wait
  sbi   DDRC,   sda_bit     ; force sda_bit low
  rcall i2cDelay_6
  sbi   DDRC,   scl_bit     ; force scl_bit low
  rcall i2cDelay_6
  clc                       ; clear carry flag
  sbic  PINC,   sda_bit     ; if sda_bit is high
  sec                       ; set carry flag
  rcall i2cDelay_6
  ret  

i2c_stop:
  sbi   DDRC,   scl_bit     ; force scl_bit low
  sbi   DDRC,   sda_bit     ; force sda_bit low
  rcall i2cDelay_6
  cbi   DDRC,   scl_bit     ; release scl_bit
  rcall i2cDelay_6
  cbi   DDRC,   sda_bit     ; release sda_bit
  rcall i2cDelay_6
  ret
  
i2cDelay_6: ; 6 clock cycles or 6 uSeconds
; rcall instruction takes 2 clock cycles
; ret instruction takes 4 clock cycles
  ret

; Data transfer is initiated with a start condition (S) signaled by sda_bit being pulled low while SCL stays high.

;************************************
lcd_init:
;* uses temp2 to send LCD Command
;************************************
  ldi   temp1,  20
	mov		delay_1ms,  temp1	;wait 20 milliseconds for LCD to stabilize
	rcall	WAIT

  ldi   temp1,  $38
	mov		temp2,  temp1			;set for 8 bits, 2 lines, default font
	rcall LCDCMD
	ldi   temp1,  2
	mov		delay_1ms,  temp1		;wait 2 millisecond
  rcall	WAIT

	ldi		temp2,$0E			;Display on, CURSOR on, blink off
	rcall LCDCMD
	ldi   temp1,  2
	mov		delay_1ms,  temp1		;wait 2 millisecond
  rcall	WAIT

	ldi		temp2,$01			;Clear screen, CURSOR home
	rcall LCDCMD
	ldi   temp1,  2
	mov		delay_1ms,  temp1		;wait 2 millisecond
  rcall	WAIT
  
	ret

;************************************
;* LCDCMD - Send a command to the LCD
;* temp2 = cmd
;*****************************************
;* LCDCHR - Display a character on the LCD
;* temp1 = data
;************************************
LCDCMD:
  push temp2
  push temp1
  mov temp1,temp2
	rcall	SENDBYTE
	cbi		PORTC,lcd_drs			;set RS low
	rjmp	LCDEXEC
LCDCHR:
  push temp2
  push temp1
	rcall	SENDBYTE
	sbi		PORTC,lcd_drs			;set RS High
LCDEXEC:
	sbi		PORTC,lcd_e				;E clocks on rising edge
	ldi   temp1,  2
	mov		delay_1ms,  temp1		;wait 2 millisecond
	cbi		PORTC,      lcd_e		;set E low
	rcall	WAIT
	pop temp1
	pop temp2
	ret

;**********************************
;* SENDBYTE clock byte into 74hc164
;* temp1 = data
;* temp2 = bitcounter
;***********************************
SENDBYTE:
  push temp1
	push	temp2
	ldi		temp2,8					;bit counter
ShiftBits:
	cbi		PORTC,lcd_drs   ;set LCD Data bit to 0
	lsl		temp1						;shift bits in AReg into carry
	brcc	ClockBit				;if zero, clock it out
	sbi		PORTC,lcd_drs   ;if 1, set LCD Data bit to 1
ClockBit: 
	sbi		PORTC,lcd_cp		  ;bit clocks on rising edge
	cbi		PORTC,lcd_cp		  ;bring clock back to 0
	dec		temp2						;shift out 8 bits
	brne	ShiftBits
	pop		temp2
	pop temp1
	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

SHOW_HEX_BYTE: ; display temp1 as two (2) hex chars
  push  temp1
  rcall LCDCMD
  pop temp1
	push	temp1
	swap	temp1
	rcall SHOW_NIBBLE ; process upper nibble
	pop		temp1
	rcall SHOW_NIBBLE ; process lower nibble
	ret
SHOW_NIBBLE: ; display lower 4 bits in temp1 as hex char
  push	temp2
	andi	temp1,  $0F
	ori		temp1,  $30
	cpi		temp1,  $3A
	brlo	SHOW_NIBBLE2
	ldi   temp2,  $07
	add 	temp1,  temp2
SHOW_NIBBLE2:
	rcall	LCDCHR  ; display temp1
	pop   temp2
	ret

;************************************
;* WAIT
;* temp1 = WAIT time in milliseconds
;************************************
WAIT:
	tst		delay_1ms
	brne	WAIT
	ret

GET_TUNE_VALUES:
	mov   temp4,  tune_rate
	cpi   temp4,  $30
	brne  tune_10
	rjmp  GET_TUNE_VALUES_EXIT
tune_10:	
	cpi   temp4,  $31
	brne  tune_20
	rjmp  GET_TUNE_VALUES_EXIT
tune_20:	
	cpi   temp4,  $32
	brne  tune_30
	rjmp  GET_TUNE_VALUES_EXIT
tune_30:
  cpi   temp4,  $33
	brne  tune_40
	rjmp  GET_TUNE_VALUES_EXIT
tune_40:
  cpi   temp4,  $34
	brne  tune_50
	rjmp  GET_TUNE_VALUES_EXIT
tune_50:
  cpi   temp4,  $35
	brne  tune_60
	rjmp  GET_TUNE_VALUES_EXIT
tune_60:
  cpi   temp4,  $36
	brne  tune_70
	rjmp  GET_TUNE_VALUES_EXIT
tune_70:
  cpi   temp4,  $37
	brne  GET_TUNE_VALUES_EXIT
GET_TUNE_VALUES_EXIT:
  ret
  
.if encoder_type  ==  2

EXT_INT0: ; logic change on INT0 (PD2)
	push	temp1           ;save temp1 register
	in		temp1,SREG      ;save the status register
	push	temp1
	push  temp2
	push  temp3
	push  temp4
  in    temp1,  PIND          ; get portd
  andi  temp1,  $0C           ; mask off portd2 & portd3
  breq  EXT_INT0_70           ; if both bits are clear decrement encoder_1
  cpi   temp1,  $0C           ; are both bits set?
  breq  EXT_INT0_70           ; if both bits are set decrement encoder_1
  inc   tune_flag
  rjmp	INT0_EXIT
EXT_INT0_70:
  dec   tune_flag
INT0_EXIT:
  pop   temp4
  pop   temp3
  pop   temp2
	pop		temp1
	out		SREG,temp1      ;restore the status register
	pop		temp1           ;restore temp1 register
  reti
  
EXT_INT1: ; logic change on INT1 (PD3)
	push	temp1           ;save temp1 register
	in		temp1,SREG      ;save the status register
	push	temp1
	push  temp2
	push  temp3
	push  temp4
  in    temp1,  PIND          ; get portd
  andi  temp1,  $0C           ; mask off portd2 & portd3
  breq  INT1_1                ; if both bits are clear increment encoder_1
  cpi   temp1,  $0C           ; are both bits set?
  breq  INT1_1                ; if both bits are set increment encoder_1
  dec   tune_flag
  rjmp	INT1_EXIT
INT1_1:
  inc   tune_flag
INT1_EXIT:
  pop   temp4
  pop   temp3
  pop   temp2
	pop		temp1
	out		SREG,temp1      ;restore the status register
	pop		temp1           ;restore temp1 register
  reti

.elif encoder_type  ==  1
	
EXT_INT0:
	push	temp1 ;save temp1 register
	in		temp1,SREG ;save the status register
	push	temp1
	lds		temp1,EICRA
	cpi		temp1,0b00000010	; test for falling edge
	breq	int15
; rising edge processing
	ldi		temp1,0b00000010	; set int0 on falling edge
	sts		EICRA,temp1
	sbis	PIND, output_b ; skip if bit is set - test PHASE
	rjmp	int11
  dec   tune_flag
	rjmp	int19
int11:
  inc   tune_flag
	rjmp	int19
int15: ; falling edge processing
	ldi		temp1,0b00000011	; set int0 for rising edge - for next interrupt
	sts		EICRA,temp1
	sbis	PIND, output_b ; skip if bit is set - test PHASE
	rjmp	int16
  inc   tune_flag
	rjmp	int19
int16:
  dec   tune_flag
int19:
	pop		temp1
	out		SREG,temp1 ;restore the status register
	pop		temp1   ;restore temp1 register
	reti
	
	EXT_INT1:
	reti

.else

EXT_INT0:
	reti

EXT_INT1:
	reti

.endif

TIMER0_OVF:
; with System Clock Prescaler set to /8
; and Timer/Counter Prescaler set to /8
; and TCNT0 loaded with 125 (see below)
  push  temp1
  push  temp2
  in    temp1,  SREG
  push  temp1
  ldi   temp1,  256-125 ;	set for 1 mS - 8 uS per count
  out   TCNT0,  temp1   ;	set for next overflow
  tst   delay_1ms
  breq  TIMER0_OVF_exit
  dec   delay_1ms
TIMER0_OVF_exit:
  pop   temp1
  out   SREG,   temp1
  pop   temp2
  pop   temp1
  reti


PCI2:
  push  temp1
  in    temp1,  SREG
  push  temp1
  
  in    temp1,  PIND
  andi  temp1,  0b00000010    ; mask off PD1
  tst   temp1
  brne  PCI2_EXIT2 ; throw away button release interrupt
  
  mov   temp1,  tune_rate
  ori   temp1,  $80   ; set bit_7 of tune_rate to flag show_rate
  dec   temp1
  cpi   temp1,  $AF
  brne  PCI2_EXIT
  ldi   temp1,  $B6   ; tune_rate
PCI2_EXIT:
  mov   tune_rate,  temp1
PCI2_EXIT2:
  pop   temp1
  out   SREG,   temp1
  pop   temp1
  reti

get_keypad:
 sbi DDRB,0 ; make PB0 an output
 cbi PORTB,0 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'1'
 sbis PINB,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'2'
 sbis PINB,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'3'
 sbis PINB,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'A'
 sbis PINB,7 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 sbi PORTB,0 ; Set Bit in I/O Register
 cbi DDRB,0 ; make PB0 an input
 
 sbi DDRB,1 ; make PB1 an output
 cbi PORTB,1 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'4'
 sbis PINB,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'5'
 sbis PINB,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'6'
 sbis PINB,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'B'
 sbis PINB,7 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 sbi PORTB,1 ; Set Bit in I/O Register
 cbi DDRB,1 ; make PB1 an input
 
 sbi DDRB,2 ; make PB2 an output
 cbi PORTB,2 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop
 ldi temp1,'7'
 sbis PINB,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'8'
 sbis PINB,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'9'
 sbis PINB,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'C'
 sbis PINB,7 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 sbi PORTB,2 ; Set Bit in I/O Register
 cbi DDRB,2 ; make PB2 an input
 
 sbi DDRB,3 ; make PB3 an output
 cbi PORTB,3 ; Clear Bit in I/O Register
 nop ; at least one 'nop' required for keypad operation
 nop 
 ldi temp1,'*'
 sbis PINB,4 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'0'
 sbis PINB,5 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'#'
 sbis PINB,6 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 ldi temp1,'D'
 sbis PINB,7 ; Skip if Bit in I/O Register is Set
 rjmp grk_exit
 sbi PORTB,3 ; Set Bit in I/O Register
 cbi DDRB,3 ; make PB3 an input
 
 clr temp1
 
 rjmp grk_exit2
grk_exit: ; keypad key found/hit
 mov  keypad,  temp1
 ldi   temp2,  250
 mov		delay_1ms,  temp2		;wait 250 millisecond to remove bounce
 rcall WAIT
grk_exit2:
 sbi PORTB,0 ; Set Bit in I/O Register
 sbi PORTB,1 ; Set Bit in I/O Register
 sbi PORTB,2 ; Set Bit in I/O Register
 sbi PORTB,3 ; Set Bit in I/O Register
 cbi DDRB,0 ; make PA0 an input
 cbi DDRB,1 ; make PA1 an input
 cbi DDRB,2 ; make PA2 an input
 cbi DDRB,3 ; make PA3 an input
 ret
