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

Wakeup immediately from sd_app_evt_wait() with external LFCLK

Hi all

We use the nRF51822 with the S130 V1.0.0. Our application initializes the TIMER2 (f = 16MHz) with a EVENTS_COMPARE interrupt on the CC channel 1 to monitor some timings.

Afterwards the SoftDevice is enabled with the LFCLK source "NRF_CLOCK_LFCLKSRC_XTAL_20_PPM". The TIMER2 stays running.

Later on, we want to reduce the power consumption. Therefore we disable the TIMER2 with the following code:

   NRF_TIMER2->TASKS_STOP = 1;
   NRF_TIMER2->TASKS_SHUTDOWN = 1;

   NVIC_DisableIRQ(TIMER2_IRQn);
   NVIC_ClearPendingIRQ(TIMER2_IRQn);

Afterwards we call the function sd_app_evt_wait() but the nRF51822 wakes up immediately. The strange thing is, that when I change the LFCLK source at the SoftDevice initialization to "NRF_CLOCK_LFCLKSRC_RC_250_PPM_TEMP_4000MS_CALIBRATION", the nRF51822 stays in the low power mode. Therefore there should be no event/interrupt in our application that awakes the chip.

Further observations are:

  • When we disable the TIMER2 before initializing the SoftDevice (LFCLK source is the XTAL) everything works fine
  • When we initialize the TIMER2 after initializing the SoftDevice (LFCLK source is the XTAL) everything works fine too

Is there a problem when the TIMER2 is running during the SD init in combination with the LF crystal? Does anyone know this behavior?

EDIT: I've added a stripped-down version of our application to reproduce this behavior:

Function to enable the query-timer:

static void query_timer_init(void)
{
   // :NOTE:
   //    Currently the following capture/compare channels are used:
   //       - Channel 0: Used to capture the timer value
   //       - Channel 1: Used to handle the overflow of the 16bit timer

   // Stop the timer before the configuration
   NRF_TIMER2->TASKS_STOP = 1;

   // Init module variables
   gTIMER2_high_word = 0;

   // Configure TIMER2 in timer mode with 16 bits
   NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
   NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;

   // Use 16 MHz (disable the prescaler)
   // -> f = HFCLK / (2 ^ prescaler_value)
   NRF_TIMER2->PRESCALER = 0;

   // Clear the timer before using it
   NRF_TIMER2->TASKS_CLEAR = 1;

   // Setup capture/compare channel 1 for timer overflow
   NRF_TIMER2->CC[1] = 0xFFFF;
   NRF_TIMER2->EVENTS_COMPARE[1] = 0;
   NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);

   // Enable interrupt for timer 2
   NVIC_SetPriority(TIMER2_IRQn, APP_IRQ_PRIORITY_HIGH);
   NVIC_ClearPendingIRQ(TIMER2_IRQn);
   NVIC_EnableIRQ(TIMER2_IRQn);

   // Start the timer
   NRF_TIMER2->TASKS_START = 1;
}

Function to disable the query-timer:

static void query_timer_disable(void)
{
   // Stop the timer
   NRF_TIMER2->TASKS_STOP = 1;

   // Shutdown the timer module
   NRF_TIMER2->TASKS_SHUTDOWN = 1;

   // Disable and clear the timer interrupt
   NVIC_DisableIRQ(TIMER2_IRQn);
   NVIC_ClearPendingIRQ(TIMER2_IRQn);
}

The main function:

int32_t main(void)
{
   uint32_t sd_stat = NRF_SUCCESS;
   ble_enable_params_t ble_enable_params;

   // Initialize the query timer
   query_timer_init();

   // Init the SoftDevice
   sd_stat = sd_softdevice_enable(
      //NRF_CLOCK_LFCLKSRC_RC_250_PPM_TEMP_4000MS_CALIBRATION, NULL); // -> OK
      NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL);                          // -> NOK
   if (sd_stat != NRF_SUCCESS) {goto exception;}

   // Init the BLE stack
   ble_enable_params.gatts_enable_params.service_changed = 0;
   ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
   sd_stat = sd_ble_enable(&ble_enable_params);
   if (sd_stat != NRF_SUCCESS) {goto exception;}

   // Disable the query timer
   query_timer_disable();

   // Activate the system ON low power mode
   sd_stat = sd_app_evt_wait();
   if (sd_stat != NRF_SUCCESS) {goto exception;}

   // -> This point should not be reached since there is no enabled wakeup source!


   // Re-enable the query timer
   query_timer_init();

   // the main loop
   while (1) {}

   // -> Should never reach this point!


exception:
   while (sd_stat != NRF_SUCCESS) {}
   return 0;
}

Kind regards

Related