nRF52832: RTOS Thread Latency causing total failure of MPSL Timeslots for micro-second TimeSync application?

Hi DevZone Team,
I am working on a high-precision, low-power Time Synchronization application running on the nRF52832 using the nRF Connect SDK (Zephyr RTOS).
Network Topology & System Constraints
The wireless architecture consists of a Tx Station (serving as the signal reference) and a Rx Sensor Node running multiple integrated peripherals (SAADC, SPIM, TWIM, DMA, and BLE communications). The goal is to keep the master clocks of both the Tx Station and the Rx Sensor Node perfectly synchronized.
The application requires microsecond-level timing accuracy to manage a high-frequency sensor signal up to 4100 Hz. To maintain proper phase alignment without destructive interference, our absolute phase error budget must stay well within a quarter-wavelength (~60 µs).
The Problem (Initial Architecture)
Initially, I implemented a time synching protocol using the nRF5-ble-timesync-demo to request dedicated radio windows alongside active BLE communications(to transmit processed data) to handle this master-to-replica clock synchronization.
  • When tested on a bare-metal architecture (via Segger Embedded Studio), this worked perfectly with zero timing issues.
  • However, when ported over to Zephyr RTOS, where the TimeSync loop was managed via threads (including the main thread) alongside multiple heavy worker threads handling the sensor data stream, the application struggled heavily. I experienced frequent MPSL_TIMESLOT_SIGNAL_BLOCKED and slot cancellation events, which regularly corrupted my synchronized data dataset.
The Solution (Current Architecture)
To bypass this, I redesigned the firmware to utilize BLE Connection time synchronization for micro-time synchronization between the Tx Station reference signal and the Rx Sensor Node clock.
  • By leveraging these hardware-level connection event timings to synchronize the master clocks, our synchronization delay is now completely stable at a maximum of 5 µs(this is what i could observe on the logic analyzer).
  • The phase correction from the reference signal is perfectly preserved, even though the rest of the Sensor Node firmware still relies heavily on Zephyr threads for high-speed sensor processing and storage.
My Theory & Questions for Nordic Community:
I want to make sure my understanding of the underlying architecture is correct so I can guarantee long-term stability for this multi-device synchronization. I suspect the MPSL thread-based failures were happening because:
  1. RTOS Context-Switching Latency: While bare-metal handles MPSL signals instantly in an ISR, handling data inside Zephyr threads introduces context-switching overhead (around 5–20 µs). By the time a thread wakes up to calculate and request the next timeslot via mpsl, the calculated absolute timeline is already stale or conflicting with a hard BLE deadline, causing MPSL to reject it.
  2. Driver Interrupt Masking (Critical Sections): The background threads on my sensor node rely heavily on SPIM, TWIM, and flash storage. I suspect these drivers call irq lock or mask interrupts briefly during transfers, delaying the core execution of the MPSL hardware timers just enough to fall out of bounds.
My Questions:
  1. Is my hypothesis correct regarding why MPSL timeslots struggle heavily under a thread-heavy Zephyr environment compared to bare-metal?
  2. By moving to BLE connection-interval-based synchronization, am I correct in assuming that the time-stamping of the reference signal occurs purely at the hardware/controller layer, making the master clock synchronization entirely immune to the jitter, preemption, or interrupt masking caused by upper-layer Zephyr threads?
  3. Are there any hidden risks to watch out for when using BLE connection events for continuous clock drift compensation while heavy DMA-backed threads (SAADC/SPIM) are actively sampling on the sensor node?
Thanks in advance for your insights!

Parents
  • Hi Sahil, 

    We are currently understaffed due to the summer vacation period, so delayed replies must be expected. I am sorry about any inconvenience this might cause. 

    What NCS version are you using?

    Are you able to reproduce the issue on nRF52DK? If so, could you provide a simple project to help us investigate the issue? 

    Regards,
    Amanda H.

  • Hi Amanda,
    Thanks for the response.
    No need to worry at all about the delayed replies, I completely understand the summer vacation constraints.
    I actually do not need a code-level solution or bug fix at this point! I have already successfully redesigned the firmware to use native BLE Connection Interval events for the master clock synchronisation, which successfully brought our jitter down to a stable 5 µs even under heavy thread loads.
    Instead, I am purely seeking architectural confirmation from your team regarding my hypothesis. Before I close this out, could you confirm if the following reasoning is theoretically correct?
    1. Thread Context-Switching Latency: While bare-metal handles the MPSL callback loop instantly in a direct hardware ISR, handling that scheduling logic inside a Zephyr thread introduces context-switching overhead. By the time the thread is context-switched and calculates the next timeslot via mpsl_timeslot_request(). The calculated absolute timeline is already stale or conflicting with a hard BLE deadline, forcing MPSL to reject or cancel the slot.
    2. Driver Interrupt Masking: Because my sensor node threads rely heavily on active SPIM, TWIM, BLE communication and flash storage drivers, these drivers likely invoke internal critical sections (irq_lock()) during active DMA transfers. This briefly masks hardware interrupts, delaying the core execution of the MPSL timer callbacks just enough to cause the MPSL_TIMESLOT_SIGNAL_BLOCKED events.
    I just want to verify whether this is the textbook reason why high-precision MPSL timeslot applications struggle in an RTOS thread environment compared to bare metal.
    Best regards,
    Sahil
  • It looks like the main reason is the frequent MPSL_TIMESLOT_SIGNAL_BLOCKED. If that didn't occur, then the customer would not be going through the low priority mpsl_timeslot_request() path to schedule the next timeslot. Instead, the scheduling with option MPSL_TIMESLOT_REQ_TYPE_NORMAL should happen in the high priority MPSL_TIMESLOT_SIGNAL_TIMER0 handler as the nRF5-ble-timesync-demo is doing.

    The MPSL low priority task can be pre-empted by any hardware interrupt, so it is possible that the low priority path can get stale, though that's difficult to comment on without knowledge of the BLE and timeslot intervals and the timeslot lengths that are involved. As for the background tasks the user has, the task priorities play a bigger role. The user can check the value of CONFIG_MPSL_THREAD_COOP_PRIO and check if it is bigger or smaller compared to the user's background tasks. Note that MPSL uses cooperative task priority, so it always has greater priority than any pre-emptible task, and cooperative tasks cannot pre-empt each other.

    If the MPSL timeslot intervals are large, then the context switching time shouldn't really matter IMO. The CPU should have plenty of time to set up the next timeslot. The background tasks or interrupt processing may have a greater impact depending on their priority configuration and load.

    Can you provide BLE connection intervals and MPSL timeslot intervals used in their app? Maybe that could explain why many MPSL_TIMESLOT_SIGNAL_BLOCKED are observed. Also, it would be worth double-checking the TIMER0 configuration to make sure the scheduling happens in the MPSL_TIMESLOT_SIGNAL_TIMER0 handler.

Reply
  • It looks like the main reason is the frequent MPSL_TIMESLOT_SIGNAL_BLOCKED. If that didn't occur, then the customer would not be going through the low priority mpsl_timeslot_request() path to schedule the next timeslot. Instead, the scheduling with option MPSL_TIMESLOT_REQ_TYPE_NORMAL should happen in the high priority MPSL_TIMESLOT_SIGNAL_TIMER0 handler as the nRF5-ble-timesync-demo is doing.

    The MPSL low priority task can be pre-empted by any hardware interrupt, so it is possible that the low priority path can get stale, though that's difficult to comment on without knowledge of the BLE and timeslot intervals and the timeslot lengths that are involved. As for the background tasks the user has, the task priorities play a bigger role. The user can check the value of CONFIG_MPSL_THREAD_COOP_PRIO and check if it is bigger or smaller compared to the user's background tasks. Note that MPSL uses cooperative task priority, so it always has greater priority than any pre-emptible task, and cooperative tasks cannot pre-empt each other.

    If the MPSL timeslot intervals are large, then the context switching time shouldn't really matter IMO. The CPU should have plenty of time to set up the next timeslot. The background tasks or interrupt processing may have a greater impact depending on their priority configuration and load.

    Can you provide BLE connection intervals and MPSL timeslot intervals used in their app? Maybe that could explain why many MPSL_TIMESLOT_SIGNAL_BLOCKED are observed. Also, it would be worth double-checking the TIMER0 configuration to make sure the scheduling happens in the MPSL_TIMESLOT_SIGNAL_TIMER0 handler.

Children
No Data
Related