This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Is it possible to dynamically detect presence of low frequency crystal for Soft Device?

Is it possible to detect the presence of a Low Frequency Crystal and configure softdevice to use if present, otherwise use the internal RC oscillator?

A proposal would be to probe presence of the crystal prior to sd_enable() and change the LFCLKSRC definition to use the crystal or RC depending on the result. Would this pattern work?

Parents Reply Children
  • Hello,

    Yes, the approach above should work. Also, if it makes sense for your application, you may consider making this a one-time check by storing the detected clock source to flash for subsequent startups. This will allow you to reduce the startup time and power consumption a bit.

    Something like this (code is untested)

    #include "nrf_delay.h"
    
    /* Make sure selected UICR CUSTOMER[n] register is not used elsewhere
     * in Application or Bootloader code.
     */
    #define UICR_CLOCK_SETTING_ADDRESS NRF_UICR->CUSTOMER[0] 
    #define UICR_CLOCK_SRC_XTAL        0x1
    #define UICR_CLOCK_SRC_RC          0x2
    
    static bool lfclk_is_xtal_available(void)
    {
        bool has_xtal = false;
    
        /* Check if we need to update the UICR register. True on first boot */
        if (UICR_CLOCK_SETTING_ADDRESS == 0xFFFFFFFF)
        {
    
            NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
            NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
            NRF_CLOCK->TASKS_LFCLKSTART = 1;
    
            nrf_delay_ms(1000);
    
            if (NRF_CLOCK->EVENTS_LFCLKSTARTED == 1)
            {
                // hurray there is an external LFCLK present.
                // you can set external LFCLK when enable softdevice
                NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
                has_xtal = true;
            }
    
            /* Use NVMC to update the UICR register with out LF clk source setting */
            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
            while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
            {
            }
            UICR_CLOCK_SETTING_ADDRESS = (has_xtal == true) ? UICR_CLOCK_SRC_XTAL : UICR_CLOCK_SRC_RC;
            while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
            {
            }
            NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
            while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
            {
            }
        }
        else
        {
            has_xtal = (UICR_CLOCK_SETTING_ADDRESS == UICR_CLOCK_SRC_XTAL) ? true : false;
        }
    
        return has_xtal;
    }

Related