COUNT command: possible accuracy issue?

kranenborg

Senior Member
Dear forum members

After some experimentation it seems to me that I cannot obtain the count accuracy as I should get according to the spec of the COUNT command. According to this spec, for a 64MHz 28X2 (with a very accurate crystal, see my recent Accurate Frequency Counter project) the following holds for the COUNT command:

* 400Khz max frequency for the incoming signal (2.5us)
* The unit of time for the sampling period used by the COUNT command: 62.5 us

So I fed a 400KHz signal to the count command with this sampling period. Since I had noticed a problem I also ran the count command with the frequency signal divided by 2 and by 4 (using a 74HC4040), and increased the sampling period to 125us and 250us respectively (to obtain the same number of counts). In all of these three cases the estimated frequency (= CountValue*divider/samplingperiod) should be really close to 400KHz. This is what I got as result as the calculated frequency based on the count value:

Divide: Sampl.period: CalcFreq (Khz):
1 (=400Khz) 62.5ms (=1x) 380.5
2 (=200KHz) 125ms (=2x) 398.7
4 (=100KHz) 250ms (=4x) 399.6

From this I think the following can be concluded:
  1. The upper limit frequency (for a single time unit) is likely much lower than 400KHz (as indicated by the first result but also by the second; even at 200KHz (divider 2) likely some signal transitions are missed.
  2. The effect of multiple time units (of 62.5us) used in a single sample period is probably very limited (maybe in the transition between time units a few counts are missed ...)

I checked the effect of DISCONNECT, it has some very minimal effect but certainly does not explain the large deviations in the first two cases.
For a test at 4MHz I got a similar result: with a divider of 16, resulting in an effective frequency of 250KHz fed to the counter (which is way lower than 400 KHz) and measurement time of 250ms I obtained an estimated frequency of 3.93Mhz instead of 4MHz, which falls in line with the results in the table

So how can we explain these results in the light of these specs:
  • Maybe the upper limit of 400KHz is incorrect and much lower?
  • Maybe some other processes interrupt the COUNT command, even within a single unit of time (62.5us at 64MHz), and if so, can they be disabled/controlled?
Does somebody know how the COUNT command is implemented, and does somebody have hints to get to the desired accuracy?

Thanks!
Jurjen Kranenborg
 

AllyCat

Senior Member
Hi,

I've never used X2s or the COUNT command, but I'm fairly sure that, like PULSOUT (and PAUSEUS), it is timed by precise Assembler code, exactly 10 PIC instructions (= 40 clock cycles) between Pulse integer counts, but 20 instructions between Edge-testing in the COUNT command (hence a minimum of 160 clock cycles for each count increment during the monitoring period). I don't know how the "window" period is controlled, but COUNT will always have a variation of +/- 1 count, depending on the delay between the start of the window and the first valid input edge (I doubt if the assembler code is clever enough to work with both edges).

I have always considered COUNT and PULSOUT to be "blocking" commands but in a thread a few months ago, I believe hippy said that it was not blocking because interrupts are NOT disabled. It surprised me that PULSOUT might not be "accurate", but I don't know which interrupts are normally active (particularly with X2s). However, the test for a new Program Download occurs BETWEEN instructions, so I wouldn't expect a DISCONNECT to make any difference. I do know that with M2s, the Timer 1 interrupt (every 20 ms), which is used for the "time" variable and Servo pulses, continues to run even if a DISABLETIME is executed.

As an alternative, I would look to some of the base PIC hardware modules, such as the "Timer 1 Gate" function which is available on all M2s (I don't know about X2s). Timer 1 normally increments at the PIC Instruction rate (i.e. 40 times faster than COUNT) but can accept an external input and can be gated by pin-hardware (perhaps driven from a PWM output), all controlled by SFR commands. You would need to check the "base PIC" data sheet for your X2, but I gave details of the M2 module in post #10 of this thread. Another possibility is the TOUCH hardware, which basically has an oscillator (that you could over-ride) and a gated period from an internal timer. But I believe the X2 Touch hardware is different to that in M2s, giving only a 10 bit result, unlike the M2's 16 bits.

Cheers, Alan.
 

kranenborg

Senior Member
Thanks Allycat, indeed trying to use the hardware modules as much as possible would likely be the best way to circumvent timing issues in the software implementation, and I will look further in that direction. Maybe - since the 28X2 has both Timer1 and Timer3 available - a setup is possible where one of them acts as a gated counter with the frequency-to-be-measured signal as gate input, and the other timer as a very accurate (driven by the crystal oscillator) fixed-length timer that stops the counter at a predefined time interval (also purely by hardware). This would then imply a hardware implementation of the COUNT command. Will dive into the PIC datasheet to see what is possible, I know my way around there ...

Maybe Technical would be willing to elaborate more on the practical accuracy of COUNT, PULSOUT as compared to the specs in my post (and maybe possible ways to improve on their accuracy towards the spec as well)

BTW: for those who need info on timer usage, the following link may be useful: Hardware timers utilization in the PICAXE
 

tmfkam

Senior Member
Hello.

Sometime back I wrote a PicAxe program that used the Count function to allow measurement of the frequency of the electricity supply to within a few milliHertz. I have since re-written that program for the base PIC processor, using another BASIC dialect. I was inspired by a MicroChip Compiled Tips 'N Tricks Guide PDF that was mentioned on a forum that I subscribe to.

Chapter 3, Section 1 describes how to use the CCP module to capture the rising and falling edges of a square wave, using a timer module to time the width of those pulses, and so calculate the frequency.

I'm sure if you read that article, the information will be valuable and allow you to achieve your goals.

For as much as it is worth, here's the code I used in my frequency meter as written in for the base PIC (it is not PicAxe BASIC and so won't compile for PicAxe). As the time taken to measure a nominal 50Hz period gets close to the timer overflow, I had to test to see if two concurrent overflow events had occurred before assuming that no signal was present. A 400kHz waveform would not require this double overflow test. Hopefully, you'll get the idea and be able to implement something similar in PicAxe BASIC.

Code:
InitTimer1 OSC, PS1_2              'Changed to PS1_2 for 250ns resolution

On Interrupt Timer1Overflow Call Overflowed

Sub GetFreq
    GetRising
    Let FreqTotal = Pulse_Width
    GetFalling
    Let FreqTotal = FreqTotal + Pulse_Width
End Sub

Sub GetRising

    Let Pulse_Width = 0
    Let OverFlow = 0
    'Configure CCP1  to Capture rising edge
    Let CCP1CON    = 5   '00000101
    StartTimer       1
    Let CCP1IF     = 0

    Do While CCP1IF = 0    'Wait for rising edge
    Loop

    Let TMR1H  = 0
    Let TMR1L  = 0   'Clear timer to zero
    Let OverFlow = 0

    CCP1IF  = 0      'Clear flag
    'Configure CCP1 to Capture Falling Edge
    CCP1CON = 4  '00000100'

    Do While CCP1IF = 0   'Wait for falling edge
    Loop

    StopTimer 1            'Stop the time
    Let Pulse_Width = Timer1   'Save the timer value
    Let CCP1IF = 0             'Clear the CCP1 flag

End Sub

Sub GetFalling

    Let Pulse_Width = 0
    Let OverFlow = 0
    'Configure CCP1  to Capture falling edge
    Let CCP1CON    = 4   '00000100

    StartTimer       1
    Let CCP1IF     = 0

    Do While CCP1IF = 0    'Wait for falling edge
    Loop

    Let TMR1H  = 0
    Let TMR1L  = 0   'Clear timer to zero
    Let OverFlow = 0

    CCP1IF = 0             'Clear flag
    'Configure CCP1 to Capture rising Edge
    CCP1CON = 5  '00000101'

    Do While CCP1IF = 0   'Wait for rising edge
    Loop

    StopTimer 1            'Stop the time
    Let Pulse_Width = Timer1   'Save the timer value
    Let CCP1IF = 0             'Clear the CCP1 flag

End Sub

Sub Overflowed
    Let OverFlow = OverFlow + 1
    If OverFlow > 1 Then
        Let CCP1IF   = 1
        Let OverFlow = 0
    End If
End Sub
Here's a link to the MicroChip PDF:
MicroChip Compiled Tips 'N Tricks
 
Top