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

BLE affects TIMER1/2 accuracy

Hi,

I'm building a product using RF Digital's Simblee that uses the nrF51822 ver 3 chip. I've narrowed down a TIMER accuracy issue to BLE. The code below starts and stops TIMER1 (16 bit, prescaler=9) on low-to-hi and hi-to-low, respectively, of a GPIO pin. I'm driving the GPIO pin with a function generator configured to send a 1 second pulse with a period of 2 seconds. An interrupt is called on hi-to-low to print out the counter value. (Simblee allows programming via the Arduino IDE.)

Given TIMER1 prescaler of 9 (Ftimer = 31250), I should be getting counter values of 31250. This is the case if I comment out the SimbleeBLE.begin() line. But if SimbleeBLE.begin() executes, I see counter values of around 31589 ±3. Same behaviour if I use TIMER2.

I thought TIMER peripherals were not impacted by other system resources. Any possibilities to eliminate the impact of BLE on timer accuracy?

Thanks. -Tim

Code:

#include <SimbleeBLE.h>

int functionGeneratorPin = 6;

void setup() {
  
  Serial.begin(9600);
  
  delay(1000);
  
  pinMode(functionGeneratorPin,INPUT);
  
  // Configure TIMER1 as timer
  NRF_TIMER1->TASKS_STOP = 1; // Stop timer
  NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;  // Set to timer mode
  NRF_TIMER1->PRESCALER = 9;  // overflow is every 2.097152 seconds
  NRF_TIMER1->TASKS_CLEAR = 1;  // Clear the timer
  NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit;  // Set to 16 bit
  
  // Configure GPIOTE channel 0 as event that occurs when functionGeneratorPin pin changes from digital
  // low to high.
  NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)
              | (functionGeneratorPin << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
  
  // Configure GPIOTE channel 1 as event that occurs when functionGeneratorPin pin changes from digital
  // high to low.
  NRF_GPIOTE->CONFIG[1] =  (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
              | (functionGeneratorPin << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
  
  // Interrupt only on high to low.
  NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_IN0_Msk;
  NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN1_Msk;
  
  // Clear all events.
  NRF_GPIOTE->EVENTS_IN[0] = 0;
  NRF_GPIOTE->EVENTS_IN[1] = 0;
  NRF_GPIOTE->EVENTS_IN[2] = 0;
  NRF_GPIOTE->EVENTS_IN[3] = 0;
  
  // Attach interrupt handler.
  dynamic_attachInterrupt(GPIOTE_IRQn, reportTime);
  
  // Configure PPI channel 0 to start TIMER1 on low to high.
  simblee_ppi_channel_assign(0, &NRF_GPIOTE->EVENTS_IN[0], &NRF_TIMER1->TASKS_START);
  // Configure PPI channel 1 to stop TIMER1 on high to low.
  simblee_ppi_channel_assign(1, &NRF_GPIOTE->EVENTS_IN[1], &NRF_TIMER1->TASKS_STOP);

  SimbleeBLE.begin();
}


void loop() {
  
}


void reportTime(void) {
  
  if (NRF_GPIOTE->EVENTS_IN[1] != 0) {

    // clear event
    NRF_GPIOTE->EVENTS_IN[1] = 0;

    // timer has been stopped, capture value
    NRF_TIMER1->TASKS_CAPTURE[0] = 1;

    // get timer value
    unsigned long timerValue = NRF_TIMER1->CC[0];

    // clear timer for next cycle
    NRF_TIMER1->TASKS_CLEAR = 1;
    
    Serial.println(timerValue);
    
  }
}
  • RTC does not use HFCLK, it only works on LFCLK.

    The softdevice keeps and internal counter for requests and release of HFCLK. So you have to request the HFCLK through softdevice API for it to know that the app explicitly requested HFCLK XTAL. Otherwise it will turn it on and off as per own usage.

    1. When you change the LFCLK to XTAL before begin(), it does not matter as the begin function will change it anyways (if it is not using XTAL).

    2. Seems like your application before calling SimbleeBLE.begin(); has started Xtal HFCLK. This means that the softdevice have no idea about this and will assume that after enabling it no one else apart from it is using Xtal HFCLK. You have to change you code little bit here.

      . first enable softdevice
      . request hfclk xtal using softdevice api sd_clock_hfclk_request. If you do not have access directly to softdevice API then ask the team who has to expose that API to you. . Now configure your Timer

    What we will achieve here is to let softdevice know that you are a user of the xtal hfclk. and Keep it on after it has finished its calibration. I would expect this to work for you.

  • Thanks Aryan. You are correct. Unfortunately my app does not have access to the softdevice API. The Simblee designers have acknowledged the issue and will fix in a future release, hopefully by exposing the hfclk softdevice calls so my app, as you suggest, can call sd_clock_hfclk_request after calling SimbleeBLE.begin(). Many thanks for your help with this Aryan.

Related