; Replacement for Cyrus AM/FM tuner controller (MAB8441) and LCD (2x20 HD44780)
; v0.0 210618 Copied from original project to extend lower frequency range to 82.4 MHz (3.5 m pirate band). Upper limit 107.9, was 108.0 MHz
; v1.0 210618 Release
LIST P=16F818, F=INHX8M
#include <p16f818.inc>
__CONFIG _WDT_OFF & _PWRTE_OFF & _INTRC_IO & _MCLR_ON & _BODEN_OFF & _LVP_OFF & _CPD_ON & _WRT_ENABLE_OFF & _DEBUG_OFF & _CCP1_RB2 & _CP_ALL
ERRORLEVEL -302 ; remove message about using proper bank
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
OSC_FREQ EQU D'4000000' ; Internal Oscillator Frequency is 4 MHz (OSCCON)
; Registers
FLAGS EQU 0x20 ; Various flags
LCDAdd EQU 0x21 ; LCD Character Address
LCDByte EQU 0x22 ; Byte to send to LCD
TEMP1 EQU 0x23 ; Temp register
TEMP2 EQU 0x24 ; Temp register
d1 EQU 0x25 ; Delay register
d2 EQU 0x26 ; Delay register
I2CBUF EQU 0x27 ; Used for I2C data
I2CCNT EQU 0x28 ; Used for I2C bitbanger
FRINDX EQU 0x29 ; Frequency Index
FR10MC EQU 0x2A ; 10 MHz display value
FR1MC EQU 0x2B ; 1 MHz display value
FR01MC EQU 0x2C ; 0.1 MHz display value
DB0 EQU 0x2D ; TSA6057 config byte 0
DB1 EQU 0x2E ; TSA6057 config byte 1
SCANCTR EQU 0x30 ; Scan speed counter
EEBUF EQU 0x31 ; Used for writing a byte to EEPROM
; Defines
#define SCL PORTB,0 ; I2C Clock
#define SDA PORTB,1 ; I2C Data
#DEFINE LCD_EN PORTB,2
#DEFINE LCD_RS PORTB,3
#DEFINE LCD_D4 PORTB,4
#DEFINE LCD_D5 PORTB,5
#DEFINE LCD_D6 PORTB,6
#DEFINE LCD_D7 PORTB,7
#DEFINE MUTE PORTA,1 ; MUTE output (active HIGH)
#DEFINE MONO PORTA,2 ; MONO (VCO Stop) (active LOW OUTPUT)
#DEFINE UP PORTA,3 ; Up button (active LOW)
#DEFINE DN PORTA,4 ; Down button (active LOW)
#DEFINE STEREO PORTA,6 ; Stereo indicator from MPX (active low)
#DEFINE STOP PORTA,7 ; Search STOP from demod (active low)
#DEFINE NAK FLAGS,0 ; Not Acknowledge after I2C byte
#DEFINE MANSCAN FLAGS,1 ; Used for debouncing buttons and automatic tuning
#DEFINE AUTOSCAN FLAGS,2
; AN0 (SIGMET) has no label defined
ORG 0
GOTO START
ORG 4
; Interrupts
; Timer0 Interrupt Handler
BCF INTCON,TMR0IF ; Clear TMR0 interrupt (every 58 ms)
CALL UPDATEDISPLAY ; Shows STEREO and signal level bar
BTFSS DN ; DN pressed?
GOTO WriteDN ; Yes
BTFSS UP ; UP pressed?
GOTO WriteUP ; Yes
CLRF TMR0
RETFIE
WriteDN
CALL LONGDLY ; Extra delay to catch short keypress
CALL BlankSTEREO
BSF MUTE
MOVLW 0x0A
MOVWF SCANCTR ; Preload Scan Speed Counter
DNScanFast
INCF SCANCTR,F ; Ensure scan test passes
DNScanSlow
DECF FRINDX,F
MOVFW FRINDX ; Get value for frequency display
CALL LOADPLL
CALL FREQDISPLAY
BTFSC AUTOSCAN ; Autoscan ongoing?
GOTO DNAuto ; Yes
BTFSC MANSCAN ; Manual scan ongoing?
GOTO DNMan ; Yes
BTFSC DN ; DN pressed again?
GOTO BTNExit ; Yes
BSF MANSCAN
DNCont
DECFSZ SCANCTR,F ; Scan speed fast?
GOTO $+2 ; No
GOTO DNScanFast
DNSlow ; Slow scan speed in case of Autoscan to provide time for correct STOP operation
CALL LONGDLY
CALL LONGDLY
GOTO DNScanSlow
DNAuto
BTFSS STOP ; STOP active (low)?
GOTO BTNExit
BTFSC DN ; DN pressed again to cancel autoscan?
GOTO DNSlow ; No
CALL LONGDLY
BTFSS DN ; Yes, released?
GOTO $-2 ; No, not released
GOTO BTNExit ; Yes, released
DNMan
BTFSC DN
BSF AUTOSCAN ; No, released, manual scan ended
GOTO DNCont ; Yes, held
WriteUP
CALL LONGDLY ; Extra delay to catch short keypress
CALL BlankSTEREO
BSF MUTE
MOVLW 0x0A
MOVWF SCANCTR ; Preload Scan Speed Counter
UPScanFast
INCF SCANCTR,F ; Ensure scan zero test passes
UPScanSlow
INCF FRINDX,F
MOVFW FRINDX ; Get value for frequency display
CALL LOADPLL
CALL FREQDISPLAY
BTFSC AUTOSCAN ; Autoscan ongoing?
GOTO UPAuto ; Yes
BTFSC MANSCAN ; Manual scan ongoing?
GOTO UPMan ; Yes
BTFSC UP ; UP pressed again?
GOTO BTNExit ; Yes
BSF MANSCAN
UPCont
DECFSZ SCANCTR,F ; Scan speed fast?
GOTO $+2 ; No
GOTO UPScanFast
UPSlow ; Slow scan speed in case of Autoscan to provide time for correct STOP operation
CALL LONGDLY
CALL LONGDLY
GOTO UPScanSlow
UPAuto
BTFSS STOP ; STOP active (low)?
GOTO BTNExit
BTFSC UP ; UP pressed again to cancel autoscan?
GOTO UPSlow ; No
CALL LONGDLY
BTFSS UP ; Yes, released?
GOTO $-2 ; No, not released
GOTO BTNExit ; Yes, released
UPMan
BTFSC UP
BSF AUTOSCAN ; No, released, manual scan ended
GOTO UPCont ; Yes, held
BTNExit
BCF MANSCAN
BCF AUTOSCAN
CALL LONGDLY
MOVFW FRINDX ; Get current index to store in EEPROM
MOVWF EEBUF
CLRW ; Point to EEPROM Address 0x00
CALL EEPROMWRITE ; Save index
CLRF TMR0
BCF MUTE
RETFIE
; Subroutines (I2C)
I2CSTART
BCF SDA
CALL I2CDELAY
BCF SCL
CALL I2CDELAY
RETURN
I2CBYTE ; Sends byte in W
MOVWF I2CBUF
MOVLW 0x08
MOVWF I2CCNT
NEXTBIT
BCF STATUS,C ; Clear carry
RLF I2CBUF,F ; Rotate MSB into carry
BTFSC STATUS,C ; Carry clear?
BSF SDA ; No, set SDA
BTFSS STATUS,C ; Carry set?
BCF SDA ; No, clear SDA
CALL I2CDELAY
BSF SCL ; Send clock
CALL I2CDELAY
BCF SCL ; Done clock
DECFSZ I2CCNT,F
GOTO NEXTBIT
; ACK handler
BSF STATUS,RP0 ; Select Bank 1
BSF TRISB,1 ; Set SDA as input to float SDA line
BCF STATUS,RP0 ; Select Bank 0
BSF NAK
CALL I2CDELAY
BSF SCL ; Solicit ACK
CLRF I2CCNT
TESTACK
BTFSC SDA ; SDA pulled low?
GOTO CONTACK ; No, continue testing for ACK until timeout (~20 ms)
BCF NAK ; Clear NAK
GOTO EXITACK ; Exit loop
CONTACK
DECFSZ I2CCNT,F
GOTO TESTACK
EXITACK
BSF STATUS,RP0 ; Select Bank 1
BCF TRISB,1 ; Set SDA as output
BCF STATUS,RP0 ; Select Bank 0
BTFSC NAK ; NAK handler
GOTO START ; Timeout, no ACK, force reset
BCF SCL
CALL I2CDELAY
RETURN
I2CSTOP
BCF SDA
CALL I2CDELAY
BSF SCL
CALL I2CDELAY
BSF SDA
RETURN
I2CDELAY
NOP ; 8 us delay
NOP
NOP
NOP
RETURN
LOADPLL
MOVFW FRINDX ; Get frequency index
CLRF DB1
MOVWF DB0
RLF DB0,F
RLF DB1,F ; Shift one bit into DB1
RLF DB0,F
RLF DB1,F ; Shift one bit into DB1
RLF DB0,F
RLF DB1,F ; Shift one bit into DB1
MOVLW 0xF8
ANDWF DB0,F ; Blank two LSBs and CP
MOVLW 0x19
ADDWF DB0,F ; Add offset
BTFSC STATUS,C ; Carry set?
GOTO $+3 ; No
MOVLW 0x1D ; Yes
GOTO $+2
MOVLW 0x1E
ADDWF DB1,F
CALL I2CSTART
MOVLW 0xC4 ; Address
CALL I2CBYTE
CLRW ; Subaddress (00)
CALL I2CBYTE
MOVFW DB0
CALL I2CBYTE
MOVFW DB1
CALL I2CBYTE
CALL I2CSTOP
RETURN
EEPROMREAD
; W contains address to read, at return contains read data
BANKSEL EEADR ; Select Bank of EEADR
MOVWF EEADR ; Data Memory Address to read from W
BANKSEL EECON1 ; Select Bank of EECON1
BCF EECON1, EEPGD ; Point to Data memory
BSF EECON1, RD ; EE Read
BANKSEL EEDATA ; Select Bank of EEDATA
MOVF EEDATA, W ; W = EEDATA
RETURN
EEPROMWRITE
; W contains address to write, data is in EEBUF
BANKSEL EECON1 ; Select Bank of EECON1
BTFSC EECON1, WR ; Wait for write
GOTO $-1 ; to complete
BANKSEL EEADR ; Select Bank of EEADR
MOVWF EEADR ; Data Memory Address to write
BANKSEL EEBUF
MOVFW EEBUF ; Data to write from buffer
BANKSEL EEDATA
MOVWF EEDATA ; Data Memory Value to write
BANKSEL EECON1 ; Select Bank of EECON1
BCF EECON1, EEPGD ; Point to DATA memory
BSF EECON1, WREN ; Enable writes
MOVLW 0x55
MOVWF EECON2 ; Write 55h
MOVLW 0xAA
MOVWF EECON2 ; Write AAh
BSF EECON1, WR ; Set WR bit to begin write
BCF EECON1, WREN ; Disable writes
BANKSEL PORTB ; Select BANK0
RETURN
; Subroutines (LCD)
LCDPOS ; makes WREG the current LCD position
BCF LCD_RS
MOVWF LCDByte ; Valid values 0x80-0x8F, 0xC0-0xCF
CALL LCDBYTE
BSF LCD_RS
CALL LONGDLY ; Needed for the LCD to process the command
RETURN
LCDCLR ; clears the entire display
BCF LCD_RS ; Instruction mode
MOVLW 0x01
MOVWF LCDByte
CALL LCDBYTE
BSF LCD_RS ; Character mode
CALL LONGDLY ; Clearing the LCD takes ages, so a larger delay is needed
RETURN
LCDBYTE
; sends the byte in WREG to the LCD in 4bit fashion. Set LCD_RS as appropriate (0: instruction, 1: character)
MOVWF LCDByte
BCF LCD_D7 ; Clear data bits
BCF LCD_D6
BCF LCD_D5
BCF LCD_D4
BTFSC LCDByte,7 ; Load high nibble
BSF LCD_D7
BTFSC LCDByte,6
BSF LCD_D6
BTFSC LCDByte,5
BSF LCD_D5
BTFSC LCDByte,4
BSF LCD_D4
BSF LCD_EN ; Strobe EN
NOP
BCF LCD_EN
BCF LCD_D7 ; Clear data bits
BCF LCD_D6
BCF LCD_D5
BCF LCD_D4
BTFSC LCDByte,3 ; Load low nibble
BSF LCD_D7
BTFSC LCDByte,2
BSF LCD_D6
BTFSC LCDByte,1
BSF LCD_D5
BTFSC LCDByte,0
BSF LCD_D4
BSF LCD_EN ; Strobe EN
NOP
BCF LCD_EN
CALL SHORTDLY ; blocks until most instructions are done
RETURN
SHORTDLY
; around 221us, 217 cycles
MOVLW 0x48
MOVWF d1
SHORTDLY_0
DECFSZ d1,F
GOTO SHORTDLY_0 ;4 cycles (including call)
RETURN
LONGDLY
; 92ms delay, 92153 cycles
MOVLW 0xFE
MOVWF d1
MOVLW 0x48
MOVWF d2
LONGDLY_0
DECFSZ d1,F
GOTO $+2
DECFSZ d2,F
GOTO LONGDLY_0 ;3 cycles
NOP
NOP ;4 cycles (including call)
RETURN
FREQDISPLAY ; Decodes index to frequency display
MOVLW 0xB0 ; Test for >= 100 MHz
SUBWF FRINDX,W
BTFSC STATUS,C ; >= 100 MHz?
GOTO TEST100MC ; Yes
MOVLW 0x4C ; Test for >= 90 MHz
SUBWF FRINDX,W
BTFSC STATUS,C ; >= 90 MHz?
GOTO TEST90MC ; Yes
MOVLW 0x38 ; < 90 MHz (ASCII "8")
MOVWF FR10MC
MOVFW FRINDX ; Get index
ADDLW 0x18 ; Compensate 1 MHz part of 80 MHz frequency (82.4 MHz == 0x00)
MOVWF TEMP1 ; Save 1 MHz value
GOTO TESTMC
TEST100MC
MOVWF TEMP1 ; Save 1 MHz value
MOVLW 0x30
MOVWF FR10MC ; Set 10 MHz to "100"
MOVFW FRINDX
SUBLW 0x7D
GOTO TESTMC
TEST90MC
MOVWF TEMP1 ; Save 1 MHz value
MOVLW 0x39
MOVWF FR10MC
TESTMC ; Calculate 1 MHz part
MOVLW 0x0A ; 0.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST0MC
MOVLW 0x0A ; 1.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST1MC
MOVLW 0x0A ; 2.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST2MC
MOVLW 0x0A ; 3.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST3MC
MOVLW 0x0A ; 4.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST4MC
MOVLW 0x0A ; 5.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST5MC
MOVLW 0x0A ; 6.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST6MC
MOVLW 0x0A ; 7.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST7MC
MOVLW 0x0A ; 8.x MHz
SUBWF TEMP1,F
BTFSS STATUS,C
GOTO TEST8MC
SUBWF TEMP1,F ; Compensate for compensation
MOVLW 0x39
MOVWF FR1MC ; Store 9 MHz display value
GOTO TEST100KC
TEST8MC
MOVLW 0x38
MOVWF FR1MC ; Store 8 MHz display value
GOTO TEST100KC
TEST7MC
MOVLW 0x37
MOVWF FR1MC ; Store 7 MHz display value
GOTO TEST100KC
TEST6MC
MOVLW 0x36
MOVWF FR1MC ; Store 6 MHz display value
GOTO TEST100KC
TEST5MC
MOVLW 0x35
MOVWF FR1MC ; Store 5 MHz display value
GOTO TEST100KC
TEST4MC
MOVLW 0x34
MOVWF FR1MC ; Store 4 MHz display value
GOTO TEST100KC
TEST3MC
MOVLW 0x33
MOVWF FR1MC ; Store 3 MHz display value
GOTO TEST100KC
TEST2MC
MOVLW 0x32
MOVWF FR1MC ; Store 2 MHz display value
GOTO TEST100KC
TEST1MC
MOVLW 0x31
MOVWF FR1MC ; Store 1 MHz display value
GOTO TEST100KC
TEST0MC
MOVLW 0x30
MOVWF FR1MC ; Store 0 MHz display value
TEST100KC ; Calculate 0.1 MHz part
MOVLW 0x3A ; Compensate previous test and create ASCII code (30-39)
ADDWF TEMP1,W
MOVWF FR01MC
; Print the frequency
MOVLW 0x80
CALL LCDPOS ; Set display leftmost corner
MOVLW 0x30
SUBWF FR10MC,W ; Test for 100 MHz
BTFSS STATUS,Z ; 100 MHz?
GOTO $+3 ; No
MOVLW 0x31 ; Print "1"
GOTO $+2
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVFW FR10MC
CALL LCDBYTE
MOVFW FR1MC ; Print 1 MHz
CALL LCDBYTE
MOVLW 0x2E ; Print "."
CALL LCDBYTE
MOVFW FR01MC ; Print 0.1 MHz
CALL LCDBYTE
RETURN
UPDATEDISPLAY
MOVLW 0xC0 ; 2nd row, leftmost position
CALL LCDPOS
BTFSC STEREO
GOTO NotSTEREO
MOVLW 0x53 ; Print "S"
CALL LCDBYTE
MOVLW 0x54 ; Print "T"
CALL LCDBYTE
MOVLW 0x45 ; Print "E"
CALL LCDBYTE
MOVLW 0x52 ; Print "R"
CALL LCDBYTE
MOVLW 0x45 ; Print "E"
CALL LCDBYTE
MOVLW 0x4F ; Print "O"
CALL LCDBYTE
GOTO LevelDisplay
NotSTEREO
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
LevelDisplay
MOVLW 0xCF
CALL LCDPOS ; Show level character in lower right corner
BSF ADCON0,GO ; Start A/D (SIGMET)
CONV0
NOP
BTFSC ADCON0,GO ; Test if done
GOTO CONV0
MOVFW ADRESH ; Move 8 bit A/D result to W
MOVWF TEMP1 ; Save in TEMP register
ADDLW 0xF1
BTFSC STATUS,C ; Level > -110 dBm?
GOTO LEVEL2 ; Yes
MOVLW 0x01
CALL LCDBYTE ; Print 2 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL2
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xED
BTFSC STATUS,C ; Level > -105 dBm?
GOTO LEVEL3 ; Yes
MOVLW 0x02
CALL LCDBYTE ; Print 3 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL3
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xE8
BTFSC STATUS,C ; Level > -100 dBm?
GOTO LEVEL4 ; Yes
MOVLW 0x03
CALL LCDBYTE ; Print 4 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL4
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xDD
BTFSC STATUS,C ; Level > -95 dBm?
GOTO LEVEL5 ; Yes
MOVLW 0x04
CALL LCDBYTE ; Print 5 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL5
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xCF
BTFSC STATUS,C ; Level > -90 dBm?
GOTO LEVEL6 ; Yes
MOVLW 0x05
CALL LCDBYTE ; Print 6 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL6
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xC3
BTFSC STATUS,C ; Level > -85 dBm?
GOTO LEVEL7 ; Yes
MOVLW 0x06
CALL LCDBYTE ; Print 7 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL7
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xBD
BTFSC STATUS,C ; Level > -80 dBm?
GOTO LEVEL8 ; Yes
MOVLW 0x07
CALL LCDBYTE ; Print 8 bar
MOVLW 0x8F
CALL LCDPOS ; Blank level in upper right corner
MOVLW 0x20
CALL LCDBYTE ; Print " "
RETURN
LEVEL8
MOVLW 0x07
CALL LCDBYTE ; Print 8 bar (still lower right corner)
MOVLW 0x8F
CALL LCDPOS ; Move to upper right corner
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xB8
BTFSC STATUS,C ; Level > -75 dBm?
GOTO LEVEL9 ; Yes
MOVLW 0x00
CALL LCDBYTE ; Print 1 bar
RETURN
LEVEL9
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xB0
BTFSC STATUS,C ; Level > -70 dBm?
GOTO LEVELA ; Yes
MOVLW 0x01
CALL LCDBYTE ; Print 2 bar
RETURN
LEVELA
MOVFW TEMP1 ; Get SIGMET
ADDLW 0xA2
BTFSC STATUS,C ; Level > -65 dBm?
GOTO LEVELB ; Yes
MOVLW 0x02
CALL LCDBYTE ; Print 3 bar
RETURN
LEVELB
MOVFW TEMP1 ; Get SIGMET
ADDLW 0x92
BTFSC STATUS,C ; Level > -60 dBm?
GOTO LEVELC ; Yes
MOVLW 0x03
CALL LCDBYTE ; Print 4 bar
RETURN
LEVELC
MOVFW TEMP1 ; Get SIGMET
ADDLW 0x84
BTFSC STATUS,C ; Level > -55 dBm?
GOTO LEVELD ; Yes
MOVLW 0x04
CALL LCDBYTE ; Print 5 bar
RETURN
LEVELD
MOVFW TEMP1 ; Get SIGMET
ADDLW 0x79
BTFSC STATUS,C ; Level > -50 dBm?
GOTO LEVELE ; Yes
MOVLW 0x05
CALL LCDBYTE ; Print 6 bar
RETURN
LEVELE
MOVFW TEMP1 ; Get SIGMET
ADDLW 0x72
BTFSC STATUS,C ; Level > -45 dBm?
GOTO FULL ; Yes
MOVLW 0x06
CALL LCDBYTE ; Print 6 bar
RETURN
FULL
MOVLW 0x07
CALL LCDBYTE ; Print 7 bar
RETURN
BlankSTEREO
MOVLW 0xC0 ; 2nd row, leftmost position
CALL LCDPOS
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
MOVLW 0x20 ; Print " "
CALL LCDBYTE
RETURN
START
; Init stuff
CLRF STATUS ; Do initialization, select Bank 0
CLRF INTCON ; Clear int-flags, disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
CLRF CCP1CON
MOVLW B'11111001'
BANKSEL TRISA
MOVWF TRISA ; RA7-3 Inputs, RA2,1 Outputs, AN0 Input
CLRF TRISB ; RB7-0 Outputs
MOVLW B'00000110' ; Timer0, prescaler 1:128
MOVWF OPTION_REG
MOVLW B'01100000' ; 4 MHz clock
MOVWF OSCCON
MOVLW B'00001110' ; AN0 Analog input, AN1-4 Digital IO, ADRESH only (ADRESL discarded)
MOVWF ADCON1
MOVLW B'01000001' ; AD conv ON, AN0 Selected, Fosc/8 (T(AD)=1us)
BANKSEL ADCON0
MOVWF ADCON0
CLRF PORTB ; Make all PORT B outputs low
CLRF FLAGS
CLRF LCDAdd
MOVLW 0x69
MOVWF FRINDX ; Set index to 98.0 MHz
CLRF FR10MC
CLRF FR1MC
CLRF FR01MC
BSF SCL
BSF SDA
BSF MONO
BSF MUTE
; DEBUG
; GOTO WriteDN
; Init LCD
CALL LONGDLY ; Set LCD to 4-bit mode
MOVLW B'00110011' ; 2x 8bit resets
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00110011' ; 2x 8bit resets
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00110010' ; 8bit reset then 4bit reset
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00101100' ; Function Set - 4bit, 2 lines
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00000110' ; Set entry mode (move cursor to right after each write)
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00001100' ; turn display on and cursor off
CALL LCDBYTE
CALL SHORTDLY
MOVLW B'00000001' ; Display Clear
CALL LCDBYTE
CALL LONGDLY ; Should wait for BUSY flag to clear but we cannot read it...
MOVLW B'00000010' ; Cursor Home
CALL LCDBYTE
CALL LONGDLY
MOVLW B'01000000' ; Set CGRAM Address for top line of character 0x00
CALL LCDPOS
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x00
CLRW
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x00
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x00 (cursor)
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x01
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x01
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x01
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x02
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x02
CLRW
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x02
CLRW
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x02
CLRW
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x02
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x02
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x02
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x02
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x03
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x03
CLRW
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x03
CLRW
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x03
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x03
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x03
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x03
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x03
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x04
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x04
CLRW
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x04
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x04
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x04
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x04
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x04
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x04
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x05
CLRW
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x05
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x05
CLRW
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x06
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for top line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x07
MOVLW 0x1F
CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x07
; Done init LCD
; Show banner
MOVLW 0x85 ; 6th position top line
CALL LCDPOS
MOVLW 0x43 ; C
CALL LCDBYTE
MOVLW 0x79 ; y
CALL LCDBYTE
MOVLW 0x72 ; r
CALL LCDBYTE
MOVLW 0x75 ; u
CALL LCDBYTE
MOVLW 0x73 ; s
CALL LCDBYTE
MOVLW 0xC2 ; 3rd postition bottom line
CALL LCDPOS
MOVLW 0x41 ; A
CALL LCDBYTE
MOVLW 0x4D ; M
CALL LCDBYTE
MOVLW 0x2F ; /
CALL LCDBYTE
MOVLW 0x46 ; F
CALL LCDBYTE
MOVLW 0x4D ; M
CALL LCDBYTE
MOVLW 0x20 ; space
CALL LCDBYTE
MOVLW 0x54 ; T
CALL LCDBYTE
MOVLW 0x75 ; u
CALL LCDBYTE
MOVLW 0x6E ; n
CALL LCDBYTE
MOVLW 0x65 ; e
CALL LCDBYTE
MOVLW 0x72 ; r
CALL LCDBYTE
; Restore index from EEPROM
CLRW
CALL EEPROMREAD
BANKSEL FRINDX
MOVWF FRINDX ; Restored Frequency Index
; Init TSA5067
CALL LOADPLL
CALL I2CSTART
MOVLW 0xC4 ; Address
CALL I2CBYTE
MOVLW 0x02 ; Subaddress (02)
CALL I2CBYTE
MOVLW 0xA4 ; DB2 (BS: Sink current -> FM)
CALL I2CBYTE
CLRW ; DB3
CALL I2CBYTE
CALL I2CSTOP
MOVLW 0x10 ; Show banner for about one second
MOVWF TEMP1
CALL LONGDLY
DECFSZ TEMP1,F
GOTO $-2
BCF MUTE
CALL LCDCLR ; Clear display
CALL LONGDLY
MOVLW 0x83 ; Set cursor at the "." position
CALL LCDPOS
MOVLW 0x2E ; .
CALL LCDBYTE
MOVLW 0x20 ; " "
CALL LCDBYTE
MOVLW 0x20 ; " "
CALL LCDBYTE
MOVLW 0x4D ; M
CALL LCDBYTE
MOVLW 0x48 ; H
CALL LCDBYTE
MOVLW 0x7A ; z
CALL LCDBYTE
CALL FREQDISPLAY
MOVLW B'10100000' ; Enable global (GIE), Timer0 (T0IE) interrupts
MOVWF INTCON
GOTO $ ; Loop forever
ORG 0x2100 ; EEPROM Data
DE 0x69 ; FRINDX
END