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

Unexpected Interrupts delays

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Herbert



Joined: 20 Jul 2008
Posts: 32
Location: Brisbane, Australia

View user's profile Send private message

Unexpected Interrupts delays
PostPosted: Sat Feb 07, 2009 10:30 pm     Reply with quote

Hi, there is something happening here that I can't get my head around. Using PCWH vers 4.079.

I have a simple ISR routine at the beginning of a lot of other code -

Code:

#include <18F2620.h>
#device ICD=TRUE              //When TRUE, debugging code is inserted
#device adc=10

int32 Timer1_Rollovers = 0;       //Timer based on counting Timer1 rollovers

#device HIGH_INTS=TRUE   //Define fast interrupt
#int_TIMER1 fast            //2us main interval timer used for timing events
/* Use it as a high priority interrupt.   
   It happens every 131.07ms.
*/
void  TIMER1_isr(void)
{
   Timer1_Rollovers++;          //Increment the rollover counter.  Don't worry about a rollover, it will never happen.
}


Timer1 ticks every 2us. I then combine (elsewhere) the Timer1_Rollovers with the current timer1 value (16bits) to give me a 48 bit, 2us resolution timer, whenever I want a current chip time. This of course involves reading and combining timer1 and the Timer1_Rollovers values.
I have noticed there are some delays between the timer1 rolling over and Timer1_Rollovers being updated which can lead to race conditions. To deal with this I introduce a blank out period around the rollover period.

Code:

void Read_2us_Timer( int8 *Start )

//Store the current timer value at Start, a 6 byte area
// LSB is at start of memory storage area and MSB at highest memory location
// First 2 bytes are the Timer1 value
// Next 4 bytes are the rollover counter.

{
   int8 *Addr;
   int16 Temp;

   Do
   {
   }
   While ( get_timer1() < 0x50 );  //loop to allow counter to properly update

   Temp_I16 = get_timer1();
   memcpy( Start, &Temp_I16, 2 );
   
   Addr = Start + 2;
   memcpy( Addr, &Timer1_Rollovers, 4 );
}
 


It seems to me the 0x50 delay is already too long and I have now seen an event where the delay would have to be out at 0xB0 to cover that event.

Looking at the assembler code the interrupt used is at address 0x0008 and the number of instructions from there to where the Timer1_Rollovers is incremented is not very long at all ( about 10). I have also searched for disable_interrupts in the code and there are none in inappropriate positions, ie. in the execution loop.

I do have two other ISRs on CCP2 and timer3 that are low priority interrupts (not specified as "fast") and are not being actioned during this testing phase.

I can't see why the delay is so long. Would anybody have any suggestions what could be happening here?


Last edited by Herbert on Sat Feb 07, 2009 11:24 pm; edited 1 time in total
Herbert



Joined: 20 Jul 2008
Posts: 32
Location: Brisbane, Australia

View user's profile Send private message

PostPosted: Sat Feb 07, 2009 10:35 pm     Reply with quote

Did forget one thing, the chip is running on a 16MHz clock.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Feb 07, 2009 11:18 pm     Reply with quote

Quote:
void TIMER1_isr(void)
{
Timer1_Rollovers++;
}

memcpy( Addr, &Timer1_Rollovers, 4 );


Quote:
.................... memcpy( Addr, &Timer1_Rollovers, 4 );
002A: CLRF FSR0H
002C: MOVLW Addr
002E: MOVWF FSR0L
0030: CLRF FSR1H
0032: MOVLW Timer1_Rollovers
0034: MOVWF FSR1L
0036: MOVLW 04
0038: MOVWF @01
003A: MOVFF POSTINC1,POSTINC0
003E: DECFSZ @01,F
0040: BRA 003A

The memcpy has to run through that loop 4 times to do the copy.
What happens if you get an interrupt somewhere in the middle of that ?
What will happen to your Timer1_Rollovers variable while it's being copied ?
Herbert



Joined: 20 Jul 2008
Posts: 32
Location: Brisbane, Australia

View user's profile Send private message

PostPosted: Sat Feb 07, 2009 11:30 pm     Reply with quote

Ahh yes. I didn't tell you about the interrupt disabled version that showed similar issues. The trouble there was that timer1 was still incrementing during the interrupt disabled period and I would get timer1 rollovers that were not resulting in being counted in time, so once again my read back 6 byte value was incorrect. By removing the interrupt disable and having a dead period around rollover I was hoping to minimise these issues.
Herbert



Joined: 20 Jul 2008
Posts: 32
Location: Brisbane, Australia

View user's profile Send private message

PostPosted: Sun Feb 08, 2009 12:06 am     Reply with quote

The following is an improved version, as it uses the first captured timer1 value and then waits for the Timer1_Rollovers to be updated, if it needs to be.

Code:

void Read_2us_Timer( int8 *Start )

{
#define Update_Period 0x50
   int8 *Addr;
   int16 Temp;

   Temp_I16 = get_timer1();
   memcpy( Start, &Temp_I16, 2 );

   If ( Temp_I16 < Update_period )
     {
      Do
        {
        }
      While ( get_timer1() < Update_Period );  //loop to allow counter to properly update
     }
     
   Addr = Start + 2;
   memcpy( Addr, &Timer1_Rollovers, 4 );
}


My problem is I can't understand why the Update_Period has to be so large.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun Feb 08, 2009 3:11 am     Reply with quote

Provided, you have no interrupt locks active during timer reads, the observed update delay can be caused only by regular processing time within the interrupt routine and in your timer read. The problem reduces to detect all cases, where an interrupt has occured between reading the partial timer results (timer1 and overflow counter) and correcting the result respectively.

Generally a good approach is to read one result twice. E.g. read overflows, read timer1, read overflows. If the readings are different, an interrupt has occured in between. You should be able to calculate the correct timer reading then.
Herbert



Joined: 20 Jul 2008
Posts: 32
Location: Brisbane, Australia

View user's profile Send private message

PostPosted: Sun Feb 08, 2009 4:35 am     Reply with quote

Yes, thank you, I have pushed the code along and have come up with a solution along the lines you suggested -

Code:

void Read_2us_Timer( int8 *Start )

{
#define Update_Period 0x10
   int8 *Addr;
   int16 Temp;

   disable_interrupts( INT_TIMER1 );   //Prevent counter from changing during read
   Addr = Start + 2;
   memcpy( Addr, &Timer1_Rollovers, 4 );

   enable_interrupts( INT_TIMER1 );    //Finished so enable interrupts again

// Now get timer1 value

   Temp_I16 = get_timer1();
   memcpy( Start, &Temp_I16, 2 );

// If we are within the time it takes to update the rollover counter, wait
// till rollover counter is updated and then sample it again.

   If ( Temp_I16 < Update_period )
     {
      Do
        {
        }
      While ( get_timer1() < Update_Period );  //loop to allow counter to properly update
     
      Addr = Start + 2;
      memcpy( Addr, &Timer1_Rollovers, 4 );
     }

}



That now seems to work without causing many of the problems I had seen previously. I guess I could also add a condition that if the new Timer1_Rollovers is not equal to the one obtained at the beginning of the routine, then I can consider that I have captured the correct value on the subsequent read.

I have also returned the timer1 isr back to a normal level, ie. not fast or high priority, and all seems well. Even with the reduced "#define Update_Period 0x10".

There however still appears to be a problem when I activate the part of the code that uses the timer3 interrupt. It looks very much like the timer1 isr gets cleared without being actioned, i.e. it misses a rollover. I am a bit surprised, as I thought the compiler took care of these details, ie. dealing with multiple interrupts.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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