PIC Series Interrupt management.

Status
Not open for further replies.

Kylobeetle

Member
Hello guys. hope you all are okay. Today I discovered that the mid ranged PIC (not sure if further pics can) only can handle one interrupt at time, someone said that the 8051 can handle multiple interrupts, not sure if true or what, but my question is .. Since I will have to work with only one interrupt and I have it already busy, from the moment i declare my registries like Global interrupt, External Interrupt, and so on ; enabled, If in some function I declare them momentary disabled (GIE=0 . PEIE=0 . ETC) Will be the ISR disabled until I re enable the registries again ? or from the moment i declared enabled they will work forever until I restart the device ? I ask because tomorrow I ll be off for some days and this could take me some hours to debugg and find out so I would like to know so my mind can working when im not here haha . I hope i could be clear .. have a nice night .
 
I don't use PICs but something seems off about your post. I think you may be running into different meanings of "handling" an interrupt:

1. The processor literally only has one interrupt line (highly unlikely).
2. The processor can only process (e.g. run code for) one interrupt at a time). This is true for all single-core processors since you only have a single processor running code.
3. A higher priority interrupt can interrupt a lower priority interrupt whose code is already running. This is called "nesting interrupts". Not nesting interrupts means that an interrupt routine that is running cannot be interrupted. At best, the higher priority interrupt that came afterward can only be pending and must wait until the current interrupt finishes before the next one can execute.

What makes the most logical sense is you are trying to say that your PIC cannot nest interrupts while the 8051 can.

What is the model of your PIC. I can take a quick look at the datasheet.

If in some function I declare them momentary disabled (GIE=0 . PEIE=0 . ETC) Will be the ISR disabled until I re enable the registries again ?
This would be a safe assumption. It's all manual If you disable interrupts when beginning, you must re-enable it if you want to use it again.

Your function is directly accessing the hardware control register for the interrupt. There is only one register. So if your function disables it in that register, it disables it everywhere else since there is only one register that you are writing to, no matter where in the code you are performing the write. You must re-enable it. It's not like a pass-by-copy function variable. There's only one register.
 
Last edited:
PICs have a limited number of "nesting levels" for interrupts.

Interrupts need RAM for the return stack and while a "normal" CPU can have as much RAM as the system designer choses and a stack pointer that the programmer can assign anywhere in memory as they chose, PICs have limited RAM and a dedicated storage area from the interrupt stack that cannot be changed.

They can handle multiple interrupts but it's up to you to save and restore registers if working at the assembly language level, and make sure execution times are appropriate so you do not get recursion.

Once enabled or disabled they stay enabled or disabled until you change things again.


For a lot of applications, a single high frequency timer interrupt, eg. running at 1KHz, 10KHz or whatever is appropriate, allows you to poll i/o and communications rather than each device having to have a separate interrupt routine.

Use circular buffers with input and output pointers or indexes to pass data between the main program and the interrupt routine, rather than doing any real processing during the interrupt.

I normally make buffers power-of-two size then do an increment on the pointer and logic AND with a suitable size bitmask, which inherently "wraps" the pointer without messing about with compare and conditional operations. eg. for a 32 byte buffer, "and" the pointer or index with with 0x1f
 
Personally, I have never run into trouble with multiple interrupts on the pic..

I write one ISR routine and have "if" statements that check each interrupt flag.

If I write code on the pic or the 8051 execution is almost identical.. Pic18's have high and low priority.. I only use high.

I also understand that my systems are not too demanding on the interrupts, whereas some people use it like an RTOS..
Free RTOS runs on the pic18 platform as well as it does on the AVR and 8051 platform, so its can't be that much of a problem..
 
Oh thanks everyone for your points of view , and excuse if i can be missleading sometimes, its the combination of my grammar and my little knowledge about this. I asked about this because yesterday I tried to add a second ISR routine, I already had one, when i added another one, I got an error saying that i had two ISR routines or something, I should compile and show you the log, I never didnt mean to run both ISR at the same time, I wanted to run a USART ISR (which im already using) and now add an external ISR with the port RB0 which will let me trigger something from outside (Real world) ..now that i have read your comments I will do some digging if maybe the pic im using (PIC16F887) has high/low ISR priorities or something. In the meantime, i was about to just code what i wanted to do without an ISR temporally disabling the actual usart ISR i have.

I know that always exist a better way to code, I'll be always happy to learn it, but in the meantime, I try my best making it work haha. I'll report back if i found something useful.

Thanks!
 
A frame work...
C:
void interrupt ISR()
   {
   if(RCIF)
       {
       // do usart stuff..
       RC1IF = 0;
       }
   if (RBIF)
       {
       // do port change stuff..
      
       // to clear RBIF you need to read the port!      
       }
   if(INT0IF)
       {
       // do external int stuff..
       INT0IF = 0;
       }
   }
 
So with this, are you suggesting to use only one ISR for those task ? I never thought it would be possible, in that case I would have to disable the UART section or something similar, because I dont want them to clash before it finish if a function was called with the external interrupt task.
 
Sometimes, multiple interrupst share the same trigger (to conserve circuitry inside the chip) so multiple interrupts (often related somehow like different types of interrupts for the same peripheral) share the same hardware trigger and routine so whenever that trigger fires, the routine must check flags to see which specific interrupt fired in order to run the appropriate code. Remember to clear that pending flag at the end of the routine or else your interrupt will instantly trigger again.
 
So with this, are you suggesting to use only one ISR for those task ?

Yes, that's how it's done, on most devices - the high/low priority isn't much different, it just decides which one gets processed first. The 24F series have a range of settings with different priorities, and each interrupt calls a separate ISR, I find that more confusing than anything else and pretty well choose the priorities at random.

You don't need to disable things, the processor takes care of what needs doing, only one interrupt at a time runs, any others are queued and run when the current one finishes.

The important thing is to keep ISR's as short and fast as possible, but that applies to interrupts in general.

Even using assembler, many more modern PIC's automatically save (and restore) the registers when ISR's are called, which saves you having to do it.
 
In single vector mode you just chain the interrupt flags checks down in a series of checks in one ISR function. It's usually a good idea to also check the enable flag for each ISR checked module first so you can easily disable interrupt servicing individually if some flags are being polled elsewhere.

There are PIC18 devices with multi-vector (more than high/low) interrupts.
https://ww1.microchip.com/downloads/en/AppNotes/90003162A.pdf
 
Okay let me go a little more in depth, Im at my office right now, so I dont have access to my MCU'S, so I will try my best.

Im sitting in a while(1); when UART is used it activates a flag and start running some sub programs. When it finish, it goes back to sit in the while(1); until being called again. But now, I would like to add a new feature, an external interrupt using an external source, lets say a PIR SENSOR like an example. If the sensor spot something, it will do something, BUT. I wouldnt like that UART interrupt activate during the external ISR process, Im not sure if im being clear, if not, I can try to explain again. So in conclusion, Would be necesary to block the UART flags or something while the PIR is working? and also the opposite, block the PIR while the UART is being executed. Im clear that ISR must be short and fast as possible.
 
I will take a look on these, but 1st , I with the help of everyone here, I will determine if its necesary to do the upgrade, I have a feeling that what im trying to do is not complex enough to need more features, in case if needed I would have to get it then.
 
You dont have to do anything if not nesting interrupts since one interrupt must finish before another one can run.

If nesting (interrupts can be interrupted):

Set uart to be a lower priority so uart can never interrupt the external interrupt. (if you want to nest interrupts but make it so two specific interrupts cannot interrupt each other then see below)

Or in the code specific to the external interrupt, disable the uart interrupt at the start and re-enable it at the end. (You can also do the opposite so two specific interrupts cannot interrupt each other)
 
Last edited:

No, use short ISR's that set flags, then check for the flags in the main program within the while{1} - it would only very rarely be useful to turn off other interrupts - the only time I do is for UART routines, where I'm expecting just a single string to be received, so I disable UART interrupts while I'm processing the current one - just in case.

However, a PIR is a VERY slow and low priority device, and hardly worth an interrupt, just polling in the while{1} should be plenty - pretty much the same as using an interrupt to set a flag, and then polling the flag.
 
Oh i get it, i guess, I could use an "if(PIR)" inside of the while(1)? where the PIR can be something like "#DEFINE PIR RB0" since my ISR is being used by an USART code, I would like then to disable momentaly the USART ISR while im proccessing the PIR program, so when the PIR finishes and goes out of the if(PIR) the flag of the USART wouldnt be activated if for some reason it was called during the other process.
 

Why?, the whole point of interrupts is that things get done - the UART routine should perform seamlessly while your PIR code is running - all it should do is write the incoming data to the UART buffer, which you then deal with the next time round your while{1}.
 
Its because my ISR has a flag=1 so when the ISR finish, with the flag a function will enter in the play and run a series of sub programs, thats why I wanted to block the UART ISR while the PIR is active, because as soon the PIR detects something, it will run a different set of sub programs, and in the meantime, the other way shouldnt work, I know that maybe is the best way but its all I got bymyself haha. With some knowledge and time it can improve
 
No...that's a bad idea. That defeats the purpose of the interrupt by turning it off until the PIR routine is done. Mainly because the PIR routine sounds like it is going to take a while to run and because there does not seem to be a good reason (as far as we can tell, you haven't told us) why the PIR code must not be interrupted.

There are few reasons why you would need to stop the UART ISR from running in the middle of the PIR code (in the main loop) is running. The main one is if the code and ISR somehow interact with each other (such as using a shared resource) that would interfere with proper operation.

For example: If the UART ISR needs to transfer a continuous sequence of characters into some memory but the PIR code also transfers characters into that same memory block and you don't want a PIR data block to end up in the middle of a UART characters sequence.

The only other good, general reason I can think of that when the PIR is triggered, the MCU enters another mode of operation permanently or semi-permanently where the UART is no longer relevant.

Answer this: If a UART interrupt tries to fire while the PIR code is running, do you want the UART ISR to run right after the PIR code is finished? If so, disabling the UART ISR is a sub-optimal and unnecessary unless the two pieces of code interfere with each other somehow (like they both used a shared resource as previously described).

Divide the PIR algorithm into two parts:
1. the stuff that must be taken cared of right away.
2. the stuff that can wait.

Divide the UART algorithm into the same two parts.

Stick the stuff that must be done right away into interrupts and put everything else into the main loop of the program. Set the flags in the ISR and read the flags in the the main loop of the program knows what's going on.
 
Last edited:
Damn you are right.. I dont want that to happen, I'll do that. As soon I get some spare time for this I will check and update. Thank you very much, Also I will be reading every comment again so I dont miss any details.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…