The nRF52840 features an ARM Cortex-M4 processor with an interrupt controller with 3 priority bits. This means there are eight possible interrupt priorities, numbered 0 through 7, with 0 being the highest priority.
The old nRF SDK documentation was very clear about which of these priority levels the application could use while working with the SoftDevice (see here). Specifically, the SoftDevice uses priorities 0, 1, and 4, so the application is free to use the others. When in an interrupt with priority 2 or 3, the application cannot call the SoftDevice functions; when in an interrupt with priority 5, 6, or 7, it can.
Clear and simple.
I'm looking for similar guidance for the newer nRF Connect SDK, but I'm having trouble finding it. The SoftDevice Controller documentation has an Integration with applications page, but that page doesn't mention interrupts at all. It does say:
The SoftDevice Controller relies on the functionality provided by Nordic Semiconductor’s Multiprotocol Service Layer, which has its own set of requirements that the application must follow.
In the documentation for the Multiprotocol Service Layer, in the Integration notes section, there is guidance on interrupt priorities. It says RTC0, TIMER0, and RADIO interrupts must be configured for priority level 0. It then says there are two other interrupts, POWER_CLOCK and low_prio_irq, that "do not have real-time requirements", but it doesn't say what priority level they should be configured for.
When I took a look at how the priority levels were actually configured when running an example, I found the following:
| Interrupt | Priority |
| RADIO | 0 |
| TIMER0 | 0 |
| RTC0 | 0 |
| POWER_CLOCK | 3 |
| SWI5 (low_prio_irq) | 6 |
I experimentally determined the interrupt configuration by running a project using the SoftDevice Controller and then calling the methods NVIC_GetEnableIRQ() and NVIC_GetPriority() for every IRQ, to see which interrupts were enabled and at what priority levels. The results are shown in the table above.
- The RADIO, TIMER0, and RTC0 interrupts are enabled and given their priority of 0 in the
mpsl_lib_init_sys()function of subsys/mpsl/init/mpsl_init.c. - Also in subsys/mpsl/init/mpsl_init.c, the low_prio_irq (which is apparently SWI5 on the nRF52840) is given a priority of 6. This happens in the
mpsl_low_prio_init()function. The priority is actually set to 4, butIRQ_CONNECT()adds two to the priority level.
One priority level is reserved ifCONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOSis set, which it is when using an ARM Cortex-M4 processor becaseCONFIG_CPU_CORTEX_M4selectsCONFIG_ARMV7_M_ARMV8_M_MAINLINEwhich selectsCONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS.
Another priority level is reserved ifCONFIG_ZERO_LATENCY_IRQSis set, which it is whenever the MPSL is in use becauseCONFIG_MPSLselectsCONFIG_ZERO_LATENCY_IRQS.
This calculation happens in Zephyr, specifically thez_arm_irq_priority_set()function of arch/arm/core/aarch32/irq_manage.c. The given priority level is increased by_IRQ_PRIO_OFFSET, which is 2 in this case. It is defined in include/zephyr/arch/arm/aarch32/exc.h. - Finally, the POWER_CLOCK interrupt is enabled and given a priority of 3 because of its device tree configuration. Specifically, in Zephyr file dts/arm/nordic/nrf52840.dtsi, the clock interrupt is given priority
NRF_DEFAULT_IRQ_PRIORITY, which is defined as 1 in dts/arm/nordic/nrf_common.dtsi. That value of 1 is passed toIRQ_CONNECT(), which adds two to it (for the reasons described above) to get 3.
This is all a lot more complicated than it was with the old nRF SDK. I hope I haven't missed anything.
- Which interrupt priority levels can my application safely use when the SoftDevice Controller is enabled? Is anything except for 0 safe? Or should my application avoid levels 0, 3, and 6?
- What should my application avoid doing at each priority level? Since the MPSL low_prio_irq is level 6, does that mean my application cannot do anything Bluetooth related in interrupt handlers at that priority level or higher (meaning it can only do so in an interrupt at priority 7, or outside of an interrupt)?
Thanks!