list n=0 ; Turn off page breaks in the List file
;
#DEFINE RIT
;
;********************************************************************************
; *
; COPYRIGHT NOTICE *
; *
; Copyright T Mowles VK5TM 2022 *
; AD9850_VFO-16F1827.asm *
; *
; *
; *******************************************************************************
;
;********************************************************************************
;
; Target Controller PIC16F1827
; __________
; RIT IN-----RA2 |1 18| RA1---SPARE
; PWR DETECT-RA3 |2 17| RA0---DDS_LOAD
; SPARE------RA4 |3 16| RA7---DDS_DATA
; SPARE------RA5 |4 15| RA6---DDS_CLK
; Ground-----Vss |5 14| VDD---+5 V
; ENCODER----RB0 |6 13| RB7---SPARE
; ENCODER----RB1 |7 12| RB6---LED STEP 10kHz
; STEP SW----RB2 |8 11| RB5---LED STEP 1kHz
; CAL--------RB3 |9 10| RB4---LED STEP 10Hz
; ----------
;
; *******************************************************************************
; * Device type and options *
; *******************************************************************************
;
processor 16F1827
radix dec
errorlevel -207 ; Skip found label after column 1
errorlevel -302 ; Skip out of bank nuisance messages
errorlevel -303 ; Skip program word too large. Truncated to core size
;
; *******************************************************************************
; * Configuration fuse information for 16F1827: *
; *******************************************************************************
;
include <P16F1827.INC>
__CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;
; *******************************************************************************
;
; *******************************************************************************
; * Allocate variables in general purpose register space *
; *******************************************************************************
;
CBLOCK 0x20 ; Start Data Block
AD9851_0 ; AD9850/AD9851 control word
AD9851_1 ; (5 bytes)
AD9851_2
AD9851_3
AD9851_4
fstep_0 ; Frequency inc/dec
fstep_1 ; (4 bytes)
fstep_2
fstep_3
mult_count ; Used in calc_dds_word
bit_count ; "
byte2send ;
osc_temp_0 ; Oscillator frequency
osc_temp_1 ; (4 bytes)
osc_temp_2
osc_temp_3
timer1 ; Used in delay routines
timer2 ; "
dir ; for encoder routine
encold ; for encoder routine
count
byte_count
flags ; RIT Flags
; flags,0 = 0 - RIT = 0
; flags,1 = 0 - RIT = same as last time
; flags,1 = 1 - RIT = changed
NumH_temp
NumL_temp
temp
rxf_0 ; VFO frequency if NO RIT
rxf_1 ; "
rxf_2 ; "
rxf_3 ; "
ritf_0 ; VFO frequency if RIT active
ritf_1 ; "
ritf_2 ; "
ritf_3 ; "
ENDC ; End of Data Block
CBLOCK 0x70 ; Use bank common locations - saves bank switching
freq_0 ; Frequency (hex)
freq_1 ; (4 bytes)
freq_2 ;
freq_3 ;
osc_0 ; Current oscillator
osc_1 ; (4 bytes)
osc_2
osc_3
step_size ; 0=10Hz 1=1kHz 2=10kHz step size
NumH ; Used in RIT routine
NumL ; "
ENDC ; End of Data Block
;
; *******************************************************************************
; * General equates. These may be changed to accommodate the reference clock *
; * frequency, the desired upper frequency limit, and the default startup *
; * frequency. *
; *******************************************************************************
;
; For 125 MHz Oscillator =======
ref_osc_3 equ 0x22 ; Most significant osc byte
ref_osc_2 equ 0x5C ; Next byte
ref_osc_1 equ 0x17 ; Next byte
ref_osc_0 equ 0xD0 ; Least significant byte
;
; Change limits to suit
;
; Limit_0...3 contains the upper limit frequency as a 32 bit integer.
;
limit_hi_3 equ 0x00 ; Most significant byte for 5.5 MHz
limit_hi_2 equ 0x53 ; Next byte
limit_hi_1 equ 0xEC ; Next byte
limit_hi_0 equ 0x60 ; Least significant byte
;
; Low_limit_3..0 contains the lower frequency limit as a 32 bit integer
;
limit_low_3 equ 0x00 ; Most significant byte for 5.0 MHz
limit_low_2 equ 0x4C ; Next byte
limit_low_1 equ 0x4B ; Next byte
limit_low_0 equ 0x40 ; Least significant byte
;
; Default contains the default startup frequency as a 32 bit integer.
; This will be overwritten by the frequency save routine in normal use.
;
default_3 equ 0x00 ; Most significant byte for 5.0 MHz
default_2 equ 0x4C ; Next byte
default_1 equ 0x4B ; Next byte
default_0 equ 0x40 ; Least significant byte
;
; Frequency at which Calibration will take place
;
cal_freq_3 equ 0x00 ; Most significant byte for 5.250 MHz
cal_freq_2 equ 0x50 ; Next byte
cal_freq_1 equ 0x1B ; Next byte
cal_freq_0 equ 0xD0 ; Least significant byte
;
EEstartup_adr equ 4 ; Location of startup frequency in EEPROM
;
#IFDEF RIT
#define center 486 ; RIT pot center value///////////////////////////
#ENDIF
;
; *******************************************************************************
; * Setup the initial constant, based on the frequency of the reference *
; * oscillator. This can be tweaked with the calibrate function. *
; *******************************************************************************
;
ORG 0xF000 ; For 16F1827
; ref_osc bytes must be first 4 bytes of EEPROM
DATA ref_osc_0
DATA ref_osc_1
DATA ref_osc_2
DATA ref_osc_3
; startup frequency bytes must be next 4 bytes of EEPROM
DATA default_0 ; startup -> freq_0
DATA default_1 ; startup -> freq_1
DATA default_2 ; startup -> freq_2
DATA default_3 ; startup -> freq_3
DATA 0
;
; *******************************************************************************
; * Assign names to IO pins. *
; *******************************************************************************
#DEFINE DDS_clk LATA,6 ; AD9850/AD9851 write clock
#DEFINE DDS_dat LATA,7 ; AD9850/AD9851 serial data input
#DEFINE DDS_load LATA,0 ; Update pin on AD9850/AD9851
#DEFINE CAL_sw PORTB,3 ; Cal switch input
#DEFINE STEP_sw PORTB,2 ; Step switch input
;
;
; 16F1827 Oscillator setup
; OSCCON - Oscillator control reg.
; ---------------------------------
; SPLLEN bit 7 enable PLL x4
; 1 = enabled 0 = disabled
; IRCF | bits 6-3 frequency selection
; 1111 = 16MHz HF
; 1110 = 8 or 32MHz HF
; 1101 = 4MHz HF
; 1100 = 2MHz HF
; 1011 = 1MHz HF
; 1010 = 500kHz HF
; 1001 = 250kHz HF
; 1000 = 125kHz HF
; 0111 = 500kHz MF (default)
; 0110 = 250kHz MF
; 0101 = 125kHz MF
; 0100 = 62.5kHz MF
; 0011 = 31.25kHz HF
; 0010 = 31.25kHz MF
; 000x = 31.25kHz LF
; Reserved bit 2 reserved, 0
; SCS bits 1-0: 1x = int. OSC.
; 01 = Timer1 oscillator
; 00 = determined by FOSC <2:0> in Configuration
; POR default 00111-00 500 kHz (POR = Power On Reset)
OSCCONVAL EQU b'01101000' ; 4MhZ CLOCK
;
; *******************************************************************************
; * Purpose: This is the start of the program. *
; *******************************************************************************
;
;
ORG 0x0000
BRA start ; Jump to main program
ORG 0x0004 ; interrupt routine data save
; BRA start
bcf INTCON,GIE ; Clear Global Interrupt Enable bit
;
BANKSEL PIR2
bcf PIR2,C2IF ; Clear comparator flag
movlb 0
;
clrf PORTA
clrf PORTB
;
retfie ; Enable general interrupts and return
;
start
clrf INTCON ; clear INTCON
clrf PORTA
clrf PORTB
clrf step_size
clrf NumH_temp
clrf NumL_temp
; Set PIC oscillator frequency
banksel OSCCON ; Select OSCCON
movlw OSCCONVAL ;
movwf OSCCON ; Loads the wanted oscillator value
; Configures I/O as analog/digital
Banksel ANSELA
; movlw b'00001000' ; RA3 analog all others digital
movlw b'00001100' ; RA2:3 analog all others digital
movwf ANSELA
clrf ANSELB ; PORTB all digital
; Disable all wakeup pull-ups
Banksel WPUA
clrf WPUA
clrf WPUB
banksel OPTION_REG
movlw b'10000000' ; Pull-ups disabled
movwf OPTION_REG ;
;
; movlw b'00111110' ; PORTA (RA0 & 6:7 outputs RA1:5 inputs)
movlw b'00111110' ; ##TEST TEMP## PORTA (RA0 & 6:7 outputs RA1:5 inputs)
movwf TRISA ;
movlw b'10001111' ; PORTB 0:3 & 7 inputs 4:6 outputs
movwf TRISB ; NOTE: Pull-up via 10k resistor all unused pins
;
BANKSEL FVRCON
; movlw b'10001100' ; FVR on, Comparator ref 4.096V
movlw b'10001000' ; FVR on, Comparator ref 2.048V
movwf FVRCON
;
movlb 0
movlw 40 ; Delay for FVR to stabilise
movwf temp
decfsz temp,f
BRA $-1
BANKSEL CM1CON0
clrf CM1CON0
clrf CM1CON1
movlw b'10100011'
movwf CM2CON1 ; Positive interrupt on
; Negative interrupt off
; C2VP connects to FVR
; C2VP connects to FVR
; Unimplemented
; Unimplemented
; C2VN connects to C12IN3- pin - RA3
; C2VN connects to C12IN3- pin - RA3
movlw b'10000110'
movwf CM2CON0 ; Comparator enabled
; Comparator Output bit polarity
; Comparator Output internal
; Comparator output is not inverted
; Unimplemented
; Comparator operates in normal power, higher speed mode
; Comparator hysteresis enabled
; Comparator output to Timer1 and I/O pin is asynchronous
movlb 0
;
; Initialize DDS Module with zero freq
;
clrf AD9851_0 ; AD9850/51 control words
clrf AD9851_1 ; (5 bytes)
clrf AD9851_2
clrf AD9851_3
clrf AD9851_4
call send_dds_word ; Send it to the DDS twice to be sure
call send_dds_word ;
;
; Enter Calibrate Mode if PORTB,3 is low when turning the power on
btfss CAL_sw ; Cal pushbutton pressed?
call calibrate ; Yes, call calibration routine
;
; Get the reference oscillator constant from the EEPROM
;
read_EEocs
;
BANKSEL EEADRL ;
clrf EEADRL ; Data Memory Address to read
call read_EEPROM ; Read EEPROM
movf EEDATL,W ; Get the first osc byte
movwf osc_0 ; Save osc frequency
call read_EEPROM ; Read EEPROM
movf EEDATL,W ;
movwf osc_1 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,W ;
movwf osc_2 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,W ;
movwf osc_3 ; Save it
;
; Set the power on frequency to the defined value
; (They always follow the osc bytes)
;
call read_EEPROM ; Read EEPROM
movf EEDATL,w ; Get the first default freq byte
movwf freq_0 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,w ; Get the next freq byte
movwf freq_1 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,w ; Get the next freq byte
movwf freq_2 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,w ; Get the last freq byte
movwf freq_3 ; Save it
call read_EEPROM ; Read EEPROM
movf EEDATL,w ; Get step size
movwf step_size ; Save it
movlb 0 ; Back to bank 0
call step_led
;
#IFDEF RIT
call freq_to_rxf ; Load rxf registers with start-up frequency
; call freq_to_ritf ; Load ritf registers with start-up frequency
BANKSEL ADCON1 ; Set up ADC
movlw b'11000000' ; right justify, FOSC/4 vdd and vss vref
movwf ADCON1 ;
BANKSEL ADCON0 ;
movlw b'00001001' ; select channel an2 & turn adc on
movwf ADCON0 ;
movlb 0
rit_test
movlw 50 ; Delay for ADC to stabilise
movwf count
decfsz count,f
BRA $-1
PAGESEL rit
call rit ; Get RIT value
PAGESEL $
btfss flags,0 ; RIT = 0 if flags,0 = 0
BRA exit_start ; No RIT shift, start with saved frequency
call stepdir ; Else add/subtract RIT to start frequency
#ENDIF
;
exit_start
call update_dds
;PIC Time Delay = 0.09999800 s with Osc = 4000000 Hz
movlw D'130' ;///Testing RIT function
movwf timer2 ;///Testing RIT function
movlw D'221' ;///Testing RIT function
movwf timer1 ;///Testing RIT function
loop
decfsz timer1,1 ;///Testing RIT function
goto loop ;///Testing RIT function
decfsz timer2,1 ;///Testing RIT function
goto loop
call rxf_to_freq ;///Testing RIT function
BRA rit_test ;///Testing RIT function
;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Currently doesn't progress past this point as testing RIT function
; operation during the start up phase but it does use routines past this point.
;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
movf PORTB,w ; Get the power on encoder value
movwf encold ; Save it
movlw b'00000011' ; Get encoder mask (PORTB,0 and PORTB,1)
andwf encold,f ; Get encoder bits and zero all other bits
clrf dir ; Clear the knob direction indicator
clrf PIR2 ; Clear interrupt flags in PIR2
BANKSEL PIE2
bsf PIE2,C2IE ; Turn on Comparator 2 interrupt
bsf INTCON,PEIE ; Turn on Periperal interrupts
bsf INTCON,GIE ; Enable general interrupts
movlb 0
;
; *******************************************************************************
; * *
; * Purpose: This is the Main Program Loop. The program's main loop *
; * calls poll_encoder, which continuously polls the rotary shaft *
; * encoder. When the shaft encoder has changed, the direction *
; * it moved is determined and stored in 'dir'. The subroutine *
; * then returns to main. *
; * *
; * The variable fstep is added or subtracted from the current *
; * VFO frequency and stored in freq. *
; * Next, the subroutine calc_dds_word is used to calculate the DDS *
; * frequency control word from the values in freq and osc. *
; * The result is stored in AD9850/AD9851. This data is transferred *
; * to the AD9851 DDS chip by calling the subroutine send_dds_word. *
; * *
; *******************************************************************************
;
main
call poll_encoder ; Check for knob movement (wait there!)
; Return here when encoder or RIT change detected
#IFDEF RIT
btfsc flags,1 ; Has RIT changed?
BRA rit_adjust ; Yes
#ENDIF
call step ; No
call stepdir
call update_dds
BRA main
#IFDEF RIT
rit_adjust
call rxf_to_freq ; move base frequency minus old RIT to freq_0:3
btfsc flags,0 ; If RIT = 0 send base frequency to DDS
call stepdir
call update_dds
BRA main
#ENDIF
;
; *******************************************************************************
; Code for pushbutton selection of step size *
; Step size 10Hz/1kHz/10kHz *
; *******************************************************************************
step ;
clrf fstep_3 ;
clrf fstep_2 ;
clrf fstep_1 ;
clrf fstep_0 ;
step1
movfw step_size ; If step_size = 0
xorlw 0
btfsc STATUS,Z
BRA step_10hz ; Set step to 10Hz
movfw step_size ; If step_size = 1
xorlw 1
btfsc STATUS,Z
BRA step_1khz ; Set step to 1kHz
; Else step_size = 10kHz
movlw 0x10 ; 10kHz steps
movwf fstep_0 ;
movlw 0x27 ;
movwf fstep_1 ;
return
step_10hz ;
movlw 0x0A ; 10Hz steps
movwf fstep_0 ;
return
step_1khz
movlw 0xE8 ; 1kHz steps
movwf fstep_0 ;
movlw 0x03 ;
movwf fstep_1 ;
return
;
; Based on the knob direction, either add or subtract the increment,
; then update DDS.
;
stepdir
btfsc dir,0 ; Is the knob going up?
BRA up ; Yes, then add the increment
down
call sub_step ; Subtract fstep from freq
return
up
call add_step ; Add fstep to freq
call check_add ; Make sure we did not exceed the maximum
return
update_dds
call calc_dds_word ; Calculate the control word for the DDS chip
call send_dds_word ; Send the control word to the DDS chip
return
;
; *******************************************************************************
; * *
; * Purpose: Poll encoder *
; * *
; *******************************************************************************
;
poll_encoder
;
btfss CAL_sw ; Test if in calibrate mode
BRA read_encoder
;
; *******************************************************************************
; * Code for pushbutton selection of step size *
; *******************************************************************************
;
btfsc STEP_sw ; Is Step switch pushed?
#IFDEF RIT
BRA read_rit
#ELSE
BRA read_encoder ;
#ENDIF
incf step_size,f
movfw step_size ; Keep step_size in range of 0 - 2
xorlw 3
btfsc STATUS,Z
clrf step_size
step_exit
btfss STEP_sw
BRA step_exit ; Wait for Step switch to be released
call step_led
#IFDEF RIT
read_rit
PAGESEL rit ;
call rit
PAGESEL $
; TEST FLAG TO SEE IF RIT VALUE CHANGED - IF YES RETURN ELSE CARRY ON TO READ ENCODER
btfsc flags,0
return
#ENDIF
;
read_encoder
movf PORTB,w ; load switch data
andlw b'00000011' ; mask encoder B and A switches
xorwf encold,w ; same as last reading?
btfsc STATUS,Z
BRA poll_encoder ; yes, branch (no change), else
xorwf encold,w ; restore encoder bits in W
rrf encold,f ; prep for B-old ^ A-new
xorwf encold,f ; encold bit 0 = direction
rrf encold,f ; now Carry bit = direction
movwf encold ; update encold (new BA bits)
;
; encoder position has changed but we only act on a change
; that occurs when the encoder falls into one of the detent
; positions (we ignore the changes between detents)
;
xorlw b'00000011' ; detent position?
btfss STATUS,Z
BRA read_encoder ; No, go test again
bcf dir,0 ; Set direction bit based on value in STATUS,C
btfsc STATUS,C ; 1 = UP
bsf dir,0
return
;
; *******************************************************************************
; * *
; * Set step size and output pulses to indicate step size *
; * *
; *******************************************************************************
step_led
movfw step_size ; If step_size = 0
xorlw 0
btfsc STATUS,Z
BRA step_led10hz ; Set 10Hz LED
movfw step_size ; If step_size = 1
xorlw 1
btfsc STATUS,Z
BRA step_led1khz ; Set 1kHz LED
;
; ; Else set 10kHz LED
;
BANKSEL LATB
bsf LATB,6 ; 10kHz LED
nop
bcf LATB,5 ; 1kHz LED
nop
bcf LATB,4 ; 10Hz LED
movlb 0
return
;
step_led10hz
BANKSEL LATB ;
bsf LATB,4
nop
bcf LATB,5
nop
bcf LATB,6
movlb 0
return
;
step_led1khz
BANKSEL LATB
bsf LATB,5
nop
bcf LATB,6
nop
bcf LATB,4
movlb 0
return
;
; *******************************************************************************
; * *
; * Purpose: This routine adds the 32 bit value of fstep to the 32 bit *
; * value in freq. When incrementing, the fstep value is a *
; * positive integer. When decrementing, fstep is the complement *
; * of the value being subtracted. *
; * *
; * Input: The 32 bit values in fstep and freq *
; * *
; * Output: The sum of fstep and freq is stored in freq. When incrementing *
; * this value may exceed the maximum. When decrementing, it may *
; * go negative. *
; * *
; *******************************************************************************
;
org 0x100
add_step
movf fstep_0,w ; Get low byte of the increment
addwf freq_0,f ; Add it to the low byte of freq
btfss STATUS,C ; Any carry?
BRA add1 ; No, add next byte
incfsz freq_1,f ; Ripple carry up to the next byte
BRA add1 ; No new carry, add next byte
incfsz freq_2,f ; Ripple carry up to the next byte
BRA add1 ; No new carry, add next byte
incf freq_3,f ; Ripple carry up to the highest byte
add1
movf fstep_1,w ; Get the next increment byte
addwf freq_1,f ; Add it to the next higher byte
btfss STATUS,C ; Any carry?
BRA add2 ; No, add next byte
incfsz freq_2,f ; Ripple carry up to the next byte
BRA add2 ; No new carry, add next byte
incf freq_3,f ; Ripple carry up to the highest byte
add2
movf fstep_2,w ; Get the next to most significant increment
addwf freq_2,f ; Add it to the freq byte
btfss STATUS,C ; Any carry?
BRA add3 ; No, add last byte
incf freq_3,f ; Ripple carry up to the highest byte
add3
movf fstep_3,w ; Get the most significant increment byte
addwf freq_3,f ; Add it to the most significant freq
return ; Return to the caller
;
; *******************************************************************************
; * *
; * Purpose: Check if freq exceeds the upper limit. *
; * If freq is below the limit, it is unchanged. Otherwise, it is *
; * set to equal the upper limit. *
; * *
; *******************************************************************************
;
check_add
;
; Check the most significant byte.
;
movlw 0xFF-limit_hi_3 ; Get (FF - limit of high byte)
addwf freq_3,w ; Add it to the current high byte
btfsc STATUS,C ; Was high byte too large?
BRA set_max ; Yes, apply limit
movlw limit_hi_3 ; Get high limit value
subwf freq_3,w ; Subtract the limit value
btfss STATUS,C ; Are we at the limit for the byte?
BRA exit1 ; No, below. Checks are done.
;
; Check the second most significant byte.
;
movlw 0xFF-limit_hi_2 ; Get (FF - limit of next byte)
addwf freq_2,w ; Add it to the current byte
btfsc STATUS,C ; Is the current value too high?
BRA set_max ; Yes, apply the limit
movlw limit_hi_2 ; Second limit byte
subwf freq_2,w ; Subtract limit value
btfss STATUS,C ; Are we at the limit for the byte?
BRA exit1 ; No, below. Checks are done.
;
; Check the third most significant byte.
;
movlw 0xFF-limit_hi_1 ; Get (FF - limit of next byte)
addwf freq_1,w ; Add it to the current byte
btfsc STATUS,C ; Is the current value too high?
BRA set_max ; Yes, apply the limit
movlw limit_hi_1 ; Third limit byte
subwf freq_1,w ; Subtract limit value
btfss STATUS,C ; Are we at the limit for the byte?
BRA exit1 ; No, below. Checks are done.
;
; Check the least significant byte.
;
movlw limit_hi_0 ; Fourth limit byte
subwf freq_0,w ; Subtract limit value
btfss STATUS,C ; Are we at the limit for the byte?
BRA exit1 ; No, below. Checks are done.
set_max
movlw limit_hi_0 ; Get least significant limit
movwf freq_0 ; Set it in freq
movlw limit_hi_1 ; Get the next byte limit
movwf freq_1 ; Set it in freq_1
movlw limit_hi_2 ; Get the next byte limit
movwf freq_2 ; Set it in freq_2
movlw limit_hi_3 ; Get the most significant limit
movwf freq_3 ; Set it in freq_3
exit1
return ; Return to the caller
;
; *******************************************************************************
; * *
; * Purpose: Subtract the increment step from freq. *
; * *
; *******************************************************************************
;
sub_step
;
call invert_fstep ; Invert fstep_3..0 to perform the subtraction
call add_step ; Add the complement to do the subtraction
;
; *******************************************************************************
; * *
; * Purpose: Test the new frequency to see if it is above the lower limit. *
; * If not, the frequency is set to the lower limit. *
; * *
; *******************************************************************************
;
low_limit_chk
; Check the most significant byte.
;
btfsc freq_3,7
BRA set_low ; Yes, set to lower frequency limit
movf freq_3,w
sublw limit_low_3
btfss STATUS,C ; Are we at the limit for the byte?
return ; No, above.
btfss STATUS,Z ; Are the bytes equal?
BRA set_low ; No, so vfo_X_3 > limit_3.
;
; Check the second most significant byte when MSB equals limit_3
;
movf freq_2,w
sublw limit_low_2
btfss STATUS,C ; Are we at the limit for the byte?
return ; No, above.
btfss STATUS,Z ; Might they be equal?
BRA set_low ; Nope, so vfo_X_2 > limit_2
;
; Check the third most significant byte.
;
movf freq_1,w
sublw limit_low_1
btfss STATUS,C ; Are we at the limit for the byte?
return ; No, above.
btfss STATUS,Z ; Check if the bytes are equal
BRA set_low ; No, so vfo_X_1 > limit_1
;
; Check the least significant byte.
;
movf freq_0,w
sublw limit_low_0
btfss STATUS,C ; Are we at the limit for the byte?
return ; No, above.
;
; The frequency is below the band lower limit. Set frequency to the
; band starting frequency.
set_low
movlw limit_low_0
movwf freq_0
movlw limit_low_1
movwf freq_1
movlw limit_low_2
movwf freq_2
movlw limit_low_3
movwf freq_3
return ; Return to caller
;
; *******************************************************************************
; * *
; * Function: invert_fstep *
; * *
; * Purpose: Support function for sub_step and calibrate. This function *
; * negates the value of fstep_3..0 to assist in the frequency *
; * decrement. This operation is performed twice by sub_step, and *
; * is also used by calibrate. *
; * *
; * Input: fstep_3, fstep_2, fstep_1, fstep_0 *
; * *
; * Output: fstep_3..0 contain the 2's complement of their original value *
; * *
; *******************************************************************************
;
invert_fstep ; Invert the bits in
comf fstep_0,f ; fstep_0
comf fstep_1,f ; fstep_1
comf fstep_2,f ; fstep_2
comf fstep_3,f ; fstep_3
incfsz fstep_0,f ; Now incremnt fstep_0 to get 2's complement
BRA invert_done ; If fstep_0 > 0, then done
; Else, there was a carry out of fstep_0
incfsz fstep_1,f ; Add 1 to fstep_1
BRA invert_done ; If fstep_1 > 0, then done
; Else, there was a carry out of fstep_1
incfsz fstep_2,f ; Add 1 to fstep_2
BRA invert_done ; if fstep_2 > 0, then done
; Else, there was a carry out of fstep_2
incf fstep_3,f ; Increment the high byte
;
invert_done
return ; Back to caller
;
; *******************************************************************************
; * *
; * Purpose: This routine is entered at start up if the calibrate pads are *
; * shorted at power-on time. *
; * *
; * The DDS chip is programmed to produce a frequency, based on the *
; * osc value stored in the EEPROM and the calibration frequency as *
; * at the head of the code. As long as the pads are shorted, the *
; * osc value is slowly altered to allow the output to be trimmed. *
; * Once the encoder is turned after the short is removed from the *
; * Cal pads, the new osc value is stored in the EEPROM and normal *
; * operation begins. *
; * *
; * Input: The original osc constant in EEPROM *
; * *
; * Output: The corrected osc constant in EEPROM *
; * *
; *******************************************************************************
;
calibrate
bcf INTCON,GIE ; Turn off interupts to be sure
;
movlw cal_freq_0 ; Move Calibration frequency constants
movwf freq_0 ; to freq_0...3 for Calibration routine.
movlw cal_freq_1 ;
movwf freq_1 ;
movlw cal_freq_2 ;
movwf freq_2 ;
movlw cal_freq_3 ;
movwf freq_3 ;
;
; Read the starting reference oscillator value from EEPROM.
;
BANKSEL EEADRL
clrf EEADRL ; Reset the EEPROM read address
call read_EEPROM ; Read first byte from EEPROM (all in bank 1)
movf EEDATL,w ; Get the first osc byte
movwf osc_0 ; Save osc frequency
call read_EEPROM ; Read second byte from EEPROM
movf EEDATL,w ;
movwf osc_1 ; Save it
call read_EEPROM ; Read third byte from EEPROM
movf EEDATL,w ;
movwf osc_2 ; Save it
call read_EEPROM ; Read fourth byte from EEPROM
movf EEDATL,w ;
movwf osc_3 ; Save it
movlb 0 ; Back to bank 0
;
cal_loop
call calc_dds_word ; Calculate DDS value based on current osc
call send_dds_word ; Update the DDS chip
call poll_encoder ; Wait until the encoder has moved.
btfsc CAL_sw ; Calibrate switch/jumper still set?
BRA cal_out ; No, go to exit and save values to EEPROM
clrf fstep_3 ; Clear the three most significant
clrf fstep_2 ; bytes of fstep
clrf fstep_1 ;
movlw 0x10 ;
movwf fstep_0 ; Use small increment
nop ; Wait a cycle
btfsc dir,0 ; Are we moving down?
BRA faster ; No, increase the osc value
;
; slower
;
comf fstep_0,f ; Subtraction of fstep is done by
comf fstep_1,f ; adding the twos compliment of fsetp
comf fstep_2,f ; to osc
comf fstep_3,f ;
incfsz fstep_0,f ; Increment last byte
BRA faster ; Non-zero, continue
incfsz fstep_1,f ; Increment next byte
BRA faster ; Non-zero, continue
incfsz fstep_2,f ; Increment next byte
BRA faster ; Non-zero, continue
incf fstep_3,f ; Increment the high byte
faster
movf fstep_0,w ; Get the low byte increment
addwf osc_0,f ; Add it to the low osc byte
btfss STATUS,C ; Was there a carry?
BRA add4 ; No, add the next bytes
incfsz osc_1,f ; Ripple carry up to the next byte
BRA add4 ; No new carry, add the next bytes
incfsz osc_2,f ; Ripple carry up to the next byte
BRA add4 ; No new carry, add the next bytes
incf osc_3,f ; Ripple carry up to the highest byte
add4
movf fstep_1,w ; Get the second byte increment
addwf osc_1,f ; Add it to the second osc byte
btfss STATUS,C ; Was there a carry?
BRA add5 ; No, add the third bytes
incfsz osc_2,f ; Ripple carry up to the next byte
BRA add5 ; No new carry, add the third bytes
incf osc_3,f ; Ripple carry up to the highest byte
add5
movf fstep_2,w ; Get the third byte increment
addwf osc_2,f ; Add it to the third osc byte
btfss STATUS,C ; Was there a carry?
BRA add6 ; No, add the fourth bytes
incf osc_3,f ; Ripple carry up to the highest byte
add6
movf fstep_3,w ; Get the fourth byte increment
addwf osc_3,f ; Add it to the fourth byte
BRA cal_loop ; Yes, stay in calibrate mode
;
; Write final value to EPROM
;
cal_out
BANKSEL EEADRL
movf osc_0,w ; Get the first osc byte to record
clrf EEADRL ; osc bytes start at EEPROM address 0
movwf EEDATL ; Put byte in EEPROM write location
call write_EEPROM ;
movf osc_1,w ; Get the second byte to record
movwf EEDATL ; Put byte in EEPROM write location
call write_EEPROM ;
movf osc_2,w ; Get the third byte to record
movwf EEDATL ; Put byte in EEPROM write location
call write_EEPROM ;
movf osc_3,w ; Get the fourth byte to record
movwf EEDATL ; Put byte in EEPROM write location
call write_EEPROM ;
movlb 0 ; Back to bank 0
return ; Return to the caller
;
; *******************************************************************************
; * *
; * Purpose: This routine will save the current frequency and step size in *
; * EEPROM on power down. *
; * *
; *******************************************************************************
;
update_EEPROM ;
bcf INTCON,GIE ; turn interrupts off
btfsc INTCON,GIE ; See AN576 - make sure interrupts are off
BRA $-2
BANKSEL EEADRL ;
movlw EEstartup_adr ; Get startup address location
movwf EEADRL ; and set up for start of EEPROM writes
movf freq_0,w ; Get the first freq byte to write
movwf EEDATL ; First freq byte to EEPROM Write register
call write_EEPROM ; Write it
movf freq_1,w ; Get the second freq byte to write
movwf EEDATL ; Second freq byte to EEPROM Write register
call write_EEPROM ; Write it
movf freq_2,w ; Get the third freq byte to write
movwf EEDATL ; Third freq byte to EEPROM Write register
call write_EEPROM ; Write it
movf freq_3,w ; Get the fourth freq byte to write
movwf EEDATL ; Fourth freq byte to EEPROM Write register
call write_EEPROM ; Write it
movf step_size,w ; Move step size value to w to save in to EEprom
movwf EEDATL ;
call write_EEPROM ; Write it
movlb 0 ; Back to bank 0
bsf INTCON,GIE ; turn interrupts on
return ;
;
; *******************************************************************************
; * *
; * Required sequence to write to EEPROM *
; * Used by update_EEPROM and calibrate routines *
; * *
; *******************************************************************************
;
write_EEPROM
bcf EECON1,CFGS ; Deselect Configuration space
bcf EECON1,EEPGD ; Point to DATA memory
bsf EECON1,WREN ; Set the EEPROM write enable bit
; Start of required sequence
movlw 0x55 ; Write 0x55 and 0xAA to EECON2
movwf EECON2 ; control register, as required
movlw 0xAA ;
movwf EECON2 ;
bsf EECON1,WR ; Set WR bit to begin write
; End of required sequence
bit_check
btfsc EECON1,WR ; Has the write completed?
BRA bit_check ; No, keep checking
bcf EECON1,WREN ; Clear the EEPROM write enable bit
incf EEADRL,f ; Increment the EE write address
return ; Return to the caller
;
; *******************************************************************************
; * *
; * Purpose: Read a byte of EEPROM data at address EEADR into EEDATA. *
; * *
; * Input: The address EEADR. *
; * *
; * Output: The value in EEDATA. *
; * *
; * NOTE: All in BANK 1 *
; * *
; *******************************************************************************
;
read_EEPROM
bcf EECON1,CFGS ; Deselect Config space
bcf EECON1,EEPGD ; Point to DATA memory
bsf EECON1,RD ; EE Read
incf EEADRL,f ; Increment the read address
return
;
; *******************************************************************************
; * *
; * Purpose: Multiply the 32 bit number for oscillator frequency times the *
; * 32 bit number for the displayed frequency. *
; * *
; * Input: The reference oscillator value in osc_3 ... osc_0 and the *
; * current frequency stored in freq_3 ... freq_0. The reference *
; * oscillator value is treated as a fixed point real, with a 24 *
; * bit mantissa. *
; * *
; * Output: The result is stored in AD9851_3 ... AD9851_0. *
; * *
; *******************************************************************************
;
org 0x200
calc_dds_word
;
clrf AD9851_0 ; Clear the AD9850/AD9851 control word bytes
clrf AD9851_1 ;
clrf AD9851_2 ;
clrf AD9851_3 ;
clrf AD9851_4 ;
movlw 0x20 ; Set count to 32 (4 osc bytes of 8 bits)
movwf mult_count ; Keep running count
movf osc_0,w ; Move the four osc bytes
movwf osc_temp_0 ; to temporary storage for this multiply
movf osc_1,w ; (Don't disturb original osc bytes)
movwf osc_temp_1 ;
movf osc_2,w ;
movwf osc_temp_2 ;
movf osc_3,w ;
movwf osc_temp_3 ;
mult_loop
bcf STATUS,C ; Start with Carry clear
btfss osc_temp_0,0 ; Is bit 0 (Least Significant bit) set?
BRA noAdd ; No, don't need to add freq term to total
movf freq_0,w ; Get the "normal" freq_0 term
addwf AD9851_1,f ; Add it in to total
btfss STATUS,C ; Does this addition result in a carry?
BRA add7 ; No, continue with next freq term
incfsz AD9851_2,f ; Yes, add one and check for another carry
BRA add7 ; No, continue with next freq term
incfsz AD9851_3,f ; Yes, add one and check for another carry
BRA add7 ; No, continue with next freq term
incf AD9851_4,f ; Yes, add one and continue
add7
movf freq_1,w ; Get the "normal" freq_0 term
addwf AD9851_2,f ; Add freq term to total in correct position
btfss STATUS,C ; Does this addition result in a carry?
BRA add8 ; No, continue with next freq term
incfsz AD9851_3,f ; Yes, add one and check for another carry
BRA add8 ; No, continue with next freq term
incf AD9851_4,f ; Yes, add one and continue
add8
movf freq_2,w ; Get the "normal" freq_2 term
addwf AD9851_3,f ; Add freq term to total in correct position
btfss STATUS,C ; Does this addition result in a carry?
BRA add9 ; No, continue with next freq term
incf AD9851_4,f ; Yes, add one and continue
add9
movf freq_3,w ; Get the "normal" freq_3 term
addwf AD9851_4,f ; Add freq term to total in correct position
noAdd
rrf AD9851_4,f ; Shift next multiplier bit into position
rrf AD9851_3,f ; Rotate bits to right from byte to byte
rrf AD9851_2,f ;
rrf AD9851_1,f ;
rrf AD9851_0,f ;
rrf osc_temp_3,f ; Shift next multiplicand bit into position
rrf osc_temp_2,f ; Rotate bits to right from byte to byte
rrf osc_temp_1,f ;
rrf osc_temp_0,f ;
decfsz mult_count,f ; One more bit has been done. Are we done?
BRA mult_loop ; No, go back and do next
#ifdef AD9850
movlw 0x00 ; No clock multiplier (AD9850)
#endif
#ifdef AD9851
movlw 0x01 ; Turn on 6x clock multiplier (AD9851)
#endif
movwf AD9851_4 ; Last byte to be sent
; Mult answer is in bytes _3 .. _0
return ; Done.
;
; *******************************************************************************
; * *
; * Purpose: This routine sends the AD9850/AD9851 control word to the DDS *
; * using a serial data transfer. *
; * *
; * Input: AD9851_4 ... AD9851_0 *
; * *
; * Output: The DDS chip register is updated. *
; * *
; *******************************************************************************
;
send_dds_word
movlw 5 ; Set number of control bytes to send
movwf byte_count ;
movlw LOW AD9851_0
movwf FSR0L
movlw HIGH AD9851_0
movwf FSR0H
next_byte
movf INDF0,w ;
movwf byte2send ;
movlw 0x08 ; Set counter to 8
movwf bit_count ;
next_bit
rrf byte2send,f ; Test if next bit is 1 or 0
btfss STATUS,C ; Was it zero?
BRA send0 ; Yes, send zero
BANKSEL LATA
bsf DDS_dat ; No, send one
bsf DDS_clk ; Toggle write clock
bcf DDS_clk ;
movlb 0 ; Bank 0
BRA break ;
send0
BANKSEL LATA
bcf DDS_dat ; Send zero
bsf DDS_clk ; Toggle write clock
bcf DDS_clk ;
movlb 0 ; Bank 0
break
decfsz bit_count,f ; Has the whole byte been sent?
BRA next_bit ; No, keep going.
incf FSR0L,f
decfsz byte_count,f ;
BRA next_byte ;
BANKSEL LATA
bsf DDS_load ; Send load signal to the AD9850/AD9851
bcf DDS_load ;
movlb 0 ; Bank 0
return ;
;
#IFDEF RIT
freq_to_rxf
movfw freq_0
movwf rxf_0
movfw freq_1
movwf rxf_1
movfw freq_2
movwf rxf_2
movfw freq_3
movwf rxf_3
return
freq_to_ritf
movfw freq_0
movwf ritf_0
movfw freq_1
movwf ritf_1
movfw freq_2
movwf ritf_2
movfw freq_3
movwf ritf_3
return
rxf_to_freq
movfw rxf_0
movwf freq_0
movfw rxf_1
movwf freq_1
movfw rxf_2
movwf freq_2
movfw rxf_3
movwf freq_3
return
ritf_to_freq
movfw ritf_0
movwf freq_0
movfw ritf_1
movwf freq_1
movfw ritf_2
movwf freq_2
movfw ritf_3
movwf freq_3
return
rxf_to_ritf
movfw rxf_0
movwf ritf_0
movfw rxf_1
movwf ritf_1
movfw rxf_2
movwf ritf_2
movfw rxf_3
movwf ritf_3
return
#ENDIF
#IFDEF RIT
org 0x800
rit
; bcf flags,0 ; Clear RIT changed flag
clrf flags ; Clear RIT flag bits
BANKSEL ADCON0
bsf ADCON0,ADGO ; start conversion
btfsc ADCON0,ADGO ; is conversion done?
BRA $-1 ; no, test again
movf ADRESH,w ; read upper 2 bits
movwf NumH ; store in gpr space
movf ADRESL,w ; read lower 8 bits
movwf NumL ; store in gpr space
movlb 0
getValue
;first do ADC-center value to discover direction
bsf dir,0 ; set direction, 1 = up
movlw high(center)
subwf NumH,f
movlw low(center)
subwf NumL,f
btfss STATUS,C
decf NumH,f
btfss NumH,7 ; is it negative
BRA notNeg
;need to negate acc
bcf dir,0 ; set direction, 1 = up
movlw 0xff
xorwf NumL,f
xorwf NumH,f
incf NumL,f
btfsc STATUS,Z
incf NumH,f
notNeg
; have now got a valid lookup value
BANKSEL EEADRL ; Select Bank for EEPROM registers
movfw NumL ;
movwf EEADRL
movfw NumH
addlw 0x0e
movwf EEADRH
bcf EECON1,CFGS ; Do not select Configuration Space
bsf EECON1,EEPGD ; Select Program Memory
bsf EECON1,RD ; Initiate read
NOP ; required 2 x NOPs
NOP
; EEDAT will now contain 0 - 2500
; and direction bit will be set
movf EEDATH,w
movlb 0
movwf fstep_1 ; for DDS frequency change
BANKSEL EEDATL
movf EEDATL,w
movlb 0
movwf fstep_0 ; for DDS frequency change
movf fstep_1,f ; Test if fstep_1 = 0
btfss STATUS,Z
BRA RIT_exit ; RIT is greater than 0
movf fstep_0,f ; Test if fstep_0 = 0
btfss STATUS,Z
BRA RIT_exit
bcf flags,0 ; RIT = 0 & flags bit 0 = 0
return
RIT_exit
; Test if same as last time
; test for value change and return if no change
bsf flags,0
movfw NumH
subwf NumH_temp,w ; Test if both registers the same. If yes test
btfss STATUS,Z ; next set of registers. else get value from table
BRA RIT_exit2
movfw NumL
subwf NumL_temp,w ; Test if both registers the same. If yes then
btfsc STATUS,Z ; nothing changed so return from here else get
return ; value from table
RIT_exit2
movfw NumH
movwf NumH_temp
movfw NumL
movwf NumL_temp
bsf flags,1 ; 0 = same as last time 1 = different
return
;
org 0xe00
;note, dead band incorporated into table
DW 0,0,0,0,0,0,0,0,0,0,5,11,16,22,28,33,39,45,50,56 ; 20
DW 62,67,73,79,84,90,96,101,107,113,118,124,130,135,141,147,152,158,164,169 ; 40
DW 175,180,186,192,197,203,209,214,220,226,231,237,243,248,254,260,265,271,277,282 ; 60
DW 288,294,299,305,311,316,322,328,333,339,345,350,356,361,367,373,378,384,390,395 ; 80
DW 401,407,412,418,424,429,435,441,446,452,458,463,469,475,480,486,492,497,503,509 ; 100
DW 514,520,526,531,537,542,548,554,559,565,571,576,582,588,593,599,605,610,616,622 ; 120
DW 627,633,639,644,650,656,661,667,673,678,684,690,695,701,707,712,718,723,729,735 ; 140
DW 740,746,752,757,763,769,774,780,786,791,797,803,808,814,820,825,831,837,842,848 ; 160
DW 854,859,865,871,876,882,888,893,899,904,910,916,921,927,933,938,944,950,955,961 ; 180
DW 967,972,978,984,989,995,1001,1006,1012,1018,1023,1029,1035,1040,1046,1052,1057,1063,1069,1074 ; 200
DW 1080,1085,1091,1097,1102,1108,1114,1119,1125,1131,1136,1142,1148,1153,1159,1165,1170,1176,1182,1187 ; 220
DW 1193,1199,1204,1210,1216,1221,1227,1233,1238,1244,1250,1255,1261,1266,1272,1278,1283,1289,1295,1300 ; 240
DW 1306,1312,1317,1323,1329,1334,1340,1346,1351,1357,1363,1368,1374,1380,1385,1391,1397,1402,1408,1414 ; 260
DW 1419,1425,1430,1436,1442,1447,1453,1459,1464,1470,1476,1481,1487,1493,1498,1504,1510,1515,1521,1527 ; 280
DW 1532,1538,1544,1549,1555,1561,1566,1572,1578,1583,1589,1595,1600,1606,1611,1617,1623,1628,1634,1640 ; 300
DW 1645,1651,1657,1662,1668,1674,1679,1685,1691,1696,1702,1708,1713,1719,1725,1730,1736,1742,1747,1753 ; 320
DW 1759,1764,1770,1776,1781,1787,1792,1798,1804,1809,1815,1821,1826,1832,1838,1843,1849,1855,1860,1866 ; 340
DW 1872,1877,1883,1889,1894,1900,1906,1911,1917,1923,1928,1934,1940,1945,1951,1957,1962,1968,1973,1979 ; 360
DW 1985,1990,1996,2002,2007,2013,2019,2024,2030,2036,2041,2047,2053,2058,2064,2070,2075,2081,2087,2092 ; 380
DW 2098,2104,2109,2115,2121,2126,2132,2138,2143,2149,2154,2160,2166,2171,2177,2183,2188,2194,2200,2205 ; 400
DW 2211,2217,2222,2228,2234,2239,2245,2251,2256,2262,2268,2273,2279,2285,2290,2296,2302,2307,2313,2319 ; 420
DW 2324,2330,2335,2341,2347,2352,2358,2364,2369,2375,2381,2386,2392,2398,2403,2409,2415,2420,2426,2432 ; 440
DW 2440,2450,2460,2470,2480,2490,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500 ; 460
DW 2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500 ; 480
DW 2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500 ; 500
DW 2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500 ; 512
#ENDIF
END
;--------------------------------------------------------------------------------