nRF5340 CPUNET Watchdog not resetting SoC on timeout (WDT_FLAG_RESET_SOC)

Hello Nordic Team,

I'm currently integrating a watchdog on the nRF5340 CPUNET core to detect and recover from potential hangs. We’ve observed that in rare cases, the device:

  • Reports as "connected" from the app core perspective,

  • But no advertising is visible,

  • And communication is completely stuck (no BLE responses).

We suspect that the network core might be stuck or deadlocked, so our plan is to use the watchdog to reset the net core in such cases.

What I’ve done

  • Based on the hci_ipc sample in NCS v3.5.99-ncs1

  • Added a watchdog with 5s timeout (WDT_FLAG_RESET_SOC)

  • Simulated a stuck net core (infinite loop after 30 seconds)

  • But no reset happens

DeviceTree (cpunet.dts)

&wdt {
    status = "okay";
};

aliases {
    watchdog = &wdt;
};

Also defined wdt0: watchdog@4100b000 in SoC .dtsi as follows:

wdt: wdt0: watchdog@4100b000 {
    compatible = "nordic,nrf-wdt";
    reg = <0x4100b000 0x1000>;
    interrupts = <11 NRF_DEFAULT_IRQ_PRIORITY>;
    status = "okay";
};

Watchdog Code (in childi_image/hci_ipc/src/main.c)

wdt_dev = DEVICE_DT_GET(DT_ALIAS(watchdog));
...
struct wdt_timeout_cfg wdt_config = {
    .window.min = 0,
    .window.max = 5000,
    .callback = NULL, // Also tested with a handler
    .flags = WDT_FLAG_RESET_SOC,
};
wdt_channel_id = wdt_install_timeout(wdt_dev, &wdt_config);
wdt_setup(wdt_dev, 0);

Main Loop (simulated hang after 30s)

if (k_uptime_get() > 30000) {
    LOG_INF("Simulating hang");
    while (1) {
        k_sleep(K_SECONDS(1));
    }
}

  • The system stops feeding the WDT

  • Expected: Reset after ~5s

  • Observed: Nothing happens — net core just keeps sleeping


Other Observations

  • WDT logs confirm it's installed and started (id 0)

  • Feeding works when enabled manually

  • .callback handler is never called either

  • No debugger is connected during test

  • Behavior same with and without WDT_OPT_PAUSE_HALTED_BY_DBG


What I’m looking for

  1. Is WDT_FLAG_RESET_SOC supported and effective on CPUNET (network core)?

  2. Is any special mechanism needed to allow watchdog reset on this core?

  3. Could the WDT IRQ or system reset logic be masked or non-functional?

  4. How can I verify if WDT is ticking or actually reaching timeout?

  5. Is there any easier / better-supported way to include watchdog functionality on the net core in this use case?


Context: I want to use the watchdog to recover from rare, hard-to-reproduce BLE communication hangs where the net core is no longer advertising/responding, but the app core still believes everything is fine.

Would really appreciate your input — especially if there’s a better or simpler way to enable this on CPUNET.

Thanks a lot in advance!

  • Hi,

    I am gonna start by not answering your questions and instead ask one question back:

    Do you see the same behaviour if you do not call k_sleep() from the loop, but just loops without anything inside instead?

    Regards,
    Sigurd Hellesvik

  • Hi Sigurd,

    Thanks for the quick response!

    I ran the test you suggested and replaced the k_sleep() in the simulated hang with a tight infinite loop (while (1) {}), and I’m still seeing the same behavior — the watchdog does not fire.

    So just to clarify:

    • I'm not using k_sleep() anymore.

    • The main thread simply gets stuck in a while (1) {} loop after 30 seconds.

    • WDT is started correctly (WDT_FLAG_RESET_SOC and optional .callback are set).

    • The .callback is never triggered and the SoC never resets.

    Thanks again!

  • Is WDT_FLAG_RESET_SOC supported and effective on CPUNET (network core)?

    I have not heard of it not being supported.

    I have not tested this myself, ither.

    • Is any special mechanism needed to allow watchdog reset on this core?

    • Could the WDT IRQ or system reset logic be masked or non-functional?

    • How can I verify if WDT is ticking or actually reaching timeout?

    • Is there any easier / better-supported way to include watchdog functionality on the net core in this use case?

    Can you try to build and flash the Watchdog sample for the network core and see how that goes?

    If you see the same error with this sample, I can try to reproduce it tomorrow.

  • After extensive investigation, I’d like to share my findings and open questions regarding WDT behavior on the network core (CPUNET):


    Confirmed:

    • The WDT_FLAG_RESET_SOC does work on the network core, as verified using the official watchdog sample flashed directly to the NET CORE. Manually blocking the thread results in a proper reset.

    • In my real-world application (based on the hci_ipc sample), the watchdog is:

      • Successfully initialized.

      • wdt_install_timeout() returns valid channel IDs (0 and 1).

      • nrfx_wdt_enable() is called.

      • Log output confirms:

        <inf> NRFX_WDT: Enabled.

    Suspicious Behavior:

    • Before the application even boots, this message appears:

      <inf> NRFX_WDT: Function: wdt_init, error code: NRFX_SUCCESS.
    • This indicates that the watchdog is already being initialized prior to app booteven with MCUboot configured to not enable the WDT (CONFIG_WATCHDOG=n in child_image/mcuboot.conf).

    • This early init seems to persist even when the WDT is explicitly disabled in the bootloader and app config.

    • In this setup, although nrfx_wdt_enable() and nrfx_wdt_channel_alloc() return success, the reset never occurs, even during intentional hangs.

    Hypothesis:

    • Some other component — potentially the SoftDevice Controller (SDC) or other early init path — may be initializing and starting the NRFX WDT before the application gets to configure it.

    • Since Zephyr’s WDT API does not provide a way to reset or reinitialize an already started WDT (which NRFX WDT doesn't allow by design), the app WDT config might be ineffective.

    • Calling nrf_wdt_request_status_get(NRF_WDT_NS) shows at least one request bit already set before any channel is allocated in the app.

    Open Questions:

    1. Could the SoftDevice Controller or another runtime component be initializing the NRFX WDT on CPUNET?

    2. Is it possible that the early WDT config (outside of my app code) prevents WDT_FLAG_RESET_SOC from taking effect later?

    3. Is there any safe way to detect, disable, or "override" a WDT that was started before app execution (e.g., by MCUboot or SDC)?

    4. Can I verify that the WDT is ticking and reaching the timeout internally (without relying on reset as confirmation)?

Related