Integration notes
This page describes how to integrate the Multiprotocol Service Layer (MPSL) into an application. The descriptions are valid for both RTOS and RTOS-free environments.
For the nRF53 Series, the requirements described are only relevant for applications running alongside the MPSL on the network processor. For the nRF54H Series, some peripherals in the global domain are reserved so the requirements described here are relevant for all processors.
Several peripherals are owned by MPSL and must not be accessed directly by the application. They are listed below, separated into instances that MPSL enables interrupts for, and ones it does not. See the Interrupt configuration section for more information on interrupts.
- For the nRF52 Series:
Interrupts:
RTC0TIMER0ECB
No interrupts:
RADIOCLOCKTEMPPPI channels:
19,30,31
- For the nRF53 Series:
Interrupts:
RTC0TIMER0TIMER1ECB
No interrupts:
RADIOCLOCKTEMPDPPI channels:
0,1,2
- For the nRF54H Series:
Interrupts:
GRTCchannels8to12, interruptGRTC_2_IRQnTIMER020TIMER021ECB031
No interrupts:
RADIODPPIC020channel0DPPIC130channel0DPPIC132channel0IPCT130channel0
- For the nRF54L Series:
Interrupts:
GRTCchannels7to11, interruptGRTC_3_IRQnNote
The
GRTCmust be started by the application before callingmpsl_init()function. Additionally, theSYSCOUNTERmust be enabled in theMODEregister. This is done automatically when using the nRF Connect SDK.TIMER10TIMER20ECB00
No interrupts:
RADIOCLOCKTEMPDPPIC10channel0DPPIC20channel0PPIB21channel0PPIB11channel0
Note
These peripherals can be used freely when MPSL is not initialized. Additional peripheral requirements may be set by the protocol stacks in use.
The mentioned resources related to RADIO and TIMER can be accessed directly using the Timeslot feature.
Limited access to some of these peripherals is provided through the following APIs:
ECBthroughmpsl_ecb.h
CLOCKthroughmpsl_clock.h
TEMPthroughmpsl_temp.h
On the nRF54L Series, the CPU clock frequency must be 128 MHz.
nRF54L Series platform callbacks
On the nRF54L Series only, mpsl.h declares low-latency hooks that your integration must define.
MPSL calls them around time-critical scheduler or radio work so the platform can switch CPU power profile (including constant-latency / CONSTLAT when needed) and non-volatile memory (NVM / RRAM) latency settings in step.
Use this single pair together:
mpsl_low_latency_acquire_callback()enter a low-latency window before MPSL runs time-critical code (for example by enabling NVM low-latency mode and related settings).mpsl_low_latency_release_callback()leave that window when MPSL no longer needs low-latency operation.
When time-critical events are scheduled back-to-back, MPSL may skip mpsl_low_latency_release_callback() between events and only call release after the last event in the sequence.
Otherwise, each call to mpsl_low_latency_acquire_callback() is followed by a matching release when that piece of work no longer needs low-latency operation.
Integrations must tolerate skipped intermediate releases (for example by counting acquires).
Note
In the nRF Connect SDK, the MPSL subsystem provides default implementations of these callbacks for Zephyr-based builds. You need your own definitions only if you integrate the MPSL library without that glue code (for example a bare-metal or fully custom port), or if you intentionally replace the default behavior.
Note
To coordinate constant-latency (CONSTLAT) with MPSL through nrf_sys_event, enable CONFIG_NRF_SYS_EVENT in the application configuration where that behavior is required.
To coordinate NVM latency with MPSL through nrf_sys_event, enable CONFIG_NRF_SYS_EVENT_IRQ_LATENCY in the application configuration where that behavior is required.
Thread and interrupt safety
The MPSL library is not reentrant. For thread-safe operation, see the Interrupt configuration and Scheduling sections.
Interrupt configuration
MPSL enables interrupts for the reserved instances, as well as for POWER_CLOCK and low_prio_irq.
The application must enable and configure all the other interrupts.
If the Timeslot API is used for RADIO access, the application is responsible for enabling and disabling the interrupt for RADIO.
The application must configure interrupts for priority level 0 ( MPSL_HIGH_IRQ_PRIORITY ) for RADIO and the reserved instances that have interrupts.
The following interrupts do not have real-time requirements:
POWER_CLOCKIt is up to the application to forward any clock-related events toMPSL_IRQ_CLOCK_Handler()in lower priority. Irrelevant events are ignored, so the application is free to forward all events for thePOWER_CLOCKinterrupt.
low_prio_irqLow-priority work is signaled by MPSL by adding the IRQ specified in thelow_prio_irqargument tompsl_init(). When this interrupt is triggered,mpsl_low_priority_process()should be called as soon as possible (at least within a couple of ms). The application should configure this interrupt priority lower thanMPSL_HIGH_IRQ_PRIORITYlevel (namely, a higher numerical value). The interrupt is enabled withmpsl_init()and disabled withmpsl_uninit()by MPSL. The interrupt is selected using theCONFIG_MPSL_LOW_PRIO_IRQNKconfig option. This Kconfig option can be used to resolve conflicts with other software modules and should be left to the default value if possible.
The reserved interrupt handlers for the RADIO, GRTC, RTC, and TIMER peripheral instances must not be reconfigured while MPSL is enabled.
In the nRF Connect SDK, it is possible to reconfigure these interrupt handlers when MPSL is disabled using the CONFIG_MPSL_DYNAMIC_INTERRUPTS Kconfig option.
Scheduling
The interaction of the MPSL library with protocol stacks is designed to run at two interrupt priority levels: one for the high-priority handlers, and one for the low-priority handler. The interaction of the MPSL library with the application happens in the thread context and in the low-priority handler.
High priority
The high-priority handlers are mostly used for timing-critical operations related to radio or scheduling. Interrupting or delaying these handlers leads to undefined behavior.
Low priority
Low priority is used for background tasks that are not directly tied to the radio or scheduling. These tasks are designed in such a way that they can be interrupted by high-priority code. The tasks are however not designed to be interrupted by other low-priority tasks. Therefore, make sure that only one MPSL API function is called from the application at any time.
All protocol stacks using MPSL must be synchronized (namely, not called concurrently) to avoid concurrent calls to MPSL functions.
Application must only call MPSL APIs from non-preemptible threads, or with interrupts disabled (namely, during initialization).
The
mpsl_low_priority_process()function should only be called from thread context, namely, not directly from the software interrupt handler.Alternatively, you can use synchronization primitives to ensure that no MPSL functions are called at the same time.
Other priorities
MPSL initialization functions, like mpsl_init() and mpsl_uninit(), are not thread-safe.
Do not call them while, for example, a protocol timeslot is in progress.
This must be enforced by application and protocol stacks.
MPSL should be initialized before any protocol stack is enabled, and uninitialized after all protocol stacks have been disabled.
Architecture diagrams
The following image shows how the MPSL integrates into an RTOS-free environment.
MPSL integration into an RTOS-free environment
The following image shows how the MPSL integrates into an RTOS.
MPSL integration into an RTOS