Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Implement Frequency Counter (using reciprocal counting)

Status
Not open for further replies.

Neyolight

Full Member level 5
Joined
Aug 29, 2011
Messages
306
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
World
Activity points
3,624
Hi all

I want to implement a simple frequency counter using the reciprocal counting method using my PIC18F4620. For the past 1 week, I have trying to do it but have failed miserably ! :shock:

So could you guys PLEASE offer me some guidance ! :-|

I know what reciprocal counting is , but not sure how to implement it using PIC18F4620.

Regards
 

Microchip have an app note for this:

https://ww1.microchip.com/downloads/en/devicedoc/41214a.pdf

Basically, you use the a CCP to capture a rising edge (it initiates an interrupt that you can use), record the timer value, then wait for the next rising edge capture interrupt and record the time again. You now have the period.

That's assuming that the period is slow enough not to overflow the counter more than once. You can deal with once by using the timer overflow flag.

If it is too fast for that then you can set the capture to be on every fourth rising edge, giving four times the frequency capability but a quarter of the resolution.
 
Read through that PDF you linked- Its interesting but opposite to what I want.

I want CCP to Capture my internal clock ticks during a "time span". Is that even possible to do so ?

From the PDF CCP module can work in capture mode for 16-bit value of Timer 1 and Time 3. I am currently using Timer 1 to create the "time span". Timer 3 is sort of linked with Timer 1. I cannot make Timer 3 increment on internal clock when Timer 1 is incrementing on external input.

I just need a way to capture internal clock cycle in a give time span! Currently Im using Timer 0 and its giving 300 points more than what I expect and also the readings arent stable !
 

The problem would be clearer if you mention the involved signal frequency and clock frequency, intended measurement resolution and duration.
 

Sure, here are the details :

1) Signal frequency 122 Khz

2) Fosc = 8Mhz

3) I measure for 100 input signal rising edges - This is 99 T, should give me 6491 ticks, but I get something 6700 ( rapidly changing as well)

I think I figured out my problem but not sure how to rectify it. I will post my problem with a diagram here in a while !
 

I don't understand why you are using timer 1 to create a 'time span'. Isn't the 'time span' the period of the waveform that you want to measure?

Read through that PDF you linked- Its interesting but opposite to what I want.

I think it does exactly what you have asked - it implements a reciprocal counter using Timer1 and the CCP peripheral.

I want CCP to Capture my internal clock ticks during a "time span". Is that even possible to do so ?

That's exactly what the example is doing... The 'time span' in the example is defined as the time from one rising edge on CCP to the next. That is the period of the waveform that you want to measure by reciprocal counting.

From the datasheet: "In Capture mode, the CCPRxH:CCPRxL register pair captures the 16-bit value of the TMR1 or TMR3 registers when an event occurs on the corresponding CCPx pin."

Timer1's prescaler is configured to count for the maximum period you expect without overflowing, CCP is configured to capture (and set interrupt) on each rising CCP edge. So, on the first rising edge it captures the timer1 value and your code uses the ISR to copy that value into a variable. On the next rising CCP edge, the CCP captures the Timer1 value again and your code records it, subtracting the first variable. You now have the period in clock cycles.

Hence, you have measured the period by reciprocal counting.

---------- Post added at 22:38 ---------- Previous post was at 22:34 ----------

[I typed my reply before seeing the above extra posts]

OK, so you want to count 100 periods. See the next chapter in the pdf - averaging. You could either run a running total/average as-is, or set the CCP to capture every 4th (and run for 25 lots of that)

Hmm... running the CPU at 8MHz (so 2MHz Fosc/4) will not be very good at catching the edges. I would use CCP in 16th rising edge mode (you get 16x better accuracy ) and live with a multiple of 16 instead of 100.

Are you sure you would not be better simply running the counter from the waveform and counting for a set time?
 
Last edited:
O.K. that's classical multi-period counting and should work well with PIC18 CCP. We would need to look at the code details to see what's wrong. Did you verify that the input signal to processor has clear edges and stable pulse width?
 

All-right in the image attached, I have my square input signal. Timer 1 starts to increment ( for 100 cycles) at the first rising after detecting a falling edge. In the image, timer 1 will starts incrementing at "green" arrow. To the contrary I start capturing internal clock cycle as I get the input (BROWN ARROW). This may have cause output to vary rapidly. What do you guys think?

How do I start capturing my internal clock at the first rising edge after a falling edge i.e at "green" arrow ?

Thanks !
 

Attachments

  • image 2.png
    image 2.png
    8.4 KB · Views: 105

Did you verify that the input signal to processor has clear edges and stable pulse width?

Yes, my input to the PIC is 4 V p-p square wave and its stable as well
 

Using CCP won't involve starting and stopping a clock. You get cycle accurate timestamps from selectable input signal edges. Using the prescaler feature, as suggested by FoxyRick allows to perform the multi-period measurement with a single timer.
 

Hmm... running the CPU at 8MHz (so 2MHz Fosc/4) will not be very good at catching the edges. I would use CCP in 16th rising edge mode (you get 16x better accuracy ) and live with a multiple of 16 instead of 100.

Are you sure you would not be better simply running the counter from the waveform and counting for a set time?

My bad, Im using PLL so Fosc = 32 Mhz and Internal clock = 8 Mhz. I actually have a frequency counter ( conventional method) that works well - but its too slow for my application and hence Im shifting to reciprocal counting.

I am making Timer 0 increment on internal clock , Timer 1 captures the input and set time frame ( 100 rising edges). Timer 1 overflows after 100 cycle and then I read timer 0 to see how many clock cycles I have in it!
 

You could:

  • Use the ISR from the CCP rising edge, in any prescaler mode
  • Record the very first timer1 captured value, and increment a counter variable
  • When the counter reaches 100 (or less if using prescaler), record the timer1 captured value again
  • You now have the time for 100 cycles

Just make sure that the ISR is quicker than a period of your waveform.

As to the falling/rising edge - could you just ignore the first rising edge (in the ISR, using the counter) to circumvent having to detect a falling edge first?
 

Timer 1 overflows after 100 cycle and then I read timer 0 to see how many clock cycles I have in it!
How? By polling the timer or a timer interrupt? That would be pretty inacurate. In this case, you should learn how to utilize CCP for exact timing measurements.
 

You could:

  • Use the ISR from the CCP rising edge, in any prescaler mode
  • Record the very first timer1 captured value, and increment a counter variable
  • When the counter reaches 100 (or less if using prescaler), record the timer1 captured value again
  • You now have the time for 100 cycles

Just make sure that the ISR routing is quicker than a period of your waveform.

As to the falling/rising edge - could you just ignore the first rising edge (in the ISR, using the counter) to circumvent having to detect a falling edge first?

I think I am already doing something similar- will try to capture timer 1 value now ! But this wouldn't solve my problem I described in the image (Post 8 ) , would it ?

I think my time stamp is accurate, its just timer 0 that starts to increment before 1st rising edge thats creating random values?

---------- Post added at 12:10 ---------- Previous post was at 12:08 ----------

How? By polling the timer or a timer interrupt? That would be pretty inacurate. In this case, you should learn how to utilize CCP for exact timing measurements.

I feed 65435 into Timer 1 at beginning of interrupt! It increments to 65535 - 100 rising edges !
 

What are you programming this in? Assembler, C, ...?

When the ISR for Timer1 runs, how many clock cycles (and possibly waveform periods) are there from the actual overflow, until you read the value in Timer0?

That's the key thing with the CCP capture - it captures the clock value instantly so you can read that captured value later, in the ISR, without concern for how long things take in between.
 
Last edited:

What are you programming this in? Assembler, C, ...?

When the ISR for Timer1 runs, how many clock cycles (and possibly waveform periods) are there from the actual overflow, until you read the value in Timer0?

That's the key thing with the CCP capture - it captures the clock value instantly so you can read that captured value later, in the ISR, without concern for how long things take in between.

Coding in C.

Not really sure about " When the ISR for Timer1 runs, how many clock cycles (and possibly waveform periods) are there from the actual overflow, until you read the value in Timer0? " How can I figure that out?
 

It depends on whether you are using interrupt priority, and if you do things like calling another function from inside the ISR. Remember that when an ISR is called, the MCU was busy doing something else and so needs the context saving. That can be minimal and quick (possibly even zero cycles) to quite long - like 50 instruction cycles for a full context save!

Check your compiler's reference on interrupts and latency. It might not be your issue but is something to be aware of if using interrupts the way you are.
 
Allright, so Im trying to use CCP now ! Now that I know what it does, it kinda seems silly what I was trying to do before =P

Anyway, I have my input at RC1 (CCP1) and timer 1 increment at internal frequency (8MHZ). I still dont get correct ouput! I have a figure attached below from PIC18F4620 spec! I dont get what " Q1: Q4" is. I have defined CCP1CON <3:0> to capture mode every rising edge (0101).

I get a value 6000-7000 more than excepted ! What could I be possibly doing wrong?
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top