; Replacement for Mostek MK3870 with 14246 ROM mask as used in Philips 22AH798 and others from 1979
; Needs custom 28-pin to 40-pin adapter
; This project is dedicated to my brother Warner who tragically took his life on 4 May 2021. I blame Mark Rutte. -Tjerk
; GPL Copyleft 2021 pic@polonai.se
; 211110 v0.00 Start project, "Hello World" PoC (tESt)
; 211111 v0.01 PLL PoC (98.0 MHz)
; 211114 v0.02 Read Rotary Encoder (RB5:4)
; 211115 v0.03 DATA riedels universalized (LOADPLL)
; 211115 v0.04 FREQ to frequency display (FREQDISPLAY)
; 211118 v0.05 LOADSYS universalized, STBY, Time display
; 211123 v0.06 Keyboardscanner: TIME function (set min, hour with tuning knob)
; 211124 v0.07 System function select (FM, TAPE, PU)
; 211124 v0.08 Startup splash screen, save/read state (EEPROM)
; 211125 v0.09 Memory tuning (store/read), MUTE behavior
; 211128 v0.10 MW, LW receive (PLL+function)
; 211128 v0.11 AM & FM IF offset (diodes)
; 211201 v1.00 Release
; 211202 v1.01 MUTE during bandswitching and solid dot when time not adjusted after powerup
; 211206 v1.02 IF offset also in band edges
LIST P=18F2420, F=INHX32
INCLUDE <P18F2420.INC>
; Micro-controller oscillator
CONFIG OSC=ECIO6, IESO=OFF, LPT1OSC=OFF
; Micro-controller configuration
CONFIG PWRT=ON, MCLRE=ON, PBADEN=OFF, CCP2MX=PORTC, STVREN=OFF
; Micro-contoller monitoring
CONFIG WDT=OFF, WDTPS=512, FCMEN=OFF, BOREN=OFF, BORV=0
; Programming/Debugging
CONFIG DEBUG=OFF, XINST=OFF, LVP=OFF
; Code Protection
CONFIG CP0=OFF, CP1=OFF, CPB=OFF, CPD=OFF
; Write Protection
CONFIG WRT0=OFF, WRT1=OFF, WRTC=OFF, WRTB=OFF, WRTD=OFF
; Table Read Protection
CONFIG EBTR0=OFF, EBTR1=OFF, EBTRB=OFF
; Registers
FLAGS EQU 0x00 ; Flags
FLAGZ EQU 0x01 ; More flags
ROTCUR EQU 0x03 ; Current value of rotary encoder
ROTPREV EQU 0x04 ; Previous value of rotary encoder
FREQHI EQU 0x05 ; PLL Frequency High Byte
FREQLO EQU 0x06 ; PLL Frequency Low Byte
DISPHI EQU 0x07 ; 3-digit value for BCD conversion High Byte
DISPLO EQU 0x08 ; 3-digit value for BCD conversion Low Byte
D0 EQU 0x09 ; LED1704 (digit 1, LSB)
D1 EQU 0x0A ; LED1703 (digit 2)
D2 EQU 0x0B ; LED1702 (digit 3)
D3 EQU 0x0C ; LED1701+1700 (digits 4 and 5)
TEMP EQU 0x0D
DATABUF EQU 0x0E ; Buffer used for shifting data out
SYS EQU 0x0F ; System state/select
MEM EQU 0x10 ; Memory pointer BCD, 0x0A is frequency at last switch to standby
TICKS EQU 0x11 ; Timer0 interrupt counter (10 per second)
SECS EQU 0x12 ; Seconds for TIME function (not displayed)
MINS EQU 0x13 ; Minutes for TIME function
TMINS EQU 0x14 ; 10 Minutes for TIME function
HOURS EQU 0x15 ; Hours for TIME function
THOURS EQU 0x16 ; 10 Hours for TIME function
STBY_SYS EQU 0x17 ; Saved system state in STBY
COUNTDOWN EQU 0x18 ; Countdown counter for briefly displaying stuff
SAVESTATECTR EQU 0x19 ; Counter for testing for changed state every 25.6 s
SAVEDSTATE EQU 0x1A ; Previous FREQLO value used to detect changed state
MEMCTR EQU 0x1B ; Timeout counter for STORE button
MEMSAV EQU 0x1C ; Saved memory value during store
MUTECTR EQU 0x1D ; Mute counter for band edges and memory tuning
FM_IF100 EQU 0x1F ; FM IF offset value low byte >=100 MHz
FM_IF90 EQU 0x20 ; FM IF offset value low byte >=90 MHz
FM_IF80 EQU 0x21 ; FM IF offset value low byte >=80 MHz
FM_BE_HI EQU 0x22 ; FM High Band Edge (low byte only)
FM_BE_LO EQU 0x23 ; FM Low Band Edge (low byte only)
MW_BE_HI EQU 0x24 ; MW High Band Edge (low byte only)
MW_BE_LO EQU 0x25 ; MW Low Band Edge (low byte only)
LW_BE_HI EQU 0x26 ; LW High Band Edge (low byte only)
LW_BE_LO EQU 0x27 ; LW Low Band Edge (low byte only)
AM_IFLO EQU 0x28 ; Low byte of AM IF adjustment
FMHISAV EQU 0x29 ; FM Frequency high byte saved when changing to MW or LW
FMLOSAV EQU 0x2A ; FM Frequency low byte saved when changing to MW or LW
MWHISAV EQU 0x2B ; MW Frequency high byte saved when changing to FM or LW
MWLOSAV EQU 0x2C ; MW Frequency low byte saved when changing to FM or LW
LWHISAV EQU 0x2D ; LW Frequency high byte saved when changing to FM or MW
LWLOSAV EQU 0x2E ; LW Frequency low byte saved when changing to FM or MW
; Defines
#define CLB PORTA,0 ; MK Pin 10 PIC Pin 2 OUT Clock
#define DATA PORTA,1 ; MK Pin 11 PIC Pin 3 OUT Data
#define DLEN1 PORTA,2 ; MK Pin 12 PIC Pin 4 OUT Enable for IC6701
#define DLEN0 PORTA,3 ; MK Pin 9 PIC Pin 5 OUT Enable for IC6700 and IC6601 (!)
#define STORE PORTA,4 ; MK Pin 19 PIC Pin 6 IN Memory store button (external pullup)
#define STBY PORTA,5 ; MK Pin 15 PIC Pin 7 IN Standby button (external pullup)
#define IF PORTA,6 ; MK Pin 6 PIC Pin 10 IN Select IF Filter center frequency (external pullup)
; PORTA,7 ; MK Pin 2 PIC Pin 9 External Clock (ECIO mode)
#define EXT_INT PORTB,0 ; MK Pin 38 PIC Pin 21 IN Remote decoder interrupt (not implemented)
#define KB1 PORTB,1 ; MK Pin 5 PIC Pin 22 IN Keyboard scanner read line
#define KB2 PORTB,2 ; MK Pin 4 PIC Pin 23 IN Keyboard scanner read line
#define KB3 PORTB,3 ; MK Pin 3 PIC Pin 24 IN Keyboard scanner read line
#define UP PORTB,4 ; MK Pin 16 PIC Pin 25 IN Up signal from tuning knob
#define DN PORTB,5 ; MK Pin 17 PIC Pin 26 IN Down signal from tuning knob
#define MUTE PORTB,6 ; MK Pin 26 PIC Pin 27 OUT Used during memory tuning (active LOW)
#define TETS PORTB,7 ; MK Pin - PIC Pin 28 OUT TETS (sic) port for debugging (GRN LED)
#define P10 PORTC,0 ; MK Pin 37 PIC Pin 11 OUT Keyboard scanner drive line
#define P11 PORTC,1 ; MK Pin 36 PIC Pin 12 OUT Keyboard scanner drive line
#define P12 PORTC,2 ; MK Pin 35 PIC Pin 13 OUT Keyboard scanner drive line
#define P13 PORTC,3 ; MK Pin 34 PIC Pin 14 OUT Keyboard scanner drive line
#define P14 PORTC,4 ; MK Pin 22 PIC Pin 15 OUT Keyboard scanner drive line
#define P15 PORTC,5 ; MK Pin 23 PIC Pin 16 OUT Keyboard scanner drive line
#define P16 PORTC,6 ; MK Pin 24 PIC Pin 17 OUT Keyboard scanner drive line
#define P17 PORTC,7 ; MK Pin 25 PIC Pin 18 OUT Keyboard scanner drive line
; MCLR MK Pin 39 PIC Pin 1
#define SYS_ON FLAGS,0 ; System is ON, STBY system state is restored
#define TIME_ON FLAGS,1 ; System is ON but shows time
#define KEYPRESS FLAGS,2 ; Key pressed, cleared when exiting Timer0 interrupt handler
#define HELD FLAGS,3 ; Key held, cleared when exiting Timer0 interrupt handler and no key is pressed
#define ShowFreq FLAGS,4 ; Used for switching between time and frequency displays to ensure correct LEDs are lit
#define SETMIN FLAGS,5 ; SET + MIN keys pressed
#define SETHOUR FLAGS,6 ; SET + HOURS keys pressed
#define SYSCHG FLAGS,7 ; System function change, used for one second function splash screen
#define KILLRBIE FLAGZ,0 ; System function active that does not need rotary encoder
#define Splash1 FLAGZ,1 ; Show startup splash screen POLO
#define Splash2 FLAGZ,2 ; Show startup splash screen nAi
#define Splash3 FLAGZ,3 ; Show startup splash screen .SE
#define Splash FLAGZ,4 ; Show startup splash message
#define MEMSCAN FLAGZ,5 ; Set when STORE is pressed
#define AM_MHZ FLAGZ,6 ; Show "1" on LED5
#define TIME_UNSET FLAGZ,7 ; Don't flash dot in time display to show time not set
#define FM FREQHI,5 ; Used to set REF1 to 0 in LOADPLL in MW and LW
#define SYS_TIME SYS,1 ; TIME system function
#define SYS_FM SYS,2 ; FM system function
#define SYS_MW SYS,3 ; MW system function
#define SYS_LW SYS,4 ; LW system function
#define SYS_PU SYS,5 ; PHONO system function
#define SYS_Relay SYS,6 ; Relay system function, set when not STBY
#define SYS_TAPE SYS,7 ; TAPE function
; Reset program location vector
ORG 0x0000
BRA INIT
; Interupt program location vector, high prio (default because RCON:IPEN not set - compatability mode)
ORG 0x0008
BTFSC INTCON,TMR0IF ; Timer0 overflow?
BRA TESTSTATE ; Yes, test the State Machine
BRA ROTTEST ; Decode the rotary encoder (aka pulser)
RETFIE ; There are no other interrupts but just in case
; Interupt program location vector, low prio (not used because RCON:IPEN not set)
ORG 0x0018
RETFIE
ORG 0x001A
BCD7SEG ; BCD to 7-segment LED display table
ADDWF PCL
RETLW 0xC0 ; Return segment code for 0
RETLW 0xF9 ; Return segment code for 1
RETLW 0xA4 ; Return segment code for 2
RETLW 0xB0 ; Return segment code for 3
RETLW 0x99 ; Return segment code for 4
RETLW 0x92 ; Return segment code for 5
RETLW 0x82 ; Return segment code for 6
RETLW 0xF8 ; Return segment code for 7
RETLW 0x80 ; Return segment code for 8
RETLW 0x90 ; Return segment code for 9
RETLW 0xFF ; Return segment code for <blank>
RETLW 0xBF ; Return segment code for -
RETLW 0xBF ; Return segment code for -
RETLW 0xBF ; Return segment code for -
RETLW 0xBF ; Return segment code for -
RETLW 0xBF ; Return segment code for -
; Initialize micro
INIT
CLRF INTCON
CLRF STATUS
MOVLW 0x07 ; Switch off comparators
MOVWF CMCON
MOVLW 0x70
MOVWF OSCCON ; 8 MHz oscillator
MOVLW 0x0F ; Make all pins digital.
MOVWF ADCON1
CLRF ADCON0 ; Switch off A/D pins, all pins digital.
CLRF INTCON2 ; Weak pullups. Set PORTB as a low pritority interupt
CLRF IPR1 ; Set all interupt priorities to low priority.
MOVLW B'10000000'
MOVWF T0CON ; Timer0 16 bit, prescaler :2, 100 ms period
MOVLW B'01110000' ; PORTA<6:4> inputs
MOVWF TRISA
MOVLW B'00111111' ; PORTB<7:6> outputs
MOVWF TRISB
CLRF TRISC ; PORTC all outputs
CLRF PORTA
CLRF PORTB
CLRF PORTC
CLRF FLAGS
CLRF FLAGZ
MOVLW 0x00
CALL EEPROM_READ
CALL LOADPLL
CALL LOADSYS
MOVLW 0x0A ; <blank>
MOVWF MEM ; Memory display (LED1706)
MOVLW 0x02
MOVWF THOURS
MOVLW 0x03
MOVWF HOURS
MOVLW 0x04
MOVWF TMINS
MOVLW 0x05
MOVWF MINS ; Preload time 23:45
MOVLW 0x2A
MOVWF FMHISAV
MOVLW 0x76 ; Preload FM 98.00 MHz
MOVWF FMLOSAV
MOVLW 0x0D
MOVWF MWHISAV
MOVLW 0xF0 ; Preload MW 1332 kHz
MOVWF MWLOSAV
MOVLW 0x05
MOVWF LWHISAV
MOVLW 0x14 ; Preload LW 198 kHz
MOVWF LWLOSAV
CALL ReadDiodes
BSF SYS_ON ; Make sure receiver is actually on and not in standby!
BSF INTCON,TMR0IE ; Enable Timer0 interrupt
BSF INTCON,GIE
BSF Splash ; Enable splash screen message
BSF Splash1 ; Show "POLO"
BSF TIME_UNSET ; Fast flash dot in time display until time is set
MOVLW 0x05
MOVWF COUNTDOWN ; Show for 0.5 s
MOVLW B'10001100' ; Show "P"
MOVWF D3
MOVLW B'11000000' ; Show "O"
MOVWF D2
MOVWF D0
MOVLW B'11000111' ; Show "L"
MOVWF D1
CALL UpdateDISP
BRA $ ; Run forever
; Interrupt routines
ROTTEST ; Rotary encoder (pulser)
MOVF PORTB,W ; Mandatory read to clear mismatch
BCF INTCON,RBIF ; Clear interrupt flag
ANDLW B'00110000' ; Blank all bits except rotary encoder PORTB<5:4>
MOVWF ROTCUR ; Save current position
MOVLW B'00000000'
SUBWF ROTCUR,W
BTFSC STATUS,Z ; Pos 00?
BRA TEST00 ; Yes
MOVLW B'00010000'
SUBWF ROTCUR,W
BTFSC STATUS,Z ; Pos 01?
BRA TEST01 ; Yes
MOVLW B'00110000'
SUBWF ROTCUR,W
BTFSC STATUS,Z ; Pos 11?
BRA TEST11 ; Yes
MOVLW B'00000000'
SUBWF ROTPREV,W
BTFSC STATUS,Z ; Prev pos 00?
BRA ROTDN ; Yes
BRA ROTUP
TEST00
MOVLW B'00010000'
SUBWF ROTPREV,W
BTFSC STATUS,Z ; Prev pos 01?
BRA ROTDN ; Yes, DN
BRA ROTUP
TEST01
MOVLW B'00110000'
SUBWF ROTPREV,W
BTFSC STATUS,Z ; Prev pos 11?
BRA ROTDN ; Yes, DN
BRA ROTUP
TEST11
MOVLW B'00100000'
SUBWF ROTPREV,W
BTFSC STATUS,Z ; Prev pos 10?
BRA ROTDN ; Yes, DN
BRA ROTUP
ROTDN
BTFSC SYS_TIME ; TIME display?
BRA TUNE_DN ; No
BTFSC SETMIN ; Set Min pressed?
BRA MIN_DN ; Yes
BTFSC SETHOUR ; Set Hours pressed?
BRA HOUR_DN ; Yes
TUNE_DN ; Nothing pressed, test for lower edge of frequency range (87.50 MHz)
BCF TIME_ON ; Clear flag to allow frequency display
MOVLW 0x0A
MOVWF MEM
CALL LOADSYS ; Blank memory display
BTFSC SYS_FM ; FM Mode?
BRA TUNE_DN_AM ; No, tune down MW/LW
MOVF FREQLO,F
BTFSC STATUS,Z ; Low byte zero?
DECF FREQHI,F ; Yes
DECF FREQLO,F
DECF FM_BE_LO,W
SUBWF FREQLO,W
BTFSS STATUS,Z
BRA DO_UPDATE
MOVF FREQHI,W
SUBLW 0x26
BTFSS STATUS,Z ; Zero?
BRA DO_UPDATE
MOVLW 0x2E
MOVWF FREQHI
MOVLW 0x5D
MOVFF FM_BE_HI,FREQLO
MOVLW 0x05
MOVWF MUTECTR
BCF MUTE ; Mute for 0.4 s
BRA DO_UPDATE
TUNE_DN_AM ; Tune down MW/LW
BTFSC SYS_MW ; MW Mode?
BRA TUNE_DN_LW ; No, tune down LW
MOVF FREQLO,F ; Test for lower edge of frequency range (520 kHz)
BTFSC STATUS,Z ; Low byte zero?
DECF FREQHI,F ; Yes
DECF FREQLO,F
DECF MW_BE_LO,W
SUBWF FREQLO,W
BTFSS STATUS,Z ; LSB part lower edge?
BRA DO_UPDATE ; No
MOVF FREQHI,W
SUBLW 0x07
BTFSS STATUS,Z ; MSB part lower edge?
BRA DO_UPDATE ; No
MOVLW 0x10 ; Preload upper edge (1620 kHz)
MOVWF FREQHI
MOVFF MW_BE_HI,FREQLO
MOVLW 0x03
MOVWF MUTECTR
BCF MUTE ; Mute for 0.3 s
BRA DO_UPDATE
TUNE_DN_LW ; Tune down LW
MOVF FREQLO,F ; Test for lower edge of frequency range (150 kHz)
BTFSC STATUS,Z ; Low byte zero?
DECF FREQHI,F ; Yes
DECF FREQLO,F
DECF LW_BE_LO,W
SUBWF FREQLO,W
BTFSS STATUS,Z ; LSB part lower edge?
BRA DO_UPDATE ; No
MOVF FREQHI,W
SUBLW 0x04
BTFSS STATUS,Z ; MSB part lower edge?
BRA DO_UPDATE ; No
MOVLW 0x05 ; Preload upper edge (280 kHz)
MOVWF FREQHI
MOVLW 0xB7
MOVFF LW_BE_HI,FREQLO
MOVLW 0x03
MOVWF MUTECTR
BCF MUTE ; Mute for 0.3 s
BRA DO_UPDATE
MIN_DN
DECF MINS
BTFSS STATUS,N ; MINS negative?
BRA EXIT_TIMESET ; No
MOVLW 0x09
MOVWF MINS
DECF TMINS
BTFSS STATUS,N ; TMINS negative?
BRA EXIT_TIMESET
MOVLW 0x05
MOVWF TMINS
BRA EXIT_TIMESET
HOUR_DN
DECF HOURS
BTFSS STATUS,N ; HOURS negative?
BRA EXIT_TIMESET ; No
MOVLW 0x09
MOVWF HOURS
DECF THOURS
BTFSS STATUS,N ; THOURS negative (midnight)?
BRA EXIT_TIMESET
MOVLW 0x02
MOVWF THOURS
MOVLW 0x03
MOVWF HOURS
BRA EXIT_TIMESET
ROTUP
BTFSC SYS_TIME ; TIME display?
BRA TUNE_UP ; No
BTFSC SETMIN ; Set Min pressed?
BRA MIN_UP ; Yes
BTFSC SETHOUR ; Set Hours pressed?
BRA HOUR_UP ; Yes
TUNE_UP
BCF TIME_ON ; Clear flag to allow frequency display
MOVLW 0x0A
MOVWF MEM ; Blank memory display
BTFSC SYS_FM ; FM Mode?
BRA TUNE_UP_AM ; No, tune up MW/LW
CALL LOADSYS
INCFSZ FREQLO,F
BRA TESTUPFM
INCF FREQHI,F ; no need to test this value because it is already tested below
BRA DO_UPDATE
TESTUPFM ; Test for upper edge of frequency range (107.99 MHz)
INCF FM_BE_HI,W ; Get low byte upper edge
SUBWF FREQLO,W
BTFSS STATUS,Z
BRA DO_UPDATE
MOVF FREQHI,W
SUBLW 0x2E
BTFSS STATUS,Z ; Zero?
BRA DO_UPDATE ; No
MOVLW 0x26 ; Preload lower edge (87.50 MHz)
MOVWF FREQHI
MOVFF FM_BE_LO,FREQLO ; Get low byte lower edge
MOVLW 0x03
MOVWF MUTECTR
BCF MUTE ; Mute for 0.3 s
BRA DO_UPDATE
TUNE_UP_AM ; Tune up MW/LW
BTFSC SYS_MW ; MW Mode?
BRA TUNE_UP_LW ; No, tune up LW
CALL LOADSYS
INCFSZ FREQLO,F
BRA TESTUPAM
INCF FREQHI,F ; no need to test this value because it is already tested below
BRA DO_UPDATE
TESTUPAM ; Test for upper edge of frequency range (1620 kHz)
INCF MW_BE_HI,W
SUBWF FREQLO,W
BTFSS STATUS,Z
BRA DO_UPDATE
MOVF FREQHI,W
SUBLW 0x10
BTFSS STATUS,Z ; Zero?
BRA DO_UPDATE
MOVLW 0x07 ; Preload lower edge (520 kHz)
MOVWF FREQHI
MOVFF MW_BE_LO,FREQLO
MOVLW 0x03
MOVWF MUTECTR
BCF MUTE ; Mute for 0.3 s
BRA DO_UPDATE
TUNE_UP_LW ; Tune up LW
CALL LOADSYS
INCFSZ FREQLO,F
BRA TESTUPLW
INCF FREQHI,F ; no need to test this value because it is already tested below
BRA DO_UPDATE
TESTUPLW ; Test for upper edge of frequency range (280 kHz)
INCF LW_BE_HI,W
SUBWF FREQLO,W
BTFSS STATUS,Z
BRA DO_UPDATE
MOVF FREQHI,W
SUBLW 0x05
BTFSS STATUS,Z ; Zero?
BRA DO_UPDATE
MOVLW 0x04 ; Preload lower edge (150 kHz)
MOVWF FREQHI
MOVFF LW_BE_LO,FREQLO
MOVLW 0x05
MOVWF MUTECTR
BCF MUTE ; Mute for 0.3 s
DO_UPDATE
CALL LOADPLL
CALL FREQDISPLAY
BSF SYS_TIME
CALL LOADSYS
MOVFF ROTCUR,ROTPREV
BCF INTCON,RBIF
RETFIE
MIN_UP
INCF MINS
MOVLW 0x0A
SUBWF MINS,W
BTFSS STATUS,C ; Overflow?
BRA EXIT_TIMESET ; No
CLRF MINS
INCF TMINS
MOVLW 0x06
SUBWF TMINS,W
BTFSS STATUS,C ; TMINS overflow?
BRA EXIT_TIMESET
CLRF TMINS
BRA EXIT_TIMESET
HOUR_UP
MOVLW 0x02 ; Test for midnight
SUBWF THOURS,W ; if true, C=1, check for midnight
BTFSC STATUS,C
BRA MIDNIGHT_UP
INCF HOURS
MOVLW 0x0A
SUBWF HOURS,W
BTFSS STATUS,C ; Overflow?
BRA EXIT_TIMESET ; No
CLRF HOURS
INCF THOURS
BRA EXIT_TIMESET
MIDNIGHT_UP
INCF HOURS,F
MOVLW 0x04 ; Test for midnight
SUBWF HOURS,W ; if true, C=1, new day
BTFSS STATUS,C
BRA EXIT_TIMESET
CLRF HOURS
CLRF THOURS
EXIT_TIMESET
CLRF SECS
CLRF TICKS ; Make sure time gets set at a whole minute
CALL SHOW_TIME
MOVFF ROTCUR,ROTPREV
BCF INTCON,RBIF
RETFIE
; Subroutines
LOADPLL
BSF DLEN0 ; Load IC6601 (SAA1056)
CALL DEL10US
CALL SHIFTZERO ; Leading zero
BTFSC FM ; AM mode (REF1=0)?
BRA $+8 ; No (why is this not $+6?!?!!? Oh wait, CALL has an extra NOP)
CALL SHIFTZERO ; REF1=0
BRA $+4
CALL SHIFTONE ; REF1=1
MOVFF FREQHI,DATABUF ; Load high byte
RLCF DATABUF,F ; Dummyshift bit 15
CALL SHIFTPLL ; Shift bit 14 (NP9)
CALL SHIFTPLL ; Shift bit 13 (NP8)
CALL SHIFTPLL ; Shift bit 12 (NP7)
CALL SHIFTPLL ; Shift bit 11 (NP6)
CALL SHIFTPLL ; Shift bit 10 (NP5)
CALL SHIFTPLL ; Shift bit 9 (NP4)
CALL SHIFTPLL ; Shift bit 8 (NP3)
MOVFF FREQLO,DATABUF ; Load low byte
CALL SHIFTPLL ; Shift bit 7 (NP2)
CALL SHIFTPLL ; Shift bit 6 (NP1)
CALL SHIFTPLL ; Shift bit 5 (NP0)
CALL SHIFTPLL ; Shift bit 4 (NS4)
CALL SHIFTPLL ; Shift bit 3 (NS3)
CALL SHIFTPLL ; Shift bit 2 (NS2)
CALL SHIFTPLL ; Shift bit 1 (NS1)
CALL SHIFTPLL ; Shift bit 0 (NS0)
CALL DEL10US
BCF DLEN0
BCF DATA
CALL DEL10US
BSF CLB
CALL DEL10US
BCF CLB ; Load pulse
CALL DEL200US ; Wait time to prevent PLL not latching in some conditions (not documented)
RETURN
FREQDISPLAY ; Convert FREQHI:LO to display
BTFSS FM
BRA SHOW_AM
MOVFF FREQHI,DISPHI ; Subtract 110.70 MHz to get three digit BCD
MOVLW 0x2B
SUBWF DISPHI,F
MOVFF FREQLO,DISPLO
MOVF FM_IF100,W ; Get low byte FM IF offset
SUBWF DISPLO,F
BTFSS STATUS,C
DECF DISPHI,F
BTFSS DISPHI,7 ; Result negative?
BRA DISP100MC ; No, display >=100 MHz
MOVFF FREQHI,DISPHI ; Subtract 100.70 MHz to get three digit BCD
MOVLW 0x27
SUBWF DISPHI,F
MOVFF FREQLO,DISPLO
MOVF FM_IF90,W ; Get lower byte FM IF offset
SUBWF DISPLO,F
BTFSS STATUS,C
DECF DISPHI,F
BTFSS DISPHI,7 ; Result negative?
BRA DISP90MC ; No, display >=90 MHz
MOVFF FREQHI,DISPHI ; Subtract 90.70 MHz to get three digit BCD <90 MHz
MOVLW 0x23
SUBWF DISPHI,F
MOVFF FREQLO,DISPLO
MOVF FM_IF80,W ; Get lower byte FM IF offset
SUBWF DISPLO,F
BTFSS STATUS,C
DECF DISPHI,F
MOVLW B'10000000' ; Show 8x MHz
MOVWF D3
BRA Bin2BCD
DISP90MC
MOVLW B'10010000' ; Show 9x MHz
MOVWF D3
BRA Bin2BCD
DISP100MC
MOVLW B'01000000' ; Show 10x MHz
MOVWF D3
BRA Bin2BCD
SHOW_AM
MOVFF FREQHI,DISPHI ; Subtract AM IF to get three digit BCD
MOVLW 0x03
SUBWF DISPHI,F
MOVFF FREQLO,DISPLO
MOVF AM_IFLO,W
SUBWF DISPLO,F
BTFSS STATUS,C ; Carry?
DECF DISPHI,F ; Yes, decrement high byte
BCF STATUS,C ; Make sure carry is clear
RRCF DISPHI ; Divide displayed frequency by 2
RRCF DISPLO
Bin2BCD ; 12 bit routine from http://www.piclist.com/techref/microchip/math/radix/b2bu-10b4d-eag.htm
movf DISPHI,w
iorlw 0xF0 ;w=H2-16
movwf D1 ;D1=H2-16
addwf D1,f ;D1=H2*2-32
addwf D1,f ;D1=H2*3-48
movwf D2 ;D2=H2-16
addlw -D'5' ;w=H2-21
addwf D2,f ;D2=H2*2-37 Done!
addlw D'41' ;w=H2+20
movwf D0 ;D0=H2+20
swapf DISPLO,w
iorlw 0xF0 ;w=H1-16
addwf D1,f ;D1=H2*3+H1-64
addwf D0,f ;D0=H2+H1+4, C=1
rlcf D0,f ;D0=(H2+H1)*2+9, C=0
comf D0,f ;D0=-(H2+H1)*2-10
rlcf D0,f ;D0=-(H2+H1)*4-20
movf DISPLO,w
andlw 0x0F ;w=H0
addwf D0,f ;D0=H0-(H2+H1)*4-20 Done!
rlcf D1,f ;C=0, D1=H2*6+H1*2-128 Done!
movlw D'5'
movwf TEMP
movlw D'10'
mod0
addwf D0,f ;D(X)=D(X)mod10
decfsz D1,f ;D(X+1)=D(X+1)+D(X)div10
NOP
btfss STATUS,C
bra mod0
mod1
addwf D1,f
decfsz D2,f
NOP
btfss STATUS,C
bra mod1
mod2
addwf D2,f
decfsz TEMP,f
NOP
btfss STATUS,C
bra mod2
; Done Bin2BCD
BTFSC FM ; AM?
CALL Calc_D2D0FM ; No
BTFSS FM ; FM? (testing is cheap)
CALL Calc_DISP_AM ; No
; Done BCD to 7-segment
UpdateDISP ; D3:D0 must already be 7-segment values
BCF DATA ; Load IC6700 (SAA1060) register B
BSF DLEN0
CALL DEL10US
BSF CLB
CALL DEL10US
BCF CLB ; Leading zero
CALL DEL10US
MOVFF D1,DATABUF ; Get second digit (100 kHz) into buffer
CALL SHIFTDISP ; Q1 a2
CALL SHIFTDISP ; Q2 b2
CALL SHIFTDISP ; Q3 c2
CALL SHIFTDISP ; Q4 d2
CALL SHIFTDISP ; Q5 e2
CALL SHIFTDISP ; Q6 f2
CALL SHIFTDISP ; Q7 g2
CALL SHIFTDISP ; Q8 dp2
MOVFF D3,DATABUF ; Get fourth digit (10 MHz) into buffer
CALL SHIFTDISP ; Q9 a4
CALL SHIFTDISP ; Q10 b4
CALL SHIFTDISP ; Q11 c4
CALL SHIFTDISP ; Q12 d4
CALL SHIFTDISP ; Q13 e4
CALL SHIFTDISP ; Q14 f4
CALL SHIFTDISP ; Q15 g4
CALL SHIFTDISP ; Q16 b5, c5
CALL SHIFTZERO ; !B
BCF DLEN0
CALL DEL10US
BSF CLB
CALL DEL10US
BCF CLB ; Load pulse
CALL DEL10US ; Wait 20 µs
CALL DEL10US
BSF DLEN0 ; Load IC6700 (SAA1060) register A
CALL DEL10US
CALL SHIFTZERO ; Leading zero
MOVFF D0,DATABUF ; Get first digit (10 kHz) into buffer
CALL SHIFTDISP ; Q1 a1
CALL SHIFTDISP ; Q2 b1
CALL SHIFTDISP ; Q3 c1
CALL SHIFTDISP ; Q4 d1
CALL SHIFTDISP ; Q5 e1
CALL SHIFTDISP ; Q6 f1
CALL SHIFTDISP ; Q7 g1
CALL SHIFTDISP ; Q8 (none)
MOVFF D2,DATABUF ; Get third digit (1 MHz) into buffer
CALL SHIFTDISP ; Q9 a3
CALL SHIFTDISP ; Q10 b3
CALL SHIFTDISP ; Q11 c3
CALL SHIFTDISP ; Q12 d3
CALL SHIFTDISP ; Q13 e3
CALL SHIFTDISP ; Q14 f3
CALL SHIFTDISP ; Q15 g3
CALL SHIFTDISP ; Q16 dp3
CALL SHIFTONE ; A
BCF DLEN0
BCF DATA
CALL DEL10US
BSF CLB
CALL DEL10US
BCF CLB ; Load pulse
CALL DEL200US ; Wait 200 µs
RETURN
SHIFTPLL ; Shift one bit onto data line (PLL)
BSF CLB
RLCF DATABUF,F ; Rotate MSB into carry
BTFSC STATUS,C ; Carry clear?
BSF DATA ; No, set DATA
BTFSS STATUS,C ; Carry set?
BCF DATA ; No, clear DATA
CALL DEL10US
BCF CLB ; Clock in data
CALL DEL10US
RETURN
SHIFTDISP ; Shift one bit onto data line (display/sys/mem)
BSF CLB
RRCF DATABUF,F ; Rotate LSB into carry
BTFSC STATUS,C ; Carry clear?
BSF DATA ; No, set DATA
BTFSS STATUS,C ; Carry set?
BCF DATA ; No, clear DATA
CALL DEL10US
BCF CLB ; Clock in data
CALL DEL10US
RETURN
SHIFTZERO
BSF CLB
BCF DATA
CALL DEL10US
BCF CLB ; Clock in data
CALL DEL10US
RETURN
SHIFTONE
BSF CLB
BSF DATA
CALL DEL10US
BCF CLB ; Clock in data
CALL DEL10US
RETURN
DEL10US ; 10-ish µs delay
NOP
NOP
NOP
NOP
RETURN
DEL200US ; something-ish µs delay
MOVLW 0x20
MOVWF TEMP
DECFSZ TEMP
BRA $-2
RETURN
Calc_D2D0FM
MOVLW 0x0F ; Look up 7-segment code for 1 MHz
ANDWF D2,F ; Sanitize pointer
RLNCF D2,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D2
BCF D2,7 ; Switch on decimal point
MOVLW 0x0F ; Look up 7-segment code for 0.1 MHz
ANDWF D1,F ; Sanitize pointer
RLNCF D1,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D1
MOVLW 0x0F ; Look up 7-segment code for 10 kHz
ANDWF D0,F ; Sanitize pointer
RLNCF D0,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D0
BTFSC SYS_ON
BCF D0,7 ; Switch on MHz LED (if not STBY)
RETURN
Calc_DISP_AM
BCF AM_MHZ
BTFSC TEMP,0 ; >= 1000 kHz?
BSF AM_MHZ ; Yes
MOVFF D2,D3
MOVLW 0x0F ; Look up 7-segment code for 100 kHz
ANDWF D3,F ; Sanitize pointer
RLNCF D3,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D3
BTFSC AM_MHZ ; >= 1000 kHz?
BCF D3,7 ; Yes, show 1 in LED5 ("D4")
MOVFF D1,D2
MOVLW 0x0F ; Look up 7-segment code for 10 kHz
ANDWF D2,F ; Sanitize pointer
RLNCF D2,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D2
MOVFF D0,D1 ; Shift all digits left
MOVLW 0x0F ; Look up 7-segment code for 1 kHz
ANDWF D1,F ; Sanitize pointer
RLNCF D1,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D1
BCF D1,7 ; Switch on decimal point and kHz LED (if not STBY)
MOVLW 0x0A ; Adjusted for two byte steps in table
MOVWF D0
BTFSS FREQLO,0 ; 0.5 kHz?
CLRF D0 ; No
MOVF D0,W ; Load W for lookup
CALL BCD7SEG
MOVWF D0
RETURN
; End rotary stuff
TESTSTATE ; Keyboard scanner every 100 ms
BCF INTCON,TMR0IF
MOVLW 0x3C
MOVWF TMR0H
MOVLW 0xB6
MOVWF TMR0L ; Preload for 100000 µs timebase
BTFSC Splash ; Startup splash screen in progress?
BRA DO_SPLASH ; Yes
CALL DO_CLOCK ; Update clock
BTFSC STBY ; Power switch in Standby position?
BRA DO_STBY ; Yes, go into standby and ignore any keypress
CALL DO_UNSTBY
BTFSC KILLRBIE ; Set when in a function that does not need rotary encoder
BCF INTCON,RBIE
BTFSC SYSCHG ; System function changed?
CALL ShowFunc ; Yes, show function in display during countdown, then time (TIME_ON)
BTFSC TIME_ON ; Time display?
CALL SHOW_TIME
DECFSZ SAVESTATECTR,F
BRA $+4
CALL SAVESTATE ; Every 25.6 s check if state has changed
BTFSS STORE ; Store pressed?
BRA MEMSTORE ; Yes
BTFSC MEMSCAN ; Wait for memory store selection?
BRA MEMSTORE2 ; Yes
DECFSZ MUTECTR ; MUTE period ended
BRA $+4 ; No
BSF MUTE
; Keyboard scanning starts here. Note that the first key encountered wins.
MOVLW B'11111110' ; Scan P10
MOVWF PORTC
BTFSS KB2 ; P9 pressed?
BRA DO_P9 ; Yes, recall P9
BTFSS KB3 ; P1 pressed?
BRA DO_P1 ; Yes, recall P1
MOVLW B'11111101' ; Scan P11
MOVWF PORTC
BTFSS KB1 ; TAPE pressed?
BRA DO_TAPE ; Yes, select SYS_TAPE
BTFSS KB3 ; P2 pressed?
BRA DO_P2 ; Yes, recall P2
MOVLW B'11111011' ; Scan P12
MOVWF PORTC
BTFSS KB2 ; FM pressed?
BRA DO_FM ; Yes, select SYS_FM
BTFSS KB3 ; P3 pressed?
BRA DO_P3 ; Yes, recall P3
MOVLW B'11110111' ; Scan P13
MOVWF PORTC
BTFSS KB2 ; FM pressed?
BRA DO_MW ; Yes, select SYS_MW
BTFSS KB3 ; P4 pressed?
BRA DO_P4 ; Yes, recall P4
MOVLW B'11101111' ; Scan P14
MOVWF PORTC
BTFSS KB1 ; PHONO pressed?
BRA DO_PU ; Yes, select SYS_PU
BTFSS KB2 ; FM pressed?
BRA DO_LW ; Yes, select SYS_LW
BTFSS KB3 ; P5 pressed?
BRA DO_P5 ; Yes, recall P5
MOVLW B'11011111' ; Scan P15
MOVWF PORTC
BTFSS KB2 ; SET + HOURS pressed?
BRA DO_SETHOUR ; Yes, adjust hours
BTFSS KB3 ; P6 pressed?
BRA DO_P6 ; Yes, recall P6
MOVLW B'10111111' ; Scan P16
MOVWF PORTC
BTFSS KB2 ; SET + MIN pressed?
BRA DO_SETMIN ; Yes, adjust minutes
BTFSS KB3 ; P7 pressed?
BRA DO_P7 ; Yes, recall P7
MOVLW B'01111111' ; Scan P17
MOVWF PORTC
BTFSS KB2 ; TIME pressed?
BRA DO_TIME ; Yes, show time
BTFSS KB3 ; P8 pressed?
BRA DO_P8 ; Yes, recall P8
EXIT_KBD
MOVLW B'11111111' ; Reset scanlines
MOVWF PORTC
BTFSC KEYPRESS ; Did a keypress occur?
BRA DoneKEYPRESS ; Yes
BCF HELD ; No keys held
BCF SETMIN
BCF SETHOUR
DoneKEYPRESS
BCF KEYPRESS
RETFIE
MEMSTORE ; STORE is pressed
BTFSC SYS_FM ; FM mode?
BRA Test_MW ; No
BRA MEMSTORE1
Test_MW
BTFSC SYS_MW ; MW mode?
BRA Test_LW ; No
BRA MEMSTORE1
Test_LW
BTFSC SYS_LW ; LW mode?
RETFIE ; No
MEMSTORE1
MOVLW 0x64 ; 10 seconds timeout
MOVWF MEMCTR
BTFSC MEMSCAN ; STORE still pressed?
BRA MEMSTORE2 ; Yes
MOVFF MEM,MEMSAV ; Save memory display to allow flashing "-" (MEM=0x0B)
MOVLW 0x0A
MOVWF MEM ; Show blank display
BSF MEMSCAN
MEMSTORE2
DECFSZ MEMCTR
BRA DO_MEMSCAN
MOVFF MEMSAV,MEM ; Restore previous memory display
MOVLW 0x0B
SUBWF MEM,W
BTFSC STATUS,Z ; Memory pointer 0x0B ("-")?
BCF MEM,0 ; Yes
BCF MEMSCAN
CALL LOADSYS ; Show previous memory display
RETFIE
DO_MEMSCAN
BTFSS TICKS,2 ; Flash "-"
BCF MEM,0
BTFSC TICKS,2
BSF MEM,0
CALL LOADSYS ; Show "-" or " "
; Memory keyboard scanning starts here
MOVLW B'11111110' ; Scan P10
MOVWF PORTC
BTFSS KB3 ; P1 pressed?
BRA STORE_P1 ; Yes
BTFSS KB2 ; P9 pressed?
BRA STORE_P9 ; Yes
MOVLW B'11111101' ; Scan P11
MOVWF PORTC
BTFSS KB3 ; P2 pressed?
BRA STORE_P2 ; Yes
MOVLW B'11111011' ; Scan P12
MOVWF PORTC
BTFSS KB3 ; P3 pressed?
BRA STORE_P3 ; Yes
MOVLW B'11110111' ; Scan P13
MOVWF PORTC
BTFSS KB3 ; P4 pressed?
BRA STORE_P4 ; Yes
MOVLW B'11101111' ; Scan P14
MOVWF PORTC
BTFSS KB3 ; P5 pressed?
BRA STORE_P5 ; Yes
MOVLW B'11011111' ; Scan P15
MOVWF PORTC
BTFSS KB3 ; P6 pressed?
BRA STORE_P6 ; Yes
MOVLW B'10111111' ; Scan P16
MOVWF PORTC
BTFSS KB3 ; P7 pressed?
BRA STORE_P7 ; Yes
MOVLW B'01111111' ; Scan P17
MOVWF PORTC
BTFSS KB3 ; P8 pressed?
BRA STORE_P8 ; Yes
MOVLW B'11111111' ; Set P17
MOVWF PORTC
RETFIE ; Nothing pressed
STORE_P1
MOVLW 0x01
BRA WRITE_Px
STORE_P2
MOVLW 0x02
BRA WRITE_Px
STORE_P3
MOVLW 0x03
BRA WRITE_Px
STORE_P4
MOVLW 0x04
BRA WRITE_Px
STORE_P5
MOVLW 0x05
BRA WRITE_Px
STORE_P6
MOVLW 0x06
BRA WRITE_Px
STORE_P7
MOVLW 0x07
BRA WRITE_Px
STORE_P8
MOVLW 0x08
BRA WRITE_Px
STORE_P9
MOVLW 0x09
WRITE_Px
MOVWF MEM
CALL LOADSYS
CALL EEPROM_WRITE ; Store FREQHI, FREQLO, SYS
BCF MEMSCAN
RETFIE
DO_STBY ; Not a CALL so exit with RETFIE
BTFSS SYS_ON ; System already in STBY?
BRA STBY_COUNTDOWN ; Yes
BCF INTCON,RBIE ; Disable PORTB<7:4> change interrupt
MOVF PORTB,W ; Mandatory read of PORTB
BCF INTCON,RBIF ; Make sure flag is cleared
MOVFF SYS,STBY_SYS ; Save current system state
MOVLW B'10111101' ; Clear all functions, switch off Relay, show TIME
MOVWF SYS
MOVFF MEM,MEMSAV
MOVLW 0x0A
MOVWF MEM ; Switch of memory display
CALL LOADSYS
BCF SYS_ON ; Clear flag
MOVLW B'10010010' ; Code for 'S'
MOVWF D3
MOVLW B'10000111' ; Code for 't'
MOVWF D2
MOVLW B'10000011' ; Code for 'b'
MOVWF D1
MOVLW B'10010001' ; Code for 'Y'
MOVWF D0
CALL UpdateDISP
MOVLW 0x0A
MOVWF COUNTDOWN ; Show "StbY" for one second
RETFIE
STBY_COUNTDOWN ; Countdown for time display in STBY
DECFSZ COUNTDOWN,F
RETFIE
INCF COUNTDOWN,F ; Make sure next decrement is zero again
CALL SHOW_TIME
RETFIE
DO_TIME
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
BTFSS ShowFreq ; Function with frequency in display?
BRA EXIT_KBD ; No
MOVLW B'00000010'
XORWF FLAGS,F ; Toggle TIME_ON
BSF HELD
BTFSC TIME_ON ; Time in display?
BRA Fix_TIME_LED ; Yes
CALL FREQDISPLAY ; Show frequency
BSF SYS_TIME
CALL LOADSYS ; Switch off TIME LED
BRA EXIT_KBD
Fix_TIME_LED ; Switch on TIME LED because of time display
BCF SYS_TIME
CALL LOADSYS
CALL SHOW_TIME_NOW
BRA EXIT_KBD
DO_SETMIN
BSF KEYPRESS
BCF TIME_UNSET ; Well, time is being set so start flashing dot
BSF SETMIN ; Set SETMIN flag
BSF INTCON,RBIE ; Enable time setting in PU and TAPE
BRA EXIT_KBD
DO_SETHOUR
BSF KEYPRESS
BCF TIME_UNSET ; Well, time is being set so start flashing dot
BSF SETHOUR ; Set SETHOUR flag
BSF INTCON,RBIE ; Enable time setting in PU and TAPE
BRA EXIT_KBD
DO_PU
BTFSS SYS_PU ; Already in PHONO?
BRA EXIT_KBD ; Yes
BSF KEYPRESS
BTFSS SYS_FM ; Previous function FM?
CALL SAVE_FM ; Yes
BTFSS SYS_MW ; Previous function MW?
CALL SAVE_MW ; Yes
BTFSS SYS_LW ; Previous function LW?
CALL SAVE_LW ; Yes
MOVLW B'11011111' ; Clear SYS_PU
MOVWF SYS
MOVFF MEM,MEMSAV ; Save any memory display
MOVLW 0x0A
MOVWF MEM ; and clear it
CALL LOADSYS
MOVLW B'10001100' ; Show "P"
MOVWF D3
MOVLW B'11000001' ; Show "U"
MOVWF D2
MOVLW 0xFF ; Show " "
MOVWF D1
MOVWF D0
CALL UpdateDISP
BCF INTCON,RBIE ; Disable rotary encoder (pulser) because PU does not need it
BSF KILLRBIE ; And keep it disabled
MOVLW 0x0A
MOVWF COUNTDOWN
BCF TIME_ON
BCF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF SYSCHG ; Set up for PU in display for 1 sec (ShowFunc)
BRA EXIT_KBD
DO_TAPE
BTFSS SYS_TAPE ; Already in TAPE?
BRA EXIT_KBD ; Yes
BSF KEYPRESS
BTFSS SYS_FM ; Previous function FM?
CALL SAVE_FM ; Yes
BTFSS SYS_MW ; Previous function MW?
CALL SAVE_MW ; Yes
BTFSS SYS_LW ; Previous function LW?
CALL SAVE_LW ; Yes
MOVLW B'01111111' ; Clear SYS_TAPE
MOVWF SYS
MOVFF MEM,MEMSAV ; Save any memory display
MOVLW 0x0A
MOVWF MEM ; and clear it
CALL LOADSYS
MOVLW B'10000111' ; Show "t"
MOVWF D3
MOVLW B'10001000' ; Show "A"
MOVWF D2
MOVLW B'10001100' ; Show "P"
MOVWF D1
MOVLW B'10000110' ; Show "E"
MOVWF D0
CALL UpdateDISP
BCF INTCON,RBIE ; Disable rotary encoder (pulser) because TAPE does not need it
BSF KILLRBIE ; And keep it disabled
MOVLW 0x0A
MOVWF COUNTDOWN
BCF TIME_ON
BCF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF SYSCHG ; Set up for tAPE in display for 1 sec (ShowFunc)
BRA EXIT_KBD
DO_FM
BTFSS SYS_FM ; Already in FM?
BRA EXIT_KBD ; Yes
BSF KEYPRESS
BCF MUTE ; Mute audio to allow PLL to settle
MOVLW 0x04
MOVWF MUTECTR ; Set mute counter for 0.4 s
BTFSS SYS_MW ; Previous function MW?
CALL SAVE_MW ; Yes
BTFSS SYS_LW ; Previous function LW?
CALL SAVE_LW ; Yes
MOVLW B'11111011'
MOVWF SYS
MOVLW 0x0A
MOVWF MEM ; Clear any memory display
CALL LOADSYS
CALL RESTORE_FM ; Restore FREQHI:LO for FM
CALL LOADPLL
MOVLW B'10001110' ; Show "F"
MOVWF D3
MOVLW B'11001000' ; Show "M"
MOVWF D2
MOVLW B'11001000' ; Show "M"
MOVWF D1
MOVLW 0xFF ; Show " "
MOVWF D0
CALL UpdateDISP
MOVLW 0x0A
MOVWF COUNTDOWN
BCF TIME_ON ; Switch off time display
BSF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF SYSCHG ; Set up for FM in display for 1 sec (ShowFunc)
BSF INTCON,RBIE ; Re-enable rotary encoder (pulser) because FM needs it
BCF KILLRBIE ; And keep it enabled
BRA EXIT_KBD
DO_MW
BTFSS SYS_MW ; Already in MW?
BRA EXIT_KBD ; Yes
BSF KEYPRESS
BCF MUTE ; Mute audio to allow PLL to settle
MOVLW 0x04
MOVWF MUTECTR ; Set mute counter for 0.4 s
BTFSS SYS_FM ; Previous function FM?
CALL SAVE_FM ; Yes
BTFSS SYS_LW ; Previous function LW?
CALL SAVE_LW ; Yes
MOVLW B'11110111' ; Clear Q4 (MW) of IC6701
MOVWF SYS ; Thus set system to MW
MOVLW 0x0A
MOVWF MEM ; Clear any memory display
CALL LOADSYS
CALL RESTORE_MW ; Restore FREQHI:LO for MW
CALL LOADPLL
MOVLW B'11001000' ; Show "M"
MOVWF D3
MOVWF D2
MOVLW B'11000001' ; Show "U"
MOVWF D1
MOVWF D0
CALL UpdateDISP
MOVLW 0x0A
MOVWF COUNTDOWN
BCF TIME_ON ; Switch off time display
BSF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF SYSCHG ; Set up for MW in display for 1 sec (ShowFunc)
BSF INTCON,RBIE ; Re-enable rotary encoder (pulser) because MW needs it
BCF KILLRBIE ; And keep it enabled
BRA EXIT_KBD
DO_LW
BTFSS SYS_LW ; Already in LW?
BRA EXIT_KBD ; Yes
BSF KEYPRESS
BCF MUTE ; Mute audio to allow PLL to settle
MOVLW 0x04
MOVWF MUTECTR ; Set mute counter for 0.4 s
BTFSS SYS_FM ; Previous function FM?
CALL SAVE_FM ; Yes
BTFSS SYS_MW ; Previous function MW?
CALL SAVE_MW ; Yes
MOVLW B'11101111' ; Clear Q5 (LW) of IC6701
MOVWF SYS ; Thus set system to LW
MOVLW 0x0A
MOVWF MEM ; Clear any memory display
CALL LOADSYS
CALL RESTORE_LW ; Restore FREQHI:LO for LW
CALL LOADPLL
MOVLW B'11000111' ; Show "L"
MOVWF D3
MOVLW B'11000001' ; Show "U"
MOVWF D2
MOVWF D1
MOVLW 0xFF ; Show " "
MOVWF D0
CALL UpdateDISP
MOVLW 0x0A
MOVWF COUNTDOWN
BCF TIME_ON ; Switch off time display
BSF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF SYSCHG ; Set up for MW in display for 1 sec (ShowFunc)
BSF INTCON,RBIE ; Re-enable rotary encoder (pulser) because MW needs it
BCF KILLRBIE ; And keep it enabled
BRA EXIT_KBD
DO_P1
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x01 ; Test for P1 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x01
BRA READ_Px
DO_P2
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x02 ; Test for P2 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x02
BRA READ_Px
DO_P3
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x03 ; Test for P3 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x03
BRA READ_Px
DO_P4
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x04 ; Test for P4 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x04
BRA READ_Px
DO_P5
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x05 ; Test for P5 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x05
BRA READ_Px
DO_P6
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x06 ; Test for P6 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x06
BRA READ_Px
DO_P7
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x07 ; Test for P7 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x07
BRA READ_Px
DO_P8
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x08 ; Test for P8 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x08
BRA READ_Px
DO_P9
BSF KEYPRESS
BTFSC HELD ; Key held?
BRA EXIT_KBD ; Yes, exit interrupt
MOVLW 0x09 ; Test for P9 already selected
SUBWF MEM,W
BTFSC STATUS,Z ; Is it?
BRA EXIT_KBD ; Yes, exit interrupt
BSF HELD
MOVLW 0x09
READ_Px
MOVWF MEM ; Load memory location for preset to read EEPROM
CALL EEPROM_READ ; Get PLL and SYS
BCF MUTE ; Mute audio to allow PLL to settle
MOVLW 0x04
MOVWF MUTECTR ; Set mute counter for 0.4 s
CALL LOADSYS ; Set system and show memory
CALL FREQDISPLAY ; Show frequency
CALL LOADPLL ; Tune PLL
BCF TIME_ON ; Switch off time display in case of PU, TAPE
BSF ShowFreq ; Make sure LEDs are correct (DO_TIME)
BSF INTCON,RBIE ; Re-enable rotary encoder (pulser) because FM needs it
BCF KILLRBIE ; And keep it enabled
BRA EXIT_KBD
; Subroutines TESTSTATE
DO_UNSTBY
BTFSC SYS_ON ; System state already restored from STBY?
RETURN ; Yes
MOVFF STBY_SYS,SYS ; Get saved system state
MOVFF MEMSAV,MEM ; and memory display
CALL LOADSYS ; Restore system state
BSF SYS_ON ; Set corresponding flag
CALL FREQDISPLAY ; Show frequency
BSF INTCON,RBIE ; Re-enable PORTB<7:4> change interrupt
RETURN
DO_CLOCK ; Handles the clock, not the time display
INCF TICKS,F ; every Timer0 interrupt
MOVLW 0x0A ; Test for SECS overflow
SUBWF TICKS,W
BTFSS STATUS,C ; Overflow?
RETURN ; No
CLRF TICKS
; Increment seconds
INCF SECS,F ; SECS are not used on the display
MOVLW 0x3C ; Test for SECS overflow (60)
SUBWF SECS,W
BTFSS STATUS,C ; Overflow?
RETURN ; No
CLRF SECS
; Increment minutes
INCF MINS,F
MOVLW 0x0A ; Test for overflow
SUBWF MINS,W ; if true, C=1, increment 10 minutes
BTFSS STATUS,C ; Overflow?
RETURN ; No
CLRF MINS
; Increment 10 minutes
INCF TMINS,F
MOVLW 0x06 ; Test for overflow
SUBWF TMINS,W ; if true, C=1, increment hours
BTFSS STATUS,C
RETURN
CLRF TMINS
; Test for midnight
MOVLW 0x02
SUBWF THOURS,W ; if true, C=1, check for midnight
BTFSC STATUS,C
BRA MIDNIGHT
; Increment hours
INCF HOURS,F
MOVLW 0x0A ; Test for overflow
SUBWF HOURS,W ; if true, C=1, increment 10 hours
BTFSS STATUS,C
RETURN
CLRF HOURS
; Increment 10 hours
INCF THOURS,F
RETURN
MIDNIGHT
INCF HOURS,F
MOVLW 0x04 ; Test for midnight
SUBWF HOURS,W ; if true, C=1, new day
BTFSS STATUS,C
RETURN
CLRF HOURS
CLRF THOURS
RETURN
SHOW_TIME ; Convert time registers to D3:D0 values
TSTFSZ TICKS ; Only update once a second to allow rotary encoder setting time
RETURN
SHOW_TIME_NOW
TSTFSZ THOURS ; Earlier than 10:00?
BRA $+8 ; No
MOVLW 0xFF ; Blank ten hours digit (D3)
MOVWF D3
BRA SHOW_TIME2
MOVLW 0x01
SUBWF THOURS,W
BTFSS STATUS,Z ; 1x:xx?
BRA $+8 ; No, time is past 20:00
MOVLW B'11111001' ; Code for '1'
MOVWF D3
BRA SHOW_TIME2
MOVLW B'10100100' ; Code for '2'
MOVWF D3
SHOW_TIME2 ; Convert BCD to 7-segment (D2-D0)
MOVFF HOURS,D2
MOVFF TMINS,D1
MOVFF MINS,D0
MOVLW 0x0F ; Look up 7-segment code for hours
ANDWF D2,F ; Sanitize pointer
RLNCF D2,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D2
BTFSS TIME_UNSET ; Don't flash dot if time not set
BTFSS SECS,0
BCF D2,7 ; Switch on decimal point on even seconds
MOVLW 0x0F ; Look up 7-segment code for ten minutes
ANDWF D1,F ; Sanitize pointer
RLNCF D1,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D1
MOVLW 0x0F ; Look up 7-segment code for minutes
ANDWF D0,F ; Sanitize pointer
RLNCF D0,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF D0
CALL UpdateDISP
RETURN
ShowFunc
DECFSZ COUNTDOWN,F
RETURN
BTFSC SYS_PU ; PU in display?
BRA TEST_TAPE ; No
BCF SYSCHG ; Switch off function display
BSF TIME_ON
BCF SYS_TIME ; Switch on TIME LED
CALL LOADSYS
CALL SHOW_TIME_NOW
RETURN
TEST_TAPE
BTFSC SYS_TAPE ; tAPE in display?
BRA TEST_FM ; No
BCF SYSCHG ; Switch off function display
BSF TIME_ON
BCF SYS_TIME ; Switch on TIME LED
CALL LOADSYS
CALL SHOW_TIME_NOW
RETURN
TEST_FM ; Also MW, LW
CALL FREQDISPLAY
BCF SYSCHG ; Switch off function display
RETURN
LOADSYS
BSF DLEN1 ; Load IC6701 (SAA1060), system function and memory preset
CALL DEL10US
CALL SHIFTZERO ; Leading zero
MOVFF SYS,DATABUF
CALL SHIFTDISP ; Q1 (none) SYS<0>
CALL SHIFTDISP ; Q2 SYS_TIME (SYS<1>)
CALL SHIFTDISP ; Q3 SYS_FM <2>
CALL SHIFTDISP ; Q4 SYS_MW <3>
CALL SHIFTDISP ; Q5 SYS_LW <4>
CALL SHIFTDISP ; Q6 SYS_PU <5>
CALL SHIFTDISP ; Q7 SYS_Relay <6>
CALL SHIFTDISP ; Q8 SYS_TAPE <7>
MOVFF MEM,DATABUF ; Retrieve memory display pointer
MOVLW 0x0F
ANDWF DATABUF,F ; Sanitize pointer
RLNCF DATABUF,W ; Adjust for two byte steps in table
CALL BCD7SEG
MOVWF DATABUF
CALL SHIFTDISP ; Q9 a6 MEM<0>
CALL SHIFTDISP ; Q10 b6 MEM<1>
CALL SHIFTDISP ; Q11 c6 MEM<2>
CALL SHIFTDISP ; Q12 d6 MEM<3>
CALL SHIFTDISP ; Q13 e6 MEM<4>
CALL SHIFTDISP ; Q14 f6 MEM<5>
CALL SHIFTDISP ; Q15 g6 MEM<6>
CALL SHIFTDISP ; Q16 (none) MEM<7>
CALL SHIFTONE ; A
BCF DLEN1
BCF DATA
CALL DEL10US
BSF CLB
CALL DEL10US
BCF CLB ; Load pulse
CALL DEL200US ; Wait 200 µs
RETURN
DO_SPLASH
DECFSZ COUNTDOWN,F
RETFIE
BTFSS Splash1 ; POLO in display?
BRA TEST_Splash2 ; No
MOVLW 0x05
MOVWF COUNTDOWN ; Show for 0.5 s
MOVLW B'11111111' ; Show " "
MOVWF D3
MOVLW B'10101011' ; Show "n"
MOVWF D2
MOVLW B'10001000' ; Show "A"
MOVWF D1
MOVLW B'11111011' ; Show "i"
MOVWF D0
CALL UpdateDISP
BCF Splash1
BSF Splash2
RETFIE
TEST_Splash2
BTFSS Splash2 ; nAi in display?
BRA TEST_Splash3 ; No
MOVLW 0x05
MOVWF COUNTDOWN ; Show for 0.5 s
MOVLW B'11111111' ; Show " "
MOVWF D3
MOVLW B'01111111' ; Show "."
MOVWF D2
MOVLW B'10010010' ; Show "S"
MOVWF D1
MOVLW B'10000110' ; Show "E"
MOVWF D0
CALL UpdateDISP
BCF Splash2
BSF Splash3
RETFIE
TEST_Splash3
BTFSS Splash3 ; .SE in display?
BRA End_Splash ; No
MOVLW 0x07
MOVWF COUNTDOWN ; Show for 0.7 s
MOVLW B'11111111' ; Show " "
MOVWF D3
MOVLW B'01111001' ; Show "1."
MOVWF D2
MOVLW B'11000000' ; Show "0"
MOVWF D1
MOVLW B'10100100' ; Show "2"
MOVWF D0
CALL UpdateDISP
BCF Splash3
RETFIE
End_Splash
BCF Splash ; Switch off splash message
BSF ShowFreq ; Tuner function active
BSF MUTE ; Unmute IC6062 (TDA1029)
CALL FREQDISPLAY
BSF INTCON,RBIE ; Enable PORTB<7:4> change interrupt
RETFIE
SAVE_FM
MOVFF FREQHI,FMHISAV
MOVFF FREQLO,FMLOSAV
RETURN
SAVE_MW
MOVFF FREQHI,MWHISAV
MOVFF FREQLO,MWLOSAV
RETURN
SAVE_LW
MOVFF FREQHI,LWHISAV
MOVFF FREQLO,LWLOSAV
RETURN
RESTORE_FM
MOVFF FMHISAV,FREQHI
MOVFF FMLOSAV,FREQLO
RETURN
RESTORE_MW
MOVFF MWHISAV,FREQHI
MOVFF MWLOSAV,FREQLO
RETURN
RESTORE_LW
MOVFF LWHISAV,FREQHI
MOVFF LWLOSAV,FREQLO
RETURN
SAVESTATE ; Gets polled every 25.6 s from Timer0 interrupt (SAVESTATECTR)
MOVF FREQLO,W
SUBWF SAVEDSTATE,W
BTFSC STATUS,Z ; Frequency changed? (lower byte)
RETURN ; No
MOVFF FREQLO,SAVEDSTATE
BSF TETS ; Test LED ON
CLRF EEADR ; Write FREQHI to EEPROM at address 0x00
MOVFF FREQHI,EEDATA
BCF EECON1,EEPGD ; Point to DATA memory
BCF EECON1,CFGS ; Access EEPROM
BSF EECON1,WREN ; Enable writes
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
INCF EEADR ; Write FREQLO to EEPROM at address 0x01
MOVFF FREQLO,EEDATA
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
INCF EEADR ; Write SYS to EEPROM at address 0x02
MOVFF SYS,EEDATA
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
BCF EECON1,WREN ; Disable writes on write complete
BCF TETS
RETURN
EEPROM_WRITE
BSF TETS ; Test LED ON
MOVFF MEM,EEADR ; Get EEPROM memory location
RLNCF EEADR
RLNCF EEADR ; Multiply by four
MOVFF FREQHI,EEDATA
BCF EECON1,EEPGD ; Point to DATA memory
BCF EECON1,CFGS ; Access EEPROM
BSF EECON1,WREN ; Enable writes
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
INCF EEADR ; Write FREQLO to EEPROM at next address
MOVFF FREQLO,EEDATA
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
INCF EEADR ; Write SYS to EEPROM at next address
MOVFF SYS,EEDATA
MOVLW 0x55
MOVWF EECON2
MOVLW 0xAA
MOVWF EECON2
BSF EECON1,WR
BTFSC EECON1,WR ; EEPROM write completed?
BRA $-2 ; No
BCF EECON1,WREN ; Disable writes on write complete
BCF TETS
RETURN
EEPROM_READ ; Read three bytes from EEPROM with MEM as pointer
BSF TETS
MOVF MEM ; Read FREQHI from EEPROM (first byte)
MOVWF EEADR ; Data Memory Address
RLNCF EEADR
RLNCF EEADR ; Multiply by four
BCF EECON1,EEPGD ; Point to DATA memory
BCF EECON1,CFGS ; Access EEPROM
BSF EECON1,RD ; EEPROM Read
MOVF EEDATA,W
MOVWF FREQHI
INCF EEADR,F ; Data Memory Address (FREQLO)
BCF EECON1,EEPGD ; Point to DATA memory
BCF EECON1,CFGS ; Access EEPROM
BSF EECON1,RD ; EEPROM Read
MOVF EEDATA,W
MOVWF FREQLO
INCF EEADR,F ; Data Memory Address (SYS)
BCF EECON1,EEPGD ; Point to DATA memory
BCF EECON1,CFGS ; Access EEPROM
BSF EECON1,RD ; EEPROM Read
MOVF EEDATA,W
MOVWF SYS ; Restore function
BCF TETS
RETURN
ReadDiodes
MOVLW B'11111110' ; Scan P10
MOVWF PORTC
BTFSS IF ; D6049 installed?
BRA D6049 ; Yes, set FM IF to 10.76 MHz
MOVLW B'11111101' ; Scan P11
MOVWF PORTC
BTFSS IF ; D6048 installed?
BRA D6048 ; Yes, set FM IF to 10.73 MHz
MOVLW B'11111011' ; Scan P12
MOVWF PORTC
BTFSS IF ; D6046 installed?
BRA D6046 ; Yes, set FM IF to 10.67 MHz
MOVLW B'11110111' ; Scan P13
MOVWF PORTC
BTFSS IF ; D6045 installed?
BRA D6045 ; Yes, set FM IF to 10.64 MHz
MOVLW 0x3E ; No diodes, set to 10.70 MHz
MOVWF FM_IF100
MOVLW 0x56
MOVWF FM_IF90
MOVLW 0x6E
MOVWF FM_IF80
MOVLW 0x5D
MOVWF FM_BE_HI ; High band edge (low byte)
MOVLW 0x5C
MOVWF FM_BE_LO ; Low band edge (low byte)
BRA SCAN_AM_IF
D6049 ; 10.76 MHz
MOVLW 0x44
MOVWF FM_IF100
MOVLW 0x5C
MOVWF FM_IF90
MOVLW 0x74
MOVWF FM_IF80
MOVLW 0x63
MOVWF FM_BE_HI ; High band edge (low byte)
MOVLW 0x62
MOVWF FM_BE_LO ; Low band edge (low byte)
BRA SCAN_AM_IF
D6048 ; 10.73 MHz
MOVLW 0x41
MOVWF FM_IF100
MOVLW 0x59
MOVWF FM_IF90
MOVLW 0x71
MOVWF FM_IF80
MOVLW 0x60
MOVWF FM_BE_HI ; High band edge (low byte)
MOVLW 0x5F
MOVWF FM_BE_LO ; Low band edge (low byte)
BRA SCAN_AM_IF
D6046 ; 10.67 MHz
MOVLW 0x3B
MOVWF FM_IF100
MOVLW 0x53
MOVWF FM_IF90
MOVLW 0x6B
MOVWF FM_IF80
MOVLW 0x5A
MOVWF FM_BE_HI ; High band edge (low byte)
MOVLW 0x59
MOVWF FM_BE_LO ; Low band edge (low byte)
BRA SCAN_AM_IF
D6045 ; 10.64 MHz
MOVLW 0x38
MOVWF FM_IF100
MOVLW 0x50
MOVWF FM_IF90
MOVLW 0x68
MOVWF FM_IF80
MOVLW 0x57
MOVWF FM_BE_HI ; High band edge (low byte)
MOVLW 0x56
MOVWF FM_BE_LO ; Low band edge (low byte)
; Done scan FM IF
SCAN_AM_IF
MOVLW B'11101111' ; Scan P14
MOVWF PORTC
BTFSS IF ; D6044 installed?
BRA D6044 ; Yes, set AM IF to 468 kHz
MOVLW B'11011111' ; Scan P15
MOVWF PORTC
BTFSS IF ; D6042 installed?
BRA D6042 ; Yes, set AM IF to 455 kHz
MOVLW B'10111111' ; Scan P16
MOVWF PORTC
BTFSS IF ; D6041 installed?
BRA D6041 ; Yes, set AM IF to 452 kHz
MOVLW 0x98
MOVWF AM_IFLO ; No diodes installed, preload AM IF frequency to 460 kHz
MOVLW 0x3F
MOVWF MW_BE_HI ; MW high band edge (low byte)
MOVLW 0xA8
MOVWF MW_BE_LO ; MW Low band edge (low byte)
MOVLW 0xC7
MOVWF LW_BE_HI ; LW high band edge (low byte)
MOVLW 0xC4
MOVWF LW_BE_LO ; LW low band edge (low byte)
BRA End_ReadDiodes
D6041
MOVLW 0x88
MOVWF AM_IFLO ; Preload AM IF frequency 452 kHz
MOVLW 0x2F
MOVWF MW_BE_HI ; MW high band edge (low byte)
MOVLW 0x98
MOVWF MW_BE_LO ; MW Low band edge (low byte)
MOVLW 0xB7
MOVWF LW_BE_HI ; LW high band edge (low byte)
MOVLW 0xB4
MOVWF LW_BE_LO ; LW low band edge (low byte)
BRA End_ReadDiodes
D6042
MOVLW 0x8E
MOVWF AM_IFLO ; Preload AM IF frequency 455 kHz
MOVLW 0x35
MOVWF MW_BE_HI ; MW high band edge (low byte)
MOVLW 0x9E
MOVWF MW_BE_LO ; MW Low band edge (low byte)
MOVLW 0xBD
MOVWF LW_BE_HI ; LW high band edge (low byte)
MOVLW 0xBA
MOVWF LW_BE_LO ; LW low band edge (low byte)
BRA End_ReadDiodes
D6044
MOVLW 0xA8
MOVWF AM_IFLO ; Preload AM IF frequency 468 kHz
MOVLW 0x4F
MOVWF MW_BE_HI ; MW high band edge (low byte)
MOVLW 0xB8
MOVWF MW_BE_LO ; MW Low band edge (low byte)
MOVLW 0xD7
MOVWF LW_BE_HI ; LW high band edge (low byte)
MOVLW 0xD4
MOVWF LW_BE_LO ; LW low band edge (low byte)
End_ReadDiodes
MOVLW B'11111111' ; Unscan Port C
MOVWF PORTC
RETURN
; End interrupts
ORG 0xF00000 ; EEPROM preload
DE 0x2C, 0xA5, B'11111011', 0x00 ;103.60 with offset because of weird RBIF bug in my code
DE 0x05, 0x14, B'11101111', 0x00 ;P1 - 198 kHz
DE 0x2A, 0x76, B'11111011', 0x00 ;P2 - 98.00 MHz
DE 0x0D, 0xF0, B'11110111', 0x00 ;P3 - 1332 kHz
DE 0x27, 0x9C, B'11111011', 0x00 ;P4 - 90.70 MHz
DE 0x27, 0xC4, B'11111011', 0x00 ;P5 - 91.10 MHz
DE 0x2C, 0xA6, B'11111011', 0x00 ;P6 - 103.60 MHz
DE 0x29, 0xB8, B'11111011', 0x00 ;P7 - 96.10 MHz
DE 0x2B, 0x66, B'11111011', 0x00 ;P8 - 100.40 MHz
DE 0x2E, 0x5D, B'11111011', 0x00 ;P9 - 107.99 MHz
END