BM833 energy saving

Dear forum,

I want to achive low energy consumption for a BM833 (with crystal).

From the following thread, I could deduct, that running the softdevice, an average of 300+ uA is required:

https://devzone.nordicsemi.com/f/nordic-q-a/10425/possible-to-shutdown-soft-device-or-ble-after-init-to-achieve-low-power

Now I could follow the instructions to shutdown the HF-Clock, as suggested, but I could read:

"The SoftDevice does not stop the LFCLK when it disables because other modules may use it (like app_timer)."

This, in reverse, could mean that stopping LFCLK might render the app_timer unusable?

I need to be able to "relaunch" the softdevice (S132) periodically to achieve periodic transmissions (send and/or receive) and currently, I'm using also timers to read from peripherals.

How would I have to proceed to achieve that goal when, at the same time, switching off the LFCLK to achieve 2uA consumption?

Can anyone give a code example?

Best regards,

Richard

Parents
  • Hello Richard,

    You should select the internal RC oscillator (LFRC) as the clock source if you don't have a 32 KHz mounted on your board. LFSYNT is generally not recommend as it forces the HFXO on and therefore leads to a significantly higher idle current (~500 uA).

    The Softdevice will keep the LF clock running as long as it is enabled for protocol timing. You also need this clock running for the app timer (RTC) to work. However, the system current with the LFCLK running (LFRC/LRXO) is only around  2-3 uA (Sleep).

    You can use our online power profiler (https://devzone.nordicsemi.com/power/w/opp/2/online-power-profiler-for-bluetooth-le) to estimate the average current when you are in the connected and advertising state.

    Best regards,

    Vidar

  • Hello Vidar,

    thank you for the initial answere.

    Let's assume I have a 32k crystal, then what should I do:

    known places for settings:

    ~\components\softdevice\common\nrf_sdh.c
    
    //without crystal
    nrf_clock_lf_cfg_t const clock_lf_cfg =
        {
            .source       = 0,
            .rc_ctiv      = 16,
            .rc_temp_ctiv = 2,
            .accuracy     = 7
        }
    
    
    //setting with soldered crystal, e.g. nRF52833 DK
    nrf_clock_lf_cfg_t const clock_lf_cfg =
        {
            .source       = NRF_SDH_CLOCK_LF_SRC,
            .rc_ctiv      = NRF_SDH_CLOCK_LF_RC_CTIV,
            .rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,
            .accuracy     = NRF_SDH_CLOCK_LF_ACCURACY
        }
    


    And in my main.c code (dependent on crystal availability), I have:

        #if CRYSTAL_ENABLED == 1
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
        #else
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Synth << CLOCK_LFCLKSRC_SRC_Pos);
        #endif

    Is that code OK to get LFCLK to use the crystal as source?

    What do I need to do to switch off HFCLK and get the low-power mode?

    Best regards,

    Richard

Reply
  • Hello Vidar,

    thank you for the initial answere.

    Let's assume I have a 32k crystal, then what should I do:

    known places for settings:

    ~\components\softdevice\common\nrf_sdh.c
    
    //without crystal
    nrf_clock_lf_cfg_t const clock_lf_cfg =
        {
            .source       = 0,
            .rc_ctiv      = 16,
            .rc_temp_ctiv = 2,
            .accuracy     = 7
        }
    
    
    //setting with soldered crystal, e.g. nRF52833 DK
    nrf_clock_lf_cfg_t const clock_lf_cfg =
        {
            .source       = NRF_SDH_CLOCK_LF_SRC,
            .rc_ctiv      = NRF_SDH_CLOCK_LF_RC_CTIV,
            .rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,
            .accuracy     = NRF_SDH_CLOCK_LF_ACCURACY
        }
    


    And in my main.c code (dependent on crystal availability), I have:

        #if CRYSTAL_ENABLED == 1
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
        #else
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Synth << CLOCK_LFCLKSRC_SRC_Pos);
        #endif

    Is that code OK to get LFCLK to use the crystal as source?

    What do I need to do to switch off HFCLK and get the low-power mode?

    Best regards,

    Richard

Children
  • Hello Richard,

    For LFXO you can use the following configuration:

    / </h> 
    //==========================================================
    
    // <h> Clock - SoftDevice clock configuration
    
    //==========================================================
    // <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 0
    #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 0
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.
     
    // <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
    // <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
    // <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
    // <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
    // <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
    // <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
    // <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
    // <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
    // <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
    // <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
    // <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
    // <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 
    
    #ifndef NRF_SDH_CLOCK_LF_ACCURACY
    #define NRF_SDH_CLOCK_LF_ACCURACY 7
    #endif
    

    And for LFRC you can use this one (notice that the accuracy is changed to 500 ppm. This is required when using the LFRC):

    // </h> 
    //==========================================================
    
    // <h> Clock - SoftDevice clock configuration
    
    //==========================================================
    // <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 0
    #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
    
    // <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.
     
    // <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
    // <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
    // <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
    // <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
    // <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
    // <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
    // <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
    // <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
    // <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
    // <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
    // <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
    // <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 
    
    #ifndef NRF_SDH_CLOCK_LF_ACCURACY
    #define NRF_SDH_CLOCK_LF_ACCURACY 1
    #endif

    RichardHdrd said:
    What do I need to do to switch off HFCLK and get the low-power mode?

    You don't need to do anything. The Softdevice turns off the HFXO after every RADIO event.

    RichardHdrd said:
    And in my main.c code (dependent on crystal availability), I have:

    The Softdevice enables the clock with the configuration given in sdk_config.h so you usually don't have to start the clock yourself in main.

    Best regards,

    Vidar

  • Hello Vidar,

    Thank you for your advice. I adjusted the sdk_config.h as suggested by you, but I keep measuring the same current average of 300+ uA.

    I then tried to modify:

    //old energy idle
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    //new energy idle
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            if (nrf_sdh_is_enabled())
            {
                nrf_sdh_suspend();
                nrf_sdh_disable_request();
                //NRF_CLOCK->TASKS_HFCLKSTOP = 1;
            }
            __WFE();
            if (!nrf_sdh_is_enabled())
            {
                //NRF_CLOCK->TASKS_HFCLKSTART = 1;
                nrf_sdh_enable_request();
                nrf_sdh_evts_poll();
            }
        }
    }

    But this did not only increase the required current, but also rendered all my timers inactive.

    BTW timers, this is the way I implemented them:

    main.c:
    
    APP_TIMER_DEF(m_bsp_tmr1);
    
    int main(void)
    {
        (...)
        uint32_t timeout_ticks1 = APP_TIMER_TICKS(2000);
        err_code = app_timer_create(&m_bsp_tmr1, APP_TIMER_MODE_REPEATED, m_timer_handler1);
        APP_ERROR_CHECK(err_code);
        app_timer_start(m_bsp_tmr1, timeout_ticks1, NULL);
        (...)
        for (;;)
        {
            idle_state_handle();
            NRF_LOG_INFO("Active");
            NRF_LOG_FLUSH();
        }
    }

    So maybe there is something additional that needs to be set, cleared or considered to get to a low current consumption while keeping timers active?

    Best regards,

    Richard

  • Hi Richard,

    There is no benefit to enabling and disabling the Softdevice as shown in your code snippet if you are going to keep the LF clock active anyway. I suggest you enable the Softdevice and use the idle_state_handle() as in our other SDK BLE examples.

    Best regards,

    Vidar

  • Hello Vidar,

    Sorry to continue the thread from here, but the forum doesn't allow me to respond from your last suggestion ("enable the Softdevice and use the idle_state_handle().").

    If I do, as you suggest, with all LFRC clock-configuration as suggested, I see an average current of 300+ uA (the same 300+ uA that were observed, before I changed the clock settings in sdk_config.h for LFRC, as you suggested below).

    So, the question still is, how to get the current down to the famous 2.2uA (or at least significantly below 300+ uA)?

    Best regards,

    Richard

  • If I do, as you suggest, with all LFRC clock-configuration as suggested, I see an average current of 300+ uA (the same 300+ uA that were observed, before I changed the clock settings in sdk_config.h for LFRC, as you suggested below).

    Which of the suggested clock configurations did you select, the LFXO or LFRC?

    So, the question still is, how to get the current down to the famous 2.2uA (or at least significantly below 300+ uA)?

    It must be caused by something else if you selected one of the clock sources above.

Related