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


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

Joined: 08 Feb 2009
Posts: 11

View user's profile Send private message

PostPosted: Sat Nov 13, 2010 6:35 pm     Reply with quote

I did some reading but have a couple of Q's regarding priority ints on 18F devices.

I am playing with a 18F2585 on CCS 4.106

I think I understand the following:

1) Using INT FAST will allow a high priority int to interrupt a low priority in progress. No context saving is performed as I seen from the listing

2)Using INT HIGH will allow a high priority int to interrupt a low priority in progress, but will generate context saving code is performed as I seen from the listing, 50 cycles or so extra over the FAST option.The compiler needs the statement #device HIGH_INTS=TRUE for priority Ints.

3) Using an interrupt that has no assigned priority (Microchip design) such an INT0 pin, will basically generate code that is the same as if HIGH was used.ex One INT_EXT and one fast int, INT_TIMER1 FAST would generate code that adds the saving overhead.

4) INT_GLOBAL, generates nothing, but the complier expects a user ISR at 0x08 which is the high vector when used (low priority vector is 0x18), else 0x08 is used for all non high priority ints


Q1) If one wants the tightest high priority int code, is it best to use INT_Global or use FAST INTs? The user would have to add context saving and check the flags for Global Ints to determine what ints occurred? If so a low int is in progress, what happens when a high priority occurs? Would it just vector back to 0x08? How does it back to the low priority int? Any good example code for something like this?

Q2) If one needed a INT such as EXT (INT0 pin) that is no a priority int, are you stuck using a Global Int as all FAST Int would be handled as HIGH and have the overhead automatically added?

Q3) Is it a good idea to have more than one high priority (HIGH or FAST) enabled at one time? What happens if two high priority ints are pending at the same time?

Q4) If one were to use GLOBAL INTS, what registers really need to be saved if one is doing basic code in the ISR such as saving a CCP ot TMR reg, or inc a counter variable? What is the point of all the saving I seen in the listing file for HIGH INT?

Q5) If one wanted tight code for non priority Ints (compatibility mode), is it GLOBAL INT to only option?

Q6) Is it common practice to mix asm (for save/restore) and C code in the ISR?

Joined: 11 Mar 2010
Posts: 12753

View user's profile Send private message

PostPosted: Sun Nov 14, 2010 3:40 am     Reply with quote

If you have _any_ interrupt set as high priority, and also have the standard 'INT' in use, this _always_ becomes a high priority INT. Hence an interrupt source test becomes 'forced'. This is a hardware limitation of the chips, with this interrupt having no 'priority' bit. This is why in your notes, when you used INT_TIMER1 FAST, the saving overhead was generated, since the compiler did this automatically. This is also your Q2 answer. If you want a single high priority interrupt with the minimum overhead, then it is vital to not have INT0 in use as well...
You can only ever have one interrupt flagged as 'FAST', since otherwise the code must test for the source, and the code to do this together with saving the registers, is automatically added.

The amount of saving needed, depends totally on the code _you_ use in the interrupt handler. If you perform array operations, the table pointers have to be saved. Most things will affect the W register, but the RETFIE1 instruction, restores this for you (and the BSR etc..). The only way to really optimise the interrupt handler, is to write the handler code, then go through the assembler listing generated, and note down every register that is used. Then add code to save these.
The compiler defaults to saving everything that it uses, even if the routines using the registers don't exist in the interrupt handler. I have often 'wished' for a compiler option, that checked for what registers were actually used in the interrupt routines, and only saved these. Lacking this, you have to do it yourself.

There is no inherent speed difference between using INT_GLOBAL, or fast INTs. In fact the 'FAST' directive, can be used to generate the exact equivalent to INT_GLOBAL for the high priority interrupts. If you generate a _single_ interrupt handler and flag it as 'FAST', this becomes the 'global' handler for high priority interrupts. You can add code to this to test for what interrupt occurred, and then manually set the priority flag for another interrupt source.

You need to slightly change your thinking about the interrupt vectors. 0008, is the 'high priority' vector address _when interrupt priorities are enabled_, and the 'global' vector address when priorities are disabled. Hence if you define INT_GLOBAL with no high priority vector enabled, the handler goes at address 8. If you wanted to handle both high and low priority interrupts, you would need to write the INT_GLOBAL routine to immediately vector to the high priority handler, and then have a second entry point for the low priority interrupts.
You can still use high priority interrupts with an INT_GLOBAL, but you have to set the priority bits yourself.

Have a look at ex_glint.c, which gives a basic example of handling an interrupt 'fast' using the global declaration.
The below is a small 'snippet' from a handler designed to give minimum latency for a quadrature change, with this needing less registers saved than the other routines:

void myint(void) {
   static int INT_scratch[10];
   //Here for maximum speed, I test the RB interrupt - since it is allways
   //enabled, I don't have to test the enable bit
   GOTO    NXT
   quad();              //Quadrature handler.
   GOTO    FEXIT        //Use the fast stack for exit
   //Now I save the registers needed for the other interrupt handlers
   MOVFF   FSR0L,INT_scratch
   MOVFF   FSR0H,INT_scratch+1
   MOVFF   FSR1L,INT_scratch+2
   MOVFF   FSR1H,INT_scratch+3
   MOVFF   FSR2L,INT_scratch+4
   MOVFF   FSR2H,INT_scratch+5
   MOVFF scratch,INT_scratch+6
   MOVFF   scratch1,INT_scratch+7
   MOVFF   scratch2,INT_scratch+8
   MOVFF   scratch3,INT_scratch+9
   //Test for the external interrupt (power fail).
   //Now for Timer 2
   BTFSS     PIE1,TMR2
   GOTO      NEXT1
   BTFSC     PIR1,TMR2
   //Receive data available
   GOTO      NEXT2
   //Transmit buffer empty
   GOTO      EXIT
   //Restore registers
   MOVFF   INT_scratch,FSR0L
   MOVFF   INT_scratch+1,FSR0H
   MOVFF   INT_scratch+2,FSR1L
   MOVFF   INT_scratch+3,FSR1H
   MOVFF   INT_scratch+4,FSR2L
   MOVFF   INT_scratch+5,FSR2H
   MOVFF   INT_scratch+6,scratch
   MOVFF   INT_scratch+7,scratch1
   MOVFF   INT_scratch+8,scratch2
   MOVFF   INT_scratch+9,scratch3
   //Here the 'fast' exit.
   RETFIE  1

The register saving used here is only about half the amount normally done. Basically the FSR registers, and four scratch locations. These represent the 'total' of registers used in all the other routines.
The 'nop' after the RETFIE 1, is because this was one of the chips with a fault requiring this.

Best Wishes
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