;*******************************************************************
;
;	Inductance & Capacitance Meter with Software calibration
;
;*******************************************************************
;
; LC002	- THIS ONE WORKS FINE WITH A WELL BEHAVED DISPLAY
;
;	Deleted  CpyBin subroutine and one call to it
;
;	Modified B2_BCD to take its input directly from <AARGB0,1,2>
;
;	Modified "oscillator test" so it copies F3   to <AARGB0,1,2>
;
;	Fixed Get_Lcal so it gets the correct number
;
;	Minor adjustment to MS100 timing to correct frequency display
;
;	Check for oscillator too slow when measuring L or C.
;
;
;*******************************************************************
;
; LC003	- Optimised / Modified to handle "bad" displays
;
;	Removed duplicated code in DATS subroutine
;
;	Added code to fix crook display (select by jumper on B4 - 10)
;
;	Optimised L & C formatting code
;
;	Optimised "Display" subroutine
;
;	Cleaned up LCDINIT
;
;
;*******************************************************************
;
; LC004 - Deleted timer Interrupt Service Routine
;
;	Modified way oscillator "out of range" condition is detected
;
;
;*******************************************************************
;
; LC628 - LC004 code ported to 16F628 by Egbert Jarings PA0EJH.
;	Mem starts now at 0x20
;	InitIO modified , 628 PortA start's up in Analog Mode 
;	So changed to Digital Mode (CMCON)
; 
;	Display's "Calibrating" to fill up dead Display time
;	when first Powerd Up.
;
;	Changed pmsg Routine, EEADR  trick  wont work with 628,
;	PCL was always 0x00 so restart occurs. EEADR is now Etemp.
;
;	Also changed EEADR in FP routine to Etemp 
;
;	Bad Display isn't bad at all, its a Hitachi HD44780, as
;	80% of all Display's are. Adress as 2 Lines x 8 Char.
;	So LCDINIT modified for 2 x 8 Display's. (0x28 added)
;
;*******************************************************************
;
; LC005 - Cosmetic rewrite of RAM allocation from LC004
;
;	No change to address of anything - I hope
;	Identified unused RAM & marked for later removal.
;
;
;*******************************************************************
;
; LC006 - Merge LC005 and LC628
;
;	All "#ifdef" F628 parts by Egbert Jarings PA0EJH.
;	(or derived from his good work)
;
;	Cleaned up RAM allocation.
;
;	Added message re: processor type, just to verify selection
;
;	Included extra initialisation (2 line) command by PA0EJH
;
;*******************************************************************
;
; lc007	Changed strings to EEPROM (it's not used for anything else)
;
;	Added "error collector" code to catch "all" FP errors
;
;       Addded macros
;
;*******************************************************************
;
; LC_swcal.000
;	Changed to use only 16F628 processor
;	Used internal comparator of F628 in place of LM311
;	Switched relay directly by digital I/O
;	Implemented software calibration via constant in EEPROM
;	Re-allocated most I/O pins
;	Added output munger for LCD connections (easy to re-allocate)
;
;*******************************************************************
;
; LC_swcal.001
;	Reintroduced code to handle 8x2(=16x1) displays
;
;*******************************************************************
;
; LC_swcal.002
;	Added code to use PortB5 as a display config input.
;	(Connect 1K from B5 to Ground for 8x2(=16x1) display.)
;
;	Modified calibration sequence by adding a dummy read
;	when applying the calibration capacitor.
;
;*******************************************************************
;
; LC_swcal.003
;	Modified frequency counting code, by using the 32 bit
;	"frequency engine" from the "newer" frequency meter
;	F1, F2, F3 changed from 16 bit to 32 bit
;	W2Stak now copies 32 bit to 24 bit to FP on stack
;	Test mode now handles 24 bit freq count (I hope).
;	655350 Hz restriction on oscillator now lifted.
;	it is now (2^24 - 1)*10 ie. about 167MHz
;
;	Modified counting code agian. Now, the T0CKI is left
;	counting for most of the time (even when not "counting").
;	It is only halted while it is being read.
;	It is reset "on the fly" (which defines the start of the
;	counting period.) This should improve oscillator stability.
;
;*******************************************************************
;
; LC_swcal.004
;	32 bit copy macro added.
;
;
;
;
;*******************************************************************
;o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o
;*******************************************************************
;
;	Some frequently used code fragments
;	Use macros to make mistreaks consistently.
;
;-------------------------------------------------------------------
;	Select Register Bank 0

bank0	macro
	errorlevel	+302		; Re-enable bank warning
	bcf		STATUS,RP0	; Select Bank 0
	endm

;-------------------------------------------------------------------
;	Select Register Bank 1

bank1	macro
	bsf		STATUS,RP0	; Select Bank 1
	errorlevel	-302		; disable warning
	endm

;-------------------------------------------------------------------
;	Swap bytes in register file via W

swap	macro	this,that

	movf	this,w		; get this
	xorwf	that,f		; Swap using Microchip
	xorwf	that,w		; Tips'n Tricks
	xorwf	that,f		; #18
	movwf	this

	endm

;-------------------------------------------------------------------
;	Copy bytes in register file via W

copy	macro	from,to

	MOVF	from,W
	MOVWF	to

	endm

;-------------------------------------------------------------------
;	Copy words in register file via W

copy16	macro	from,to

	MOVF	from,W
	MOVWF	to

	MOVF	from+1,W
	MOVWF	to+1

	endm

;-------------------------------------------------------------------
;	Copy medium words in register file via W

copy24	macro	from,to

	MOVF	from,W
	MOVWF	to

	MOVF	from+1,W
	MOVWF	to+1

	MOVF	from+2,W
	MOVWF	to+2

	endm

;-------------------------------------------------------------------
;	Copy big words in register file via W

copy32	macro	from,to

	MOVF	from,W
	MOVWF	to

	MOVF	from+1,W
	MOVWF	to+1

	MOVF	from+2,W
	MOVWF	to+2

	MOVF	from+3,W
	MOVWF	to+3

	endm

;*******************************************************************
;
;	CPU configuration
;

	MESSG		"Processor = 16F628"
	processor	16f628
	include		<p16f628.inc>
	__CONFIG        _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _BODEN_ON & _LVP_OFF

;**********************************************************
;
;	I/O Assignments.
;

#define	LCD0	PORTB,3
#define	LCD1	PORTB,2
#define	LCD2	PORTB,1
#define	LCD3	PORTB,0
#define	ENA	PORTB,4		; Display "E"
#define	RS	PORTB,5		; Display "RS" & Disp type link
#define	functn	PORTB,6		; 0 = "Inductor"
#define relay	PORTB,7		; Switches Ccal

;*******************************************************************
;
;	file register declarations: uses only registers in bank0
;	bank 0 file registers begin at 0x0c in the 16F84
;	and at 0x20 in the 16F628
;
;*******************************************************************

	cblock	0x20
;
;       Floating Point Stack and other locations used by FP.TXT
;
;	FP Stack: TOS	A = 	AEXP:AARGB0:AARGB1:AARGB2:AARGB3:AARGB4
;			B = 	BEXP:BARGB0:BARGB1:BARGB2
;			C = 	CEXP:CARGB0:CARGB1

	AARGB4
	AARGB3
	AARGB2
	AARGB1
	AARGB0
	AEXP			; 8 bit biased exponent for argument A
	SIGN			; save location for sign in MSB

	FPFLAGS			; floating point library exception flags
	
	BARGB2
	BARGB1
	BARGB0
	BEXP			; 8 bit biased exponent for argument B

	TEMPB3			; 1 Unused byte
	TEMPB2			; 1 Unused byte
	TEMPB1			; Used
	TEMPB0			; 1 Unused byte

	CARGB1
	CARGB0			; most significant byte of argument C
	CEXP			; 8 bit biased exponent for argument C

;
;	"Main" Program Storage
;
 
	COUNT			; Bin to BCD convert (bit count)
	cnt			;                    (BCD BYTES)

	CHR 

	F1:4
	F2:4
	F3:4
	
	bcd:4			; BCD, MSD first 

	TabStop			; Used to fix bad displays.
	TabTemp

	FPE			; Collect FP errors in here
	
	R_sign			; Holds "+" or " " (sign)

	EEflag:1		; Cal adjust flag
	
	
	endc

	cblock	0x70		; Common RAM

	cal_t:2			; Ccal temporary value

	PB_data:1		; LCD output munger temp
	
	links:1			; User test links copy
	DispType:1		; Initial copy of test links

	COUNT1			; Used by delay routines
				; and "prescaler flush"
	COUNT2			; Timing (100ms)

	COUNT3

	endc

EXP	equ	AEXP		; Used by FP.TXT
TEMP	equ	TEMPB0
;AARG	equ	AARGB0		; Unused
;BARG	equ	BARGB0		; Unused
;CARG	equ	CARGB0		; Unused

;*******************************************************************
;
;       GENERAL MATH LIBRARY DEFINITIONS
;
;
;	define assembler constants

B0		equ	0
B1		equ	1
B2		equ	2
B3		equ	3
B4		equ	4
B5		equ	5
B6		equ	6
B7		equ	7

MSB		equ	7
LSB		equ	0

;     STATUS bit definitions

#define	_C	STATUS,0
#define	_Z	STATUS,2

;*******************************************************************
;
;       FLOATING POINT literal constants
;

EXPBIAS         equ     D'127'

;
;       floating point library exception flags
;

IOV             equ     0       ; bit0 = integer overflow flag

FOV             equ     1       ; bit1 = floating point overflow flag

FUN             equ     2       ; bit2 = floating point underflow flag

FDZ             equ     3       ; bit3 = floating point divide by zero flag

NAN		equ	4	; bit4 = not-a-number exception flag

DOM		equ	5	; bit5 = domain error exception flag

RND             equ     6       ; bit6 = floating point rounding flag, 0 = truncation
                                ; 1 = unbiased rounding to nearest LSB

SAT             equ     7       ; bit7 = floating point saturate flag, 0 = terminate on
                                ; exception without saturation, 1 = terminate on
                                ; exception with saturation to appropriate value

;**********************************************************
;
;	Motorola syntax branches
;

#define	beq	bz 
#define	BEQ	bz
#define	BNE	bnz
#define	bne	bnz

#define	BCC	bnc
#define	bcc	bnc
#define	BCS	bc
#define	bcs	bc

#define	BRA	goto
#define	bra	goto


;**********************************************************
;
;	Begin Executable Stuff(tm)
;

	org	0

GO	clrwdt			; 0 << Reset

	bsf	FPFLAGS,RND	; FP round to nearest
	bsf	FPFLAGS,SAT	; FP Saturate to appropriate

	call	InitIO
	bcf	relay		; Remove Ccal

;	Read state of PortB links so we can display "Calibrating"

	bank1			; PORTB:-
	movlw	b'01101111'	; LCD data bits to read
	movwf	TRISB		; 1 = input
	bank0			; 0 = output

	call	MS2		; Settling time
	copy	PORTB,DispType

	bank1
	movlw	b'01000000'	; restore data direction
	movwf	TRISB		; 1 = input
	bank0			; 0 = output

;**********************************************************
;
;	Main Program
;

START	CALL	LCDINIT	 	; INITIALIZE LCD MODULE	
	call	EE_RD		; Retrieve CCal integer value

cmdloop	call	HOME

;
;	"Zero" the meter.
;

Chk4Z	MOVLW   Calibr-0x2100	; Display " Calibrating "
	call	pmsg		; to entertain the punters

	call	Measure		; Dummy Run to stabilise oscillator.
	call	MS200
	call	Measure		; Get freq in F3

	copy32	F3,F1		; Copy F3 to F1

;	copy	F3+0,F1+0	; Copy F3 to F1
;	copy	F3+1,F1+1
;	copy	F3+2,F1+2
;	copy	F3+3,F1+3

	bsf	relay		; Add standard capacitor

	call	MS200
	call	Measure		; Dummy Run to stabilise oscillator.
	call	MS200
	call	Measure		; Get freq in F3

	copy32	F3,F2		; Copy F3 to F2

;	copy	F3+0,F2+0	; Copy F3 to F2
;	copy	F3+1,F2+1
;	copy	F3+2,F2+2
;	copy	F3+3,F2+3
	
	bcf	relay		; Remove standard capacitor

	call	MS200
	call	Measure		; Dummy Run to stabilise oscillator.

;
;	Now we resume our regular pogrom
;	Read state of user test links on LCD bus
;

M_F3	bank1			; PORTB:-
	movlw	b'01101111'	; LCD data bits to read
	movwf	TRISB		; 1 = input
	bank0			; 0 = output

	call	MS2		; Settling time
	copy	PORTB,links

	bank1
	movlw	b'01000000'	; restore data direction
	movwf	TRISB		; 1 = input
	bank0			; 0 = output

;---------------------------------------------------------------
;
;	Take a break from regular duties to do something interesting
;
	btfss	links,0		; Raise Ccal value
	goto	cal_up

	btfss	links,1		; Lower Ccal value
	goto	cal_dn

	btfss	links,2		; Test osc without Ccal
	goto	osc1

	btfss	links,3		; Test osc with Ccal
	goto	osc2

;
;	None of the above
;

	bcf	relay		; In case of osc test
	btfss	EEflag,0	; Time to save Ccal value?
	goto	cont		; No. Back to work
	
	bcf	EEflag,0	; To say we have done it
	call	EE_WR		; So, we better save it
	goto	cont		; Hi Ho, its off to work I go

;
;	Add +10 to cal_t:2
;

cal_up	bsf	EEflag,0	; Say "we're adjusting"
	movlw	0x0a		; +10
	addwf	cal_t+1,f
	bcc	cont
	
	incf	cal_t+0,f
	goto cont

;
;	Add -10 to cal_t:2
;

cal_dn	bsf	EEflag,0	; Say "we're adjusting"
	movlw	0xf6		; -10
	addwf	cal_t+1,f
	bcc	hi_byte
	
	incf	cal_t+0,f

hi_byte	movlw	0xff
	addwf	cal_t+0,f
	goto	cont		

;
;	Measure & display osc freq for initial setup
;

osc2	bsf	relay		; Add Ccal
	
osc1	call	HOME
	call	Measure		; Measure Local Osc Freq.
	call	CLEAR
	
	movf	F3+1,W		; Copy F3 to 24 bit number
	movwf	AARGB0		; in AARGB0, 1, 2
	movf	F3+2,W		; for display
	movwf	AARGB1		; NB; Ignore MSByte of F3
	movf	F3+3,W		; It should be zero
	movwf	AARGB2

	call	Display
	goto	M_F3

;---------------------------------------------------------------

cont	call	HOME
	call	MS200
	call	Measure		; Measure F3 & leave it there

	movf	F3+0,w		; Test for "too low" frequency
	iorwf	F3+1,w
	iorwf	F3+2,w 
	bne	OK2GO		; F < 2560Hz ?
	
OORange	MOVLW	ovr-0x2100	; Over/Under range message
	call	pmsg
	
	goto	M_F3

;
;	Precompute major bracketed terms cos
;	we need 'em both for all calculations
;

OK2GO	clrf	FPE		; Declare "error free"
	call	F1_F2
	call	F1_F3

;
;	See what mode we are in
;

	btfss	functn		; 0=Inductor
	goto	Do_Ind

;
;	OK, we've been told it's a capacitor
;

Do_Cap	call	C_calc
	movf	FPE,f		; Any FP errors?
	bne	complain
	
	movlw	Cintro-0x2100	; C =
	call	pmsg

	call	C_disp
	goto	M_F3

;
;	Now, they reckon it's a @#$*! inductor
;

Do_Ind	call	L_calc
	movf	FPE,f		; Any FP errors?
	bne	complain
	
	movlw	Lintro-0x2100	; L =
	call	pmsg

	call	L_disp
	goto	M_F3

;
;	Got a Floating Point Error of some sort
;

complain	movlw	ovr-0x2100	; Over Range
		call	pmsg
	
		goto	M_F3

;**********************************************************
;
;	Print String addressed by W
;	Note: Strings are in EEPROM
;	We do a lotta bank switching here.

pmsg	bank1
	movwf	EEADR		; pointer

pm1	BSF     EECON1,RD       ; EE Read
        MOVF    EEDATA,W        ; W = EEDATA, affects Z bit
        bank0			; Does not change Z bit
 
	btfsc	STATUS,Z	; ZERO = All done
	return			; so quit

	call	DATS		; Byte -> display

	bank1
	INCF    EEADR,F         ; bump address
	goto	pm1

;**********************************************************
;
;	Delay for 2ms (untrimmed)
;

MS2	MOVLW	0xFD		; DELAY 2ms
	MOVWF	COUNT1

	MOVLW	0x66
	MOVWF	COUNT2

	goto	L3		

;**********************************************************
;
;	Delay for about 200ms or 300ms (untrimmed)
;

MS300	call	MS100

MS200	call	MS100

;**********************************************************
;
;	Delay for about 100ms
;

MS100	MOVLW	0x7e		; Count up
	MOVWF	COUNT1		; to roll-over

	MOVLW	0x20		; was 0x19, then 0x25, then 1f
	MOVWF	COUNT2			

L3	INCFSZ	COUNT2,F
	GOTO	L3

	INCFSZ	COUNT1,F
	GOTO	L3

	RETLW	0

;**********************************************************
;
;	Put a BCD nybble to display
;

PutNyb	ANDLW	0x0F		; MASK OFF OTHER PACKED BCD DIGIT
	ADDLW	0x30		; Convert BIN to ASCII

;**********************************************************
;
;	Put a byte to display
;

	MESSG		"PortB5 = Display select link."

DATS	btfsc	DispType,5	; Check display type
	goto	DAT1

	decf	TabStop,F	; Time to tickle 8x2 display?
	bne	DAT1		; Not yet
	
	movwf	TabTemp		; Save character
	CALL	LINE2		; Move to Line 2
	movf	TabTemp,W	; Restore character

DAT1	BSF	RS		; SELECT DATA REGISTER
CM	MOVWF	CHR		; STORE CHAR TO DISPLAY
	SWAPF	CHR,W		; SWAP UPPER AND LOWER NIBBLES (4 BIT MODE)

	call	PB_dly

	MOVF	CHR,W		; GET CHAR AGAIN 

;**********************************************************
;
;	Put 4 bits to LCD & wait (untrimmed)
;

PB_dly	movwf	PB_data		; Save nybble

	btfss	PB_data,0	; copy LSbit
	bcf	LCD0
	btfsc	PB_data,0
	bsf	LCD0
	
	btfss	PB_data,1
	bcf	LCD1
	btfsc	PB_data,1
	bsf	LCD1
	
	btfss	PB_data,2
	bcf	LCD2
	btfsc	PB_data,2
	bsf	LCD2
	
	btfss	PB_data,3	; copy MSbit
	bcf	LCD3
	btfsc	PB_data,3
	bsf	LCD3
	
	BSF	ENA		; ENA HIGH
	NOP			
	BCF	ENA		; ENA LOW 

;	goto	D200us		; Fall into DELAY subroutine

;**********************************************************
;
;	Delay for 200us (untrimmed)
;

D200us	MOVLW	0x42		; DELAY  200us
	MOVWF	COUNT1	
NXT5	DECFSZ	COUNT1,F
	GOTO	NXT5	
	RETLW	0

;******************************************************************
;
;	Convert 24-bit binary number at <AARGB0,1,2> into a bcd number
;	at <bcd>. Uses Mike Keitz's procedure for handling bcd 
;	adjust; Modified Microchip AN526 for 24-bits.
;

B2_BCD

b2bcd   movlw   .24		; 24-bits
        movwf   COUNT		; make cycle counter

        clrf    bcd+0		; clear result area
        clrf    bcd+1
        clrf    bcd+2
        clrf    bcd+3
        
b2bcd2  movlw   bcd 		; make pointer
        movwf   FSR
        movlw   .4
        movwf   cnt

; Mike's routine:

b2bcd3  movlw   0x33            
        addwf   INDF,f          ; add to both nybbles
        btfsc   INDF,3          ; test if low result > 7
        andlw   0xf0            ; low result >7 so take the 3 out
        btfsc   INDF,7          ; test if high result > 7
        andlw   0x0f            ; high result > 7 so ok
        subwf   INDF,f          ; any results <= 7, subtract back
        incf    FSR,f           ; point to next
        decfsz  cnt,f
        goto    b2bcd3
        
        rlf     AARGB2,f	; get another bit
        rlf     AARGB1,f
        rlf     AARGB0,f

        rlf     bcd+3,f         ; put it into bcd
        rlf     bcd+2,f
        rlf     bcd+1,f
        rlf     bcd+0,f

        decfsz  COUNT,f         ; all done?
        goto    b2bcd2          ; no, loop
        return                  ; yes


;*********** INITIALISE LCD MODULE 4 BIT MODE ***********************

LCDINIT CALL	MS100		; WAIT FOR LCD MODULE HARDWARE RESET
	BCF	RS		; REGISTER SELECT LOW
	BCF	ENA		; ENABLE LINE LOW
	
	MOVLW	0x03		; 1
	call	PB_dly
	CALL	MS100		; WAIT FOR DISPLAY TO CATCH UP

	MOVLW	0x03		; 2
	call	PB_dly

	MOVLW	0x03		; 3
	call	PB_dly

	MOVLW	0x02		; Fn set 4 bits
	call	PB_dly
	
	MOVLW	0x0C		; 0x0C DISPLAY ON
	CALL	ST200us

	MOVLW	0x28		; DISPLAY 2 Line , 5x7 Dot's
	CALL	ST200us		; New in LC628/LC006 version
	
	MOVLW	0x06		; 0x06 ENTRY MODE SET
	CALL	ST200us		; Fall into CLEAR

;************ CLEAR DISPLAY ***************************

CLEAR	MOVLW	0x01		; CLEAR DISPLAY
	goto	Home2		; LONGER DELAY NEEDED WHEN CLEARING DISPLAY


;*********** MOVE TO HOME *****************************

HOME	movlw	0x09		; Count characters
	movwf	TabStop		; before tickling display.

	MOVLW	0x02		; HOME DISPLAY
Home2	CALL	STROBE
	goto	MS2


;**********************************************************
;
;	SENDS DATA TO LCD DISPLAY MODULE (4 BIT MODE)	
;

STROBE	BCF	RS		; SELECT COMMAND REGISTER
	GOTO	CM


;************ MOVE TO START OF LINE 2 *****************

LINE2	MOVLW	0xC0		; ADDRESS FOR SECOND LINE OF DISPLAY

ST200us	CALL	STROBE
	goto	D200us


;********************************************************************
;       Initialise Input & Output devices
;********************************************************************

InitIO	movlw	b'00000110'
	movwf	CMCON 	   	; Select Comp mode

	bank1

	movlw	b'00000000'
	movwf	VRCON 	   	; Set Volt ref mode to OFF

	movlw	0x37		; Option register
	movwf	OPTION_REG	; Port B weak pull-up enabled
				; INTDEG Don't care
				; Count RA4/T0CKI
				; Count on falling edge
				; Prescale Timer/counter
				; divide Timer/counter by 256

				; PORTA:-
	movlw	b'11100111'	; initialise data direction
				; 1 = input
				; 0 = output
								;
	movwf	TRISA		; PORTA<0>   = comp1 "-" in
				; PORTA<1>   = comp2 "-" in
				; PORTA<2>   = comp1&2 "+" in
				; PORTA<3>   = comp1 out
				; PORTA<4>   = comp2 out, T0CKI in
				; PORTA<5:7> = unused
				;
				;
				; PORTB:-
	movlw	b'01000000'	; initialise data direction
				; 1 = input
				; 0 = output
				;
	movwf	TRISB		; PORTB<0>   = LCD out "DB4"
				; PORTB<1>   =         "DB5"
				; PORTB<2>   =         "DB6"
				; PORTB<3>   =         "DB7"
				; PORTB<4>   = E  out to LCD
				; PORTB<5>   = RS out to LCD
				; PORTB<6>   = function in
				; PORTB<7>   = Ccal switch out

	bank0

	return	

;**********************************************************
;
;	Measure Frequency. Stash in "F3:4"
;

	MESSG		"32 bit counting engine"

Measure	CLRF	TMR0		; RESET INTERNAL COUNT (INCLUDING PRESCALER)
				; See page 27 Section 6.0

	bcf	INTCON,T0IF	; Clear any previous overflow

	CLRF	F3+0		; Ready to receive 32 bit number
	CLRF	F3+1
	CLRF	F3+2
	CLRF	F3+3

	CALL	MS400		; 400MS DELAY (now 100ms)

	bank1

	movlw	b'11110111'	; Disable RA4 output to T0CKI
	movwf	TRISA		; 1 = input
				; 0 = output
	bank0

	nop			; and allow time for
	nop			; the registers to catch up
	nop
	nop
	nop
	
	call	RollOver	; Final check, just in case

	MOVF	TMR0,W		
	MOVWF	F3+2

;	Now empty the prescaler

PSC1	bank1

	bcf	OPTION_REG,T0SE	; Clock the prescaler
	nop
	bsf	OPTION_REG,T0SE

	bank0
	
	DECF	F3+3,F	; Decrement the counter
	
	movf	TMR0,W		; Has TMR0 changed?
	xorwf	F3+2,W	; if unchanged, XOR -> 0

	beq	PSC1
		
; F3 : F3+1 : F3+2 : F3+3 now holds 32 bit result
; Rollover subroutine has set F3+0 and F3+1 suitably.

	bank1
				; OPEN GATE
	movlw	b'11100111'	; Enable RA4 output to T0CKI
	movwf	TRISA		; 1 = input
				; 0 = output
	bank0

	return

;**********************************************************
;
;	Delay for 100ms (trimmed for actual clock freq)
;	Check for Timer register roll over and count 'em
;
;	Uses: W, COUNT1, COUNT2, COUNT3 & others
;
;**********************************************************

MS400	MOVLW	0xff		; 100 MS DELAY LOOP		
	MOVWF	COUNT1		; 4 MHZ XTAL

	MOVLW	0x7f		; Count up
	MOVWF	COUNT2		; to 24 bit overflow

	MOVLW	0xf5
	MOVWF	COUNT3

L3a	INCFSZ	COUNT3,F
	GOTO	L3a
	
	call	RollOver	; Check for Timer0 RollOver

	INCFSZ	COUNT2,F
	GOTO	L3a

	INCFSZ	COUNT1,F
	GOTO	L3a

	RETLW	0

;**********************************************************
;
;	Account for TMR0 overflows when counting
;	Check at regular intervals and handle as
;	necessary.
;
;	Needs to be done at less than 936us (@ 70MHz in)
;	intervals, or else it can lose counts.
;

RollOver

	btfss	INTCON,T0IF	; Rolled over?
	goto	RO3		; No

RO1	bcf	INTCON,T0IF	; Yes. ACK!

	INCF	F3+1,f	; Count it
	bne	RO2		; Overflowed?

	incf	F3+0,f	; No need to check

RO2	return

;	Balance path lengths

RO3	nop
	nop
	goto	RO2

;**********************************************************
;
;	Display contents of AARGB0,1,2 on LCD
;	First convert to BCD, Then ASCII (nybble at a time)
;

Display	CALL	B2_BCD		; CONVERT COUNT TO BCD		

	call	Swap0		; GET NEXT DIGIT
	call	Move0		; GET OTHER BCD DIGIT
	call	Swap1
	call	Move1
	call	Swap2
	call	Move2
	call	Swap3
	goto	Move3		; includes return

;**********************************************************
;
;	Formatted display of BCD work area for Capacitor
;

C_disp	movf	R_sign,w	; Sign
	call	DATS

F_C1	MOVF	bcd+0,W
	ANDLW	0x0F
	beq	F_C2

	CALL	PutNyb
	call	Swap1
	call	Move1
	CALL	DoDP		; Print DP
	call	Swap2
	goto	F_C3U

;--------------------------------------------------

F_C2	swapf	bcd+1,W
	ANDLW	0x0F
	beq	F_C3

	CALL	PutNyb
	call	Move1
	CALL	DoDP		; Print DP
	call	Swap2
	call	Move2
	goto	F_C3U		; print nF. includes RETURN

;--------------------------------------------------

F_C3	MOVF	bcd+1,W
	ANDLW	0x0F
	beq	F_C4

	CALL	PutNyb
	CALL	DoDP		; Print DP
	call	Swap2
	call	Move2
	call	Swap3

F_C3U	movlw	Unit1-0x2100	; nF
	goto	pmsg		; includes RETURN

;--------------------------------------------------

F_C4	SWAPF	bcd+2,W		; Digit1 == 0 ?
	ANDLW	0x0F
	bne	NoB1_C

	MOVLW	0x20		; YES PRINT A SPACE
	call	DATS

	MOVF	bcd+2,W		; Digit2 == 0 ?
	ANDLW	0x0F
	bne	NoB2_C

	MOVLW	0x20		; YES PRINT A SPACE
	call	DATS
	bra	NoB3_C

NoB1_C	call	Swap2		; 1
NoB2_C	call	Move2		; 2
NoB3_C	call	Swap3		; 3
	CALL	DoDP		; Print DP
	call	Move3		; 4

	movlw	Unit2-0x2100	; pF
	goto	pmsg		; includes RETURN

;**********************************************************
;
;	Formatted display of BCD work area for Inductor
;

L_disp	movf	R_sign,w	; Sign
	call	DATS

F_L1	MOVF	bcd+0,W
	ANDLW	0x0F
	beq	F_L2

	CALL	PutNyb
	call	Swap1
	CALL	DoDP		; Print DP
	call	Move1
	call	Swap2
	goto	F_L2U		; Print mH. includes RETURN

;--------------------------------------------------

F_L2	swapf	bcd+1,W
	ANDLW	0x0F
	beq	F_L3

	CALL	PutNyb
	CALL	DoDP		; Print DP
	call	Move1
	call	Swap2
	call	Move2
	
F_L2U	movlw	Unit3-0x2100	; mH
	goto	pmsg		; includes RETURN

;--------------------------------------------------

F_L3	MOVF	bcd+1,W
	ANDLW	0x0F
	beq	F_L4

	CALL	PutNyb
	call	Swap2
	call	Move2
	CALL	DoDP		; Print DP
	call	Swap3
	goto	F_L4U		; Print uH. includes RETURN

;--------------------------------------------------

F_L4	SWAPF	bcd+2,W		; Digit1 == 0 ?
	ANDLW	0x0F
	bne	NoB1_L

	MOVLW	0x20		; YES PRINT A SPACE
	call	DATS

	goto	NoB2_L

NoB1_L	call	Swap2		; 1
NoB2_L	call	Move2		; 2
	CALL	DoDP		; Print DP
	call	Swap3		; 3
	call	Move3		; 4

F_L4U	movlw	Unit4-0x2100	; uH
	goto	pmsg		; includes RETURN

;--------------------------------------------------
;
;	Common subroutine for formatted output
;

DoDP	MOVLW	'.'		; Print DP
	goto	DATS		; Return from DATS

Swap0	SWAPF	bcd+0,W		; GET NEXT DIGIT
	goto	PutNyb		; DISPLAY IT

Move0	MOVF	bcd+0,W		; GET OTHER BCD DIGIT
	goto	PutNyb

Swap1	SWAPF	bcd+1,W
	goto	PutNyb

Move1	MOVF	bcd+1,W
	goto	PutNyb

Swap2	SWAPF	bcd+2,W
	goto	PutNyb

Move2	MOVF	bcd+2,W
	goto	PutNyb

Swap3	SWAPF	bcd+3,W
	goto	PutNyb

Move3	MOVF	bcd+3,W
	goto	PutNyb

;********************************************************************
;
;	Stack operations
;
;********************************************************************	

;add		call	FPA24
;		goto	S_fix

subtract	call	FPS24
		goto	S_fix

divide		call	FPD24
		goto	S_fix

multiply	call	FPM24
;		goto	S_fix

;
;	Fix stack after add, subtract, divide & multiply
;	AND Collect ALL Floating Point Errors in FPE

S_fix	iorwf	FPE,f			; W may hold Error (0xff)

	copy	CARGB1,BARGB1		; C -> B
	copy	CARGB0,BARGB0
	copy	CEXP,BEXP
	return

;
;	Push stack (duplicates TOS)
;

S_push	copy	BARGB1,CARGB1		; B -> C
	copy	BARGB0,CARGB0
	copy	BEXP,CEXP

	copy	AARGB1,BARGB1		; A -> B
	copy	AARGB0,BARGB0
	copy	AEXP,BEXP
	return

;
;	Swap A and B

S_swap	swap	AARGB1,BARGB1		; A <-> B
	swap	AARGB0,BARGB0
	swap	AEXP,BEXP
	return

;********************************************************************
;
;	Calculate Unknown Capacitance OR inductance
;	
;       Output: 24 bit positive integer (scaled)
;	right justified in AARGB0, AARGB1, AARGB2
;	also as BCD in bcd:bcd+1:bcd+2:bcd+3
;
;********************************************************************	

C_calc	call	divide
	call	Get_Ccal	; Times 10,000 ( = 1000.0pF)
	call	multiply
	goto	PorM		; includes return

;--------------------------------------------------------------------

L_calc	call	multiply
	call	Get_Lscale	; Precomputed Scale_factor/(4*PI*PI)
	call	multiply
	call	Get_Ccal
	call	S_swap
	call	divide

L_divF1	call	Get_F1		; Divide by F1^2
	call	S_push
	call	multiply
	call	S_swap
	call	divide

;
;	Handle Space or Minus in front of FP number
;	

PorM	btfss	AARGB0,7	; test sign
	goto	Pplus
	
Pminus	movlw	0x2d		; minus
	goto	PMdisp

Pplus	movlw	0x20		; plus

PMdisp	movwf	R_sign		; save for later display
	bcf	AARGB0,7	; make plus anyway

;
;	Format as raw BCD string in bcd:bcd+1:bcd+2:bcd+3
;

	call	INT2424		; To INT in AARGB0 etc.
	iorwf	FPE,f		; W may hold Error (0xff)
	goto	B2_BCD		; includes return

;********************************************************************
;
;	Calculate (F1/F3)^2-1, leave result on stack
;
;********************************************************************	

F1_F3	call	Get_F3
	goto	F1_F1

;********************************************************************
;
;	Calculate (F1/F2)^2-1, leave result on stack
;
;********************************************************************	

F1_F2	call	Get_F2
F1_F1	call	Get_F1
	call	divide		; F1/Fx
	call	S_push
	call	multiply	; (F1/Fx)^2
	call	Get_One
	call	S_swap
	goto	subtract	; (F1/Fx)^2-1
				; includes return

;********************************************************************
;	Fetch assorted things used for the calculation
;	of Unknown L and C
;
;********************************************************************	

Get_Lscale	call	S_push		; make room first
		movlw	0xB8		; 2.53303e+17
		movwf	AEXP		; Create FP version of
		movlw	0x60		; Precomputed 1/(4*PI*PI)
		movwf	AARGB0		; times any needed
		movlw	0xFA		; fiddle factor (1/100)
		movwf	AARGB1
		return

Get_One		call	S_push		; make room first
		clrf	AEXP		; Create a binary 1
		clrf	AARGB0
		clrf	AARGB1
		movlw	0x01
		goto	LSB2stak
	

;********************************************************************
;	Copy 16 bit numbers to stack
;	and convert to FP (positive value only)
;	via a 24 bit number in AARGB0,1,2
;********************************************************************	

Get_Ccal	movlw	cal_t		; Get integer value

;********************************************************************
;	Copy 16 bit number, pointed to by W, to stack
;	and convert to FP (positive value only)
;	via a 24 bit number in AARGB0,1,2
;********************************************************************	

W16toStak	movwf	FSR
		call	S_push		; make room first

		clrf	AEXP
		clrf	AARGB0

		goto	w16toS

;********************************************************************
;	Copy 32 bit numbers to stack
;	and convert to FP (positive value only)
;	via a 24 bit number in AARGB0,1,2
;	Assumes MSB of 32 bit number is zero (and discards it).
;
;********************************************************************	

Get_F1		movlw	F1		; Includes stack push
		goto	W2stak

Get_F2		movlw	F2		; Includes stack push
		goto	W2stak

Get_F3		movlw	F3		; Includes stack push
;		goto	W2stak

;********************************************************************
;
;	Copy 32 bit number, pointed to by W, to stack
;	and convert to FP (positive value only)
;	via a 24 bit number in AARGB0,1,2
;	Assumes MSB of 32 bit number is zero (and discards it).
;
;********************************************************************	

W2stak		addlw	0x01		; skip first byte
	
		movwf	FSR
		call	S_push		; make room first

		clrf	AEXP

		movf	INDF,W		; Second biggest Byte first
		movwf	AARGB0

		incf	FSR,F		; then next byte

w16toS		movf	INDF,W
		movwf	AARGB1

		incf	FSR,F		; then little byte

		movf	INDF,W
LSB2stak	movwf	AARGB2
		
		CALL	FLO2424		; 24 bit int -> 24 bit FP
		iorwf	FPE,f		; W may hold Error (0xff)
		RETURN

;********************************************************************
;	Read EEPROM into "cal_t"
;********************************************************************	

EE_RD	bank1
	movlw	cal_p-0x2100	; Address to read
	MOVWF	EEADR
	bank0

	CALL	EE_R
	MOVWF	cal_t+0

	CALL	EE_Rinc
	MOVWF	cal_t+1

	RETURN

EE_Rinc	bank1
	INCF	EEADR,F		; bump address

EE_R	bank1
	BSF	EECON1,RD	; EE Read
	MOVF	EEDATA,W	; W = EEDATA
	bank0

	RETURN


;********************************************************************
;	Write EEPROM from "cal_t"
;********************************************************************	

EE_WR	bank1
	movlw	cal_p-0x2100
	MOVWF	EEADR		; Address to write

	MOVF	cal_t+0,W	; Data byte #0
	CALL	EE_W

	MOVF	cal_t+1,W	; Data byte #1
	CALL	EE_Winc

	bank0
	RETURN

	errorlevel	-302	; In Bank 2

EE_Winc	INCF	EEADR,F		; bump address
	
EE_W	MOVWF	EEDATA
	BSF	EECON1,WREN	; Enable Write
	MOVLW	0x55		;
	MOVWF	EECON2		; Write 0x55
	MOVLW	0xAA		;
	MOVWF	EECON2		; Write 0xAA
	BSF	EECON1,WR	; Set WR bit (begin write)

EE_W2	BTFSC	EECON1,WR	; Wait for write to finish
	GOTO	EE_W2

	bank0
	BCF	PIR1,EEIF	; clear interrupts
	bank1
	RETURN	

	errorlevel	+302

;********************************************************************	

	INCLUDE <FP.TXT>

;********************************************************************
;
;	Text Strings (stored in data EEPROM)
;

        ORG 0x2100

ovr	de	"   Over Range   ",0
Unit1	de	" nF",0
Unit2	de	" pF",0
Unit3	de	" mH",0
Unit4	de	" uH",0
Cintro	de	" C = ",0
Lintro	de	" L = ",0
Calibr  de	"  Calibrating   ",0

cal_p	de	0x27,0x10		; Initial value = 10000

 	END

;********************************************************************
