;===============================================================================
;
;   u_PLL 1.1.16F84
;   Ing. Mario Kienspergher
;   OE9MKV
;
;-------------------------------------------------------------------------------
; 
;   Original Header follows:
;
;       ;***************************************
;       ;***    U6223B u_pll - micro PLL     ***
;       ;***   Assembler AS (public domain)  ***
;       ;***************************************
;
;       		CPU	16C54
;       
;       ident	macro	
;		DATA	"u_PLL 1.1 08.03.96 DF1OG"
;       	endm
;
;===============================================================================

		TITLE	"PLL 1.1.16F84"
		LIST	P=16F84A

;=======================================
;constant and storage definitions
;=======================================

kc100_10l	EQU	0AH		;100 kc binary conversion
kc100_10h	EQU	00H
kc100_100l	EQU	64H
kc100_100h	EQU	00H
kc100_1000l	EQU	0E8H
kc100_1000h	EQU	03H
kc100_10000l	EQU	10H
kc100_10000h	EQU	27H

kc125_10l	EQU	08H		;125 kc binary conversion
kc125_10h	EQU	00H
kc125_100l	EQU	50H
kc125_100h	EQU	00H
kc125_1000l	EQU	20H
kc125_1000h	EQU	03H
kc125_10000l	EQU	40H
kc125_10000h	EQU	1FH

AdrByte		EQU	0C2H		;pll address byte: device address open
CtrlByte1	EQU	0C6H		;control byte 1: hi current, scale 512
CtrlByte2	EQU	00H		;control byte 2: hi impedance outputs

;=======================================
;Registers:
;=======================================

Indirect	EQU	00H		;virtual indirect register
RTCC		EQU	01H		;realtime clock/counter
PClo		EQU	02H		;program counter low
Status		EQU	03H		;status register
FSR		EQU	04H		;file select register
Port_A		EQU	05H		;port A
Port_B		EQU	06H		;port B

;---------------------------------------
;Register flags / bits
;---------------------------------------

RP0		EQU	05H		; Bank Select Bit 0
RP1		EQU	06H		; Bank Select Bit 1

;---------------------------------------
;general purpose registers:
;---------------------------------------

R0		EQU	10H		;general purpose register 0
R1		EQU	11H		;general purpose register 1
R2		EQU	12H		;general purpose register 2

Kc100		EQU	13H		;frequency bcd values 100/125 kc
Mc1		EQU	14H		;		 	    1 mc
Mc10		EQU	15H		;			   10 mc
Mc100		EQU	16H		;			  100 mc
Mc1000		EQU	17H		;			 1000 mc

Control		EQU	18H		;bit 2 off 100 kc steps
					;       on 125 kc steps

SwChange	EQU	19H		;switch change check
					
DevAdr		EQU	1AH		;device address
PDB1		EQU	1BH		;program divider byte 1
PDB2		EQU	1CH		;program divider byte 2
CB1		EQU	1DH		;control byte 1
CB2		EQU	1EH		;control byte 2

;---------------------------------------
;allocation status register flags:
;---------------------------------------

Flag_C		EQU	00H		;carry flag
Flag_DC		EQU	01H		;digit carry flag
Flag_Z		EQU	02H		;zero flag

;---------------------------------------
;destination register:
;---------------------------------------

w		EQU	00H		;destination w register
f		EQU	01H		;destination f register

;===============================================================================
;Code follows
;===============================================================================

		ORG	000H
Start:		goto	Init		;subroutines in first 256 code bytes

		ORG	004H		;forget about ISR
		RETURN

		ORG	008H		;subroutines within first 256 bytes

;---------------------------------------
;scan switches
;---------------------------------------

ScanSw:		movlw	Kc100		;set pointer to freq. registers
		movwf	FSR
		
		movlw	05H		;five switches to scan
		movwf	R0

		movlw	b'11111110'	;start with low significant switch
		movwf	R1

ScanSw10:	movf	R1,w		;put scan information onto port

		movwf	Port_B
		tris	Port_B

		movf	Port_B,w	;read scan information bits 0-2
		andlw	b'11100000'
		movwf	Indirect
		swapf	Indirect,f
		bcf	Status,Flag_C
		rrf	Indirect,f

		movf	Port_A,w	;read scan information bit 3
		movwf	R2
		rlf	R2,w
		andlw	b'00001000'

		iorwf	Indirect,f	;combine bits to negative logic
		movlw	b'00001111'
		xorwf	Indirect,f

		bsf	Status,Flag_C	;prepare next scan
		rlf	R1,f

		incf	FSR,f

		decfsz	R0,f
		goto	ScanSw10	;all switches scaned?
		
ScanSw99:	retlw	0

;---------------------------------------
;set pll data using i2c protocol
;---------------------------------------

SetPLL:		movlw	DevAdr		;set pointer to pll data
		movwf	FSR
		movlw	05H		;5 bytes have to be transfered
		movwf	R0

		movlw	b'11111101'	;start condition
		tris	Port_A
		nop
		nop
		nop
		movlw	b'11111100'
		tris	Port_A

SetPLL10:	movlw	08H		;set bit counter
		movwf	R1

SetPLL20:	rlf	Indirect,f	;carry flag stores the bit

		btfsc	Status,Flag_C
		goto	SetPLL30

		movlw	b'11111100'	;set data low
		tris	Port_A
		call	ClkOut			
		goto	SetPLL40

SetPLL30:	movlw	b'11111110'	;set data high
		tris	Port_A
		call	ClkOut		

SetPLL40:	decfsz	R1,f
		goto	SetPLL20	;one byte transfered?

		movlw	b'11111110'	;handle acknowledge
		tris	Port_A
		call	ClkOut			

		rlf	Indirect,f	;now all has left correctly again
        	incf	FSR,f		;set pointer to next byte  
	
		decfsz	R0,f
		goto	SetPLL10	;all bytes transfered?

		movlw	b'11111100'	;stop condition
		tris	Port_A
		movlw	b'11111101'
		tris	Port_A
		nop
		nop
		nop
		movlw	b'11111111'
		tris	Port_A

SetPLL99:	retlw	0			

;---------------------------------------

ClkOut:		iorlw	b'00000001'	;set clock high
		tris	Port_A
		nop
		nop
		nop
		andlw	b'11111110'	;set clock low
		tris	Port_A

		retlw	0

;---------------------------------------

SwChk:		movlw	-10		;check for greater than nine
		addwf	Indirect,w

		btfss	Status,Flag_C
		goto	SwChk99
		
		movlw	9		;if greater set to nine
		movwf	Indirect

SwChk99:	retlw	0

;---------------------------------------

AddPDB:		movf	R0,w		;do while not zero...

		btfsc	Status,Flag_Z
		goto	AddPDB99

		movf	R2,w		;add LSBs
		addwf	PDB2,f

		btfsc	Status,Flag_C
		incf	PDB1,f		;add carry to MSB

		movf	R1,w		;add MSBs
		addwf	PDB1,f

		decf	R0,f		;decrement loop count		
		goto	AddPDB		;loop...

AddPDB99:	retlw	0

;---------------------------------------

	       	DATA	" * * *   u _ P L L   1 . 1   0 8 . 0 3 . 9 6   D F 1 O G   * * *  "
		DATA	" 1 . 1 . 1 6 F 8 4   1 5 . 0 7 . 0 2   O E 9 M K V   * * *"

;=======================================
;start of main program...
;=======================================

		ORG	100H

Init:		bcf	Status,RP0	; select register bank 0
		bcf	Status,RP1	; only for upward compability

		movlw	b'11111100'	;prepare SDA and SCL ports
		movwf	Port_A

		clrf	Kc100		;clear freq. registers		
		clrf	Mc1
		clrf	Mc10
		clrf	Mc100
		clrf	Mc1000
		clrf	Control
		clrf	SwChange	;initiate freq. setting
		decf	SwChange,f

;---------------------------------------
;main program loop
;---------------------------------------
Main:		call	ScanSw		;scan switches

;---------------------------------------
		movlw	Mc1000		;mask out 1000 mc
		movwf	FSR
		movf	Indirect,w
		movwf	Control
		andlw	b'00000011'	;bit 0-1 frequency
		movwf	Indirect
		movlw	b'00000100'	;bit 2 control
		andwf	Control,f
		
		decf	FSR,f		;check for valid BCD
		call	SwChk		;100 mc

		decf	FSR,f
		call	SwChk		;10 mc

		decf	FSR,f
		call	SwChk		;1 mc
					
		decf	FSR,f		;Kc100 mustn't exceed 9 at 100 kc

		btfsc	Control,2	;and mustn't exceed 7 at 125 kc steps
		goto	Main10

		call	SwChk		;100 kc steps
		goto	Main20

Main10:		movlw	-8		;125 kc steps
		addwf	Indirect,w

		btfss	Status,Flag_C
		goto	Main20
		
		movlw	7		;if greater than seven set to seven
		movwf	Indirect

;---------------------------------------
Main20:		movlw	Kc100		;check for switch change
		movwf	FSR

		clrw			;add frequency and control values
		addwf	Indirect,w	;100 kc

		incf	FSR,f
		addwf	Indirect,w	;1 mc

		incf	FSR,f
		addwf	Indirect,w	;10 mc

		incf	FSR,f
		addwf	Indirect,w	;100 mc

		incf	FSR,f
		addwf	Indirect,w	;1000 mc

		incf	FSR,f
		addwf	Indirect,w	;control

		incf	FSR,f
		xorwf	Indirect,f	;compare to old switch change check
		movwf	Indirect	;store new change check

		btfsc	Status,Flag_Z
		goto	Main		;no change, back to main loop...

;---------------------------------------
		clrf	PDB1		;convert 100/125 kc into binary format
			
		movf	Kc100,w		;100/125 kc		
		movwf	PDB2

		btfsc	Control,2	;100/125 kc steps?
		goto	Main30

		movf	Mc1,w		;100 kc steps 1 mc 
		movwf	R0
		movlw	kc100_10h
		movwf	R1
		movlw	kc100_10l
		movwf	R2
		call	AddPDB

		movf	Mc10,w		;10 mc
		movwf	R0
		movlw	kc100_100h
		movwf	R1
		movlw	kc100_100l
		movwf	R2
		call	AddPDB

		movf	Mc100,w		;100 mc
		movwf	R0
		movlw	kc100_1000h
		movwf	R1
		movlw	kc100_1000l
		movwf	R2
		call	AddPDB

		movf	Mc1000,w	;1000 mc
		movwf	R0
		movlw	kc100_10000h
		movwf	R1
		movlw	kc100_10000l
		movwf	R2
		call	AddPDB
	
		goto	Main40

Main30:		movf	Mc1,w		;125 kc steps 1 mc
		movwf	R0
		movlw	kc125_10h
		movwf	R1
		movlw	kc125_10l
		movwf	R2
		call	AddPDB

		movf	Mc10,w		;10 mc
		movwf	R0
		movlw	kc125_100h
		movwf	R1
		movlw	kc125_100l
		movwf	R2
		call	AddPDB

		movf	Mc100,w		;100 mc
		movwf	R0
		movlw	kc125_1000h
		movwf	R1
		movlw	kc125_1000l
		movwf	R2
		call	AddPDB

		movf	Mc1000,w	;1000 mc
		movwf	R0
		movlw	kc125_10000h
		movwf	R1
		movlw	kc125_10000l
		movwf	R2
		call	AddPDB

;---------------------------------------

Main40:		movlw	AdrByte		;load pll parameter
		movwf	DevAdr
		movlw	CtrlByte1	
		movwf	CB1
		movlw	CtrlByte2
		movwf	CB2
		call	SetPLL		;transfer pll data

		goto	Main		;main loop...

;=======================================
		END
;=======================================
