简体   繁体   中英

Polling or Interrupt based method

When should one use polling method and when should one use interrupt based method ? Are there scenarios in which both can be used ?

If the event of interest is:

  1. Asynchronous
  2. Urgent
  3. Infrequent

then an interrupt based handler would make sense.

If the event of interest is:

  1. Synchronous (ie you know when to expect it within a small window)
  2. Not Urgent (ie a slow polling interval has no ill effects)
  3. Frequent (ie 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.

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.

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 (eg 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 (eg 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 (eg 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.

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.

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)

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.

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.

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.

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.

You don't want to have your host waiting in the busy loop for a long time, and also polling can become inefficient when frequent checks are made for data that is not there frequently. So there for, if t he host and the device are both fast, then polling if pretty fast.

It is much better to go with Interrupt based design compared to polling based because polling based is flawed in the sense that it expects the data to be returned on every poll. Now, you might say that I will get around this case where a single poll has returned me an error but why the heck waste all the CPU cycles polling for something when it could as well return an error ?? And to expect a poll might fail is practical product scenario.

Interrupt based designs make even more sense when there is a lot of layers of functions involved in a single poll. To me its a common practice: Would you keep asking ( polling ) your friend again & again everyday whether he has the information you need OR would you just tell him that interrupt me when you have the information I need. I think we do the right thing in day to day lives but fail to realize.

But interrupt based architectures when implemented require solid understanding of the publish-subscribe design principle . And, when done in app domains, they require the part of the code sending interrupts to be really well written. This good as it squeezes the complexity to one place as well.

Additional to above, following are the other advantages that polling based architecture provides you free of cost:

  • Asynchrounous
  • Fits well in case of infrequent events/updates
  • Update only when there is data available scenarios
  • Better error handling & management
  • Better usage of CPU cycles
  • Better battery life mgmt
  • Keeps the listeners free from complexity underneath

Whenever you are designing sw & you have this choice, you should always choose an interrupt based design over polling based, because an interrupt based design can fill up for polling based situation using listeners but a polling based design can never fulfill the requirement needing interrupt based design.

Following is a brief comparison matrix:

                     -INTERRUPT-      -LOOP-
Speed                  fast            slow
Eficiency              good            poor
CPU waste              low             high
multitasking           yes             no
complexity             high            low
debugging              +/- easy        easy
critical in time       excellent       poor
code bloat             low impact      high impact

See, we have main 5 methodologies:

1) Blind

CPU checks every x ms for data. ETC check pin 12.

2)Polling( Busy/Wait)

The CPU is always checking and waiting for Flag to be raised, like UART raising a flag after a packet is transferred. Forever checking the Flag register. (Best response time) but the CPU cant perform anything else.

3) Interrupt:

CPU performs normally, if interrupt happens, CPU will switch context to ISR. if Pin 18 saw a falling edge, perform ISR (1). Not bad response time and CPU can do anything while the ISR is not active. Do it with urgent apps that you do not know when it might happen.

4)Periodic Polling:

CPU is doing its stuff but, every ms seconds its checking pin 11. Blind is doing nothing in between. The worse response time, not urgent apps, do it when you don't trust the hardware will raise the interrupt. it can be created using a timer interrupt.

5) Direct memory access.

Advanced interfacing approach. Transfers data directly from/to memory. Input will be read to memory directly. Output will be written from memory directly. Both uses a controller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM