![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
rolox
Joined: 25 Dec 2014 Posts: 33
|
Delay calling IRQ handler ( CCP ) |
Posted: Wed Jun 10, 2015 7:29 am |
|
|
Hi,
i'm using CCP2 for measuring a short signal (some msec) with low frequency (some 100 Hz). It works as expected - but i noticed that it takes much longer than expected until the ISR is called.
After the Input signal rises, it takes about 3usec, until the ISR starts. this time increases up to 8usec, having more isr (serial, timer0) implemented
The pic runs with 32MHz, so the few instructions to save wreg etc should be done in <1usec.
When i enable the int_timer0 before leaving the ISR, this time is not constant and goes from about 1us to 10us :-(
Where does the other time get lost?
simple code which just generates a short as possible pulse in the ISR :
Code: | #include <16f1788.h>
#define CLOCK_FREQ 32000000
#use delay(internal=CLOCK_FREQ)
#use FAST_IO(B)
#define TESTPIN1 PIN_B5
#int_ccp2
void isr_ccp2test()
{
output_high(TESTPIN1);
output_low(TESTPIN1);
// with this line enabled, the dely is no longer constant :
//enable_interrupts(INT_TIMER0);
}
void init(void)
{
port_b_pullups(TRUE);
SET_TRIS_B( 0b00001010 );
// Output : B7, B6, B5, B4, , B2, , B0
// Input : B3 B1
SET_TRIS_C( 0b11111010 );
// Input : c7, C6, C5, C4, C3, , C1,
// Output : C2 C0
setup_ccp2(CCP_CAPTURE_RE); // Configure CCP to capture rise
setup_timer_1(T1_INTERNAL);
enable_interrupts(INT_CCP2); // Setup interrupt
enable_interrupts(GLOBAL);
}
void main(void)
{
init();
while (TRUE)
{
}
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Wed Jun 10, 2015 7:47 am |
|
|
hmm..
//enable_interrupts(INT_TIMER0);
You _must_ have an ISR with EVERY enabled interrupt !
Otherwise the PIC can (will) go into 'Lala Land' and crash or do 'weird' things.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Wed Jun 10, 2015 8:05 am |
|
|
The key to the question though, is that you have to save a lot more than just the Wreg etc..
The interrupt handler has to test what interrupt is happening (you obviously want to use more than one, and if you do there has to be such a test), and also saves every register that might be changed in the handler. Typically about 30+ instructions.
You can code without this, but then you are going to have to go through the assembler, and verify exactly what registers are touched in the handler (will be more than you expect - remember an array access will touch the indirect addressing registers, any maths will affect the status, etc. etc..). How to do this is shown in ex_glint.c |
|
![](templates/subSilver/images/spacer.gif) |
rolox
Joined: 25 Dec 2014 Posts: 33
|
|
Posted: Thu Jun 11, 2015 12:47 am |
|
|
ok ...adding an empty ISR for timer0 keeps the delay still constant - as it should be.
The explanation for that delay is understandable, and as long its quite constant, it doesn't matter when measuring pulsewidth....
I need to have a short interval for timer0 (around 100us) - and as soon as there is more than a few instructions in that timer0 ISR, the CCP2 ISR has no longer a constant delay regarding the input pulse (which is understandable in that way, that it might get longer in the case, the pic is in the timer0 ISR when the input pulse arrives: In that case it's clear that the CCP ISR can be executed only after the timer0 ISR has finished. But how could the delay be shorter than without timer0...?)
I understand its a matter of design: I need to convert a pulse width from 0...5ms into a corresponding PWM signal, and that should be done already during the pulse, to have the PWM "ready" right after the falling edge....thats why i have that sort timer0 interval to adapt PWM during pulse width. |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Jun 11, 2015 3:39 am |
|
|
The time to enter an ISR is called interrupt latency. There is some related to hardware - the processor samples the interrupt line (internal or external) on at some point in its processing cycle. It then has to stall the pipeline save hardware context and start executing the code at the interrupt vector.
Then a global interrupt handler has to run as PICs don't have fully vectored interrupts. The global handler has to save code specific contexts, that varies with the user's code. Then it polls the enabled interrupt sources one by one to see which requires servicing, and calls the appropriate ISRs.
The global interrupt handler (normally provided by the compiler, but you can do your own if you really want, and know what you're doing!) is simple enough for a short program with only one interrupt source/ISR. When there are two sources/ISRs, the polling has to be done in some order. I have seen, somewhere but I can't remember where, a discussion of the default ordering of interrupt polling. If its not what you need, you can change it using the #priority directive. This is often thought of as only useful when two interrupts happen at once, but it controls the polling order - you don't your time critical ISR to be polled last, you want it polled first to reduce its latency.
When you have two ISRs, if one is empty, probably the complier doesn't call the ISR, it my simply clear the interrupt. Enabling the interrupt source inside the ISR should have no effect as global interrupts are still turned off (they are turned off by hardware and re-enabled as the last thing done by by the global interrupt handler, in fact as part of the return from interrupt instruction. DO NOT enable global interrupts in an ISR unless you know exactly what you're doing and you've made suitable firmware preparations.
If you have two, or more non-empty ISRs, then they cannot interrupt each other. If one is running when an interrupt occurs, it must run to completion before the other ISR can run. That means that with two or more ISRs, interrupt latency for any source can never be guaranteed to be constant. It will vary by at least the execution time of the other ISRs. That's one very good reason for NOT using delays or long execution time code such as floating point, eeprom or program memory writes and so on, in ISRs.
The only way to get consistent interrupt latency is to have just one ISR, anything else will give a lot of jitter. Of course, there will always be some jitter due to hardware constraints. This means that if timing is critical, interrupts and firmware in general, is not a good way of achieving it. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Thu Jun 11, 2015 8:14 am |
|
|
The default ordering, is the order the handlers are declared. Very simple.
All of the comments of course 'change' if you switch 'up' a family or two.
The PIC18, does allow two hardware priorities (so one interrupt can interrupt another), but there are restrictions on this (INT_EXT is always high priority).
Then the PIC24, does have separate vectors for the separate interrupts. |
|
![](templates/subSilver/images/spacer.gif) |
rolox
Joined: 25 Dec 2014 Posts: 33
|
|
Posted: Thu Jun 11, 2015 2:57 pm |
|
|
Thanks at all - good explanations - think i got it. Changed design according to this and latency is now constant enough for my needs. Also results are good enough when my PWM is changed every 500us instead of every 100us. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|