When should one use polling method and when should one use interrupt based method ? Are there scenarios in which both can be used ?
the short answer is to use the interrupt method when polling is too slow. (by too slow, I mean if polling loses data, the interrupt method is necessary)
Polling should be avoided where possible, as it typically eats a lot of CPU cycles unnecessarily (unless either (a) you are only going to poll for a short time or (b) you can afford to sleep for a reasonable time in your polling loop). Wasting CPU cycles is bad not only from a performance perspective, but it also drives up power consumption, which may well be an issue for battery-powered embedded applications.
Basically, polled mode is used in case interrupt mode is unavailable due to some hardware or software reasons. So, interrupt mode is more preferable from power consumption, performance, etc points of view (agree with Paul R). Polled mode is also can be used at prototyping, for cores without peripheral needed and for some testing purposes.
If the event of interest is:
- Asynchronous
- Urgent
- Infrequent
then an interrupt based handler would make sense.
If the event of interest is:
- Synchronous (i.e. you know when to expect it within a small window)
- Not Urgent (i.e. a slow polling interval has no ill effects)
- Frequent (i.e. majority of your polling cycles create a 'hit')
then polling might be a better fit.
Other considerations include whether you are writing a device driver for an OS or just writing bare metal code with no thread support. In bare metal situations the CPU is often just looping when it isn't busy so it might as well be polling something.
Sometimes you actually need to use both. For example if the events are sporadic but come in a high speed burst; you may need to first respond to an interrupt, and then before re-enabling the interrupt poll to see if another event has already occurred avoiding some of the overhead of the interrupt context switching. I believe Linux Network Interface operates in this mode.
Interrupts are preferred when low latency is required. If you poll for some condition N times per second, then on average you will discover that condition in time one half of 1/N after it has actually happened.
Polling is sometimes preferred when absolute deterministic timing is required. By their very nature, interrupts can occur at unpredictable times and greatly complicate timing analysis, whereas with polled systems, it is relatively easy to make provable statements about deadline satisfaction.
Always use a interrupt. That way you never lose data. In event driven or threaded applications even the slowest signals should be interrupt driven.
The only time that you should use polling is when you are using a scheduler and the buffers on your hardware are deep enough to ensure no data loss.
Polling mode can be useful in systems with high frequency events, where the overhead associated with entering and exiting interrupt handlers uses more CPU cycles than simply polling. For example polling might be used in an IP router to maximise CPU bandwidth available to packet processing.
When deciding upon polling or interrupt you have to fully understand the nature of the event you are trying to follow and your response to it.
Interrupts require no processing when nothing is happening, but require all your attention when something is happening. If the event is external and has noisy edges or fast pulses then this can cause major headaches with interrupts, you have to be careful around the setup of interrupts.
In this example the interrupt routine is responding to a laser beam having become clear and is setting itself up for an event where it becomes blocked:
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
There are 2 weak points of this code: 1) If the laser beam has become blocked again before the interrupt flag is cleared (BEAM_INTR_FLAG = FALSE;). The interrupt will have been missed and the code will be out of sync with the laser beam state.
2) When setting up interrupts in either in the background routine or for a higher priority than the priority this code is on, care must be taken when enabling the interrupt. If the interrupt flag was already set (incorrectly) prior to it being enabled, the interrupt routine would be called incorrectly as soon as it was enabled and maybe for the wrong edge.
The easiest way to fix 1) is to double check after you set up the interrupt, if it has occurred then force an interrupt. To fix 2) move the enabling of the interrupts to after the the double check:
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
/*Double check beam state to see if it has already gone blocked*/
if (BEAM_STATE == BEAM_BLOCKED)
{
BEAM_INTR_FLAG = TRUE; /*Force the interrupt to re-enter the ISR after exiting*/
}
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
The forcing of the interrupt makes the system work with the same state machine, just forcing it round manually to cover the blind spot.
Basically:
Set the edge to detect the next interrupt event
Clear the interrupt flag
if (the event has already occurred)
{
Set the interrupt flag to force the interrupt
}
Enable the interrupt
If the time of the response to an event is has to be consistent (e.g. 1ms +/-10us after after the input line goes high, transmit the event signal) then interrupts are usually best.
If the time of the response to an event is has to be within a certain time (e.g. within 1ms of the input line going high, transmit the event signal), then an interrupt would be best.
The problem with interrupts is you have to start thinking about threading and that two pieces of code can access the same data at the same time.
Interrupts are also good for allow processors to go into low power modes (sleep/idle etc.) whilst waiting for something to happen.
Having said all that polling can give very tight time responses to events if there is only one thing for the processor to do, often interrupt hardware takes several cycles to respond to an event whilst a tight polling loop will do.
If the event is none timing critical and potentially noisy (e.g. someone pressing a switch) then polling allows simple filtering without missing the long term transitions. A common mistake is to poll multiple times when setting things up:
void fnInitialiseSystem(void)
{
if (MODE_INPUT == MODE_A) /*First polling of the MODE_INPUT*/
{
PR2 = PR2_MODE_A;
}
else
{
PR2 = PR2_MODE_B;
}
OpenTimer2( TIMER_INT_ON &
T2_PS_1_1 &
T2_POST_1_8 );
if (MODE_INPUT == MODE_A) /*Second polling of the MODE_INPUT*/
{
CurrentMode = MODE_A;
PROBE_INT_EDGE = CLEAR_TO_BLOCKED;
}
else
{
CurrentMode = MODE_B;
PROBE_INT_EDGE = BLOCKED_TO_CLEAR;
}
}
In the above example MODE_INPUT is an external switch, if the two times MODE_INPUT is polled differ then the behaviour is unexpected. When reading these kinds of signals it is best to use filtering to decide upon the long term state of the input, and perform actions on the filtered version.
For example with switch de-bouncing just check a switch regularly (every 1ms?) and if a number of them (say 16) are different (switch closed) from the filtered version (switch open) then update the result and perform the action required. Be careful with signal aliasing, an oscillating signal may look stable!
An example of use of polling and interrupts is, again, for the use of a input which doesn't change often but is noisy when it does. Yet again a switch is a good example of this: the code can set up an interrupt to check for a change in the switch state, when an interrupt occurs then the switch can be regularly polled until the switch state is "stable" (either changed state or back to what it was). This gives the advantage of low processing overhead when nothing is happening, and noise filtering when something is happening.
There are many design constraints that can drive the decision. My app has a combination of interrupt and polling:
- External and internal clock sources trigger interrupts - it's critical to timestamp both accurately so we can synchronize them.
- Incoming serial messages trigger interrupts. The recieve FIFOs must be serviced before they overflow.
- Outgoing messages trigger interrupts when the FIFO is partially empty - it must be refilled before it underflows.
- The ISR's set semaphores that are polled for in the background. This has 2 advantages:
- The computation needed to handle incoming events can be lengthy; if it were left in the ISR it could delay other ISRs beyond their service deadlines.
- Events can be sequenced. For instance, a polling loop can ensure that calculation X always occurs between ADC data collection and incoming message parsing, even if sometimes the message arrives a little earlier than expected.
Here are few interesting links that i came across while analyzing the polling vs interrupt methods -
http://web.engr.oregonstate.edu/~traylor/ece473/lectures/interrupts.pdf - Very interesting link
http://www.atarimagazines.com/compute/issue149/60_Interrupts_made_easy.php
http://www.electro-tech-online.com/micro-controllers/8440-interrupt-vs-polling.html
http://www.microchip.com/forums/m397196-print.aspx
http://www.cs.huji.ac.il/course/2006/67630/Lectures/interrupts.pdf
http://sunsite.nus.edu.sg/LDP/LDP/tlk/node86.html
Hope this is helpful.