MC9S12XEP100, problem with TIM that seems to freeze sometimes

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MC9S12XEP100, problem with TIM that seems to freeze sometimes

440 Views
Rhapsody
Contributor III


Dear All,

I've implemented a firmware that is running well but sometimes I have an issue.

I've implemented a sleep routine like this:

 

void sleep_us(uint us) {   uint target;   uchar overflow;   uint now;    TIM_TFLG2_TOF = 1;   target = TIM_TCNT + us;   if (TIM_TCNT > target) {   while(TIM_TFLG2_TOF == 0);   TIM_TFLG2_TOF = 1;   }   while(TIM_TCNT < target); }

 

This routine is used to sleep a specified amouth of microseconds.

It is then used to implement the sleep_ms routine that is like this:

 

void sleep_ms(uint ms) {   uint i;   for (i = 0; i < ms; i++) sleep_us(1000); }

 

Everything seems to go just fine, but sometimes the sleep_ms sleeps for more time than required. For example, even if I require a sleep of 1000 ms it could happen that the sleep_ms blocks for some seconds.

While calling the sleep_us and sleep_ms there are two PIT active along with their interrupt service routine, but I don't think that they could justify the so-long sleep interval.

 

The timer init configuration is set using a prescaler in order to have a 1us period.

 

void timer_init() {      TIM_TSCR1_PRNT = 1;       TIM_PTPSR = 0x2f;       TIM_OCPD = 0xff;           TIM_TSCR1_TEN = 1;      }

 

I cannot figure out why the sleep should wait more time than expected. Can someone give me some hints on how to solve this problem?

 

Thanks in advance,

ale

 

 

 

 

 

IM_

 

 

 

PTPSR = tim_prescaler;

TIM_TSCR1_TEN = 0; TIM_OCPD = 0xff; // scollego tutti dalle uscite. TIM_TSCR1_TEN = 1;

Labels (1)
Tags (3)
0 Kudos
2 Replies

351 Views
RadekS
NXP Employee
NXP Employee

Hi Allessandro,

I could see a potential issue in the case of any interrupt. Any interrupt between commands “target = TIM_TCNT + us;” and “if (TIM_TCNT > target)” could lead to the wrong result of this branch - especially when this interrupt is periodical.

Could you please try this small modification?:

uint test;

//…

  test= TIM_TCNT;

  target = test + us;

  if (test > target) {

//…

Additionally there is additional overhead in some instructions from sleep_ms() and sleep_us() functions. This overhead (time for processing instructions out of the main interval) is multiplied by 1000 (and additionally multiplied by another 1000)

In general, you have two basic options for generating long delays by ECT timer.

  1. You could divide target interval by some reasonable interval and simply counts these intervals. The disadvantage of this approach is in the case when we want to count a lot of intervals. Any error in the base interval will be multiplied by counter value. So, any error in sleep_us() will be multiplied by 1000 in your case. Also, an overhead of this approach is higher.
  2. You could modify timer clock prescaler for generating slower time base. The Precision Timer Prescaler allow you divide input clock by value only up to 256. However, we could additionally use pulse accumulator A as pre-divider for timer clock.

In the attachment, you could find two very simple example codes where I generate 1 min intervals via ECT.


I hope it helps you.

Have a great day,
RadekS

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

351 Views
kef2
Senior Contributor IV

sleep_us() doesn't look right. TOF should be used only for measuring long time difference. You could use it also for periodic interrupt source. TOF is useless to produce fine resolution delays. For pulse generation with t > 2^16 timer ticks, you should skip required number N = t / (2^16) of timer compare interrupts (equivalent to timer overflows) and prepare timer pin to toggle on last timer compare + t % (2^16). Small t % (2^16), which could be shorter than interrupt latency, like t=0x10010, can be handled dividing t into two intervals, for example t1=0x8000 and t2 = t - 0x8000.

Simple routine to delay for up to 2^15 timer ticks. 2^15, because short int sign is involved. TOF is not used:

void delay(int ticks)

{

     int target = TCNT + ticks;

     while (  (signed int)(TCNT - target) < 0)

    {

    }

}

0 Kudos