CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Workaround for timer latency
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

Workaround for timer latency
PostPosted: Wed Jan 19, 2005 4:09 pm     Reply with quote

Hello,

As many of you (as far I seen in the forum), I have discovered that timer as a blind latency due to context saving... Ok great it answers the question I had from long time : why my 69.5us timer is doing a 79us time.
I have seen a lot of answers from Ttelmah and also one from Mark explaining this problem and possible workaround : adding value to the timer, ccp usage, soft counter usage.
Ok but I have dificulties to understand all of them :
adding value to the timer
Ok here is the solution I thought I have understood...but I have done the following trials (quick and dirty code, teh final goal is not to generate output pulse but internal timing)
Code:
#use delay(clock=16000000)       // 16 MHz OSC




int1 debug_pin1;


#INT_TIMER0
void timer_interrupt(void) //4800*3 /sec , 1/(4800*3) = 69.444us => 69.5us by dividing by 4*2 + overflow at 139
{

//set_timer0(256-139);  //cause around 10us time more
set_timer0 (get_timer0()+256-139);

if (debug_pin1 == 0) debug_pin1 = 1;
else debug_pin1 = 0;
output_bit (LED, debug_pin1);
return;
}




void main (void)
{

  int1 delire;
  setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_2);
  //setup_counters (RTCC_INTERNAL, RTCC_DIV_2);
  enable_interrupts (INT_TIMER0);
  enable_interrupts (GLOBAL);
  set_timer0(256-139);
  set_tris_b (LED_WRITE);
  debug_pin1 = 0;
 
  while (1)
    {
 if (delire == 0) delire = 1;
else delire = 0;
    }
}

and in the fact, at the output, the level 1 (debug_pin1 = 1) has the right time : around 69us. But the level 0 has still the 79us time (?!)... So still open question here.

ccp usage
Really do not precisely understand the idea behind..may-be it is really not accurate for my purpose....check http://www.ccsinfo.com/forum/viewtopic.php?t=21479&highlight=timing+interrupt

Counter usage
http://www.ccsinfo.com/forum/viewtopic.php?t=18175&highlight=latency
here also, I am not so sure it is accurate for my purpose...

Thanks
Pac
Haplo



Joined: 06 Sep 2003
Posts: 659
Location: Sydney, Australia

View user's profile Send private message

PostPosted: Wed Jan 19, 2005 6:26 pm     Reply with quote

Not an answer to your question, but a suggestion. If you need a very precise timer interrupt, you can use #INT_GLOBAL. This stops the Compiler from generating any context saving/dispatching code:


Quote:
#INT_GLOBAL
Syntax: #int_global
Elements: None
Purpose: This directive causes the following function to replace
the compiler interrupt dispatcher. The function is
normally not required and should be used with great
caution. When used, the compiler does not generate
start-up code or clean-up code, and does not save the
registers.
Examples: #int_global
isr() { // Will be located at location 4
#asm
bsf isr_flag
retfie
#endasm
}
Example Files: ex_glint.c
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 1:39 am     Reply with quote

Interesting information...even if for me I prefer to have the classical context savings....
In fact I do not understand why my code with get_timer0() doesn't work well (in fact it is working half time)...
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 2:45 am     Reply with quote

Are you using a processor from the PIC16 or PIC18 series? I'm asking this because of the different overheads in interrupt processing for both processor lines.

Code:
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_2);
Please add RTCC_8_BIT. For the PIC18 series this is compulsory or you'll get a 16-bit timer, for the PIC16 series it's just a nice add-on.

You are not showing your whole program. Are you sure there is no other interrupt interfering?
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 4:00 am     Reply with quote

Sorry I miss to include the "#include" line, but except this mistake this is the whole code...
I am using a PIC16F876A so no choice : timer 0 is a 8Bit counter
no other interrupt
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 4:25 am     Reply with quote

Quote:
Sorry I miss to include the "#include" line, but except this mistake this is the whole code...
I still can't compile; LED and LED_WRITE are missing too. Please post these as well.

Looking at your code, I think the timing error is in the way you meassure the data. Am I right when I assume you are only meassuring the first pulse? The first pulse has the interrupt overhead included but following pulses would be correct. It is quiet difficult in this setup to get the first pulse correct, the only way I can think of is by hard coding a correction factor, but newer compiler releases might affect this.
Is it important to you to have the very first pulse exact?


Last edited by ckielstra on Thu Jan 20, 2005 4:36 am; edited 1 time in total
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 4:32 am     Reply with quote

Really strange... my goal wa to do a copy paste of my whole code but clearly lines are missing...
I am at work and to not have access to my code here...hummmm let me try...yes I have the info needed...here is the part missing (hope it will be ok this time)
Code:

#include <16F876A.H>
#use fast_io(B)
#device *=16
#fuses HS,PUT,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOBROWNOUT

#define RS232_XMIT       PIN_C6
#define RS232_RCV       PIN_C7       // PIC line which receives PC transmission
#define LED               PIN_B1
#define LED_WRITE       0x0

#use delay(clock=16000000)       // 16 MHz OSC
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 6:44 am     Reply with quote

Now your code is complete and compiles.

You didn't answer my two questions.

Code:
set_timer0 (get_timer0()+256-139);

Note that 256 is a 16-bit constant. The CCS preprocessor is terrible and does a bad job of resolving constants, resulting in 16-bit runtime calculations. It takes an incredible 15 instructions to read and update the timer. At 16MHz that's an error of 3,75us.
Change to
Code:
unsigned int8 TMR0;
#locate TMR0=0x0001

TMR0 += (int8)(256-139);
Which is just 2 instructions.... And, taking in account your RTCC_DIV_2, you can even correct for that by changing to:
Code:
TMR0 += (int8)(256-139+1);
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 6:48 am     Reply with quote

Quote:

Looking at your code, I think the timing error is in the way you meassure the data. Am I right when I assume you are only meassuring the first pulse?

No I am measuring pulse some time after and so I am sure I do not see the first one...second when I trace with my scope, I see several pulse, so clearly the error is not comnig from there....But it was better to clarify
Quote:

Is it important to you to have the very first pulse exact?

Not at all...
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 6:50 am     Reply with quote

ckielstra wrote:
Now your code is complete and compiles.

You didn't answer my two questions.

Code:
set_timer0 (get_timer0()+256-139);

Note that 256 is a 16-bit constant. The CCS preprocessor is terrible and does a bad job of resolving constants, resulting in 16-bit runtime calculations. It takes an incredible 15 instructions to read and update the timer. At 16MHz that's an error of 3,75us.
Change to
Code:
unsigned int8 TMR0;
#locate TMR0=0x0001

TMR0 += (int8)(256-139);
Which is just 2 instructions.... And, taking in account your RTCC_DIV_2, you can even correct for that by changing to:
Code:
TMR0 += (int8)(256-139+1);


Ok interesting to know.... but it should not cause the error I have, no?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

Re: Workaround for timer latency
PostPosted: Thu Jan 20, 2005 7:16 am     Reply with quote

darrepac wrote:
Hello,

As many of you (as far I seen in the forum), I have discovered that timer as a blind latency due to context saving... Ok great it answers the question I had from long time : why my 69.5us timer is doing a 79us time.
I have seen a lot of answers from Ttelmah and also one from Mark explaining this problem and possible workaround : adding value to the timer, ccp usage, soft counter usage.
Ok but I have dificulties to understand all of them :
adding value to the timer
Ok here is the solution I thought I have understood...but I have done the following trials (quick and dirty code, teh final goal is not to generate output pulse but internal timing)
Code:
#use delay(clock=16000000)       // 16 MHz OSC




int1 debug_pin1;


#INT_TIMER0
void timer_interrupt(void) //4800*3 /sec , 1/(4800*3) = 69.444us => 69.5us by dividing by 4*2 + overflow at 139
{

//set_timer0(256-139);  //cause around 10us time more
set_timer0 (get_timer0()+256-139);

if (debug_pin1 == 0) debug_pin1 = 1;
else debug_pin1 = 0;
output_bit (LED, debug_pin1);
return;
}




void main (void)
{

  int1 delire;
  setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_2);
  //setup_counters (RTCC_INTERNAL, RTCC_DIV_2);
  enable_interrupts (INT_TIMER0);
  enable_interrupts (GLOBAL);
  set_timer0(256-139);
  set_tris_b (LED_WRITE);
  debug_pin1 = 0;
 
  while (1)
    {
 if (delire == 0) delire = 1;
else delire = 0;
    }
}

and in the fact, at the output, the level 1 (debug_pin1 = 1) has the right time : around 69us. But the level 0 has still the 79us time (?!)... So still open question here.

ccp usage
Really do not precisely understand the idea behind..may-be it is really not accurate for my purpose....check http://www.ccsinfo.com/forum/viewtopic.php?t=21479&highlight=timing+interrupt

Counter usage
http://www.ccsinfo.com/forum/viewtopic.php?t=18175&highlight=latency
here also, I am not so sure it is accurate for my purpose...

Thanks
Pac


Should be exactly the same. Maybe you counting rise and fall times in the 0 state? Try this, toggle the output pin every other cycle. If what you say is true, then I would expect the level 1 time to be 69+79 = 148us.

[/code]
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 7:21 am     Reply with quote

Excuse-me Mark, but I have difficulty to understand your idea...Could you elaborate more?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Jan 20, 2005 7:38 am     Reply with quote

darrepac wrote:
Excuse-me Mark, but I have difficulty to understand your idea...Could you elaborate more?


Code:

void timer_interrupt(void) //4800*3 /sec , 1/(4800*3) = 69.444us => 69.5us by dividing by 4*2 + overflow at 139
{

  static int8 count=0;

  set_timer0 (get_timer0()+256-139);
 
  count++;
  if (count == 2)
  {
    output_high(LED);
  }
  else if (count == 4)
  {
    output_low(LED);
    count = 0;
  }
  return;
}


But this is how I would do it

Code:


unsigned int8 TMR0;
#locate TMR0=0x0001

#INT_TIMER0
void timer_interrupt(void) 
{

  static int1 toggle=0;

  TMR0 += 117; //(256-139);
 
  if (toggle)
  {
    output_high(LED);
    toggle = 1;
  }
  else 
  {
    output_low(LED);
    toggle = 0;
  }
  return;
}
darrepac



Joined: 19 Jan 2005
Posts: 22

View user's profile Send private message

PostPosted: Thu Jan 20, 2005 8:02 am     Reply with quote

Ok I understand that you want me to do somehow a frequency divider by 2...ok I can try and see the level 0 and 1 time in that case...
But for
Quote:
Maybe you counting rise and fall times in the 0 state?
what do you mean exactly?
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Jan 20, 2005 8:12 am     Reply with quote

darrepac wrote:
Ok I understand that you want me to do somehow a frequency divider by 2...ok I can try and see the level 0 and 1 time in that case...
But for
Quote:
Maybe you counting rise and fall times in the 0 state?
what do you mean exactly?


Signals don't change instantaneous. It takes a certain amount of time for this to occur. Inductance and Capacitance play a big role in this. The rise/fall time can also be called the slope of the line. Rise time is the amount of time it takes for the signal to go from the low level to the high level. The fall time is the time it take to go from the high level to the low level.

For your original code, try measuring the time between the rising edges. See if you get 138us or 148us.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group