Not able to disable/stop Watchdog on NRF54L15-DK.

I am trying to enable a watchdog and then stop it. i closely followed the datasheet way to do this. the problem is that the watchdog once enabled will always fire. i want to enable then disable the watchdog. See code: 

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/device.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <hal/nrf_clock.h>
#include <zephyr/sys/reboot.h>
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/drivers/timer/nrf_grtc_timer.h>
#include <haly/nrfy_grtc.h>
#include <errno.h>
#include <zephyr/sys/util.h> // BIT()

#define WDT_TIMEOUT_MS 5000
/* wdt30 base (GLOBAL): 0x50108000 */
#define WDT30_BASE 0x50108000UL
#define REG32(o) (*(volatile uint32_t *)(WDT30_BASE + (o)))
#define TASKS_START 0x000
#define TASKS_STOP 0x004
#define EVENTS_STOPPED 0x104
#define RUNSTATUS 0x400
#define CRV 0x504
#define RREN 0x508
#define CONFIG_REG 0x50C
#define TSEN 0x520
#define TSEN_KEY 0x6E524635
#define RR0 0x600
#define STOPEN_BIT      2u              /* CONFIG bit that allows STOP */


/* ---- GRTC helpers: 1 tick = 1 us ---- */
#define GRTC_BITS 48
#define GRTC_MASK ((1ULL << GRTC_BITS) - 1)

static inline uint64_t grtc_now(void) { return nrfy_grtc_sys_counter_get(NRF_GRTC) & GRTC_MASK; }
static inline uint64_t grtc_delta(uint64_t now, uint64_t ref) { return (now - ref) & GRTC_MASK; }

static void print_reset_cause(uint32_t cause)
{
    if (cause == 0)
    {
        printk("Cold boot\n");
        return;
    }
    printk("Reset cause: 0x%08x\n", cause);
    if (cause & RESET_SOFTWARE)
        printk(" - software reset\n");
    if (cause & RESET_WATCHDOG)
        printk(" - watchdog reset\n");
    if (cause & RESET_PIN)
        printk(" - pin reset\n");
    if (cause & RESET_CLOCK)
        printk(" - System OFF wake by GRTC\n");
    if (cause & RESET_LOW_POWER_WAKE)
        printk(" - System OFF wake by GPIO\n");
}

static void ensure_lfclk_xtal(void)
{
    const struct device *clk = DEVICE_DT_GET(DT_NODELABEL(clock));
    if (!device_is_ready(clk))
    {
        printk("clock not ready!\n");
        return;
    }

    int rc = clock_control_on(clk, CLOCK_CONTROL_NRF_SUBSYS_LF);
    if (rc && rc != -EALREADY)
    {
        printk("clock_control_on rc=%d\n", rc);
    }

    while (clock_control_get_status(clk, CLOCK_CONTROL_NRF_SUBSYS_LF) != CLOCK_CONTROL_STATUS_ON)
    {
        k_sleep(K_MSEC(1));
    }
    bool running = nrf_clock_lf_is_running(NRF_CLOCK);
    nrf_clock_lfclk_t src = nrf_clock_lf_src_get(NRF_CLOCK); // 0=RC,1=XTAL,2=SYNTH (most nRFs)
    printk("LFCLK running=%d src=%d (0=RC,1=XTAL,2=SYNTH)\n", running, src);
}

static inline uint32_t ms_to_crv(uint32_t ms)
{
    /* T = (CRV+1)/32768. Clamp to >=16 cycles and do ceil to avoid shorter than requested. */
    uint64_t cycles = (uint64_t)ms * 32768u + 999u;  /* ceil(ms*32768/1000) */
    cycles /= 1000u;
    if (cycles < 16u) cycles = 16u;
    return (uint32_t)(cycles - 1u);
}

static inline bool wdt_is_running(void)
{
    return (REG32(RUNSTATUS) & 1u) != 0;
}

static inline bool wdt_is_stoppable(void)
{
    return (REG32(CONFIG_REG) & (1u << STOPEN_BIT)) != 0;
}

static void wdt_start_stoppable(uint32_t timeout_ms)
{
    if (wdt_is_running()) return;                     /* already running */

    /* Set STOPEN before START, preserve other bits */
    uint32_t cfg = REG32(CONFIG_REG);
    cfg |= (1u << STOPEN_BIT);
    REG32(CONFIG_REG) = cfg;

    REG32(CRV)  = ms_to_crv(timeout_ms);
    REG32(RREN) = 1u;                                 /* enable RR0 */
    REG32(TASKS_START) = 1u;
}

static bool wdt_stop(uint32_t timeout_ms)
{
    if (!wdt_is_running()) return true;               /* nothing to do */
    // if (!wdt_is_stoppable()) return false;            /* started earlier w/ STOPEN=0 → cannot stop */

    REG32(TSEN) = TSEN_KEY;                           /* arm STOP */
    REG32(EVENTS_STOPPED) = 0;
    REG32(TASKS_STOP) = 1;

    k_sleep(K_MSEC(timeout_ms));
    REG32(TSEN) = 0;                                  /* disarm on timeout */
    return (REG32(RUNSTATUS) & 1u) == 0;
}

/* static int start_wdt_zephyr(void)
{
    // Ensure the DT node is OKAY at build-time; see overlay below

    const struct device *wdt = DEVICE_DT_GET(DT_NODELABEL(wdt30));
    if (!device_is_ready(wdt))
    {
        printk("WDT '%s' not ready\n", wdt->name);
        return -ENODEV;
    }

    struct wdt_timeout_cfg cfg = {
        .window = {.min = 0, .max = WDT_TIMEOUT_MS},
        .callback = NULL, // no bark ISR, go straight to reset
        .flags = WDT_FLAG_RESET_SOC,
    };
    int ch = wdt_install_timeout(wdt, &cfg);
    if (ch < 0)
    {
        printk("wdt_install_timeout failed: %d\n", ch);
        return ch;
    }

    int rc = wdt_setup(wdt, 0); // do NOT pause in sleep/debug
    if (rc < 0)
    {
        printk("wdt_setup failed: %d\n", rc);
        return rc;
    }

    printk("WDT armed on dev='%s' for %u ms; not feeding…\n", wdt->name, WDT_TIMEOUT_MS);
    return 0;
} */

int main(void)
{
    ensure_lfclk_xtal();

    bool ok = wdt_stop(100);
    wdt_start_stoppable(WDT_TIMEOUT_MS);

    uint32_t cause = 0;
    hwinfo_get_reset_cause(&cause);
    print_reset_cause(cause);
    hwinfo_clear_reset_cause();

    uint64_t startup_ticks = z_nrf_grtc_timer_startup_value_get();
    uint64_t now_ticks = grtc_now();
    uint64_t since_start = grtc_delta(now_ticks, startup_ticks);
    printk("GRTC at startup: %llu  | now: %llu  | (+%llu us since boot)\n",
           (unsigned long long)startup_ticks,
           (unsigned long long)now_ticks,
           (unsigned long long)since_start);

    // if (start_wdt_zephyr() == 0)
    // {
    k_sleep(K_SECONDS(2)); /* don’t feed; WDT will reset us */

    ok = wdt_stop(100);
    k_sleep(K_MSEC(5));

    sys_reboot(SYS_REBOOT_COLD);
    // }
    return 0;
}
Parents Reply Children
No Data
Related