Due nested interrupt priorities

354 views
Skip to first unread message

Collin Kidder

unread,
Feb 18, 2015, 8:50:47 AM2/18/15
to developers
A little background: I'm the maintainer of due_can, which is probably
the most used canbus library for Arduino Due and compatible boards. I
also worked to get a pull request put together to make sure that
serial transmission was interrupt driven on the Due. The due_can
library supports registering callback functions so that incoming
frames can be automatically routed without having to poll. A user of
the library ended up putting calls to Serial.print within one of the
callbacks. I'm sure many of you can guess how well this worked out. At
some point the serial buffer filled and the routines to store
characters in the buffer blocked which locked the sketch up forever.
Yes, people aren't supposed to make calls like that within interrupt
context. But, the Due has nested interrupts. I was able to fix this
problem by lowering the canbus interrupt priority so that serial
interrupts can preempt the canbus interrupt (and thus, the callback
function).

There were other potential fixes. Users could not do all sorts of work
in interrupt context. I could change the callbacks to being done via a
polling mechanism and not directly from the interrupt. But, this is
difficult to do without requiring the user to put a polling function
in their loop() or modifying the Arduino core loop function like the
serial code does. So, options exist. But, it seems as if every
interrupt is currently at the default priority which is maximum
priority. Thus, Arduino interrupts do not preempt each other. But,
they could. That's the whole point of a nested interrupt controller.

So, my question is: is there any interest in this? I feel that we
could come to an agreement about a priority hierarchy. Many people
have libraries for the Due and everyone would have to change their own
library to set a reasonable priority. But, the core files could be
updated. This would allow the end users to do some things that they
currently cannot do such as using serial output in interrupt context.
Also, it could result in lower latency for important interrupts. My
thought is that serial interrupts should have very high priority as
should timers. I2C can probably be a little lower. Canbus interrupts
can be lower still (I set the priority to 12 on a scale of 0-15 where
0 is highest and 15 is lowest). I realize that this is advanced stuff
and it probably isn't something the average Arduino user is going to
ever worry about but, as in my example above, it is currently easy for
users to accidentally walk into a minefield.

Sebastian Vik

unread,
Feb 19, 2015, 4:55:06 AM2/19/15
to devel...@arduino.cc
Hi Collin,

Changing the interrupt priorities will likely affect the behavior of many existing sketches and libraries that depend on the interrupt priorities being equal (if they were equal during their development). It is easy to write code when all interrupts have the same priority and it is harder to write code that can safely handle state being modified by interrupts of different priorities, perhaps at the same time.

The safest way I see of getting CAN interrupt handlers to be "Serial.print()-safe" without changing the behavior of existing code would be to lower all interrupt priorities to the same level somewhere in the middle of the scale, say 7. That way all existing code will work because there will be no concurrent interrupt handlers executed by default, yet individual developers can change the priority of a single interrupt either up or down if they need to and feel they can take responsibility for the involved code behaving correctly under those circumstances.

How does Serial.print() behave when a lower-priority interrupt, like the reset handler, is inside a call to Serial.print() (either blocking because the buffer is full or actively modifying the buffer or counters) and a higher-priority interrupt takes over and also makes one or more calls to Serial.print()?


Best regards,
Sebastian

Sebastian Vik

unread,
Feb 19, 2015, 5:11:00 AM2/19/15
to devel...@arduino.cc
On the other hand, do we know how many libraries (or sketches for that matter) already modify the default interrupt priorities? Their behavior would be altered regardless of how you changed them.


Regards,
Sebastian

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Cristian Maglie

unread,
Feb 19, 2015, 9:44:26 AM2/19/15
to devel...@arduino.cc

Hi,

I'm not sure that there is a common set of priorities that fits
everywhere, maybe someone expects CAN to have an higher priority than
UART. If we are going to change default priorities it seems more
reasonable to set all the interrupt priority to a common mid-level as
suggested by Sebasian and leave to the user the choice to
increase/decrease as needed, but...

Il 19/02/2015 11:10, Sebastian Vik ha scritto:
> On the other hand, do we know how many libraries (or sketches for that
> matter) already modify the default interrupt priorities? Their behavior
> would be altered regardless of how you changed them.

This is another good point. In principle, even if this is not part of
the "official" Arduino API, if people rely on them we cannot change it.

Another solution may be to provide a function like
NVIC_SetPriorityForAllInterrupts(...) so one can easily set all
priorities at once during setup?

C


--
Cristian Maglie <c.ma...@arduino.cc>

Collin Kidder

unread,
Feb 19, 2015, 11:00:57 AM2/19/15
to developers
Those are all good points. Anybody can change any interrupt they want
to so it's difficult to know who is setting what. I think that its a
good idea to set all interrupts to 7 (the mid-level) by default. As
you both said, that seems like the best compromise approach and allows
sketch writers to either raise or lower from there. So, I'm wondering
if this change should be done by default? Maybe right at the start of
the code execution? It has essentially no effect if nobody has changed
any priorities but, on the other hand, it would change the behavior in
subtle ways if various libraries are already setting priorities. But,
the current situation can lead to poor behavior as well so I'm not
sure there is any "right" way to set things by default.

Tom Igoe

unread,
Feb 19, 2015, 11:09:30 AM2/19/15
to devel...@arduino.cc
Maybe just publishing what the default interrupt priority settings are, combined with an API to change them would be handy?

t.

Sebastian Vik

unread,
Feb 22, 2015, 3:58:21 AM2/22/15
to devel...@arduino.cc
Good idea, NVIC_SetPriorityForAllInterrupts(priority) combined with the
existing ASF NVIC_SetPriority(IRQn, priority) would make it easy to work
with interrupt priorities without breaking any existing code.

I cannot think of a better solution.

/S

On 02/19/2015 05:09 PM, Tom Igoe wrote:
> Maybe just publishing what the default interrupt priority settings are, combined with an API to change them would be handy?
>
> t.

Thibaut VIARD

unread,
Feb 22, 2015, 1:37:45 PM2/22/15
to devel...@arduino.cc

NVIC_SetPriority() is part of ARM CMSIS, nor ASF.

By the way, only few drivers (ADC at least) have been adapted from ASF while I was driving both ports (ASF and Due) in 2011. The others were partly taken from ATSAM softpacks considering what was needed by Arduino.

As far as I know, all nvic priorities are at same level by default with maybe a different one for USB. To be checked.

Thibaut

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

Collin Kidder

unread,
Feb 23, 2015, 8:49:15 AM2/23/15
to developers
Yes, I do think that this is a viable strategy and probably the best
we're going to be able to do without affecting existing code.
Reply all
Reply to author
Forward
0 new messages