> From: "Richard A. Smith" <spam_OUTras2TakeThisOuTTANT.COM>
>
> Non-PIC-topic:
>
> I am looking for some references on doing fixed point math (16.16 or
> possibly 32.16 and maybe even 32.32 ) with an 8-bit MC. I have to
> implement Newtons divided difference polynomial interpolation, 2nd order
> for an optical sensor I am working on.
>[cut]
D.E.Knuth 'The Art of Computer Programming' Vol 2 Chapter 4 will point
you in the right direction, for sure.
{Quote hidden}> PIC-topic:
>
> On this same project I read square wave frequencys from a TSL-235 Light to
> Frequency converter. Currently I am using the cycles/time method for
> getting the frequency input. I am using 100mS right now which puts
> me at 10Hz resolution. This is ok for our prototype work but the next step
> needs less than 1Hz resolution which would make me wait > 1 second between
> readings minimum. Plus I have to watch for counter overflows.
>
> I need to switch to a period based freq measurement. The PIC with
> it's high clock speed ability and single clock instruction cycle seems ideal
> for the task.
>
> Has anybody who has done this have some info on which PIC would be the
> best (cost is an issue), what speed would be needed, and perhaps any
> gotchas that they ran into.
>
> Specs:
> - Must read 2 freq inputs to within 1Hz.
> - Freq are within 20KHz to 1000Hz 50% duty cycle.
> - Conversion time needs to be less than 100mS.
> - Chip has to implement some other functions at the same time so interrupt
> driven would be nice. (see first topic above)
> - As cheap as possible. (Or I would use an embedded-486)
'Cheapness' would imply an '84 or a '5X. Probably the '84 is the choice
these days because of the EEPROM, and also it supports interrupts.
'Interrupt driven' implies an '84 or 'XX part. However, the very minimum
number of cycles swallowed by your interrupt routine is about 12 cycles
(saving and restoring W and status without doing anything else) so,
depending on the method chosen, this may well limit your accuracy.
Assuming a clock speed of 10MHz, your basic time quantum is 400ns (or
possibly 100ns if using certain CCP functions of the 'XX part).
Looking at your spec, one can do some arithmetic to determine how accurately
one can measure period or, equivalently, frequency.
If you sample for a fixed time of 100ms then you sample f/10 cycles. If
the total time for f/10 cycles is quantised to units of T (seconds) then
the uncertainty in period is 10T/f and uncertainty in frequency is
10Tf/(1+10T).
Using a 10MHz 16C84 as an example (because I am a minimalist), without
interrupts for simplicity, a 16-bit counter would be used to count
cycles and the 8-bit TMR0 would be used to gate the sampling interval.
Using the prescaler and TMR0 makes a maximum gate period of
400ns*256*256 = 26.2144ms. This comes a bit short of 100ms, but let's
see how it goes. Shorter gating times reduce accuracy.
The following code keeps track of the gate period by looking for on-off
transitions of the TMR0 clock MSB. It also counts on-off transitions of the
signal to be measured; at each of these transitions it also records the
timestamp relative to the first transition. The timestamp is maintained in
a 16-bit counter.
Note that this code is off the top of my head (and probably won't assemble
let alone run). It has the advantage (?) of constant percentage error
which is not obtained with a simple frequency/period counter. However,
this assumes that you do the 16-bit fixed point divisions optimally. That
task is 'left as an exercise for the reader'.
cblock
; registers
cych ; high word of cycle count
cycl ; low word of CC
timeh ; current time high
timel ; current time low
stmph ; high time stamp of last transition
stmpl ; low ditto
flags ; Flags (see below)
endc
#define INPUT porta,0 ; test input bit
F_CLKHI equ 0 ; Bit set when TMR0 MSB goes high
F_INBIT equ 1 ; Previous state of input
; On return, cyc and stmp contain number of cycles (c) and total time (t) for
; those cycles measured. Frequency is computed by
; f = xt/c where x is a scale factor. The division should be performed
; using fixed-point arithmetic. It turns out that the unit of time is
; 10.4us, given the following code.
measure equ $
; Init counters etc to zero
clrf cych
clrf cycl
clrf timeh
clrf timel
clrf flags
; Wait for 1st 1->0 transition of input
btfss INPUT
goto $-1
btfsc INPUT
goto $-1
; Reset timer (chich also clears invisible prescaler)
clrf tmr0
; main loop. Inside loop, check for 1->0 transition of TMR0 and exit
; if found. Then check for 1->0 transition of input. If found, increment
; cycle count and transfer timestamp. Finally increment the timestamp.
; Everything must be isochronous i.e. exactly same number of cycles must
; happen in the loop no matter which branch is taken. Hence the time-
; wasting instructions. Instructions after ';==' are isochronous points.
; This loop is amenable to optimisation (I can see how to save 2 cycles
; but can't be bothered re-doing my arithmetic!)
;==
loop btfss flags,F_CLKHI ; Clock MSB set previously?
goto cont1 ; No, skip next
btfss tmr0,7 ; Check current MSB
return ; Exit loop since MSB now 0
goto cont2
cont1 btfsc tmr0,7 ; Clock MSB gone high?
bsf flags,F_CLKHI ; Yes, set flag indicating this.
nop ; Total 6 instruction cycles
;==
cont2 btfss INPUT ; Check input
goto cont3 ; Currently 0 (go see if changed)
bsf flags,F_INBIT ; Currently 1, reflect in flags
goto cont4
cont3 btfss flags,F_INBIT ; Previous bit 1?
goto cont5 ; No, no change
bcf flags,F_INBIT ; Reflect new state in flags
incfsz cycl ; Increment 16-bit cycle counter (low)
goto $+2 ; Skip next if no carry
incf cych ; Inc high
movf timel,w ; Move time stamp hi and low
movwf stmpl
movf timeh,w
movwf stmph
goto cont6 ; Total 15 instr. cyc.
cont4 nop
cont5 nop
goto $+1 ; Waste time (10 instr max)
goto $+1
goto $+1
goto $+1
;==
cont6 incfsz timel ; Increment timer
goto $+2
incf timeh ; Total 3 instr. cyc.
;==
goto loop
; Total loop time is 6 + 15 + 3 + 2 = 26 intructions. This is 26*400ns =
; 10.4us (quantisation error). The maximum frequency which
; could be measured (assuming 50% duty) is 1/(2*10.4us) = 48KHz.
; The frequency measurement error is then (10.4/26214.4)*100% = 0.04%.
; For 20KHz this is a 8Hz error, but for 1KHz is 0.4Hz error.
Note that this code requires interrupts to be disabled. Since the conversion
time is only 26ms (instead of the nominated 100ms) perhaps the 'other tasks'
mentioned could be slotted into the remaining time???
Of course, the CCP modules in the 16CXX series could be used to advantage
since there is also a 16-bit timer etc. This would enhance accuracy.
Regards,
SJH