nRF52832 + NCS v3.3.1 + MPSL: UARTE disable/enable at runtime breaks BLE connection

Environment:

  • SoC: nRF52832
  • SDK: nRF Connect SDK v3.3.1 (Zephyr)
  • CONFIG_MPSL=y
  • CONFIG_PM=n (not supported on nRF52832)

Goal: Completely disable the UARTE peripheral during idle to reduce power consumption (~0.3–0.4 mA overhead observed), then re-enable it on demand, without breaking BLE connectivity.

Reference (working baseline): In nRF5 SDK 17.0 (no MPSL), the following pattern worked correctly with no BLE impact:

// Sleep app_uart_close(); // → nrf_uarte_disable() // Wake uart_init(NRF_UART_BAUDRATE_9600);

Attempted approaches in NCS v3.3.1:

Approach A – Disable IRQ only (current workaround)

// Sleep uart_irq_rx_disable(uart_dev); gpio_pin_interrupt_configure(gpio_dev, UART_RX_PIN, GPIO_INT_EDGE_TO_ACTIVE); // Wake gpio_pin_interrupt_configure(gpio_dev, UART_RX_PIN, GPIO_INT_DISABLE); uart_irq_rx_enable(uart_dev);

Result: BLE White check mark | UARTE peripheral remains active X (~0.3–0.4 mA extra)


Approach B – Direct register access via nrf_uarte HAL

// Sleep uart_irq_rx_disable(uart_dev); nrf_uarte_task_trigger(NRF_UARTE0, NRF_UARTE_TASK_STOPRX); nrf_uarte_task_trigger(NRF_UARTE0, NRF_UARTE_TASK_STOPTX); while (!nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_TXSTOPPED)) {} while (!nrf_uarte_event_check(NRF_UARTE0, NRF_UARTE_EVENT_RXTO)) {} nrf_uarte_disable(NRF_UARTE0); // Wake nrf_uarte_enable(NRF_UARTE0); uart_irq_rx_enable(uart_dev);

Result: BLE advertising works but connection fails (GATT CONN TIMEOUT / service discovery failure) X

Variants tested:

Variant BLE Result
STOPRX/STOPTX + disable + nrf_uarte_int_disable(0xFFFFFFFF) X Fail
STOPRX/STOPTX + disable (no int_disable) X Fail
STOPRX/STOPTX only (no disable) X Fail

Approach C – Async API

// Sleep uart_rx_disable(uart_dev); // wait for UART_RX_DISABLED callback via semaphore, then configure GPIO wakeup // Wake (via k_work, deferred from GPIO ISR) uart_rx_enable(uart_dev, rx_buf[0], RX_BUF_SIZE, 100000);

Issues fixed before testing: buffer index flip timing, missing semaphore sync on uart_rx_disable(), direct API call from ISR context, stack sizes increased (MAIN: 3072, SYSTEM_WORKQUEUE: 6144).

Result: BLE connection fails X | RAM overflow by 2736 bytes X


Questions:

  1. Is there a supported way in NCS v3.3.1 to fully disable and re-enable UARTE at runtime on nRF52832 with MPSL active, without affecting BLE?
  2. Does MPSL place any constraints on UARTE peripheral access (e.g. interrupt priority, shared resources) that would explain why direct register manipulation breaks BLE?
  3. Is there an nRFx or Zephyr API equivalent to nrf_uarte_disable() that is MPSL-safe?
  4. nrfx_uart_pwr_manage() was suggested but does not appear to exist in NCS v3.3.1 — is there an alternative?
Parents
  • Platform:

    • Chip: nRF52832 (QFAA)
    • SDK: nRF Connect SDK (NCS) v3.3.1 based on Zephyr RTOS
    • SoftDevice: S140 (integrated in Zephyr build, MPSL enabled)
    • Toolchain: nRF Connect for Desktop

    Application Overview:
    We are developing a BLE UART transparent transmission module (NUS service). The module works as a BLE Peripheral, receiving AT commands and data from a host device via BLE, and forwarding them to a target device via UART, and vice versa.

    UART Working Mode:

    • UART baudrate: configurable from 4800 to 921600 via AT commands (runtime changeable)
    • UART pins: TX=P0.06, RX=P0.08
    • When UART is actively transmitting/receiving data, it operates normally in interrupt-driven mode
    • When UART is idle for a configurable timeout (default 3 minutes), the module should enter low-power sleep mode:
      • UART peripheral should be fully powered down / disabled to minimize leakage current
      • RX pin is configured as GPIO wake source (edge-triggered interrupt) to detect incoming data and wake the module
    • When data arrives on RX pin during sleep:
      • GPIO interrupt triggers
      • UART peripheral is re-enabled and re-initialized
      • Normal UART communication resumes

      Power Consumption Requirement:

    • Target idle current: as close to the nRF52832 base current as possible (~0.3mA or less)
    • The old firmware (nRF5 SDK 17.0 + SoftDevice S132, no MPSL) achieves this by calling app_uart_close()  nrf_drv_uart_uninit()  nrf_uarte_disable() to fully power down the UARTE peripheral during sleep, and uart_init() to fully re-initialize on wake. This works perfectly with no BLE issues.

    The Problem:
    In the NCS/Zephyr + MPSL architecture, any direct UARTE register operations (including nrf_uarte_disable(), nrf_uarte_int_disable(), STOPRX/STOPTX tasks) conflict with MPSL shared resources and cause BLE connection failures. Even the Zephyr UART Async API (uart_rx_disable() / uart_rx_enable()) causes BLE connection failures on nRF52832.

    What We Need:
    A recommended approach to fully power down the UARTE peripheral during idle periods on nRF52832 with NCS/Zephyr + MPSL, and re-enable it on GPIO wake, without breaking BLE connectivity. Specifically:

    1. Is there a safe API or driver-level method to completely disable UARTE (similar to nrf_drv_uart_uninit() in nRF5 SDK) that is compatible with MPSL?
    2. If direct register access is not safe, what is the correct Zephyr driver approach to power down UART when idle and restore it on wake?
    3. Are there any known limitations or workarounds for UART Async API coexistence with BLE on nRF52832?

    Additional Note:

    • CONFIG_PM is not available on nRF52832 (Zephyr power management framework not supported for this SoC)
    • LFCLK source: internal RC oscillator (no external 32.768kHz crystal)
    • P0.09 and P0.10 are used as GPIO (LED and BUTTON), requiring UICR.NFCPINS to be configured for GPIO mode
Reply
  • Platform:

    • Chip: nRF52832 (QFAA)
    • SDK: nRF Connect SDK (NCS) v3.3.1 based on Zephyr RTOS
    • SoftDevice: S140 (integrated in Zephyr build, MPSL enabled)
    • Toolchain: nRF Connect for Desktop

    Application Overview:
    We are developing a BLE UART transparent transmission module (NUS service). The module works as a BLE Peripheral, receiving AT commands and data from a host device via BLE, and forwarding them to a target device via UART, and vice versa.

    UART Working Mode:

    • UART baudrate: configurable from 4800 to 921600 via AT commands (runtime changeable)
    • UART pins: TX=P0.06, RX=P0.08
    • When UART is actively transmitting/receiving data, it operates normally in interrupt-driven mode
    • When UART is idle for a configurable timeout (default 3 minutes), the module should enter low-power sleep mode:
      • UART peripheral should be fully powered down / disabled to minimize leakage current
      • RX pin is configured as GPIO wake source (edge-triggered interrupt) to detect incoming data and wake the module
    • When data arrives on RX pin during sleep:
      • GPIO interrupt triggers
      • UART peripheral is re-enabled and re-initialized
      • Normal UART communication resumes

      Power Consumption Requirement:

    • Target idle current: as close to the nRF52832 base current as possible (~0.3mA or less)
    • The old firmware (nRF5 SDK 17.0 + SoftDevice S132, no MPSL) achieves this by calling app_uart_close()  nrf_drv_uart_uninit()  nrf_uarte_disable() to fully power down the UARTE peripheral during sleep, and uart_init() to fully re-initialize on wake. This works perfectly with no BLE issues.

    The Problem:
    In the NCS/Zephyr + MPSL architecture, any direct UARTE register operations (including nrf_uarte_disable(), nrf_uarte_int_disable(), STOPRX/STOPTX tasks) conflict with MPSL shared resources and cause BLE connection failures. Even the Zephyr UART Async API (uart_rx_disable() / uart_rx_enable()) causes BLE connection failures on nRF52832.

    What We Need:
    A recommended approach to fully power down the UARTE peripheral during idle periods on nRF52832 with NCS/Zephyr + MPSL, and re-enable it on GPIO wake, without breaking BLE connectivity. Specifically:

    1. Is there a safe API or driver-level method to completely disable UARTE (similar to nrf_drv_uart_uninit() in nRF5 SDK) that is compatible with MPSL?
    2. If direct register access is not safe, what is the correct Zephyr driver approach to power down UART when idle and restore it on wake?
    3. Are there any known limitations or workarounds for UART Async API coexistence with BLE on nRF52832?

    Additional Note:

    • CONFIG_PM is not available on nRF52832 (Zephyr power management framework not supported for this SoC)
    • LFCLK source: internal RC oscillator (no external 32.768kHz crystal)
    • P0.09 and P0.10 are used as GPIO (LED and BUTTON), requiring UICR.NFCPINS to be configured for GPIO mode
Children
No Data
Related