Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Can't get BLE device to sleep

I have a custom PCBA with which has the flow of:

- Boot

- Advertise some temperature data read from TWI with a 5 second timeout using `ble_adv_fast_timeout`.

- I then set a timer to wake the `app_timer_start(m_awake_timer_id, APP_TIMER_TICKS(SLEEP_IN_MS), NULL);`

And I expect the device to go into sleep whilst its BLE is not advertising. Here's my main.c file:

#include "app_timer.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_crypto_init.h"
#include "nrfx_clock.h"

#include "SEGGER_RTT.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_delay.h"

#include "customble.h"
#include "peripheral.h"
#include "encryption.h"

void timers_init(void)
{
  ret_code_t err_code = app_timer_init();
  APP_ERROR_CHECK(err_code);
}

static void idle_state_handle(void)
{
  if (NRF_LOG_PROCESS() == false)
  {
    nrf_pwr_mgmt_run();
  }
}

/**@brief Function for initializing power management.
 */
void power_management_init(void)
{
  ret_code_t err_code;
  err_code = nrf_pwr_mgmt_init();
  APP_ERROR_CHECK(err_code);
}

int main(void)
{
  NRF_LOG_INIT(NULL);
  NRF_LOG_DEFAULT_BACKENDS_INIT();

  ret_code_t reta = nrf_crypto_init();
  APP_ERROR_CHECK(reta);

  timers_init();
  ble_timers_init();
  ble_stack_init();

  power_management_init();

  gap_params_init();
  advertising_init();

  advertising_start();

  for (;;)
  {
    idle_state_handle();
  }
}

and here's the relevant sections of the customble.c code

void awake_timer_handler()
{
  NRF_LOG_INFO("Awake and start advertising");

  update_advertising_data_while_advertising();
  advertising_start();
}

void sleep_timer_handler()
{
  NRF_LOG_INFO("asleep");

  sd_ble_gap_adv_stop(m_advertising.adv_handle); // i've tried with and without this

  // Proceed with setting the device to low power mode
  app_timer_start(m_awake_timer_id, APP_TIMER_TICKS(SLEEP_IN_MS), NULL); // 60 seconds
}

void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
  NRF_LOG_INFO("BLE EVENT");
  switch (ble_adv_evt)
  {
  case BLE_ADV_EVT_IDLE:
    NRF_LOG_INFO("Advertising event: Idle");
    sleep_timer_handler();
    break;
  }
}

I have measured the amps on the device and during advertising it jumps to about 3mA and when it's not advertising (when I thought it would sleep) it's using ~1.48mA. What exactly am I doing wrong here?

I have commented lots of things out, and it's not the TWI causing the issue, it's definitely the BLE. When I comment out starting BLE, I get ~400uA constant.

  • Hello Nathan,

    Right. An external LFXTAL is one way (I assume you meant externla LF clock, and not HF clock, since you probably have an external HF clock already. That one is mandatory, but the LF XTAL is optional).

    Yes, the SYNTH is an easy way to make sure that the LFCLK is working properly, but this is not intended for production, as it is way too power-hungry. 

    Let me try to get this straight, so that we get the RC oscillator up and running:

    There are several sets of definitions in sdk_config.h regarding the clock configuration. If you search this file for "LF_SRC", you will find:

    NRFX_CLOCK_CONFIG_LF_SRC
    CLOCK_CONFIG_LF_SRC
    NRF_SDH_CLOCK_LF_SRC

    Try to make these align. You can check the file apply_old_config.h to see how NRFX_CLOCK_CONFIG_LF_SRC and CLOCK_CONFIG_LF_SRC work together, but I usually just set them equal to one another, so I don't need to remember which one overwrites the other. 

    The NRF_SDH_CLOCK_LF_SRC is not part of apply_old_config.h, but it is used by the softdevice. When this is set to 0 (NRF_CLOCK_LF_SRC_RC, you need to set NRF_SDH_CLOCK_LF_RC_CTIV, NRF_SDH_CLOCK_LF_RC_TEMP_CTIV and NRF_SDH_CLOCK_LF_ACCURACY accordingly. 

    This is not very intuitive, but if you look in nrf_sdm.h (which will be included in you application project), you can look at the declaration of the struct nrf_clock_lf_cfg_t. In the parameter description it says:

    uint8_t rc_temp_ctiv;   /**<  Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration
                                    intervals) the RC oscillator shall be calibrated if the temperature
                                    hasn't changed.
                                         0: Always calibrate even if the temperature hasn't changed.
                                         1: Only calibrate if the temperature has changed (legacy - nRF51 only).
                                         2-33: Check the temperature and only calibrate if it has changed,
                                               however calibration will take place every rc_temp_ctiv
                                               intervals in any case.
    
                                    @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC.
    
                                    @note For nRF52, the application must ensure calibration at least once
                                          every 8 seconds to ensure +/-500 ppm clock stability. The
                                          recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is
                                          rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at
                                          least once every 8 seconds and for temperature changes of 0.5
                                          degrees Celsius every 4 seconds. See the Product Specification
                                          for the nRF52 device being used for more information.*/

    So if you have NRF_CLOCK_LF_SRC_RC (0), then you must also set:

    NRF_SDH_CLOCK_LF_RC_CTIV 16
    NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
    NRF_SDH_CLOCK_LF_ACCURACY 1

    If not, the initialization of the softdevice will fail, as you can see from nrf_sdh.c, line 76:

    #if (   (NRF_SDH_CLOCK_LF_SRC      == NRF_CLOCK_LF_SRC_RC)          \
         && (NRF_SDH_CLOCK_LF_ACCURACY != NRF_CLOCK_LF_ACCURACY_500_PPM))
        #warning Please select NRF_CLOCK_LF_ACCURACY_500_PPM when using NRF_CLOCK_LF_SRC_RC
    #endif
    

    Try that, and let me know whether it works.

    Best regards,

    Edvin

  • Depending on your application you may or may not benefit from adding an LFXTAL. The disadvantage of an external LFCLK is that you have one more component that will draw current, but the advantage is that if you are (often) in a connection, you will have a more accurate LFCLK, which means that the radio will be able to more accurately determine when it will receive a radio packet, which means that it can narrow down the timeslot where the radio will be active (in RX mode). 

    This is however only when you are in a connection. If your application is a beacon that is only advertising, the increased accuracy of the LFCLK doesn't come with any benefits. 

    BR,

    Edvin

  • That's interesting, it sounds like (as I'm just using BLE advertising) that a external LFCLK should not be needed then.

    I had set these from reading through the following document which was quite useful (see section for "Internal RC low-frequency oscillator (LFRC)"). The problem I have is that when I set (as you mentioned in your post), the configuration:

    #define CLOCK_CONFIG_LF_SRC 0
    #define NRFX_CLOCK_CONFIG_LF_SRC 0
    #define NRF_SDH_CLOCK_LF_SRC 0
    #define NRF_SDH_CLOCK_LF_RC_CTIV 16
    #define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
    #define NRF_SDH_CLOCK_LF_ACCURACY 1

    the BLE device is no longer detectable. What I mean by this is that I can no longer detect the signal using my laptop or mobile phone (both are using nRF Connect bluetooth app).

    It sounds to me like you're saying this should work. My assumption was that it was a hardware issue which caused the RC oscillator to not be stable enough... I will just double check this with one of the example applications and updating the above configuration. 

  • prsboy said:

    LFCLK should not be needed then.

    In that case, I don't see any benefits from using an LFXTAL, so at least if you haven't designed it in already, I wouldn't bother.

    With the configuration that you have there, when you are not able to detect the BLE device, does the log say anything relevant?

    Is the BLE stack enabled as it should? Does the application reach the advertising_start() function? Do you see any logs at all if you enable logging and use your custom board? Did you remember to remove the DEVELOP_IN_NRF52832 preprocessor definition?

    Best regards,

    Edvin

  • I have completely removed all reference of DEVELOP_IN_NRF52832.

    When i try and deploy it on my custom PCBA I can see logs as usual:

    <info> app_timer: RTC: initialized.
    <info> app: Starting temperature measurement.
    <info> app: Reading temperature data.
    <info> app: Calculated temperature: 22.64 C
    <info> app: number: 2264
    <info> app: Starting humidity measurement.
    <info> app: Reading humidity data.
    <info> app: Calculated humidity: 64.30%
    <info> app: number: 6430
    <info> app: BLE EVENT
    <info> app: start ble
    <info> app: BLE EVENT
    <info> app: Advertising event: Idle
    <info> app: asleep
    <info> app: Awake and start advertising
    <info> app: Starting temperature measurement.
    <info> app: Reading temperature data.
    <info> app: Calculated temperature: 22.75 C
    <info> app: number: 2275
    <info> app: Starting humidity measurement.
    <info> app: Reading humidity data.
    <info> app: Calculated humidity: 63.59%
    <info> app: number: 6359
    <info> app: BLE EVENT
    <info> app: start ble
    <info> app: BLE EVENT
    <info> app: Advertising event: Idle
    <info> app: asleep

    but I'm unable to pick anything up when scanning for the device which is very strange, the device behaves exactly how it does when I set the LFCLK to XTAL, apart from I can't detect the BLE signal. Is there any way I'm able to check the state of the LFCLK? I tried setting

    #define NRFX_CLOCK_CONFIG_LOG_ENABLED 1
    #define NRFX_CLOCK_CONFIG_LOG_LEVEL 4

    but no additional logs are output to the console (as seen from the console output above).

Related