'Info on Fixed Point Math [+freq. metering]'
|> From: "Richard A. Smith" <TANT.COM> ras2
> 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.
D.E.Knuth 'The Art of Computer Programming' Vol 2 Chapter 4 will point
you in the right direction, for sure.
'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
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'.
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)
#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
; Wait for 1st 1->0 transition of input
; Reset timer (chich also clears invisible prescaler)
; 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
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
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
goto cont6 ; Total 15 instr. cyc.
goto $+1 ; Waste time (10 instr max)
cont6 incfsz timel ; Increment timer
incf timeh ; Total 3 instr. cyc.
; 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.
More... (looser matching)
- Last day of these posts
- In 1996
, 1997 only
- New search...