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

Interrupt Latency

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



Joined: 18 Nov 2013
Posts: 160

View user's profile Send private message

Interrupt Latency
PostPosted: Fri Mar 06, 2015 5:34 pm     Reply with quote

I'm using a 18F8722 with v5.042 IDE.

I have the pic configured for PWM, half-bridge, at 100kHz, 50% duty cycle, using timer 2. Works great. I'm assuming this free runs without involving any interrupts or cpu interaction.

The pic is also trying to respond to external interrupt #2 every 10usec. The ISR executes in 3.3usec max. The first interrupt is responded to in 2.8usec. The second interrupt is responded to in 6.74usec. The third interrupt is responded to in 9.18usec. Add in the 3.3usec processing time, and the pic has just missed the next interrupt.

There are no other interrupts enabled. But timer0 is running providing ticks for the wizard generated scheduler.

According to the pic data sheet, the external interrupt latency is 3 or 4 instruction cycles. At 40MHz, that should be 400nsec.

What am I missing?

Code:

#use delay(clock=40000000,crystal=10000000,restart_wdt)

void main()
  setup_timer_2(T2_DIV_BY_1,99,1); // Used by CCP1 for PWM mode.
  setup_ccp1(CCP_PWM|CCP_PWM_HALF_BRIDGE, 2);
  set_pwm1_duty((int16)198);   // 50% duty cycle.
  ext_int_edge( 2, L_TO_H );
  enable_interrupts(GLOBAL);

  TICK_TYPE CurrentTick, PreviousTick;

  CurrentTick = PreviousTick = get_ticks();

  while(TRUE)
  {
      CurrentTick = get_ticks();

      if ( GetTickDifference(CurrentTick, PreviousTick) >= oneSec )
      {
          PreviousTick = CurrentTick;
         
          heartbeat();

          GetData();  // Int2 is enabled in this function.
       }

       CheckStatus();

    }
}
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Mar 06, 2015 5:45 pm     Reply with quote

What you're missing is the time it takes for the PIC to execute the CCS created interrupt 'handler'. The time you're referring to is the PICs hardware responding to the interrupt. To that you have to add the time it takes for the PIC program to save some registers,decide which interrupt flag is set, maybe the 'priority' of the interrupts,clearing the flags, etc..
If you print out the listing of your program you'll see there's a LOT going on.
Now you can 'trim' the 'latency' time , if you create your own 'handler' and some guys do to get max performance BUT you better KNOW what you're doing.
'Old school' guys always write their own handlers as they KNOW the hardware and software inside out. With that knowledge you could cut the 'latency' time by a factor of 5 to 10 over the 'generic' one CCS supplies.
Just remember the CCS one does WORK.

Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 06, 2015 6:08 pm     Reply with quote

Quote:

But timer0 is running providing ticks for the wizard generated scheduler.

Post your #use timer() line.
SeeCwriter



Joined: 18 Nov 2013
Posts: 160

View user's profile Send private message

PostPosted: Fri Mar 06, 2015 6:18 pm     Reply with quote

Code:

#use TIMER(TIMER=0,TICK=204us,BITS=32,ISR)


That blows one of my assumptions.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sat Mar 07, 2015 1:34 am     Reply with quote

As a comment, if the interrupt is only providing 'ticks' for your internal handler, then don't use an interrupt at all. Just read one of the timers.....

Feed your external signal as the clock input to a 16bit timer, and you can read the value from it at any point, and it'll just merrily count the signal.
SeeCwriter



Joined: 18 Nov 2013
Posts: 160

View user's profile Send private message

PostPosted: Sat Mar 07, 2015 12:17 pm     Reply with quote

I may have to scrap the whole ticks thing and do something much simpler.

But the 100kHz interrupt is a little more involved than counting pulses. The 100kHz clock is a free-running clock used to clock out data from an A/D converter. It's constantly running, but for 16-clocks the ADC is not enabled so the serial data into the PIC is high. For the next 16-clocks the ADC is enabled and clocks out 16-bits of data. And since the ADC is a 12-bit ADC, the upper 4-bits are always low when the ADC is enabled.

Every few seconds the PIC needs to sync up with the ADC by looking for 16-clocks (interrupts) with the data input high. When that condition is met, the next 16-clocks (interrupts) are considered valid data and are shifted in.

But since I'm not going to replace the CCS interrupt handling scheme with my own, I may have to re-write the program to not use interrupts and instead spin on the clock and data ports.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sat Mar 07, 2015 12:21 pm     Reply with quote

The alternative is to poll the interrupt.
This is much faster than using the interrupt hardware.
You test the interrupt flag, and when it goes true, do your task, and clear the flag.
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sat Mar 07, 2015 9:59 pm     Reply with quote

SeeCwriter wrote:

But since I'm not going to replace the CCS interrupt handling scheme with my own, I may have to re-write the program to not use interrupts and instead spin on the clock and data ports.


It is easier that you think. The PIC18F supports (in hardware) high priority and standard priority interrupts. You can fool the CCS compiler to think you are only using standard priority interrupts. For your critical interrupt handler place it at the HP interrupt vector , code it in assembler using ASM statements within the standard C construct. Do not use any local variables. Add code to save registers on entry for only the registers your code will modify and restore these at the end prior to adding a return from interrupt at the end of this handler. Add instructions in the mainline to enable high priority interrupts.

This will give you a low latency high priority interrupt handler which will interrupt the low priority handler. The high priority handler will be both lower and consistent latency and still enable you to use the standard CCS interrupt handler for all other interrupt sources.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Sun Mar 08, 2015 2:04 am     Reply with quote

You don't have to fool the compiler like this at all....

Just enable the priorities (#device HIGH_INTS=TRUE).

Declare all your normal interrupts.

Then declare just one interrupt as 'FAST', (not HIGH).

This creates a single high priority interrupt, using the RETFIE abilities (so automatically saving the minimum registers only). Write your interrupt code, and look in the assembler at what registers are used other than the basic W etc.. As Asmallri says, then just add the code to save and restore these.

The 'fast' interrupt is treated like it is a global interrupt handler for the high priority interrupts, so does half the work for you. Smile

However caveats.
Remember that the INT interrupt will always be 'high' if priorities are enabled. Study the data sheet on this.
SeeCwriter



Joined: 18 Nov 2013
Posts: 160

View user's profile Send private message

PostPosted: Mon Mar 09, 2015 11:12 am     Reply with quote

I tried changing the tick timer from interrupt driven to polled and polling doesn't seem to work. I never get inside the if statement.
Code:

//#use TIMER(TIMER=0,TICK=204us,BITS=32,ISR)
#use TIMER(TIMER=0,TICK=204us,BITS=32,NOISR)

// Initiialize Tick values.
CurrentTick = PreviousTick1s = get_ticks();

while(TRUE)
{
   CurrentTick = get_ticks();

   if( GetTickDifference(CurrentTick, PreviousTick1s) >= oneSec )
   {
      PreviousTick1s = CurrentTick;
                // do stuff
         }
}


Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Mon Mar 09, 2015 1:17 pm     Reply with quote

Forget the CCS tick function.

Problem is you don't know how it really sets things up. It'll often use combinations that are less than optimal.

Just poll the _interrupt_.

If you don't enable the interrupt you were using, but setup the timer yourself, then it'll still trigger as before.
So test the interrupt flag (if (interrupt_active(THE_INT)), and when this goes true, just clear it, and do your job.

Obviously 'THE_INT' is whatever interrupt you were using.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Mar 09, 2015 1:34 pm     Reply with quote

Here are some examples of programs that poll the interrupt flag for
various interrupts, using the interrupt_active() function:
http://www.ccsinfo.com/forum/viewtopic.php?t=48121&highlight=interrupt_active&start=1
http://www.ccsinfo.com/forum/viewtopic.php?t=41403&highlight=interrupt_active&start=5
http://www.ccsinfo.com/forum/viewtopic.php?t=50907&highlight=interrupt_active&start=9
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