; ******************************************************************************* ; * * ; * Si5351 Software to program 4 frequencies for a Local Oscillator * ; * Copyright T Mowles VK5TM April 2015 * ; * * ; * This code may be used for personal, non-profit use only. * ; * * ; * Commercial use of this code or any derivatives of it is expressly forbidden.* ; * * ; * Use in any profit making enterprise of any kind is also expressly forbidden,* ; * whether or not this software (or any derivatives of it) is provided free * ; * of charge, unless WRITTEN permission is obtained from the copyright owner. * ; * * ; ******************************************************************************* ; * * ; * This program will initialize an Si5351A-B-GT with 1 of 4 preprogammed * ; * frequencies depending on the state of the GP1 & GP2 inputs. * ; * It also allows switching of the frequencies without having to powerdown. * ; * The 12F629 goes to sleep when not actively changing the frequency. * ; * * ; ******************************************************************************* ; ; ******************************************************************************* ; * Device type and options * ; ******************************************************************************* ; processor PIC12F629 ; directive to define processor #include ; processor specific variable definitions ; ; ******************************************************************************* __CONFIG _CP_OFF & _CPD_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT errorlevel -302 ; Turn off annoying Bank messages ; ; ******************************************************************************* ; * * ; * PIC12F629 * ; * _________ * ; * +3.3V------Vdd |1 8| Vss----GND * ; * SCL--------GP5 |2 7| GP0----ICSPDAT * ; * SDA--------GP4 |3 6| GP1----ICSPCLK/Frequency select 1 * ; * MCLR/Vpp/--GP3 |4 5| GP2----Frequency select 2 * ; * _________ * ; * * ; ******************************************************************************* ; ; ******************************************************************************* ; * Assign names to PIC IO pins * ; ******************************************************************************* ; ; GPIO Port Assignment: ; ;FREQ equ 0x02 ; Frequency select input SDA equ 0x04 ; I2C Data SCL equ 0x05 ; I2C Clock ; ; ******************************************************************************* ; * DATA MEMORY * ; ******************************************************************************* CBLOCK 20h count ; Gen purpose counter temp ; Temporary work register bytcnt ; used in i2c driver ebyte ; I2C device data to be sent freq ; holds state of freq select pins ENDC ; ; ******************************************************************************* ; * PROGRAM START * ; ******************************************************************************* ORG 0x00 ;Reset vector address goto Start ORG 0x04 ; Interrupt Vector address goto Start ; ; ******************************************************************************* Start ; clrf INTCON ; Disable interrupts movlw H'07' ; Disable Comparator module movwf CMCON ; Initialise GPIO port for i2c ; First set all as inputs, then clear individual bits as outputs banksel TRISIO ; Switch to register bank 1 movlw b'00001110' ; GPIO,1,2,3 as inputs, 0,4,5 as outputs ; movlw H'FF' ; All inputs movwf TRISIO ; bcf TRISIO,SCL ; SCL set as output ; bcf TRISIO,SDA ; Set SDA as output clrf OPTION_REG ; General enable pullups (bit 7 clear) movlw b'00000110' ; Enable pullups on GPIO,1 & 2 movwf WPU ; call 0x3FF ; retrieve factory calibration value movwf OSCCAL ; Setup interupt on change pins movlw b'00000110' ; Set GPIO,1 & 2 to interupt on change movwf IOC ; banksel GPIO ; Switch to bank 0 bsf INTCON,GPIE ; Enable Port Change Interupt clrf GPIO ; Resting state of i2c bus is SCL low, SDA high bsf GPIO,SDA ; Set SDA high bcf GPIO,SCL ; Set SCL low call wait_10ms ; Wait to be sure Si5351 completes power up ; ; ******************************************************************************* ; Determine state of frequency select pins and store in 'freq' begin movfw GPIO ; Get state of GPIO pins andlw b'00000110' ; Mask to read GPIO 1 & 2 movwf freq ; Move to register bcf STATUS,C ; Clear 'C' ready for rotate rrf freq,f ; Rotate bits into bits 0 & 1 of 'frequency' ; ;******************************************************************************** Sendsiregs call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'3' ; Address Register 3 movwf ebyte call putbyte ; Output byte and get ACK movlw H'FF' ; Register command - disable outputs movwf ebyte call putbyte ; Output byte and get ACK call stop ; Send Stop to Si5351 call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'187' ; Address Register 187 movwf ebyte call putbyte ; Output byte and get ACK clrf ebyte ; Register command - fanout enable call putbyte ; Output byte and get ACK call stop ; Send Stop to Si5351 call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'16' ; Address Register 16 movwf ebyte call putbyte ; Output byte and get ACK movlw d'8' ; Loop count movwf temp movlw H'80' ; Register command - power down output drivers (16 -23) movwf ebyte call putbyte ; Output byte and get ACK decfsz temp,f goto $-4 call stop ; Send Stop to Si5351 ;________________________________________________________________________________ call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'183' ; Address Register 183 movwf ebyte call putbyte ; Output byte and get ACK movlw H'D2' ; Register command - set crystal capacitor 10pF ; movlw H'92' ; Register command - set crystal capacitor 8pF ; movlw H'52' ; Register command - set crystal capacitor 6pF movwf ebyte call putbyte ; Output byte and get ACK call stop ; Send Stop to Si5351 ;________________________________________________________________________________ call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'15' ; Address Register 15 movwf ebyte call putbyte ; Output byte and get ACK clrf ebyte ; Command - PLL Input source call putbyte ; Output byte and get ACK (15) ;________________________________________________________________________________ ; movlw H'4C' ; Register command - 2mA output ; movlw H'4D' ; Register command - 4mA output ; movlw H'4E' ; Register command - 6mA output movlw h'4F' ; Register command - 8mA output movwf ebyte call putbyte ; Output byte and get ACK (16)17 - 23 already 0x80 call stop ; Send Stop to Si5351 ;________________________________________________________________________________ call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'24' ; Address Register 24 movwf ebyte call putbyte ; Output byte and get ACK clrf ebyte ; Register command - CLK 0-3 disable state call putbyte ; Output byte and get ACK (24) clrf ebyte ; Register command - CLK 4-7 disable state call putbyte ; Output byte and get ACK (25) ;________________________________________________________________________________ ; Register 26 movfw freq ; move file to 'W' for test xorlw 3 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1 ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2 ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3 ; = 2 so set to 3rd frequency movfw freq xorlw 0 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4 ; = 3 so set to 4th frequency out1 movlw H'00' ; 54MHZ goto outend1 out2 movlw H'30' ; 53.9985MHz goto outend1 out3 movlw H'30' ; 53.0015MHz goto outend1 out4 movlw H'F4' ; 53.9993MHz outend1 movwf ebyte call putbyte ; Register 27 movfw freq ; move file to 'W' for test xorlw 3 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1a ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2a ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3a ; = 2 so set to 3rd frequency movfw freq xorlw 0 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4a ; = 3 so set to 4th frequency out1a movlw H'19' ; 54MHZ goto outend1a out2a movlw H'D4' ; 53.9985MHz goto outend1a out3a movlw H'D4' ; 53.0015MHz goto outend1a out4a movlw H'24' ; 53.9993MHz outend1a movwf ebyte call putbyte ; _______________________________________________________________________________ clrf ebyte call putbyte ; Output byte and get ACK (28) ;________________________________________________________________________________ movlw H'0A' ; Register command - (54MHZ) movwf ebyte call putbyte ; Output byte and get ACK (29) ; Register 30 movfw freq ; move file to 'W' for test xorlw 3 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1b ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2b ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3b ; = 2 so set to 3rd frequency movfw freq xorlw 0 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4b ; = 3 so set to 4th frequency out1b movlw H'F5' ; 54MHZ goto outend1b out2b movlw H'B8' ; 53.9985MHz goto outend1b out3b movlw H'F5' ; 53.0015MHz goto outend1b out4b movlw H'F5' ; 53.9993MHz outend1b movwf ebyte call putbyte ;________________________________________________________________________________ clrf ebyte call putbyte ; Output byte and get ACK (31) ; Register 32 movfw freq ; move file to 'W' for test xorlw 3 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1c ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2c ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3c ; = 2 so set to 3rd frequency movfw freq xorlw 0 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4c ; = 3 so set to 4th frequency out1c movlw H'00' ; 54MHZ goto outend1c out2c movlw H'14' ; 53.9985MHz goto outend1c out3c movlw H'20' ; 53.0015MHz goto outend1c out4c movlw H'AF' ; 53.9993MHz outend1c movwf ebyte call putbyte ;________________________________________________________________________________ ; Register 33 movfw freq ; move file to 'W' for test xorlw 3 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1d ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2d ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3d ; = 2 so set to 3rd frequency movfw freq xorlw 0 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4d ; = 3 so set to 4th frequency out1d movlw H'13' ; 54MHZ goto outend1d out2d movlw H'20' ; 53.9985MHz goto outend1d out3d movlw H'9C' ; 53.0015MHz goto outend1d out4d movlw H'0C' ; 53.9993MHz outend1d movwf ebyte call putbyte ;________________________________________________________________________________ movlw d'9' movwf temp clrf ebyte call putbyte ; Output byte and get ACK (34 - 42) decfsz temp,f goto $-3 movlw H'01' ; Register command - movwf ebyte call putbyte ; Output byte and get ACK (43) clrf ebyte call putbyte ; Output byte and get ACK (44) movlw H'04' ; Register command - (54MHZ) movwf ebyte call putbyte ; Output byte and get ACK (45) movlw d'47' movwf temp clrf ebyte call putbyte ; Output byte and get ACK (46 - 92 decfsz temp,f goto $-3 call stop ; Send Stop to Si5351 call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'149' ; Address Register 149 movwf ebyte call putbyte ; Output byte and get ACK movlw d'22' ; Loop counter movwf temp clrf ebyte call putbyte ; Output byte and get ACK (149 - 170) decfsz temp,f goto $-3 call stop ; Send Stop to Si5351 call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'177' ; Address Register 177 movwf ebyte call putbyte ; Output byte and get ACK movlw H'AC' ; Register command - soft reset movwf ebyte call putbyte ; Output byte and get ACK call stop ; Send Stop to Si5351 call openw ; Open for Write, signal start, send 0xC0, ask for ACK movlw d'3' ; Address Register 3 movwf ebyte call putbyte ; Output byte and get ACK movlw H'FE' ; Register command - enable CLK0 output movwf ebyte call putbyte ; Output byte and get ACK call stop ; Send Stop to Si5351 ; Put PIC to sleep until a change on any input movf GPIO,w ; clear the change condition (see 12F629 data sheet) bcf INTCON,GPIF ; clear the interrupt flag sleep ; Night,night. Sweet dreams. call wait_10ms ; 10mS delay to account for switch bounce, ; increase as necessary call wait_10ms goto begin ; ; ******************************************************************************* ; Open for write openw call i2cstart movlw H'C0' ; Send Si5351 address movwf ebyte call putbyte ; Output Address byte and get ACK return ; ; ******************************************************************************* ; * I2C ROUTINES * ; ******************************************************************************* ; Start condition; data goes from hi to low with SCL high ; Normal state is: SCL low, data high i2cstart banksel TRISIO bcf TRISIO,SDA ; SDA is output banksel GPIO bsf GPIO,SDA ; Set SDA High bsf GPIO,SCL ; SCL hi nop bcf GPIO,SDA ; SDA low nop bcf GPIO,SCL ; SCL low nop bsf GPIO,SDA ; SDA High on exit return ; ; ******************************************************************************* ; Output a byte in ebyte to Si5351 and then get an ACK putbyte banksel TRISIO bcf TRISIO,SDA ; SDA is output banksel GPIO movlw H'08' ; Counter movwf bytcnt bcf STATUS,C senlp rlf ebyte,f btfss STATUS,C goto zerb bsf GPIO,SDA ; SDA hi goto zerb1 zerb bcf GPIO,SDA ; SDA low zerb1 bsf GPIO,SCL ; SCL hi nop nop bcf GPIO,SCL ; SCL low decfsz bytcnt,f goto senlp bsf GPIO,SDA ; Exit with data high call getack return ; ; ******************************************************************************* ; Read acknowledge signal from Si5351. SDA low with SCL high getack banksel TRISIO bsf TRISIO,SDA ; SDA is Input banksel GPIO bsf GPIO,SCL ; SCL hi nop nop bcf GPIO,SCL ; SCL low return ; With C clear if ack received, set otherwise ; ; ******************************************************************************* ; Stop condition; data goes from low to hi with SCL high ; Normal state is: SCL low, data high stop nop banksel TRISIO bcf TRISIO,SDA ; SDA is output banksel GPIO bcf GPIO,SDA ; SDA low nop nop bsf GPIO,SCL ; SCL hi nop nop bsf GPIO,SDA ; SDA hi nop nop bcf GPIO,SCL ; SCL low return ; ; ******************************************************************************* ; * * ; * Purpose: Wait for a specified number of milliseconds * ; * * ; * Entry point wait_10ms : Wait for 10 msec * ; * Entry point wait_1ms * ; * * ; * Input: None * ; * * ; * Output: None * ; * * ; ******************************************************************************* wait_10ms ; ****** Entry point ****** movlw D'20' ; Set up outer loop counter to 20 movwf count goto outer_loop ; Into the wait loops wait_1ms movlw D'2' ; Set up outer loop counter to 2 movwf count ; ; Wait loops used by other wait routines ; - 1 microsecond per instruction (with a 4 MHz microprocessor clock) ; - 498 instructions per inner loop ; - (temp * 498) instructions (.498 msec) per outer loop ; - Round off to .5 ms per outer loop ; outer_loop movlw H'A4' ; Set up inner loop counter to 165 movwf temp inner_loop decfsz temp,f ; Decrement inner loop counter goto inner_loop ; If inner loop counter not down to zero, ; then go back to inner loop again decfsz count,f ; Yes, Decrement outer loop counter goto outer_loop ; If outer loop counter not down to zero, ; then go back to outer loop again return ; Yes, return to caller ; ******************************************************************************* END ; Move these tests into register setting area!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! movfw freq ; move file to 'W' for test xorlw 0 ; Test if 'freq' = 0 btfsc STATUS,Z ; Jump to next test if not 0 goto out1 ; = 0 so set to 1st frequency movfw freq xorlw 1 ; Test if 'freq' = 1 btfsc STATUS,Z ; Jump to next test if not 1 goto out2 ; = 1 so set to 2nd frequency movfw freq xorlw 2 ; Test if 'freq' = 2 btfsc STATUS,Z ; Jump to next test if not 1 goto out3 ; = 2 so set to 3rd frequency movfw freq xorlw 3 ; Test if 'frequency' = 3 btfsc STATUS,Z ; Jump to next test if not 1 goto out4 ; = 3 so set to 4th frequency out1 movlw goto outend1 out2 movlw goto outend1 out3 movlw goto outend1 out4 movlw outend1 movwf ebyte call putbyte