3
\$\begingroup\$

This is for the more experienced one's out there.

I am currently involved with a large AVR project (using ATMega328) and it's getting confusing with respect to interrupts.

The project involves interrupts from the following sources

  • USART
  • TWI
  • SPI
  • External Interrupt (INT0 and INT1)

With so many interrupt sources and the fact that global interrupts get disabled when an ISR is executing, I am afraid of missing out on interrupts that might fire when my code is servicing another interrupt.

So is there some more structuralized method of managing interrupts in a large project?

\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

The first rule of using interrupts: Keep them very short.

When an interrupt occurs, whether it is enabled or not, and whether it is currently servicing an interrupt or not, an Interrupt Fired flag gets set. Every interrupt has one of these flags associated with it (such as SPSR.SPIF). That always gets set as soon as the interrupt fires.

The interrupt system then cycles through the interrupts looking for any interrupt flags that have been set, and if the interrupt is enabled it then jumps to the ISR.

It will do that no matter how long ago the interrupt occurred.

So the question is not "will I miss an interrupt because I'm in an ISR", but "Will I miss successive interrupts because I am in an ISR".

So first you need to calculate the maximum rate at which an interrupt from one source can occur.

Then you check your ISR routines, and make sure that they never exceed that minimum interrupt period. Consider moving code out of an ISR and instead setting flags to get your main loop to perform operations instead.

In a more complex environment (5 interrupts is NOT lots!) you may, if resources allow, consider creating an interrupt event queue, where an event is added to a list of incoming events when the interrupt occurs, and your main loop is then free to process those events in order. You may need to use queues with different priorities for different interrupts.

That's not really feasible on a small MCU like the '328P as it lacks the resources to effectively manage those kinds of queues.

\$\endgroup\$
3
  • \$\begingroup\$ So assuming I am servicing interrupt from source A during which the interrupt flag gets set because of interrupt from source B. In this case the ISR for B will execute once ISR for A ends. So the only real danger is missing successive interrupts from A itself. \$\endgroup\$
    – Ankit
    Jul 10, 2014 at 18:08
  • 1
    \$\begingroup\$ @Ankit, yes. If a second interrupt from B occurs before you have cleared the flag from the first event then you will have missed it. Also, Majenko the queue is a wonderful suggestion! I once had a project for class in which we implemented something called a priority queue in which events were added and removed in O(lgn) time, so it really was no big requirement insofar as processing power. \$\endgroup\$
    – sherrellbc
    Jul 10, 2014 at 18:15
  • 2
    \$\begingroup\$ @sherrellbc I'm more concerned with RAM usage for event queues. Dynamic memory is not good on a 2K chip, and overflowing a static sized queue is not a happy thing to do. \$\endgroup\$
    – Majenko
    Jul 10, 2014 at 18:30
2
\$\begingroup\$

I am afraid of missing out on interrupts that might fire when my code is servicing another interrupt.

Majenko stated that "The interrupt system then cycles through the interrupts looking for any interrupt flags that have been set, and if the interrupt is enabled it then jumps to the ISR.". This is not entirely true because:

The interrupts have priority in accordance with their interrupt vector position. The lower the interrupt vector address, the higher the priority.

This means that an interrupt source can "starve". After an ISR is completed, the controller will prefer high priority interrupts. Depending on interrupt frequency, it may happen that there is always a high level interrupt flag set, essentially blocking a lower prio one permanently.

Keeping ISR's short and knowing their execution time is good advice.

5 interrupts really isn't much, but still requires careful though on a simple fixed priority driven system.

AVR XMEGA for example takes it to another level. I have a XMEGA project that has to handle 22 different interrupt sources (4xUART tx/rx = 8 + 4 timers + 8 ADC complete + 2 other). However, the XMEGA features a "programmable multilevel interrupt controller". This allows you to manually assign one of three interrupt levels to each interrupt (within those, interrupt vector number priority still counts). Further, you can activate a round-robin priority scheme, which addresses the before mentioned "starvation" problem.

To avoid the possible starvation problem for low-level interrupts with static priority, where some interrupts might never be served, the PMIC offers round-robin scheduling

So regarding your original question:

So is there some more structuralized method of managing interrupts in a large project?

It depends on the capabilities of your system. For a controller like the ATMega328 with simple static priority driven interrupt management there make sure that no interrupt starves and hold on to "short" and "know your execution time". For a controller like the XMEGA, there is more planning involved because you just have more control. You have to carefully distribute the priorities and have to consider using features like "round robin".

\$\endgroup\$
3
  • \$\begingroup\$ How would i go about calculating the execution time of a particular ISR? \$\endgroup\$
    – Ankit
    Jul 11, 2014 at 16:11
  • 1
    \$\begingroup\$ @Ankit: Three options come to mind: 1.Look at the assembler code and count instructions 2.Take an estimated guess about the number of instructions from looking at the C code 3.Toggle a pin at the beginning and at the end of the ISR and use a scope to examine the execution time. / I like option 3 because its easy and precise enough in most scenarios (it is omitting pre- and post ISR processing). When every single instruction counts, option 1 would probably be the best. \$\endgroup\$
    – Rev
    Jul 12, 2014 at 14:14
  • \$\begingroup\$ Thanks! option 3 was damn smart! I'll give this a go and report back \$\endgroup\$
    – Ankit
    Jul 12, 2014 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.