;	program to load Silicon Labs synthesizer
;	SI4133-GT from Microchip 
;	PIC 16F688
;	Beacon Keyer for 1296.500000
; 
;     ---------------------------------------------------------------			
; 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 
;
P=16F688
		include P16F688.inc
		errorlevel  -302        ; suppress message 302 from list file
	    				; RC internal clock
	         __config 0x30E4   	; watchdog timer off 
				    	; power-up timer on
	                            	; code protect   off
	                            	; BOD enabled in run
	                            	; MCLR EXTERNAL
	         radix    hex 
;			 
; 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 16F688 
;
;************************************************************************************
	cblock 0x20
reg_H			; High bits of register
reg_M			; Mid bits of register
reg_L			; Low bits of register
regC  			; delay register
regD  			; delay register
regE  			; delay register
w_temp			;store a copy of W register while int
status_temp		;store a copy of Status Reg while int
;
	endc			;

;************************************************************************
;
	ORG     0x00          	; startup address = 0000
	goto	start	
;
;---------------------------
;
;			store W and STATUS
;
	ORG     0x04       	; interrupt vector location
;
	MOVWF 	w_temp 		;copy W to temp register,
				;could be in either bank
	SWAPF 	STATUS,W	;swap status to be saved into W
	BCF	STATUS,RP0 	;change to bank 0 regardless of
				;current bank
	MOVWF	status_temp 	;save status to bank 0 register
;
	GOTO	PER_INT
;
;---------------------------
;
;			PORTC INIT
;
start	
	CLRF 	STATUS 		; Bank0
	CLRF 	PORTC 		; Initialize PORTC by clearing output data latches
;
	BSF 	STATUS, RP0 	; Bank1
	CLRF	ANSEL		;   clear the analog register pins for digital i/o
	BCF	PCON,ULPWUE 	;   DISable ULP Wake-up
	MOVLW 	0x20		;   Value used to initialize data direction
	MOVWF 	TRISC 		;   ALL outputs except RC5 is input
	CLRF 	STATUS 		; Bank0
	BSF	PORTC, 3	;   HOLD SEN ENABLE HIGH UNTIL WRITING
;
;			PORTA INIT
;
	BANKSEL	PORTA 		;
	CLRF	PORTA		;Init PORTA
	MOVLW	07h 		;Set RA<2:0> to
	MOVWF	CMCON0 		;digital I/O
	BANKSEL ANSEL 		;
	CLRF	ANSEL		;digital I/O
	MOVLW 	0x3F 		;   5:0 INPUTS
	MOVWF 	TRISA 		;   make all inputs See notes
	BCF	PCON,ULPWUE 	;   DISable ULP Wake-up
	CLRF	CMCON1		;   clear the register
	CLRF	PIR1		;   DISABLE int flags in the PIR REGISTER
	BSF 	STATUS, RP0 	; Bank1
	CLRF	PCON		;   deny that any resets occurred
	CLRF	PIE1		;   disable tmr1 - other stuff we don't need
	MOVLW	0x03		;   IOCA register (is in bank1)
	MOVWF 	IOCA		;   set interrupt-on-change RA2 (NOT)
	BSF	OPTION_REG, 7	;   RA pull ups enable
	BSF	OPTION_REG, 6	;   set interrupt on RISING edge   (INTEDG)
	MOVLW	0x03		;   weak p/u RA0 and RA1
	MOVWF	WPUA		;   do it (enabled = 1)
	CLRF 	STATUS		; Bank0
	CLRF	INTCON		;  Disable interrupts and clear some flags
;
;		Set the interrupts
	BCF	INTCON, 3	; RAIE disable RA int enable 
	BCF	INTCON, 0	; RAIF - Clear Flag Bit Just In Case
	BCF	INTCON, 4	; INTE - external Interrupt Enable (1=enable) enable this after loading registers
	BCF	INTCON, 1	; INTF - Clear Flag Bit Just In Case
	BCF	INTCON, 5	; TIMER OVERFLOW INT ENABLE ( 1 = enable)
	BCF	INTCON, 2	; T0IF  clear TIMER OVERFLOW FLAG
	BCF	INTCON, 6	; disable peripheral interrupts
	
;	
;*************************************************************************
;
; PIC pins are high by pull-up, if high then switch is NOT active
; or there is no switch. simulate with pin stimulus  A0 and  A1
; if only 2 frequencies are used connect pin 12 (clock) for
; the second frequency
;
	CALL	dly100		; wait for 4112 to settle 
;	CALL	pins
	CALL	freq0
	GOTO	FLandINT
;
;pins
;	BTFSS	PORTA, 0	; skip next if RA0 high	
;	GOTO	pa10		; RA0 low
;	GOTO	pa11		; RA0 high
;-------------------------------------------------------------
;pa10	BTFSS	PORTA, 1	; skip next if RA1 high
;	GOTO	freq4		; RA0 low and RA1 low
;	GOTO	freq3		; RA0 low and RA1 high
						; RA0 is pin 13 of chip, pin 4 of ICSP
;pa11	BTFSS	PORTA, 1	; skip next if RA1 high
;	GOTO	freq2		; RA0 high and RA1 low
				; RA1 is pin 12 of chip, pin 5 of ICSP
;	GOTO	freq1		; RA0 high and RA1 high
;
;*************************************************************************
;
FLandINT
	BCF	INTCON, RAIF 	; Clear the RA interrupt flag
	BCF	INTCON, 1	; Clear INT flag before enabling GIE AND INT
	BSF	INTCON, 3	; enable RA int (RAIE)
	BSF	INTCON, 4	; INTE - external Interrupt Enable
	BSF	INTCON, 7	; GIE – Global interrupt enable (1=enable)
				; hold interrupts until all registers load
;	CALL	BLINK5		; debug	
;
;  BEGIN MAIN LOOP
;
mnlp
	BCF	PORTC, 4	; set pin 6 low LED OFF
	SLEEP
	nop
	goto	mnlp
;
;  END MAIN LOOP
;
;*************************************************************************
;
;   INTERRUPT SERVICE ROUTINE
;------------frequency change ------------------
;
PER_INT 
	BTFSS	INTCON, RAIF	; are we changing freq ?
	GOTO	isINTF		; NO, must be lock problem
	CALL	freq0;     ---------------------------------------------------------------
;---------------- - - - Lock LED-------INTERRUPT SEVICE  ROUTINE---------- - - - - - - - - -
; 
isINTF	; an INT ocurred so turn on the light, if I find otherwise
	; then exit the routine and the LED is turned off by the main loop
	; before sleep.
	; this all depends on the status of the lock detect (auxout)
	; while it's high I don't want to clear INTF. So, test RA2
	; to see when it's clear, and keep the LED on 'til then.
	
;
	BTFSS	PORTA, 2	; is LK DET high ? if yes skip next line
	BCF	INTCON, INTF	; clear the INTF interrupt flag
	BTFSC	PORTA, 2	; is LK DET low ? if yes skip next line
	BSF	PORTC, 4	; set pin 6 high LED ON
	BTFSC	PORTA, 2	; is LK DET low ? if yes skip next line
	CALL	dly500		; LED on for 1/2 sec
;
;*************************************************************************
;
RESTREG	
	SWAPF 	status_temp,W	; swap STATUS_TEMP register into
				; W, sets bank to original state
	MOVWF	STATUS 		; move W into STATUS register
	SWAPF	w_temp,F 	; swap W_TEMP with F
	SWAPF	w_temp,W 	; swap W_TEMP into W
	RETFIE 			; Return from interrupt
;
;   END INTERRUPT SERVICE ROUTINES
;
;
; Load the MAIN '4133 RF1 register (0)
; MSB first
freq0
; 1296.5
;
	bcf	PORTC, 0		; turn off RF post amp
;	bsf	PORTC, 0		; turn  on RF post amp
; Load the main register (0)
	nop				; debug 00000
	movlw	0x03			; 
	movwf	reg_H			;
	movlw	0xC0			; 
	movwf	reg_M			;
	movlw	0x00			; 
	movwf	reg_L			;
	call	sendreg			; Send data to REGISTERS
;
; Load the phase det register (1)
; MSB first
;
	movlw	0x00			; 
	movwf	reg_H			;
	movlw	0x00			; 
	movwf	reg_M			;
	movlw	0xC1			; 
	movwf	reg_L			;
	call	sendreg			; Send data to REGISTERS
;
; Load the power down register (2)
; MSB first
;
	movlw	0x00			; 
	movwf	reg_H			;
	movlw	0x00			; 
	movwf	reg_M			;
	movlw	0x12			; PDIB
	movwf	reg_L			;
	call	sendreg			; Send data to REGISTERS
;
; Load the RF1 N register (3)2593d = A21h
;
	movlw	0x00			; 
	movwf	reg_H			;
	movlw	0xA2			; 
	movwf	reg_M			;
	movlw	0x13			; 
	movwf	reg_L			;
	call	sendreg			; Send data to REGISTERS
;
; REG 4 RF2 N divider
; REG 5 IF  N divider
;
; Load the RF1 R register (6) 20d = 14h
; MSB first
;
	movlw	0x00			; 
	movwf	reg_H			;
	movlw	0x01			; 
	movwf	reg_M			;
	movlw	0x46			; 
	movwf	reg_L			;
	call	sendreg			; Send data to REGISTERS
;
; REG 7 RF2 R divider
; REG 8 IF  R divider
;
;
	RETURN				;
;
;
; Load data  to a 4133 synth register
;
sendreg
	bcf   PORTC, 3			; sen low to enable writing to reg
	nop
	btfss reg_H,5			; Bit 22
	call		zero		; 0
	btfsc	reg_H,5			;
	call		one		; 1
	btfss	reg_H,4			; Bit 21
	call		zero		; 0
	btfsc	reg_H,4			;
	call		one		; 1
	btfss	reg_H,3			;	Bit 20
	call		zero		; 0
	btfsc	reg_H,3			;
	call		one		; 1
	btfss	reg_H,2			; Bit 19
	call		zero		; 0
	btfsc	reg_H,2			;
	call		one		; 1
	btfss	reg_H,1			; Bit 18
	call		zero		; 0
	btfsc	reg_H,1			;
	call		one		; 1
	btfss	reg_H,0			; Bit 17
	call		zero		; 0
	btfsc	reg_H,0			;
	call		one		; 1
	btfss	reg_M,7			; Bit 16
	call		zero		; 0
	btfsc	reg_M,7			;
	call		one		; 1
	btfss	reg_M,6			; Bit 15
	call		zero		; 0
	btfsc	reg_M,6			;
	call		one		; 1
	btfss	reg_M,5			; Bit 14
	call		zero		; 0
	btfsc	reg_M,5			;
	call		one		; 1
	btfss	reg_M,4			; Bit 13
	call		zero		; 0
	btfsc	reg_M,4			;
	call		one		; 1
	btfss	reg_M,3			; Bit 12
	call		zero		; 0
	btfsc	reg_M,3			;
	call		one		; 1
	btfss	reg_M,2			; Bit 11
	call		zero		; 0
	btfsc	reg_M,2			;
	call		one		; 1
	btfss	reg_M,1			; Bit 10
	call		zero		; 0
	btfsc	reg_M,1			;
	call		one		; 1
	btfss	reg_M,0			; Bit 9
	call		zero		; 0
	btfsc	reg_M,0		;
	call		one		; 1
	btfss	reg_L,7			; Bit 8
	call		zero		; 0
	btfsc	reg_L,7			;
	call		one		; 1
	btfss	reg_L,6			; Bit 7
	call		zero		; 0
	btfsc	reg_L,6			;
	call		one		; 1
	btfss	reg_L,5			; Bit 6
	call		zero		; 0
	btfsc	reg_L,5			;
	call		one		; 1
	btfss	reg_L,4			; Bit 5
	call		zero		; 0
	btfsc	reg_L,4			;
	call		one		; 1
	btfss	reg_L,3			; Bit 4
	call		zero		; 0
	btfsc	reg_L,3			;
	call		one		; 1
	btfss	reg_L,2			; Bit 3
	call		zero		; 0
	btfsc	reg_L,2			;
	call		one		; 1
	btfss	reg_L,1			; Bit 2
	call		zero		; 0
	btfsc	reg_L,1			;
	call		one		; 1
	btfss	reg_L,0			; Bit 1
	call		zero		; 0
	btfsc	reg_L,0			;
	call		one		; 1
;
	bsf   PORTC, 3			; make sen high to enter DATA AND CLOSE REG
	nop
	nop
	nop
	nop
	nop
	RETURN
;
; Subroutines to send 0 and 1
; sen is low while writing
; data clocked in on rising edge
; sen pin RC3 (pin 8), portc, 3
; clock on portc, 2
; data on portc, 1
;									
zero
	bcf	PORTC, 1		; RC1 data LOW
	bsf	PORTC, 2		; set clock RC2 HIGH
	nop
	nop
	nop
	bcf	PORTC, 2		; set clock low
					; all port C outputs are now low
					; sen was low and is still low
	RETURN
;
one 
	bsf	PORTC, 1		; RC1 data high
	bsf	PORTC, 2		; set clock bit RC2 HIGH
	nop
	nop
	nop
	bcf	PORTC, 2		; set clock RC2 LOW
	bcf	PORTC, 1		; all port C outputs are now low
					; sen was low and is still low
	RETURN
;
;*************************************
bcnmsg
;
from
	call	dash		; D
	call	dot
	call	dot
	call	dly200		; char spacing
	call	dot		; E
	call	dly600		; word spacing
callsign
	call	dash		; letter K
	call	dot 
	call	dash
	call	dly200		; character spacing
	call	dash		; number D
	call	dot
	call	dot
	call	dly200		; character spacing
	call	dash		; number 7
	call	dash
	call	dot
	call	dot
	call	dot
	call	dly200		; character spacing
	call	dash		; letter T
	call	dly200		; character spacing
	call	dot		; letter S
	call	dot
	call	dot
	call	dly200		; character spacing
	call	dash		; /
	call	dot
	call	dot
	call	dash
	call	dot
	call	dly200
	call	dash		; B
	call	dot
	call	dot
	call	dot
	call	dly600		; word spacing
	call	dly600		; word spacing
grid
	call	dash		; letter C
	call	dot
	call	dash
	call	dot
	call	dly200		; character spacing
	call	dash		; letter N
	call	dot
	call	dly200		; character spacing
	call	dash		; number 8
	call	dash
	call	dash
	call	dot
	call	dot
	call	dly200		; character spacing
	call	dash		; number 7
	call	dash
	call	dot
	call	dot
	call	dot
	call	dly200		; character spacing
	call	dot		; letter U
	call	dot
	call	dash
	call	dly200		; character spacing
	call	dot		; letter J
	call	dash
	call	dash
	call	dash
	call	dly600		; word spacing
	call	dly600		; word spacing
	call	key30		; 30 second keydown
	call	dly600
	call	dly600		; word spacing
	RETURN
;
;************** PIN 7 **************************
; DOT LENGTH SUBROUTINE was PORTC, 4
; 
dot
	bsf	PORTC, 0	; output the key down data bits
	call	dly100		; key down for 100 msec
	bcf	PORTC, 0	; output the key up data bits
	call	dly100		; key up for 100 msec
	RETURN			; 
;
; Dash length subroutine
;
dash	
	bsf	PORTC, 0	; output the key down data bits
	call	dly300		; key down for 300 msec
	bcf	PORTC, 0	; output the key up data bits
	call	dly100		; key up for 100 msec
	RETURN			; 
;
; Keydown subroutine
;
key10
	bsf	PORTC, 0	; output the key down data bits
	call	dly10sec	; key down for 10 seconds
	bcf	PORTC, 0	; output the key up data bits
	call	dly600		; key up for 600 msec
	call	dly100		; key up for 100 msec
	RETURN			; 
;
key30
	bsf	PORTC, 0	; output the key down data bits
	call	dly10sec	; key down for 30 seconds
	call	dly10sec	;
	call	dly10sec	;
	bcf	PORTC, 0	; output the key up data bits
	call	dly600		; key up for 600 msec
	call	dly100		; key up for 100 msec
	RETURN
;
;**************************************************
dly10sec
	clrf	regC
	movlw   0x63		; 63h = 99 decimal
	movwf   regE
wait9
	movlw   0x82		; 82h = 130 decimal
	movwf   regD
wait8
	decfsz  regC, F	 	; 3 clock cycles x 256 = 768 uS
	goto	wait8
	decfsz  regD, F	 	; 768 x 180 = 139008 * .789 = 109.677312 mS
	goto	wait8
	decfsz  regE, F		; 109.677312 x 99 = 10858.053888 mS
	goto	wait9
dly700
	movlw   0x82		; 0x82 = 130 decimal-- change here
	movwf   regD
wait7
	decfsz  regC, F	
	goto	wait7		; each 100 increment in this subroutine
	decfsz  regD, F		; is dependent on the length of the clock	
	goto	wait7		; period
dly600
	movlw   0x82		; 0x82 = 130  decimal-- change here		
	movwf   regD		; Use of an external RC with 220 pF and 6K8 
wait6
	decfsz  regC, F		; resistor gives approx 2 uS clock period. 
	goto	wait6		; For a 4 MHz (the default) of the internal
	decfsz  regD, F		; calibrated oscillator, 016h should be changed 
	goto	wait6		; to 82h in seven places.
dly500
	movlw   0x82		; 0x82 = 130  decimal-- change here 
	movwf   regD		
wait5
	decfsz  regC, F		; = 3F84 @ 2007h	
	goto	wait5		; FOSC2:FOSC0 = 100 for 4 MHZ internal osc.
	decfsz  regD, F	
	goto	wait5
dly400
	movlw   0x82		; 0x82 = 130  decimal-- change here			
	movwf   regD
wait4
	decfsz  regC, F	
	goto	wait4
	decfsz  regD, F	
	goto	wait4
dly300
	movlw   0x82		; 0x82 = 130  decimal-- change here	
	movwf   regD
wait3   decfsz  regC, F	
	goto	wait3
	decfsz  regD, F	
	goto	wait3
dly200
	movlw   0x82		; 0x82 = 130  decimal-- change here	
	movwf   regD
wait2
	decfsz  regC, F	
	goto	wait2
	decfsz  regD, F	
	goto	wait2
dly100
	movlw   0x82		; 0x82 = 130  decimal-- change here	
	movwf   regD
wait1
	decfsz  regC, F	
	goto	wait1
	decfsz  regD, F	
	goto	wait1
;	
	RETURN
;*****************************************
	end
