;************************************************************************ ; Nick Hubbard ; ; LMX2331 PLL driver ; Assembler version: 2.0000 ; Filename: ; p16demo.asm (main routine) ; Dependances: ; p16lcd.asm ; p16math.asm ; 16f877.lkr ; Designed to run at 4MHz ;************************************************************************ list p=16F877 #include p16F877.inc __CONFIG _CP_OFF & _WDT_OFF & _HS_OSC & _LVP_OFF & _BODEN_OFF #define scroll_dir TRISA,4 #define scroll PORTA,4 ;Push-button RA4 on PCB #define select_dir TRISB,0 #define select PORTB,0 ;Push-button RB0 on PCB ; The 3 pins RB 0, 1, 2 connect to the PLL chip. ; RB1 (LED D3) Pin 34 Data ; RB2 (LED D4) Pin 35 Latch Enable ; RB3 (LED D5) Pin 36 Clock #define PLL_DT PORTB, 1 #define PLL_LE PORTB, 2 #define PLL_CK PORTB, 3 #define PLL_DT_DIR TRISB, 1 #define PLL_EN_DIR TRISB, 2 #define PLL_CK_DIR TRISB, 3 EXTERN LCDInit, temp_wr, d_write, i_write, LCDLine_1, LCDLine_2 EXTERN UMUL0808L, UDIV1608L, AARGB0, AARGB1, BARGB0 variables UDATA 0x28 ptr_pos RES 1 ptr_count RES 1 temp_1 RES 1 temp_2 RES 1 temp_3 RES 1 cmd_byte RES 1 LSD RES 1 MsD RES 1 MSD RES 1 NumH RES 1 NumL RES 1 TenK RES 1 Thou RES 1 Hund RES 1 Tens RES 1 Ones RES 1 keyTimer RES 1 keyAction1 RES 1 keyAction2 RES 1 channel res 1 mode res 1 addlsb res 1 addmsb res 1 mulpH Res 1 ; MSB of multiplier. mulpL Res 1 ; LSB of multiplier. prodH Res 1 ; MSB of product. prodL Res 1 ; LSB of product. index Res 1 ; temporary counter pll_serLsb Res 1 pll_serMsb Res 1 pll_count Res 1 pll_temp Res 1 pll_msb Res 1 pll_lsb Res 1 DATA_EE_ADDR equ 0x70 DATA_EE_DATA equ 0x71 chan_msb equ 0x72 chan_lsb equ 0x73 temp_4 equ 0x74 #define EE_DEF_CHAN 0 STARTUP CODE NOP goto start NOP NOP NOP PROG1 CODE start ; folowing initialisation is from the PICDEM 2 source call LCDInit banksel T1CON ;Configure Timer1 for real time clock movlw 0x0F ; start here for timer "warm-up" movwf T1CON banksel TXSTA ;initialize USART movlw B'10100100' ;Master mode, 8-bit, Async, High speed movwf TXSTA movlw .25 ;9.6Kbaud @ 4MHz movwf SPBRG banksel RCSTA movlw B'10010000' movwf RCSTA banksel TRISC ;configure CCP1 module for buzzer bcf TRISC,2 banksel T2CON ;bank 0 movlw 0x05 ;postscale 1:1, prescaler 4, Timer2 ON movwf T2CON bsf TRISA,4 ;make switch RA4 an Input bsf TRISB,0 ;make switch RB0 an Input banksel TRISB bcf PLL_DT_DIR ; Set data bits to outputs bcf PLL_CK_DIR bcf PLL_EN_DIR banksel ptr_pos clrf mode ; channel toggle mode == 0 ; soft defaults BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movlw EE_DEF_CHAN movwf DATA_EE_ADDR call readee BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movwf channel call getChanFreq ; channel passed in W call setpll call report1 call report2 mainloop ; PLL key debounce clrf keyAction1 clrf keyAction2 ; wait for both keys up call debounce ; wait for both keys up settle1 movfw keyAction1 movwf keyAction2 call delay_50ms settle2 call getkey ; get command code in W. (zero - no key down) iorlw 0x00 ; Test for any key down. Z set if none btfsc STATUS,Z ; same! goto settle2 ; no key down movwf keyAction1 ; save command in current image subwf keyAction2,w ; same as last? btfss STATUS,Z ; same! goto settle1 ; not same ; we now have the command. ; time how long before any key is released. clrf keyTimer settle3: movfw keyTimer sublw .10 btfsc STATUS,C incf keyTimer movfw keyTimer sublw .10 btfsc STATUS,Z call cls ; clear screen call delay_50ms call getkey iorlw 0x00 ; Test for any key down. Z set if none btfss STATUS,Z ; goto settle3 ; loop if key down ; evaluate command movfw keyTimer sublw .10 btfss STATUS,C goto flipmode movfw mode sublw .0 btfss STATUS,Z goto bumpadj call bumpchan goto update bumpadj call bumpfreq goto update flipmode ; 0 channel change ; 1 Adj 40MHz increment ; 2 Adj 1MHz increment ; 3 Adj 25kHz increment movfw mode sublw .3 ; leaving fine mode btfsc STATUS,Z call burnfreq ; program freq incf mode movfw mode sublw .4 btfsc STATUS,Z clrf mode ; wrap to channel mode update call setpll call report1 call report2 goto mainloop hint25kHz movlw A'(' call writew movlw A'2' call writew movlw A'5' call writew movlw A'k' call writew movlw A'H' call writew movlw A'z' call writew movlw A')' call writew return hint1MHz movlw A'(' call writew movlw A'1' call writew movlw A'M' call writew movlw A'H' call writew movlw A'z' call writew movlw A')' call writew return hint40MHz movlw A'(' call writew movlw A'4' call writew movlw A'0' call writew movlw A'M' call writew movlw A'H' call writew movlw A'z' call writew movlw A')' call writew return report1 call LCDLine_1 ;display A/D result on 1st line movfw mode sublw .0 btfss STATUS,Z goto reportadj ; go and display modes other than 0 movlw A'C' call writew movlw A'h' call writew movlw A'a' call writew movlw A'n' call writew goto showchan reportadj movlw A'A' call writew movlw A'd' call writew movlw A'j' call writew call showchan call writesp movfw mode sublw .1 btfsc STATUS,Z call hint40MHz movfw mode sublw .2 btfsc STATUS,Z call hint1MHz movfw mode sublw .3 btfsc STATUS,Z call hint25kHz return ; bump frequency bumpfreq movfw keyAction1 sublw .2 btfsc STATUS,Z goto incfreq movfw keyAction1 sublw .1 btfsc STATUS,Z goto decfreq ; clr freq clrf chan_msb clrf chan_lsb goto rangefreq decfreq ; invert - treat as add - then invert comf chan_lsb comf chan_msb call dobump comf chan_lsb comf chan_msb goto rangefreq incfreq call dobump goto rangefreq rangefreq return ; 1 Adj 40MHz * 1600 ; 2 Adj 1MHz * 40 ; 3 Adj 25kHz native dobump movfw mode sublw .3 btfss STATUS,Z goto dobump1 movlw 1 movwf addlsb movlw 0 movwf addmsb dobump1 movfw mode sublw .2 btfss STATUS,Z goto dobump2 movlw 0x28 movwf addlsb movlw 0 movwf addmsb dobump2 movfw mode sublw .1 btfss STATUS,Z goto dobump3 movlw 0x40 movwf addlsb movlw 0x06 movwf addmsb dobump3 movfw addlsb ; Get low byte addwf chan_lsb,f ; Add to destination movfw addmsb ; Get high byte btfsc STATUS,C ; Check for carry incf chan_msb ; Add one for carry addwf chan_msb,f ; Add high byte into DST return ; bump channel bumpchan movfw keyAction1 sublw .2 btfsc STATUS,Z goto incchan movfw keyAction1 sublw .1 btfsc STATUS,Z goto decchan ; clr channel clrf channel goto range decchan decf channel goto range incchan incf channel goto range ;------------------ 50ms Delay -------------------------------- delay_50ms banksel temp_1 movlw 0xFF movwf temp_1 movlw 0x41 movwf temp_2 decfsz temp_1,f goto $-1 decfsz temp_2,f goto $-3 return ;------------------ 100ms Delay -------------------------------- delay_100ms banksel temp_1 movlw 0xFF movwf temp_1 movlw 0x83 movwf temp_2 decfsz temp_1,f goto $-1 decfsz temp_2,f goto $-3 return ;---------------- 1s Delay ----------------------------------- delay_1s banksel temp_1 movlw 0xFF movwf temp_1 movwf temp_2 movlw 0x05 movwf temp_3 decfsz temp_1,f goto $-1 decfsz temp_2,f goto $-3 decfsz temp_3,f goto $-5 return ;---------------- Binary (8-bit) to BCD ----------------------- ; 255 = highest possible result bin_bcd banksel MSD clrf MSD clrf MsD movwf LSD ;move value to LSD ghundreth movlw .100 ;subtract 100 from LSD subwf LSD,w btfss STATUS,C ;is value greater then 100 goto gtenth ;NO goto tenths movwf LSD ;YES, move subtraction result into LSD incf MSD,f ;increment hundreths goto ghundreth gtenth movlw .10 ;take care of tenths subwf LSD,w btfss STATUS,C goto over ;finished conversion movwf LSD incf MsD,f ;increment tenths position goto gtenth over ;0 - 9, high nibble = 3 for LCD movf MSD,w ;get BCD values ready for LCD display xorlw 0x30 ;convert to LCD digit movwf MSD movf MsD,w xorlw 0x30 ;convert to LCD digit movwf MsD movf LSD,w xorlw 0x30 ;convert to LCD digit movwf LSD retlw 0 ;---------------- Binary (16-bit) to BCD ----------------------- ; xxx = highest possible result bin16_bcd ; Takes number in NumH:NumL ; Returns decimal in TenK:Thou:Hund:Tens:Ones swapf NumH,w andlw 0x0F addlw 0xF0 movwf Thou addwf Thou,f addlw 0xE2 movwf Hund addlw 0x32 movwf Ones movf NumH,w andlw 0x0F addwf Hund,f addwf Hund,f addwf Ones,f addlw 0xE9 movwf Tens addwf Tens,f addwf Tens,f swapf NumL,w andlw 0x0F addwf Tens,f addwf Ones,f rlf Tens,f rlf Ones,f comf Ones,f rlf Ones,f movf NumL,w andlw 0x0F addwf Ones,f rlf Thou,f movlw 0x07 movwf TenK movlw 0x0A ; Ten Lb1: addwf Ones,f decf Tens,f btfss 3,0 goto Lb1 Lb2: addwf Tens,f decf Hund,f btfss 3,0 goto Lb2 Lb3: addwf Hund,f decf Thou,f btfss 3,0 goto Lb3 Lb4: addwf Thou,f decf TenK,f btfss 3,0 goto Lb4 retlw 0 debounce ; wait for both keys up call getkey ; get command code in W. (zero - no key down) iorlw 0x00 ; Test for any key down. Z set if none btfss STATUS,Z ; same! goto debounce ; key down call delay_50ms debounce1 call getkey ; get command code in W. (zero - no key down) iorlw 0x00 ; Test for any key down. Z set if none btfss STATUS,Z ; same! goto debounce1 ; key down return; getkey movlw 0x00 btfss select iorlw 0x01 ; btfss scroll iorlw 0x02 ; return showchan clrf NumH movfw channel movwf NumL call bin16_bcd ;get ready for LCD call writesp movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# goto writew report2 call LCDLine_2 ;display on 2nd line call showfreq movlw A'M' ;send decimal point "." call writew movlw A'H' ;send decimal point "." call writew movlw A'z' ;send decimal point "." goto writew showfreq call showfreqr ; calculate real part for display goto showfreqf ; then fractional part showfreqr clrf PCLATH movfw chan_msb bcf PCLATH,4 ;page 1 bsf PCLATH,3 movwf AARGB0 clrf PCLATH movfw chan_lsb bcf PCLATH,4 ;page 1 bsf PCLATH,3 movwf AARGB1 movlw 0x28 ;divide by 40 movwf BARGB0 call UDIV1608L bcf PCLATH,4 ;page 1 bsf PCLATH,3 movf AARGB0,w ;prepare for 16-bit binary to BCD clrf PCLATH movwf NumH bcf PCLATH,4 ;page 1 bsf PCLATH,3 movf AARGB1,w clrf PCLATH movwf NumL call bin16_bcd ;get ready for LCD movf Thou,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Hund,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# call writew return showfreqf movfw chan_lsb movwf mulpL movfw chan_msb movwf mulpH call Multiply ; mod 40 then * 25 movfw prodH ;prepare for 16-bit binary to BCD movwf NumH movfw prodL movwf NumL call bin16_bcd ;get ready for LCD movlw A'.' ;send decimal point "." call writew movf Hund,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# goto writew Multiply ; ; we need only look at the modulus of the result. Getting into 24 bit maths - forget it. ; ; we are displaying fractional digits from .000, .025 ... , 0.975 ; there is (mod) 40 of them - so don't get caried away when 0xfffe, 0xffff, 0x0000 wrapping occurs ; CLRF prodH ; Clear product to make CLRF prodL ; way for new calculation. m0 movfw mulpH ; if more than 40, take off 40 sublw 0x00 btfsc STATUS,C goto mi movlw 0xd8 ; Get low byte -40 ffd8 addwf mulpL,f ; Add to destination movlw 0xff ; Get high byte btfsc STATUS,C ; Check for carry incf mulpH ; Add one for carry addwf mulpH,f ; Add high byte into DST goto m0 mi MOVLW 0x19 ; * 25 MOVWF index Multiply_loop BCF STATUS,C movfw mulpL addwf prodL, f BTFSC STATUS,C incf prodH movfw mulpH addwf prodH, f DECFSZ index GOTO Multiply_loop return; showchanc ; shows as channel number TESTING clrf NumH movfw channel movwf NumL call bin16_bcd ;get ready for LCD call writesp movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# call writew movfw chan_msb movwf NumH movfw chan_lsb movwf NumL call bin16_bcd ;get ready for LCD call writesp movf TenK,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Thou,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Hund,w ; call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Tens,w ;get tens call bin_bcd movf LSD,w ;send low digit x.#x call writew movf Ones,w ;get ones call bin_bcd movf LSD,w ;send low digit x.x# call writew return writew movwf temp_wr goto d_write writesp movlw A' ' goto writew cls call LCDLine_1 call clrrow call LCDLine_2 clrrow call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; call writesp; goto writesp; range movfw channel andlw 0xf movwf channel ; remember default channel number BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movfw channel BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_DATA movlw EE_DEF_CHAN movwf DATA_EE_ADDR call writeee ; get the channel data BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movfw channel goto getChanFreq readee BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 MOVFW DATA_EE_ADDR ; Data Memory MOVWF EEADR ; Address to read BSF STATUS,RP0 ; Bank 3 BCF EECON1,EEPGD ; Point to Data memory BSF EECON1,RD ; EE Read BCF STATUS,RP0 ; Bank 2 MOVFW EEDATA ; W = EEDATA return writeee BSF STATUS,RP1 ; BSF STATUS,RP0 BTFSC EECON1,WR ;Wait for write GOTO $-1 ;to complete BCF STATUS, RP0 ;Bank 2 MOVF DATA_EE_ADDR,W ;Data Memory MOVWF EEADR ;Address to write MOVF DATA_EE_DATA,W ;Data Memory Value MOVWF EEDATA ;to write BSF STATUS,RP0 ;Bank 3 BCF EECON1,EEPGD ;Point to DATA memory BSF EECON1,WREN ;Enable writes BCF INTCON,GIE ;Disable INTs. MOVLW 0x55 ; MOVWF EECON2 ;Write 55h MOVLW 0xAA ; MOVWF EECON2 ;Write AAh BSF EECON1,WR ;Set WR bit to begin write BSF INTCON,GIE ;Enable INTs. BCF EECON1,WREN ;Disable writes return getChanFreq ; 2 bytes allocated per channel addlw 0x01 ; step over default channel movwf temp_4 rlf temp_4 call delay_100ms movfw temp_4 BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_ADDR call readee BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movwf chan_msb call delay_100ms movfw temp_4 addlw 0x01 BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_ADDR call readee BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movwf chan_lsb return; burnfreq call LCDLine_2 ;display A/D result on 2nd line movlw A'B' ;send decimal point "." call writew movlw A'u' ;send decimal point "." call writew movlw A'r' ;send decimal point "." call writew movlw A'n' ;send decimal point "." call writew call delay_1s BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movfw channel addlw 0x01 ; step over default channel movwf temp_4 rlf temp_4 movfw temp_4 BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_ADDR BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movfw chan_msb BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_DATA call writeee BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 call delay_100ms movfw temp_4 addlw 0x01 BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_ADDR BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 movfw chan_lsb BSF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 2 movwf DATA_EE_DATA call writeee BCF STATUS,RP1 ; BCF STATUS,RP0 ; Bank 0 return ;--------------------------------------------------------------------------- setpll movfw chan_msb movwf pll_msb movfw chan_lsb movwf pll_lsb call sendIFR call sendRFR call sendIFN call sendRFN banksel ptr_pos return sendIFR call dropLE movlw .9 ; IFR 20 = 0; 19 = 1; 18 = 0; 17 = 0; 16 = 0 movwf pll_serLsb movlw .5 ; movwf pll_count call serialise movlw 0x50 ; B counter R = 336 (150) movwf pll_serLsb movlw 0x01 ; B counter movwf pll_serMsb movlw .15 ; 15 bits movwf pll_count call serialise call send0 call send0 goto raiseLE sendRFR call dropLE movlw 0x03 ; was b 01011 now 3 00011 20 = 0; 19 = 0; 18 = 0; 17 = 1; 16 = 1 movwf pll_serLsb movlw .5 ; movwf pll_count call serialise movlw .48 ; B counter movwf pll_serLsb movlw .0 ; B counter movwf pll_serMsb movlw .15 ; 15 bits movwf pll_count call serialise call send1 call send0 goto raiseLE sendIFN call dropLE movlw .1 ; IFN 20 = 0; IFN 19 = 1 movwf pll_serLsb movlw .2 ; movwf pll_count call serialise movfw pll_msb movwf pll_serMsb movfw pll_lsb movwf pll_serLsb ; divide 16 for B rrf pll_serMsb rrf pll_serLsb rrf pll_serMsb rrf pll_serLsb rrf pll_serMsb rrf pll_serLsb rrf pll_serMsb rrf pll_serLsb movlw .11 ; 11 bits (B) movwf pll_count call serialise movfw pll_lsb andlw 0x0f movwf pll_serLsb movlw .7 ; 7 bits (A) movwf pll_count call serialise call send0 call send1 goto raiseLE sendRFN call dropLE movlw 0x03 ; RFN 20 = 1; RFN 19 = 1 (power down) movwf pll_serLsb movlw .2 ; movwf pll_count call serialise movlw .0 movwf pll_serMsb movlw 0x21 ; arbitary value movwf pll_serLsb movlw .11 ; 11 bits movwf pll_count call serialise movlw .0 ; A counter movwf pll_serLsb movlw .7 ; 7 bits movwf pll_count call serialise call send1 call send1 goto raiseLE dropLE bcf PLL_LE bcf PLL_CK bcf PLL_DT return; raiseLE bsf PLL_LE return; send0 bcf PLL_DT ; present data (0) bsf PLL_CK ; Flip clock bcf PLL_CK ; .. return; send1 bsf PLL_DT ; present data (0) bsf PLL_CK ; Flip clock bcf PLL_CK ; .. return; serialise ; ; The data is sent to the PLL with the MSB sent first. ; Enter with data in pll_serLsb and pll_serMsb. Set the number of bits to send in pll_count. ; ; first shuffle the fake 16bit data register. Move the required bits to the MSB ; ; MOVFW pll_count ; 16 sublw 0x10 MOVWF pll_temp shuffle_Loop rlf pll_serLsb rlf pll_serMsb DECFSZ pll_temp GOTO shuffle_Loop ; Data now at MSB - now we're ready to send data! MOVFW pll_count MOVWF pll_temp shuffle_Loop1 rlf pll_serLsb rlf pll_serMsb btfss STATUS, C goto senddata0 call send1 ser1 DECFSZ pll_temp GOTO shuffle_Loop1 return; senddata0 call send0 goto ser1 ;--------------------------------------------------------------------------- end