This was written for the midrange core, but it should work (or be
adaptable to the 16-bit core). Andy David has written a square root
routine specifically for the 17Cxx family. Maybe he'll post it? Or you
can try contacting him:
> Hi all !
> Where could I get a 16 bit square root routine for PIC 17C43 ?
>
> Juha
The following code takes the sqrare root of a 16 bit number and returns a
fixed point result of 8 bits integer and 8 bits fraction. The main loop of
the
routine generates one bit fro every interation. There are square root
routines
that converge in fewer interations.
Walter Banks
#pragma has PIC16;
#pragma has MUL;
long SQRT (long l)
/*
Square root V1.0.
Hayward/Banks approximation.
This routine generates a square root to
16 bit resolution taking a 16 bit argument
normalizing the argument and returning a 16 bit
real number that consists of 8 bits interger and
8 bit fractional parts. The MS8bits are the interger
part.
i i i i i i i i . f f f f f f f f
| | | | | | | | | | | | | | | |
128 |32 | 8 4 2 1 .5 | | | | | | .00390625
64 16 .25 | | | | --.0078125
.125- | | ----.015625
.0625-- ------.03125
These routines may be adapted for any purpose when
used with the MPC Code Development system. No
warranty is implied or given as to their usability
for any purpose.
>Hi all !
>Where could I get a 16 bit square root routine for PIC 17C43 ?
>
>Juha
The following is a C version to provide a 16-bit input with 8-bits of
output. This uses perfect rounding. It is not difficult to expand this to
provide more bits of output, ie. fixed point results.
unsigned byte Sqrt16(unsigned int X)
{ unsigned int Test = 0xFF00;
unsigned int Bit = 0x8000;
if (X == 0) return 0;
X = X - 1;
do {
Test = (Test ^ Bit) >> 1;
if (X >= Test)
{ X -= Test;
Test |= Bit;
}
} while ((Bit >>= 2) != 0);
return (unsigned byte)(Test >> 1);
}
Convertion to PIC assembly language is not difficult. The following is
this same code for the 14-bit midrange PIC code. I have never tried to write
it for the 16-bit versions.
; Routine : Sqrt16
; Purpose : Takes a squareroot of a 16-bit number, result is an 8-bit
; number. Rounds results, inputs between (n*(n+1))
; and (n*(n-1))-1 are returned as n. The algorithm is a
; optimized binary search algorithm, creating the results a
; bit per loop.
; Inputs : Acc -- word accumulater. 16-bit input.
; Returns : w -- results of the square root, rounded.
; Acc -- value in here is trashed.
; Globals : sqrt_tst -- temp word variable.
; sqrt_bit -- temp word variable.
; Timing : 219 to 227 cycles including short call and return.
; decrease input by 1 step, to change compare direction.
incf Acc+1,f
decfsz Acc,f
decf Acc+1,f
; set up bit value and partial for testing.
clrf sqrt_bit ; clear bit pattern, want 0x8000
clrf sqrt_bit+1 ; high byte, first clear.
bsf sqrt_bit+1,7 ; set the highest bit.
clrf sqrt_tst
movlw high ((256*255)) ; sqrt_tst == 0xFF00
movwf sqrt_tst+1
; loop, we do this until all bits are shifted out of sqrt_bit.
; This is done a total of 8 loops.
clrc ; clear carry
Sqrt16_loop
; set test value to (test - bit) / 2, can use XOR to subtract.
movf sqrt_bit,w ; start with low byte.
xorwf sqrt_tst,f
movf sqrt_bit+1,w ; high byte, deal with borrow.
xorwf sqrt_tst+1,f
; do /2
rrf sqrt_tst+1,f
rrf sqrt_tst,f
; check if accumulator is greater than test value.
movf sqrt_tst,w
subwf Acc,f
movf sqrt_tst+1,w
skpc ; skip if not borrow.
incfsz sqrt_tst+1,w
subwf Acc+1,f ; carry set if borrow
bc Sqrt16_c ; branch if no borrow
Sqrt16_a
; on borrow we want to undo the subtract. Undo high byte.
addwf Acc+1,f ; reverse high byte.
movf sqrt_tst,w ; get low byte.
addwf Acc,f ; all undone, can ignore carry.
; test value is left unchanged, clear carry for later code.
clrc
goto Sqrt16_d ; down to end of loop test.
Sqrt16_c
; set test to test + bit, can use OR instead.
movf sqrt_bit,w
addwf sqrt_tst,f ; carry is not possible
movf sqrt_bit+1,w ; using ADD to clear carry.
addwf sqrt_tst+1,f ; carry is not possible here.
Sqrt16_d
; shift bit pattern down by 2 bits, carry is already clear.
rrf sqrt_bit+1,f ; shift down by 2.
rrf sqrt_bit,f ; first bit out always is 0.
rrf sqrt_bit+1,f ; shift down by 2 again.
rrf sqrt_bit,f ; if carry out if this bit then done.
bnc Sqrt16_loop ; loop until done.
; return results, test value / 2.
rrf sqrt_tst+1,w
rrf sqrt_tst,w