time function not updating time variables after some time?

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some time ago you will remember I was asking about system time variables being incrememented inside a timer interrupt....I managed to use the time.h and sys/time.h header files for this and was able to successfully get the timer variables incremented. However recently after running my device for a while I have noticed a problem with it.

At times it seems after a while of running the device, the timer variable will not increment.

The following is what I do:

//the 1ms timer interrupt handler
__attribute__((__interrupt__))
static void TaskTimerInterrupt(void)
{
  //update the system time variables
  sys_tv.tv_usec += 1000;	//1000us in 1ms
  if(sys_tv.tv_usec == 1000000)	//1000,000us in 1s
  {
    sys_tv.tv_usec = 0;
    sys_tv.tv_sec += 1;
  }	
	
  //task timer tick variable
  TaskTick = 1;
	
  //reset the timer interrupt
  TASK_TIMER->channel[TC_1MS_CHANNEL].sr; 	// dummy read of status register to clear interrupt flag
}

Inside my HTTP page building function I do this:

//Get current time stamp
char timeStr[64];
time_t curtime;
struct tm *loctime;
curtime = time(NULL);	
loctime = localtime(&curtime);
strftime(timeStr, 64, "(percent)Y-(percent)m-(percent)d (percent)H:(percent)M:(percent)S (percent)Z", loctime);
				
sprintf(httpCon->FileBuffer, "(percent)s

Weather Station Data:

" "


" "

Time stamp: (percent)s


" "(percent)s", HTML_IndexHeader, timeStr, HTML_IndexFooter);

How on earth could it be possible that the timer variables arent being incremented? If you tell me the interrupt routine is not running may be, well you will see there is a TaskTick variable inside the interrupt, well its the tick that allows the processing of sockets and other tasks inside the micro. And they are obviously all running, as I can load the HTTP page. The page just keeps showing the same time every time.

Note that this only happens after running the system for a while....

I was thinking something along the lines of making the

extern volatile struct timeval sys_tv;

volatile. But that hasnt fixed the problem either....

I had the device running last night from about 1am till 8:40am in the morning...when I woke up I loaded the HTTP page and I saw the time stamp stopped at 8:32am....it will not update no matter how many times I try to reload the HTTP page. :(

Do you guys see any possible cause?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This probably isn't the problem, but the timer code would be more robust if you change:

  sys_tv.tv_usec += 1000;   //1000us in 1ms 
  if(sys_tv.tv_usec == 1000000)   //1000,000us in 1s 
  { 
    sys_tv.tv_usec = 0; 
    sys_tv.tv_sec += 1; 
  }

to

  sys_tv.tv_usec += 1000;   //1000us in 1ms 
  if(sys_tv.tv_usec >= 1000000)   //1000,000us in 1s 
  { 
    sys_tv.tv_usec -= 1000000; 
    sys_tv.tv_sec += 1; 
  }    

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I found the problem but dont know how to fix it!
Ok I added a command line feature that lets me type in "time" and it prints out the current time. I just got this one now:

Time: 2012-02-05 20:13:48:836325

That is really scary!
Looks like inside my timer interrupt shown above the "if" condition never gets executed? Hence the microseconds keep rolling up but seconds never get updated! Well until the micro seconds roll down again...i type "time" again and I can see the micro seconds keep increasing!

But how can the if condition be missed in the first place??? I do initialize the:

sys_tv.tv_usec = 0;
sys_tv.tv_sec  = 0;

in my timer init code...
Any idea?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would suggest that some other piece of code is inadvertantly stomping in the memory area where the sys_tv variable is stored.

- S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can we see the definition of the sys_tv struct?

Also what happens if you change:

if(sys_tv.tv_usec == 1000000)   //1000,000us in 1s

to be

if(sys_tv.tv_usec >= 1000000)   //1000,000us in 1s

Finally could the fault be where you either parse an ASCII time specification into binary representation or where you convert it back for display?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had tried the >= option after I found the problem and it certainly fixes it. But need to find the cause...and I think I have a possible cause....

When I do the NTP calculation after I get NTP response from the server, I calculate the offset, this offset calculation is giving me grief..could be an issue with signed and long long size data type being added to a sys_tv.tv_usec variable....I am investigating.

I can see by printing that tv_sec certainly goes bellow 1000 after adding the offset calculation. It should never be lower than 1000 and infact should always be a multiple of 1000! So thats where the == test fails.

sys_tv is defined as:

#ifndef _WINSOCK_H
struct timeval {
  time_t      tv_sec;
  suseconds_t tv_usec;
};
...

inside

C:\Program Files (x86)\Atmel\AVR Studio 5.0\AVR ToolChain\avr32\include\sys\time.h

I am wondering if that struct actually ever gets defined.... I wonder I am actually writing to an unknown space in the memory when I am accessing the members of the struct :P

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am wondering if that struct actually ever gets defined....

Is this not the very reason you run the code through a compiler? So it can tell you if it thinks anything is wrong?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

I am wondering if that struct actually ever gets defined....

Is this not the very reason you run the code through a compiler? So it can tell you if it thinks anything is wrong?

Oh boy sure... but I have seen compilers do very strange things in the past :)

I tried to redefine the struct in my code header file and the compiler complained about it being redefined. So that means the definition of the struct in time.h was OK and used.

I then placed Disable_global_interrupt() and Enable_global_Interrupt() before and after my NTP offset calculation:

Disable_global_interrupt();
sys_tv.tv_sec += offset/1000;    //offset is in ms
sys_tv.tv_usec += (offset % 1000)*1000;
Enable_global_Interrupt()

I think this has fixed it... I am not seeing the issue any more in my printed value...

Also I have changed the timer tick code in my interrupt as:

  if(sys_tv.tv_usec >= 999000)   //1000,000us in 1s 
  { 
    sys_tv.tv_usec = 0; 
    sys_tv.tv_sec += 1; 
  } 
  else
    sys_tv.tv_usec += 1000;   //1000us in 1ms 

I shall keep an eye on the issue, if I dont post again it means the above has solved it. :D
Thanks again guys!

PS: is >= more proecessor intensive than == test? Would be nice to keep the interrupt routine as efficient as possible, specially when it gets run so frequently.