; 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