> From: "Richard A. Smith" > > 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. > 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