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_requestsdh_state_observer_notifyhandler(evt, p_observer->p_context) (which is sd_state_evt_handler in the first iteration of my loop)nrfx_clock_enablenrf_drv_clock_lfclk_releaselfclk_stop7.
nrfx_clock_lfclk_stopwhile(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?