Using LFRC as the softdevice LFCLK source, enabling and running the WDT causes the softdevice to hang until the watchdog reset when calling nrf_sdh_disable_request. This is with SDK v15.3.0 on both S112 and S140.
Configuring the WDT to pause on debugging, I was able to trace the call to following:
nrf_sdh_disable_request
sdh_state_observer_notify
handler(evt, p_observer->p_context)
(which is sd_state_evt_handler
in the first iteration of my loop)nrfx_clock_enable
nrf_drv_clock_lfclk_release
lfclk_stop
7.
nrfx_clock_lfclk_stop
while(nrf_clock_lf_is_running()). <--- Hangs here (nrfx_clock.c:245)
Given the functions below, I don't see a way for the softdevice to successfully disable while using an LFRC that is also in use by the WDT, without registering an
m_clock_cb.lfclk_requests
, which the nrfx_wdt
drivers do not appear to do:/** * @brief SoftDevice enable/disable state handler. * * @param[in] state State. * @param[in] p_context Context. */ static void sd_state_evt_handler(nrf_sdh_state_evt_t state, void * p_context) { switch (state) { case NRF_SDH_EVT_STATE_ENABLE_PREPARE: NVIC_DisableIRQ(POWER_CLOCK_IRQn); break; case NRF_SDH_EVT_STATE_ENABLED: CRITICAL_REGION_ENTER(); /* Make sure that nrf_drv_clock module is initialized */ if (!m_clock_cb.module_initialized) { (void)nrf_drv_clock_init(); } /* SD is one of the LFCLK requesters, but it will enable it by itself. */ ++(m_clock_cb.lfclk_requests); m_clock_cb.lfclk_on = true; CRITICAL_REGION_EXIT(); break; case NRF_SDH_EVT_STATE_DISABLED: /* Reinit interrupts */ ASSERT(m_clock_cb.module_initialized); nrfx_clock_enable(); /* SD leaves LFCLK enabled - disable it if it is no longer required. */ nrf_drv_clock_lfclk_release(); break; default: break; } }
void nrf_drv_clock_lfclk_release(void) { ASSERT(m_clock_cb.module_initialized); ASSERT(m_clock_cb.lfclk_requests > 0); CRITICAL_REGION_ENTER(); --(m_clock_cb.lfclk_requests); if (m_clock_cb.lfclk_requests == 0) { lfclk_stop(); } CRITICAL_REGION_EXIT(); }
nrfx_err_t nrfx_wdt_init(nrfx_wdt_config_t const * p_config, nrfx_wdt_event_handler_t wdt_event_handler) { NRFX_ASSERT(p_config); nrfx_err_t err_code; #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ) NRFX_ASSERT(wdt_event_handler != NULL); m_wdt_event_handler = wdt_event_handler; #else NRFX_ASSERT(wdt_event_handler == NULL); (void)wdt_event_handler; #endif if (m_state == NRFX_DRV_STATE_UNINITIALIZED) { m_state = NRFX_DRV_STATE_INITIALIZED; } else { err_code = NRFX_ERROR_INVALID_STATE; NRFX_LOG_WARNING("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } nrf_wdt_behaviour_set(p_config->behaviour); nrf_wdt_reload_value_set((p_config->reload_value * 32768) / 1000); #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ) NRFX_IRQ_PRIORITY_SET(WDT_IRQn, p_config->interrupt_priority); NRFX_IRQ_ENABLE(WDT_IRQn); #endif err_code = NRFX_SUCCESS; NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; }
Am I missing a softdevice call or step that enables it to proceed while sharing the LFCLK source with WDT?
Here are my clock settings for the softdevice:
// <o> NRF_SDH_CLOCK_LF_SRC - SoftDevice clock source.
// <0=> NRF_CLOCK_LF_SRC_RC
// <1=> NRF_CLOCK_LF_SRC_XTAL
// <2=> NRF_CLOCK_LF_SRC_SYNTH
#ifndef NRF_SDH_CLOCK_LF_SRC
#define NRF_SDH_CLOCK_LF_SRC 1
#endif
// <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval.
#ifndef NRF_SDH_CLOCK_LF_RC_CTIV
#define NRF_SDH_CLOCK_LF_RC_CTIV 16
#endif
// <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature.
// <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
// <i> if the temperature has not changed.
#ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
#define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
#endif
Commenting out the call to nrf_drv_clock_lfclk_release
or lfclk_stop
prevents the hang.
Also, if I switch NRF_SDH_CLOCK_LF_SRC
to LFSYNT, the softdevice disables successfully without any hanging. However, the softdevice documentation states that there are only two sources usable for the softdevice: the internal RC and XTAL.
Is LFSYNT not recommended for the softdevice? Or is this a valid alternative as an "internal RC" if the additional current consumption is acceptable?