|
|
View previous topic :: View next topic |
Author |
Message |
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
Fast interrupts |
Posted: Thu Feb 26, 2009 5:47 am |
|
|
Hello superforum,
I'm polling the RTCC timer to have a fixed program turn around time.
I'm also having 2 interrupt to be handled. CCP1 with high priority and EXT (RB0) with low priority.
Processor is PIC18F4520, Clock is 16 MHz.
Code: | setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32|RTCC_8_BIT);
// Internal osc and timeroverflow for every 2.048mS by 16 MHz
|
This means that the RTCC is incremented every 8 uSec.
I want to disable the interrupt when the RTCC is close to rollover for not distubing my fix program turn around so my question is:
How fast can I make these interrupts?
(my ISR code is predictable and short , but I can see that the compiler add both some hidden runtime code and a lot of other code lines. I have measured the time of the int_ext interrupt and this take about 11 uS, which then is 44 program cycles. Only the 4 of cycles is my ISR code.) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Thu Feb 26, 2009 3:41 pm |
|
|
Thanks, but I all ready have read this and this is good, but I'm an old ASM-programmer and wonder why this interrupt take so long.
Normally in ASM I use to save W, status and pclatch registers (PIC16F873) and I could put in some code just before RETFIE to adjust some register parameter if I want to. In the C-programming I have no control over the last code lines and can't make such adjustments.
In ASM programming I can see how long the interrupt takes by counting the ASM, but in C programming something is hidden for me with the runtime "*" mark.
However I like the C-programming and I don't want to put in ASM lines in the interrupt code to make it faster. (I know it can be dangerous).
I only want to learn to be a good C-programmer so:
Is it right that the shortest interrupt, including saving the important registers like W, STATUS, BSR, will be about 40 cycles? |
|
|
Guest
|
|
Posted: Thu Feb 26, 2009 11:11 pm |
|
|
Have you looked at the .lst file to see what assembly is being generated? You may find your answers there. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Fri Feb 27, 2009 1:49 am |
|
|
Yes, I have read the lst-file, but something is marked with "*" which is hidden from me and some of the last instructions I don't understand. Some of the last instructions is like this and it seems to be some modifications in the "@ interrupt area"
Code: |
0064: MOVFF 0F,00
0068: MOVFF 10,01
006C: MOVFF 11,02
0070: MOVFF 12,03
0074: MOVFF 13,04
0078: BSF 0E.7
007A: MOVFF 0D,FE9
007E: MOVFF 08,FEA
0082: MOVFF 09,FE1
0086: MOVFF 0A,FE2
008A: MOVFF 0B,FD9
008E: MOVFF 0C,FDA
0092: MOVFF 14,FF3
0096: MOVFF 15,FF4
009A: MOVFF 16,FFA
009E: MOVF 05,W
00A0: MOVFF 07,FE0
00A4: MOVFF 06,FD8
00A8: RETFIE 0 |
However I can't remove this lines - so I must live with them. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Fri Feb 27, 2009 2:54 am |
|
|
I solve the problem.
In the start of my code I put in:
Code: | #device high_ints=true // activate high priority for not missing ext1 |
In my interrupt routines I put in some timer0 control:
Code: | #INT_CCP1 HIGH
void speed_isr()
{
TMR0_temp = get_timer0();
if ((TMR0_temp == 0) || (TMR0_temp == 1) || (TMR0_temp > 253)) set_timer0(253); // dont miss tmr0 overflow
// user code
// user code
// user code
}
#INT_EXT1
void opt_isr() // EXT1 is the RB1 interrupt
{
TMR0_temp = get_timer0();
if ((TMR0_temp == 0) || (TMR0_temp == 1) || (TMR0_temp > 253)) set_timer0(253); // dont mis tmr0 overflow
// user code
// user code
} |
Now I don't miss the timer0 rollover in the main program and the the main timer of 2.048 mS is only affected a litthe when interrupt is comming when timer0 is 0, 1, 254 and 255. This mean the possiblity of affection is 4/256. Because the main program timing of 2.048 mS is used for long time timers in seconds area it's not critical. |
|
|
Ttelmah Guest
|
|
Posted: Fri Feb 27, 2009 3:10 am |
|
|
As some further comments.
If you look at the thread that PCM pointed you to,you will see that using the _FAST_ keyword, rather than the 'HIGH' keyword, will tell the compiler _not_ to add it's handler, and get rid of the extra code. However, just as when using INT_GLOBAL, you will then have to add your own code to do the minimum saving necessary.
To see the extra code, that is missing from your listing, 'remark out', the line 'nolist', near the top of the processor include file. By default, CCS, does not show things like the code for it's own maths routines, and some of the handler stuff for interrupts and timings. Removing this, makes these visible.
Third comment, why are you woried about missing the timer rollover?. It sounds rather as if you are polling this timer in the main code?. Instead, just read it's interrupt flag (and clear it when you have seen it trigger). This is set by the hardware, when the rollover takes place, and will happen, whether or not you are in interrupts at the time. You don't then need to fiddle around with changing the timer value. Remember you can use the interrupt flags themselves, without haviong to have an interrupt handler. Take advantage of the hardware, and let it avoid your problem for you.
Best Wishes |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Fri Feb 27, 2009 5:07 am |
|
|
Ohh I like this super forum.
I haven't thought of polling the timer0 overflow bit instead. I have just made this and it work fine. Many thanks to you.
About using FAST interrupt, if I understand this correct:
Using #INT_CCP1 FAST and #INT_EXT1 as normal.
CCP1 will still save W, STATUS and BSR because the RETFIE 1 restore these.
More critical is that the #INT_EXT1 is missed if this come when the #INT_CCP1 is running.
Am I right? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Mar 01, 2009 4:32 pm |
|
|
Quote: | More critical is that the #INT_EXT1 is missed if this come when the #INT_CCP1 is running.
Am I right? | No. Each interrupt has its own interrupt flag and the interrupts will be handled sequential. |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Wed Mar 04, 2009 1:07 am |
|
|
I don't think I understand your answer right.
If I use #INT_CCP1 FAST and #INT_EXT1 as normal.
What is lost comparred to using #INT_CCP1 HIGH? |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 04, 2009 3:20 am |
|
|
'Lost', nothing, but _you_ will have to add the code to your 'FAST' function, to save any registers this function uses. Using 'HIGH', the compiler does this for you, but at the cost of bulkier code.
Best Wishes |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Wed Mar 04, 2009 7:41 am |
|
|
If I use FAST my code will be:
Code: | #INT_CCP1 FAST
void speed_isr()
{
a_speed = CCP_1;
set_timer1(0);
speed_con_1 = 1;
}
#INT_EXT1
void pulse_isr()
{
pulse = 1; // pulse is observed
} |
What need to be saved or done? |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 04, 2009 10:21 am |
|
|
You need to look at the listing code generated (the assembler), see what registers are used. Verify if any are used that are not automatically saved, and if so, save them at the start of the interrupt, and restore them at the end.
Look at the global interrupt example, for how to do this.
Best Wishes |
|
|
Mortenc
Joined: 22 Feb 2007 Posts: 55
|
|
Posted: Thu Mar 05, 2009 4:26 am |
|
|
Well, I have tried to used the CCP1 FAST and the ASM list file looks like this:
--------------------------------------------------------------
.................... #INT_CCP1 FAST
.................... void speed_isr()
.................... {
.................... a_speed = CCP_1;
*
00AE: MOVFF FBF,7D
00B2: MOVFF FBE,7C
.................... set_timer1(0);
00B6: CLRF FCF
00B8: CLRF FCE
.................... speed_con_1 = 1;
00BA: BSF 25.4
.................... }
00BC: BCF F9E.2
00BE: RETFIE 1
.................... #INT_EXT1
.................... void pulse_isr() //
.................... {
.................... pulse = 1; // pulse is observed
00C0: BSF 21.2
.................... test_timer = 5; //
00C2: MOVLW 05
00C4: MOVWF 61
.................... }
....................
.................... //**********************************************************
.................... //
00C6: BCF FF0.0
00C8: GOTO 0068
---------------------------------------------------------
When someone look at this they should know that all FAST and HIGH priority interupt goes to interrupt vector 0008 and low priority interrupt goes to 0018.
If I take a look on interrupt vector 0008 I can see a GOTO 00AE which is just back to my code so nothing is done. However the "RETFIE 1" is used at the end of the CCP1 lines which is a special processor routine which restores the W, STATUS and BSR.
It's strange to see that that a runtime "*" symbol is shown at the CCP1 interrupt, but nothing is shown at the EXT1 interrupt. So you have to know that this interupt goes to vector 0018 because you can't see this. In this vector we can see that e.g. the W register is saved first.
However this was some explanation I hope someone else could use (and I hope I'm right about this).
Still I'm not 100% sure and I'm afraid to use the CCP1 FAST.
I can see that W, STATUS and BSR is saved and this is the most important registers to save and restore. What other I still don't know.
Is it the register used in the EXT1 routine you mean I must take care of, because the CCP1 FAST will disturb the EXT1 if it comes when the EXT1 is runing?
I have also tried to mark out the "nolist" in the 18F4520.h file as you told. I thought then get the code inline, but nothing seems to happen. |
|
|
|
|
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
|