IPB

Welcome Guest ( Log In | Register )

> Best Method For Accumulated Timer
soft2
post Dec 18 2007, 03:40 AM
Post #1


Regular
*

Group: EstablishedMember
Posts: 62
Joined: 29-September 07
From: Vermont
Member No.: 3,810



There are several threads discussing timer issues, implementing free running timers, etc. I use different methods depending on the app... and hoping some of you can help me find the best method for my current project.

Using a PIC18xxxx at 20 Mhz, Timer 1 prescaled 1:4 provides adequate resolution (approx 1 uS). The timer is used by several things at once, some of them measuring intervals of several minutes, so I can't reset it. My question is what is the most efficient method of storing and retrieving the accumulated time? Note that it is not required to be in sync with real time. I created a global variable that is incremented each time Timer 1 overflows on interrupt. I would like to have a handy object that I can use most anywhere to give me the current accum time count. There are a few ways i can do this:

CODE
// global counter incremented each time tmr1 overflows
volatile unsigned int uTimer = 0;

// here is a handy variable we can use every time we need to access the accumulated time
#define TIMER    (uTimer*65536 + tmr1l + tmr1h*256)

void interrupt( void )
{
    //Handle timer1 interrupt
    if( pir1 & (1<<TMR1IF) )
    {
        uTimer++;            // increment ulTimer
        clear_bit( pir1, TMR1IF );    //clear timer1 interrupt bit
    }
}


There are at least 2 problems with defining TIMER this way. First it's not efficient - multiplying 16 and 32 bit numbers is slow and hogs code space. Tried shifting bits but the way the compiler implements << it was actually slower than multiplying! Probably the algorithm I used huh.gif . I have to use TIMER many times in the code. The other problem is that every once in 65000 cycles the interrupt will fire before it finishes calculating TIMER, producing an inacurate result.

I tested several variations of functions for TIMER() that returned unsigned long. None of them effectively solve the problem that on rare occasion the interrupt can roll over before completing the result, but some were a lot faster and smaller. I cobled one solution together that borrowed code from MAKESHORT( dst, lobyte, hibyte ) that worked the best but I don't know asm (although lots of experience with c/c++). I would prefer something that didn't require a function with the resulting overhead.

How do you solve this problem? OK I can go with an Arm7 solution w/ 32 bit processing at 40 Mhz. But this app runs on small batteries and for other reasons I want to use a PIC.

Thanks
update SourceBoost release 6.97 is available.
Download Now
Go to the top of the page
 
+Quote Post
 
Start new topic
Replies
Orin
post Dec 18 2007, 05:40 PM
Post #2


Regular
*

Group: EstablishedMember
Posts: 55
Joined: 17-November 07
Member No.: 3,897



QUOTE (soft2 @ Dec 17 2007, 07:40 PM) *
There are several threads discussing timer issues, implementing free running timers, etc. I use different methods depending on the app... and hoping some of you can help me find the best method for my current project.

Using a PIC18xxxx at 20 Mhz, Timer 1 prescaled 1:4 provides adequate resolution (approx 1 uS). The timer is used by several things at once, some of them measuring intervals of several minutes, so I can't reset it. My question is what is the most efficient method of storing and retrieving the accumulated time? Note that it is not required to be in sync with real time. I created a global variable that is incremented each time Timer 1 overflows on interrupt. I would like to have a handy object that I can use most anywhere to give me the current accum time count. There are a few ways i can do this:

CODE
// global counter incremented each time tmr1 overflows
volatile unsigned int uTimer = 0;

// here is a handy variable we can use every time we need to access the accumulated time
#define TIMER    (uTimer*65536 + tmr1l + tmr1h*256)

void interrupt( void )
{
    //Handle timer1 interrupt
    if( pir1 & (1<<TMR1IF) )
    {
        uTimer++;            // increment ulTimer
        clear_bit( pir1, TMR1IF );    //clear timer1 interrupt bit
    }
}


There are at least 2 problems with defining TIMER this way. First it's not efficient - multiplying 16 and 32 bit numbers is slow and hogs code space. Tried shifting bits but the way the compiler implements << it was actually slower than multiplying! Probably the algorithm I used huh.gif . I have to use TIMER many times in the code. The other problem is that every once in 65000 cycles the interrupt will fire before it finishes calculating TIMER, producing an inacurate result.

I tested several variations of functions for TIMER() that returned unsigned long. None of them effectively solve the problem that on rare occasion the interrupt can roll over before completing the result, but some were a lot faster and smaller. I cobled one solution together that borrowed code from MAKESHORT( dst, lobyte, hibyte ) that worked the best but I don't know asm (although lots of experience with c/c++). I would prefer something that didn't require a function with the resulting overhead.

How do you solve this problem? OK I can go with an Arm7 solution w/ 32 bit processing at 40 Mhz. But this app runs on small batteries and for other reasons I want to use a PIC.

Thanks


Use a union. It's what unions are for:

CODE
typedef  struct _access {
         unsigned char lowByte;
         unsigned char midByte;
         unsigned int    highWord;
   } access;

typedef union _timerUnion {
    unsigned long longVal;
    access           bytes;
} timerUnion;

timerUnion theTimer;

#define TIMER (theTimer.bytes.lowByte = tmr1l, theTimer.bytes.midByte = tmr1h, theTimer.longVal)
#define uTimer theTimer.bytes.highWord


Yes, it's kind of messy with the typedefs, but on the PIC16 version of the compiler at least, the syntax works. I didn't succeed with the PIC16 compiler putting a structure definition inside a union. YMMV with the PIC18.

The TIMER definition uses on the comma operator and has the value of the last expression, ie. theTimer.longVal. It would be more readable if it was split into two defines:

#define READTIMER theTimer.bytes.lowByte = tmr1l; theTimer.bytes.midByte = tmr1h;
#define TIMER theTimer.longVal

Then you could do the following:

READTIMER;
/* expression involving TIMER */

I used unions and defines in a similar way to pick apart packet headers in a protocol for the nRF2401 wireless chip. It works fine, has no overhead over accessing any other global variable, and realisticly, should produce the same code as doing it by hand in assembly.

Orin.

This post has been edited by Orin: Dec 19 2007, 08:07 AM
Go to the top of the page
 
+Quote Post
soft2
post Dec 19 2007, 06:00 AM
Post #3


Regular
*

Group: EstablishedMember
Posts: 62
Joined: 29-September 07
From: Vermont
Member No.: 3,810



Orin, I see you corrected the second typedef... Have you ever been able to get the comma operator to work like this on any Boot C compiler? Thanks.

This post has been edited by soft2: Dec 20 2007, 03:39 AM
Go to the top of the page
 
+Quote Post
Orin
post Dec 19 2007, 04:57 PM
Post #4


Regular
*

Group: EstablishedMember
Posts: 55
Joined: 17-November 07
Member No.: 3,897



QUOTE (soft2 @ Dec 18 2007, 10:00 PM) *
QUOTE (Orin @ Dec 18 2007, 05:40 PM) *
Use a union. It's what unions are for:
...


Orin,
Clever use of the comma operator. I didn't know you could do that. cool.gif
Assuming the second typedef is a union...
The Boost C compiler has a problem with the TIMER definition. I haven't had time to fiddle with it yet... Maybe someone knows what it needs to compile?? for example, using TIMER like this:
CODE
timeElapsed = TIMER - ulRefTime;

generates error: missing right paren

I will spend more time with it tomorrow...

Thanks!


Well, you can do that with some C compilers... I don't actually see the comma operator documented in the BoostC docs.

I fixed the typedef - it is a union.

The following does work on the 16C compiler:

#define READTIMER theTimer.bytes.lowByte = tmr1l; theTimer.bytes.midByte = tmr1h;
#define TIMER theTimer.longVal

READTIMER;
timeElapsed = TIMER - ulRefTime;

I was trying to preserve the original syntax. I wouldn't normally use the comma operator like that, it doesn't make very readable code.

Orin.
Go to the top of the page
 
+Quote Post

Posts in this topic


Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 



Lo-Fi Version Time is now: 3rd September 2010 - 02:49 PM