A generic 32 bit counter

Discuss PIC and electronic related things

Moderators: David Barker, Jerry Messina

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

A generic 32 bit counter

Post by Coccoliso » Sat May 13, 2017 9:03 am

Hi at all,

there is a counter that is incremented automatically by which I can understand how many "ticks" are spent internally in a procedure after I call other works?
I would need it with a resolution as close as possible to uSeconds and as you've been told me to work with an interrupt (like Ticks.bas) at this resolution is impossible.

Thanks

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Sat May 13, 2017 1:05 pm

Getting a 32-bit counter with a pic18 that doesn't involve using interrupts and overhead isn't easy.

If you can live with a 16-bit counter then it's not too bad. Here's what I usually do:
- Pick an unused 16-bit timer. Depending on your device TMR1/3 are usually present, but TMR0 gives a better range if you have that one.
- Set the timer to count FOSC/4 (instruction cycles), and start the timer. Let it free run.

The timer will continuously count up, overflow, and start all over from 0 again.
To time a section of code:
- read the timer. this is 'start_time'
- run the desired code
- read the timer again. subtract this from the start_time and you get elapsed time:

Code: Select all

	word start_time, elap_time
	
	start_time = read_timer()
	<do stuff>
	elap_time = read_timer() - start_time
With no prescaler you're limited to counting 65535 instruction cycles. If you use a prescaler then this can be extended to x16 or even higher, but you loose precision since you're not counting individual cycles anymore.

If you really want to count usecs then you need more hardware involved, ie set TMR2 to run in PWM mode at 1MHz.
Run the output of TMR2 into TMR1 ext input and set TMR1 to count external events. Now TMR1 counts in usecs.

You can come up with all sorts of schemes using multiple timers, gated timers, and the CCP peripherals but they get more and more complex. You could probably rig up one timer to trigger another to get a 32-bit counter, but usually at that point I just toggle an LED and measure it with a scope!

Not exactly what you were looking for, but using a timer this way doesn't involve interrupts or bother your existing code in any way. Do you really need 32-bits? If so, what device are you using and what timers/CCP peripherals are free?

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Sun May 14, 2017 7:14 am

Hi Jerry,

I use a 18F2685 at 40MHz and with HW USART for TX/RX comunications and must use the PWM.
At the moment there is no need to use other timers.
The pulses I have to generate are between 6 and 10 uSec for a 3 axes CNC and clearly logic brings much of the work but I must keep the pulse duration as consistent as possible with the limits.
Placement routines I got from an Arduino project and it is rumored on net that the PIC18 can not do it, maybe I have to use ASM as much as possible for the bresenham algorithm code section.
I could still switch to other MPUs maybe a PIC18F4682.

Thanks in advance Jerry.

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Sun May 14, 2017 3:18 pm

Sorry, I don't know enough about what you're doing to offer any good suggestions.

If you need more horsepower (and you still want the CAN peripheral) you might look at the 18FxxK80 series.
They'll run at 64MHz so you'd get an immediate 50% increase over 40MHz.

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Sun May 21, 2017 4:10 pm

Hi Jerry,

documenting I read that the 18F26K80 (which I have already used and have in my basket and you suggested me) has the features I need (4 CCP / 1 ECPP).
I intend to use a PWM channel with TMR1 as a counter to have the uSec number and I can use another PWM to adjust the spindle speed.

WORK IN PROGRESS :D

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Sun May 21, 2017 10:43 pm

The 26K80 has 5 CCP modules, but it looks like two of them are shared with the CANTX/CANRX lines (CCP3/CCP4).

Take a look at the functions on RB5 (RB5/T0CKI/T3CKI/CCP5). You could use CCP5 as PWM5 output, and then either TMR0 or TMR3 CLKIN on the same pin.

That leaves you with CCP1 and CCP2 to do with as you will. Be careful of the shared PWM timer source (TMR2/TMR4). You'll need one for CCP5.

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Mon May 22, 2017 9:59 am

Hi Jerry,
Jerry Messina wrote:TMR0 or TMR3 CLKIN on the same pin.
without physically connecting the PWM to the counter input?!? :D .. or I figured badly

I was trying with TMR1 and CCP2 because I did not need the CAN but I follow your advice ..
I rewrite everything by setting TMR3 and CCP5.

This MPU is a bomb :shock: .

I worry about that tide of "single shot" , enabling and flip-flop on the TMRx gating.. then CAN pins that can be assigned to other two .. a nightmare when you forget someone and nothing works :|

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Mon May 22, 2017 10:21 am

without physically connecting the PWM to the counter input?!?
I've done that with other chips before and it's worked.

Usually the input functions still work even though you set the pin to output mode... saves you a pin and an external connection but you can still monitor the PWM output to make sure it's working as you expect.

I forgot about the CANMX bit that lets you move the CANTX/RX pins to PORTB. That might be a better choice if you need the other CCP peripherals. Thanks for reminding me!

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Thu May 25, 2017 4:20 pm

Hi Jerry, then..

1) PWM by CCP5 controlled by TMR4 at 1MHz and duty of 50% with output on PORTB.5 .. done
2) TMR3 listen and count .. done

.. all work fine but..

at this point I tried to enable an interrupt in case of TMR3 overflow to lengthen the count period with a recycle counter.
I started to have problems with the Longword value that should return the uSec elapsed (returns values ​​multiplied by 10).

Some ideas about it?

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Thu May 25, 2017 6:19 pm

If you let TMR3 free-run and just subtract two count values from one another then it's limited to 16-bits (65.535ms @ 1us counts). The nice thing about this method is that it's easy to use and accurate. You don't have to worry about starting/stopping the timer or trying to account for any interrupts, counter reloading, etc.

If you want to extend it to 32-bits then you'll have to preload the timer, start it, account for overflows, etc. Also, other interrupt sources may interfere with counting.

Do you really need it to be longer than 65msecs?

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Thu May 25, 2017 7:16 pm

Hi Jerry,

the problem is that the pulses (from 5 to 20 uSec) are in the order of 320000 to move an axis from its 0 to 20 cm and they are 3.
Then to move the 3 axes simultaneously, the one having the largest delta then work on the other two by difference.
In the original project (Arduino / NETMF) I used the ticks differently to check the minimum duration of each single impulse (X / Y / Z) and now I have the problem of passing the counter from 65535 to 0.
Since the duration control is done immediately after each impulse I could check if the new TMR3 value is lower than the previous one and add $FF by accepting the error without using the interrupt.
However in similar projects someone is highly disinterested in this dislocation by putting a nice DelayUS(xuSec) and just enough .. maybe all this is a sophism.
I have to connect stepping motors and try what's going on.
A longer duration than nominal heaters frightfully drivers.

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Fri May 26, 2017 9:40 am

Hi Jerry,

:D GOOD NEWS :D

Finally, optimizing the Longword increment at TMR3's overflow, I managed to get a uSec accuracy using also the interrupt.

Thanks !

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Sat May 27, 2017 4:05 pm

Glad you got it working!

I probably should have mentioned that there's a simpler way that only involves using TMR0, but it only works for some clock settings where you can set the timer to count in usecs.
The module below gives a 32-bit timer (w/1us resolution) with a range of over 71 minutes. There's about 32 instructions of overhead in using it, so that's about 2us @ 64MHz.

EDIT: code removed... had issues

User avatar
Coccoliso
Posts: 152
Joined: Mon Feb 17, 2014 10:34 am

Re: A generic 32 bit counter

Post by Coccoliso » Mon May 29, 2017 7:48 am

Hi Jerry,
I thank you for the answer ... as always exhaustive.

Your solution is definitely more accurate in the time calculation.
I'm noticing that steppers are enough of "wide views" and they are satisfied with impulse "major of" and neglect pulses higher than expected. Clearly considering the number of impulses that are to be generated better than they are as short as possible.
I put your example aside because it can always serve .. if I change and rotate something :D

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: A generic 32 bit counter

Post by Jerry Messina » Mon May 29, 2017 2:23 pm

I pulled the code I had posted before.

There's a problem with the read() function. I had declared it as:
public function read() as usecs

where 'usecs' was the 32-bit counter value. I goofed... you can't do it this way since 'usecs' can be modified by the interrupt routine.

It worked 99% of the time, but if you have just the right timing it fails. I'll repost it later once I get a chance to test it better.

Post Reply