Truncated match.
PICList
Thread
'fast 16 bit counter'
1998\04\25@224331
by
Dwayne Reid
|
Hiya, gang.
I'm trying to measure the period of a pulse that varies from 5mS through
30mS with at better than 10 uS resolution. The target processor is running
at 4 MHz (1uS instruction cycles). My problem is that I need a timeout
function, so that a missing signal doesn't become a fatal condition.
The easiest way seemed to call for a 16 bit counter. I immediately thought
of Andrew Warren's fast 5 cycle counter, but I can't think of an easy way to
detect overflow without increasing the loop time drastically.
so... I came up with the following:
;measure HI period
clrf HiPerLO
clrf HiPerHI
movlw 1
MeasHiPerLoop ;8 cycles per count
addwf HiPerLO,F ;add puts carry in known state
skpnc ;lower byte roll over?
addwf HiPerHI,F
skpnc ;upper byte roll over?
goto TimeOut
btfsc PIN ;pin still HI?
goto MeasHiPerLoop
I get 8 cycles for the loop. I can also limit my timeout period by using
bit tests on the high byte if necessary (replace the 2nd 'skpnc' with a
btfsc HiPerHI, n). But I REALLY like Andy's 5 cycle version and am hoping
that someone can come up with an idea on how to do better than what I've
come up with.
Just a reminder: here is Andy's 5 cycle timing loop:
Andrew Warren wrote:
; 5 cycles per count
CHECK_PULSE:
INCFSZ pulse_width_lo
DECF pulse_width_hi
BTFSC PULSE_PORT,PULSE_BIT
GOTO CHECK_PULSE
DONE:
MOVF pulse_width_lo,W
ADDWF pulse_width_hi
My other thought was to use Andy's version, then use the watchdog timer to
limit how long I would wait for the pulse to end. But I need the prescaler
for my main timekeeping routines - and I couldn't reliably measure pulses
that would approach the full time that the counters would be capable of.
Ideas, suggestions?
Thanks!
dwayne
1998\04\25@230031
by
Dwayne Reid
Well, it looks as if I forgot something - the watchdog timer! So my loop is
now going to be 9 cycles. I may just stick a 'nop' in there and make it 10
cycles for 10 uS resolution <grin>.
;measure HI period
clrf HiPerLO
clrf HiPerHI
movlw 1
MeasHiPerLoop ;9 cycles per count
clrwdt
addwf HiPerLO,F ;add puts carry in known state
skpnc ;lower byte roll over?
addwf HiPerHI,F
skpnc ;upper byte roll over?
goto TimeOut
btfsc PIN ;pin still HI?
goto MeasHiPerLoop
Ideas, suggestions?
Thanks!
dwayne
1998\04\26@102432
by
Jan Erik Bertram
Dwayne Reid wrote:
> Well, it looks as if I forgot something - the watchdog timer! So my loop is
> now going to be 9 cycles. I may just stick a 'nop' in there and make it 10
> cycles for 10 uS resolution <grin>.
This loop takes 7 Cycles (8 with clrwdt)
clrf CounterLo
clrf CounterHi
Loop:
btfss PULSE_PORT,PULSE_BIT ; If low then end
goto MeasureEnd
incfsz CounterLo
decf CounterHi
incfsz CounterHi
goto Loop
goto TimeOut
Ciao
Jan Erik
1998\04\26@135358
by
Sujay Sirur
|
Hi Dwayne Reid,
I'm new to PIC, but have worked with other mc's. Am sending my comment,
might be of use.
If I had to measure the pulse width using 80C51 or 80C552 I would AND the
input pulse and a 100KHz (10uS resolution) clock and give it to the on-chip
counter. If the onchip counter is 8 bit, I would program it to generate an
interrupt on overflow, and use the interrupt to inc. the high byte/word.
Something equivalent should be possible with PIC.
At 20:43 4/25/98 -0600, Dwayne Reid wrote:
{Quote hidden}>Hiya, gang.
>
>I'm trying to measure the period of a pulse that varies from 5mS through
>30mS with at better than 10 uS resolution. The target processor is running
>at 4 MHz (1uS instruction cycles). My problem is that I need a timeout
>function, so that a missing signal doesn't become a fatal condition.
>
>The easiest way seemed to call for a 16 bit counter. I immediately thought
>of Andrew Warren's fast 5 cycle counter, but I can't think of an easy way to
>detect overflow without increasing the loop time drastically.
>
>so... I came up with the following:
>
>;measure HI period
>
> clrf HiPerLO
> clrf HiPerHI
> movlw 1
>
>MeasHiPerLoop ;8 cycles per count
> addwf HiPerLO,F ;add puts carry in known state
> skpnc ;lower byte roll over?
> addwf HiPerHI,F
> skpnc ;upper byte roll over?
> goto TimeOut
> btfsc PIN ;pin still HI?
> goto MeasHiPerLoop
>
>I get 8 cycles for the loop. I can also limit my timeout period by using
>bit tests on the high byte if necessary (replace the 2nd 'skpnc' with a
>btfsc HiPerHI, n). But I REALLY like Andy's 5 cycle version and am hoping
>that someone can come up with an idea on how to do better than what I've
>come up with.
>
>Just a reminder: here is Andy's 5 cycle timing loop:
>
>Andrew Warren wrote:
> ; 5 cycles per count
>
> CHECK_PULSE:
>
> INCFSZ pulse_width_lo
> DECF pulse_width_hi
>
> BTFSC PULSE_PORT,PULSE_BIT
> GOTO CHECK_PULSE
>
> DONE:
>
> MOVF pulse_width_lo,W
> ADDWF pulse_width_hi
>
>
>My other thought was to use Andy's version, then use the watchdog timer to
>limit how long I would wait for the pulse to end. But I need the prescaler
>for my main timekeeping routines - and I couldn't reliably measure pulses
>that would approach the full time that the counters would be capable of.
>
>Ideas, suggestions?
>
>Thanks!
>
>dwayne
>
>
1998\04\26@183412
by
Dwayne Reid
Hiya Jan
I must be particularily obtuse today, but I don't see how this can work.
The first count terminates the loop.
{Quote hidden}>
>This loop takes 7 Cycles (8 with clrwdt)
>
> clrf CounterLo
> clrf CounterHi
>
>Loop: cnt_hi cnt_lo
> btfss PULSE_PORT,PULSE_BIT ; If low then end 00 00
> goto MeasureEnd
> incfsz CounterLo 00 01
> decf CounterHi ff 01
> incfsz CounterHi 00 01
> goto Loop skipped because cnt_hi ==0
> goto TimeOut
Kind of neat how you correct the count in CounterHi !
how about:
Loop CntHi CntLo
btfss PULSE_PORT,PULSE_BIT ; If low then end 00 00
goto MeasureEnd
incf CounterLo 00 01
skpnz skip next
incfsz CounterHi
goto Loop
goto TimeOut
It looks as if this might work. Thanks for the tip!
Any other ideas on how I can speed this up even more?
dwayne
1998\04\26@215908
by
Russell McMahon
What PIC cpu are you using?
On eg 16F84 you could perhaps use interrupt on change caused
by the end of the pulse to drag you out of the fast counter
loop.
If you haven't got interrupts available this may not be easy
to implement :-)
{Original Message removed}
1998\04\27@120417
by
Scott Dattalo
|
On Sun, 26 Apr 1998, Dwayne Reid wrote:
>
> Loop CntHi CntLo
> btfss PULSE_PORT,PULSE_BIT ; If low then end 00 00
> goto MeasureEnd
> incf CounterLo 00 01
> skpnz skip next
> incfsz CounterHi
> goto Loop
> goto TimeOut
>
> It looks as if this might work. Thanks for the tip!
>
> Any other ideas on how I can speed this up even more?
>
Sure! This will get you back down to 5 cycles per sample and
it can be scaled to how ever many bytes you wish. I show 3
just as an example.
MOVLW C_LOW
MOVWF count_low
MOVLW C_MID
MOVWF count_mid
MOVLW C_HIGH
MOVWF count_high
s1:
BTFSC IOPORT,IOBIT
goto went_high
DECFSZ count_low,F
goto s1
NOP
BTFSC IOPORT,IOBIT
goto went_high
DECFSZ count_mid,F
goto s1
NOP
BTFSC IOPORT,IOBIT
goto went_high
DECFSZ count_high,F
goto s1
time_out:
The three-byte count is pre-loaded with the desired time-out. If
the code reaches the label 'time_out' then the IOPORT didn't
change states.
One caveat: The three byte count is actually:
COUNT = C_LOW + 257*C_MID + 257^2 * C_HIGH
(note 257 and not 256). So to preset the count you'll need to do
something like:
C_LOW EQU COUNT % 257
C_MID EQU (COUNT / 257) % 257
C_HIGH EQU (COUNT / 257 / 257) % 257
Scott
1998\04\27@142049
by
paulh
|
You don't need a 4 cycle loop to check something every 4 cycles.
Here is a 16 cycle loop with a test every 4 cycles.
NOTE: This hasn't been assembled or tested. Before using, make sure
I test the correct status bits, and include ,f and ,w where appropriate.
Also, make that the btfss's shouldn't be btfsc and vice versa.
I've been busy recently and have switched to the digest format. So,
someone else may have answered, and I missed it. Also, this uses many
words of program space. I didn't try to make it small. There are
many oportunities for optimization.
;
; Sample pin PulseBit of port PulsePort every 4 cycles until it
; goes high, or 2^18 passes through the loop, whichever comes first.
; The low 2 bits of the count will be in HiPerLo, the next 8 bits
; will be in HiPerMid, the high 8 bits in HiPerHi.
;
; preload HiPerMid and HiPerHi with some other value to get the loop
; to timeout sooner.
;
; Check my cleanup logic for when the middle byte goes from 255 -> 0.
;
clrf HiPerMid
clrf HiPerHi
sampleloop;
btfsc pulsePort,PulseBit ; 1 Test the bit
goto gotpulse0 ; 2
nop ; 3
incf HiPerMid,f ; 4 increment the middle 8 bits
btfsc pulsePort,PulseBit ; 1 Test the bit again
goto gotpulse1 ; 2
btfsc status,z ; 3 Does it carry into the high 8 bits
incf HiPerHi,f ; 4
btfsc pulsePort,PulseBit ; 1 and again
goto gotpulse2 ; 2
btfsc status,z ; 3
goto timeout ; 4
btfsc pulsePort,PulseBit ; 1 and again
goto gotpulse3 ; 2
goto sampleloop ; 4
gotpulse0
clrf HiPerLo ; low 2 bits zero
; add delay here for constant path length.
; otherwise the loop is fastest when the low
; 2 bits are zero.
return
gotpulse1
decf HiPerMid,f ; undo last increment
movlw 1
movwf HiPerLo
goto fixupa
gotpulse2
movlw 2
movwf HiPerLo
goto fixupb
gotpulse3
movlw 3
movwf HiPerLo
fixupb
movf HiPerMid,f ; Test for zero
btfsc status,z ; optionally undo inc of Hi byte
decf HiPerHi,f
fixupa
decf HiPerMid,f
return
timeout ;
; Do something usefull here.
return
==================================
I do something similar in my latest sonar code. There I'm checking for
and echo on 4 transducers every 4 cycles. The transducers are hooked
pins 0-3 on porta, pin 4 is pulled low. I swapf porta,w, then 4 cycles
later iorwf porta,w. Testing the Z flag tells if any transducer saw
an echo. Looking at the bits in W tells which transducer(s) and whether
it saw the echo on the 1st or second test in the loop.
--
spam_OUTpaulhTakeThisOuT
hamjudo.com http://www.hamjudo.com
The April 97 WebSight magazine describes me as "(presumably) normal".
1998\04\27@142110
by
Mike Keitz
On Sun, 26 Apr 1998 16:32:05 -0600 Dwayne Reid <.....dwaynerKILLspam
@spam@PLANET.EON.NET>
writes:
>Any other ideas on how I can speed this up even more?
Use a timer interrupt for the timeout. Rather than return from the ISR,
jump out to the timeout handler. The counter routine needs to be at the
top-level (i.e. not a subroutine) so corrupting the stack by not
returning from the interrupt doesn't cause problems. A similar approach
uses a hardware interrupt caused by the pulse being measured to stop the
counting.
_____________________________________________________________________
You don't need to buy Internet access to use free Internet e-mail.
Get completely free e-mail from Juno at http://www.juno.com
Or call Juno at (800) 654-JUNO [654-5866]
1998\04\27@151013
by
Dwayne Reid
Hi there Sujay
>If I had to measure the pulse width using 80C51 or 80C552 I would AND the
>input pulse and a 100KHz (10uS resolution) clock and give it to the on-chip
>counter. If the onchip counter is 8 bit, I would program it to generate an
>interrupt on overflow, and use the interrupt to inc. the high byte/word.
I don't have any of those available. I'm using the 12c508 with the internal
clock - no external fast clock is available and there are no interrupts on
this chip. I'm measuring duty cycle of an incoming signal - absolute times
are not important but the ratio of HI period to LO period is important.
Thanks anyways!
dwayne
1998\04\27@151445
by
Dwayne Reid
|
Excellent!!
just a minor bit of subtraction to find the actual number of samples and
home free. Many thanks.
dwayne
{Quote hidden}>
>Sure! This will get you back down to 5 cycles per sample and
>it can be scaled to how ever many bytes you wish. I show 3
>just as an example.
>
> MOVLW C_LOW
> MOVWF count_low
>
> MOVLW C_MID
> MOVWF count_mid
>
> MOVLW C_HIGH
> MOVWF count_high
>
>s1:
> BTFSC IOPORT,IOBIT
> goto went_high
>
> DECFSZ count_low,F
> goto s1
>
> NOP
>
> BTFSC IOPORT,IOBIT
> goto went_high
>
> DECFSZ count_mid,F
> goto s1
>
> NOP
>
> BTFSC IOPORT,IOBIT
> goto went_high
>
> DECFSZ count_high,F
> goto s1
>
>time_out:
>
>The three-byte count is pre-loaded with the desired time-out. If
>the code reaches the label 'time_out' then the IOPORT didn't
>change states.
>
>One caveat: The three byte count is actually:
>
>COUNT = C_LOW + 257*C_MID + 257^2 * C_HIGH
>
>(note 257 and not 256). So to preset the count you'll need to do
>something like:
>
>
>C_LOW EQU COUNT % 257
>C_MID EQU (COUNT / 257) % 257
>C_HIGH EQU (COUNT / 257 / 257) % 257
>
>Scott
>
>
1998\04\27@173502
by
Dwayne Reid
|
Scott - since I don't need a particular timeout for this application, why
wouldn't INCFSZ work. That is:
clrf c_low
clrf c_mid
clrf c_high
s1:
BTFSC IOPORT,IOBIT
goto went_high
INCFSZ c_low,F
goto s1
clrwdt ;
BTFSC IOPORT,IOBIT
goto went_high
INCFSZ c_mid,F
goto s1
nop
BTFSC IOPORT,IOBIT
goto went_high
INCFSZ c_high,F
goto s1
time_out:
Note also that your routine lets me take care of the watchdog with no added
penalty!
Now, since incrementing each added byte of counter causes the previous bytes
to miss a count (the mod 257 that you alluded to in your message),
correcting to mod 256 should be easy. The modulus changes as you extend the
counter: in the 3 byte counter above, the lowest byte misses the counts
accumulated by both of the upper bytes; the mid byte misses the counts
accumulated by the high byte. A first pass of the correction routine
follows - but its pretty stinky and I'm sure that I am missing something
obvious.
went_hi
movfw c_mid ;add mid byte to lower; propogate carries
addwf c_low,F
movlw 1
skpnc
addwf c_mid,F
skpnc
addwf c_high,F
movfw c_high ;add high byte to lowest; propogate carries
addwf c_low,F
movlw 1
skpnc
addwf c_mid,F
skpnc
addwf c_high,F
movfw c_high ;add high byte to mid; propogate carries
addwf c_low,F
movlw 1
skpnc
addwf c_mid,F
skpnc
addwf c_high,F
Back to you, Scott (and the rest of the PicListers).
ideas, improvements?
dwayne
1998\04\28@005718
by
Dwayne Reid
|
After looking at the last message that Scott sent me, I think that I have a
solution that fits my purposes. It will accumulate up to 65,535 counts
without error and times out after 65,791 counts. The count in the region
between those two numbers is held at 65,535 (ffff).
;measure puse width on a 12c508 with 5 uSec resolution.
;Times out after about 327 mSec.
clrf c_low
clrf c_high
s1:
BTFSC IOPORT,IOBIT ;5 cycles
goto went_high
INCFSZ c_low,F
goto s1
clrwdt ;
BTFSC IOPORT,IOBIT ;5 cycles
goto went_high
INCFSZ c_high,F
goto s1
;note: each time HI byte increments, LO byte to misses a count
;final count == LoByte + HiByte
time_out:
;do time out stuff here
went_high ;fix up the mod 257 counter
movfw c_high ;
addwf c_low,F
skpnc ;no carry - leave Hi byte alone
incfsz c_high,F ;carry - does Hi byte contain ff?
goto $+2 ;either no carry or did not wrap
movwf c_low ;wrapped past ffff - hold at ff
movwf c_high ;ditto
The logic is simple - if the high byte contained ff and a carry was
generated when the 2 bytes were added together (which would wrap the high
byte to 00), the value in W (which could only be ff) is written to both
bytes. The choice of $+2 for the junp is deliberate - both paths take the
same # of cycles.
My thanks to all who contributed ideas and suggestions. Scott - Thank you
again for taking time out of your very busy day.
dwayne
1998\04\28@094512
by
Scott Dattalo
|
On Mon, 27 Apr 1998, Dwayne Reid wrote:
> After looking at the last message that Scott sent me, I think that I have a
> solution that fits my purposes. It will accumulate up to 65,535 counts
> without error and times out after 65,791 counts. The count in the region
> between those two numbers is held at 65,535 (ffff).
Scrap it.
Here's a routine that gives you 3-cycle resolution:
CLRF count_3lsbs
CLRF count_low
CLRF count_mid
CLRF count_high
loop
BTFSC IOPORT,IOBIT
goto went_high_1st
MOVLW 1
BTFSC IOPORT,IOBIT
goto went_high_2nd
ADDWF count_low,F
BTFSC IOPORT,IOBIT
goto went_high_3rd
RLF count_3lsbs,W
BTFSC IOPORT,IOBIT
goto went_high_4th
ADDWF count_mid,F
BTFSC IOPORT,IOBIT
goto went_high_5th
RLF count_3lsbs,W
BTFSC IOPORT,IOBIT
goto went_high_6th
ADDWF count_high,F
BTFSC IOPORT,IOBIT
goto went_high_7th
CLRWDT
BTFSS IOPORT,IOBIT
goto loop
went_high_8th
INCF count_3lsbs,F
went_high_7th
SUBWF count_high,F
INCF count_3lsbs,F
went_high_6th
INCF count_3lsbs,F
went_high_5th
SUBWF count_mid,F
INCF count_3lsbs,F
went_high_4th
INCF count_3lsbs,F
went_high_3rd
DECF count_low,F
INCF count_3lsbs,F
went_high_2nd
INCF count_3lsbs,F
went_high_1st
CLRC
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_low,F
RLF count_mid,F
RLF count_high,F
MOVF count_3lsbs,W
ADDWF count_low,F
SKPZ
goto done
INCFSZ count_mid,F
goto done
INCF count_high,F
done
>
> My thanks to all who contributed ideas and suggestions. Scott - Thank you
> again for taking time out of your very busy day.
It's really early in the morning right now...
Scott
1998\04\28@153259
by
Dwayne Reid
Scott Dattalo wrote:
>
>Scrap it.
>
>Here's a routine that gives you 3-cycle resolution:
most of routine snipped
BRAVO! BRAVO!
Fantastic!
Talk about lateral thinking!
I have 2 observations: I don't see any way for the routine to time out. It
looks as if I can either look after the watchdog or have timeout capability
but not both. I'll keep looking, tho.
The other observation is slightly more serious, I think. If the routine
exits without incrementing any counters, (enters the routine but the pin
went or was non-active - zero time) an erroneous result will occur. I think
the solution is simple: relpace the 'SKPZ' below with 'SKPC'. Of course - I
might be out to lunch . . .
This is at the end of the normalisation routine:
{Quote hidden}>
> MOVF count_3lsbs,W
> ADDWF count_low,F
> SKPZ
> goto done
>
> INCFSZ count_mid,F
> goto done
>
> INCF count_high,F
>
>done
This is extremely impressive, Scott. Many thanks.
dwayne
1998\04\28@201841
by
Scott Dattalo
|
On Tue, 28 Apr 1998, Dwayne Reid wrote:
> I have 2 observations: I don't see any way for the routine to time out. It
> looks as if I can either look after the watchdog or have timeout capability
> but not both. I'll keep looking, tho.
I think you can extend the concept to 16 samples (or whatever) per loop
instead of 8 and do something like this
BTFSC IOPORT,IOBIT
goto went_high_x
BTFSS count_high,7 ;Overflow bit
BTFSC IOPORT,IOBIT
goto went_high_y
....
BTFSS IOPORT,IOBIT
goto loop
went_high_z:
.....
went_high_y:
BTFSC count_high,7
goto over_flowed
...
>
> The other observation is slightly more serious, I think. If the routine
> exits without incrementing any counters, (enters the routine but the pin
> went or was non-active - zero time) an erroneous result will occur. I think
> the solution is simple: relpace the 'SKPZ' below with 'SKPC'. Of course - I
> might be out to lunch . . .
I thought about that too. The skpc to skpz change won't fix it though.
It may be easier to add a flag that's initialized before the sampling
begins, and is cleared in the loop. Then during the normalization you
can check the flag and process the counters accordingly. It might also
be necessary to sample the IOPORT once before the loop begins and abort
if it's already high. Tell us how you decide to solve it :).
Scott
1998\04\29@005240
by
Dwayne Reid
|
Scott Dattalo wrote:
>I think you can extend the concept to 16 samples (or whatever) per loop
>instead of 8 and do something like this
I'll look at that.
{Quote hidden}>> The other observation is slightly more serious, I think. If the routine
>> exits without incrementing any counters, (enters the routine but the pin
>> went or was non-active - zero time) an erroneous result will occur. I think
>> the solution is simple: relpace the 'SKPZ' below with 'SKPC'. Of course - I
>> might be out to lunch . . .
>
>I thought about that too. The skpc to skpz change won't fix it though.
>It may be easier to add a flag that's initialized before the sampling
>begins, and is cleared in the loop. Then during the normalization you
>can check the flag and process the counters accordingly. It might also
>be necessary to sample the IOPORT once before the loop begins and abort
>if it's already high. Tell us how you decide to solve it :).
Scott - how about a little bit different slant on things. Instead of
shifting the counter bytes over to make room for the LSBs accumulated by
the main loop, why not just add those LSBs to the count, propogating
carries as required. The main loop doesn't have to be a power of 2 states
and allows easy addition of the overflow logic.
That is:
Counter routine that gives 3-cycle resolution:
CLRF count_3lsbs
CLRF count_low
CLRF count_mid
CLRF count_high
loop
BTFSC IOPORT,IOBIT
goto went_high_1st
MOVLW 1
BTFSC IOPORT,IOBIT
goto went_high_2nd
ADDWF count_low,F
BTFSC IOPORT,IOBIT
goto went_high_3rd
RLF count_3lsbs,W ;shift C into W (add 0 or 1 to next byte)
BTFSC IOPORT,IOBIT
goto went_high_4th
ADDWF count_mid,F
BTFSC IOPORT,IOBIT
goto went_high_5th
RLF count_3lsbs,W
BTFSC IOPORT,IOBIT
goto went_high_6th
ADDWF count_high,F
BTFSC IOPORT,IOBIT
goto went_high_7th
CLRWDT
BTFSC IOPORT,IOBIT
goto went_high_8th
SKPC ;test for overflow
BTFSC IOPORT,IOBIT
goto went_high_9th
BTFSS IOPORT,IOBIT
goto loop
went_high_10th
INCF count_3lsbs,F
went_high_9th
INCF count_3lsbs,F
went_high_8th
INCF count_3lsbs,F
went_high_7th
skpnc
goto overflow
SUBWF count_high,F
INCF count_3lsbs,F
went_high_6th
INCF count_3lsbs,F
went_high_5th
tstf count_low ;had low byte wrapped?
skpnz
decf count_mid,F
INCF count_3lsbs,F
went_high_4th
INCF count_3lsbs,F
went_high_3rd
DECF count_low,F
INCF count_3lsbs,F
went_high_2nd
INCF count_3lsbs,F
went_high_1st
MOVF count_3lsbs,W
ADDWF count_low,F
SKPC
goto done
INCFSZ count_mid,F
goto done
INCFSZ count_high,F
goto done
overflow ;wrapped past ff ff ff - hold at ff
movlw ff
movwf count_low
movwf count_mid
movwf count_high
done
Now, having done all that, I think that I see a fundamental problem with
the middle byte in your routine. Assume that the loop terminated at the
6th, or later exits. There is no way of knowing whether the middle byte
had incremented or not: the carry information is lost. In other words,
just because the high byte didn't increment, that doesn't say that the
middle byte didn't also. The middle byte could have incremented without
wrapping. I fixed it by seeing if the low byte was zero at that point.
I think that it will work (I'll try tommorrow, after I've heard your
thoughts).
dwayne
1998\04\29@152622
by
Dwayne Reid
|
Hiya gang. Hiya Scott. The more I muddle with this, the deeper in
trouble I get. My previous 2 attempts were useless, lets see how
this one does.
This is back to Scott's routine, with a few mods.
;up to 19 bit counter routine with 3-cycle resolution:
CLRF count_low
CLRF count_mid
CLRF count_high ;used as known zero for main loop
loop
BTFSC IOPORT,IOBIT
goto went_high_1st
MOVLW 1
BTFSC IOPORT,IOBIT
goto went_high_2nd
ADDWF count_low,F
BTFSC IOPORT,IOBIT
goto went_high_3rd
RLF count_high,W ;get C into W lsb (adding 0 or 1)
BTFSC IOPORT,IOBIT
goto went_high_4th
ADDWF count_mid,F
BTFSC IOPORT,IOBIT
goto went_high_5th
btfss count_mid,5 ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpc = 19
BTFSC IOPORT,IOBIT
goto went_high_6th
nop
BTFSC IOPORT,IOBIT
goto went_high_7th
CLRWDT
BTFSS IOPORT,IOBIT
goto loop
went_high_8th
INCF count_high,F ;count_high now used to accumulate LSBs
went_high_7th
INCF count_high,F
went_high_6th
INCF count_high,F
went_high_5th
btfsc count_high,5 ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpnc =19
goto overflow ;
SUBWF count_mid,F
INCF count_high,F
went_high_4th
INCF count_high,F
went_high_3rd
DECF count_low,F
INCF count_high,F
went_high_2nd
INCF count_high,F
went_high_1st
CLRC
RLF count_low,F ;make room for lower 3 LSBs
RLF count_mid,F
RLF count_high,F ;LSB count gets shifted safely out of the way
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_high,F ;get 3 LSBs that got moved into w
swapf count_high,w
andlw b'00000111'
RRF count_high,F
iorwf count_low,F
goto done
overflow ;do whatever we want here
movlw ff
movwf count_low
movwf count_mid
movwf count_high
done
I'm trying to figure out an easier way to simulate this. Comments anyone?
dwayne
Dwayne Reid <dwayner
KILLspamplanet.eon.net>
Trinity Electronics Systems Ltd Edmonton, Alberta, CANADA
(403) 489-3199 voice (403) 487-6397 fax
1998\04\30@022323
by
Dwayne Reid
|
Scott Dattalo wrote:
>The code looks good (your latest post - 19 bits of dynamic range).
>
>Probably the easiest way to test the code is with the stopwatch.
>Make IOPORT a ram register, single step to the first sample,
>clear the stopwatch, and press F9 (run). After it runs for a while,
>force a break. Then go modify the ram register to where IOPORT
>points. Single step and note the value of the stop watch when
>you break out of the loop. This value should be 3 times the value
>get in the counters.
>
>Repeat this process a few times - perhaps even attempt the timeout.
>
>Scott
Hi again, Scott.
Looking not too bad right now. I found a couple errors: testing the wrong
register for overflow in 1 spot and I wasn't fixing up 'count_high' at the
end of the normalisation routine. I've been simulating for the past couple
hours - no probelms so far, with no more than 1 count error between
calculated and actual count. I'm about to stick the code into a 12c508
driving some LED displays (my standard serial stuff that I have on the
shelf) and I'm going to see if it actually works when I feed the output of a
pulse generator to it.
This is neat stuff, Scott. I can't even begin to thank you for all your help.
dwayne
Here is the code for those interested.
;up to 19 bit counter with 3 cycle resolution
;original concept by Scott Dattalo; this version by Dwayne Reid
CLRF count_low
CLRF count_mid
CLRF count_high ;used as known zero for main loop
loop
BTFSC PULSE
goto went_high_1st
MOVLW 1
BTFSC PULSE
goto went_high_2nd
ADDWF count_low,F
BTFSC PULSE
goto went_high_3rd
RLF count_high,W ;get C into W lsb (adding 0 or 1)
BTFSC PULSE
goto went_high_4th
ADDWF count_mid,F
BTFSC PULSE
goto went_high_5th
;use either of the following lines (not both)
; btfss count_mid,5 ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpc = 19
skpc ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpc = 19
BTFSC PULSE
goto went_high_6th
nop
BTFSC PULSE
goto went_high_7th
CLRWDT
BTFSS PULSE
goto loop
went_high_8th
INCF count_high,F ;count_high now used to accumulate LSBs
went_high_7th
INCF count_high,F
went_high_6th
INCF count_high,F
went_high_5th ;use either of the following lines (not both)
; btfsc count_mid,5 ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpnc =19
skpnc ;5 = 16 bits; 6 = 17 bits; 7 = 18; skpnc =19
goto overflow ;
SUBWF count_mid,F ;undo increment, if any
INCF count_high,F
went_high_4th
INCF count_high,F
went_high_3rd
DECF count_low,F ;undo increment
INCF count_high,F
went_high_2nd
INCF count_high,F
went_high_1st
CLRC
RLF count_low,F ;make room for lower 3 LSBs
RLF count_mid,F
RLF count_high,F ;LSB count gets shifted safely out of the way
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_low,F
RLF count_mid,F
RLF count_high,F
RLF count_high,F ;get LSB count into w
swapf count_high,w
andlw b'00000111'
RRF count_high,F
iorwf count_low,F ;put LSBs into low byte
movlw b'00000111' ;toss extraneous bits - we're done with them
andwf count_high,F
goto done
overflow ;do whatever we want here
movlw 0xff
movwf count_low
movwf count_mid
movwf count_high
done
dwayne
Dwayne Reid <.....dwaynerKILLspam
.....planet.eon.net>
Trinity Electronics Systems Ltd Edmonton, Alberta, CANADA
(403) 489-3199 voice (403) 487-6397 fax
More... (looser matching)
- Last day of these posts
- In 1998
, 1999 only
- Today
- New search...