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);
    
  }
}
Parents
  • Yes - do a search - this is discussed many times a week.

    The softdevice has a higher interrupt priority than anything else, it has to have, it has critical timing requirements. So your interrupt can get delayed by up to several milliseconds, the more the bluetooth stack does, the more you get delayed. All the timings are in the softdevice specification. Once you're in a connection shoving data around, your delays are going to get only larger.

    You cannot do interrupt-based precise timings with the softdevice in use, it doesn't work. You need to use PPI or the PWM module which Nordic provides which uses PPI to work independently of the softdevice.

  • Thanks Aryan. The call to SimbleeBLE.begin() starts the softdevice. Unfortunately I don't have access to that code. Before calling SimbleeBLE.begin(), I change the LFCLK source to Xtal and no difference in behaviour. I did notice something interesting though. When I check the NRF_CLOCK->HFCLKSTAT register before calling SimbleeBLE.begin(), I get the value 0x00010001, which, according to the Nordic nRF51822 v3 reference manual, means the HFCLK source is Xtal (16 MHz HFCLK crystal). After calling SimbleeBLE.begin(), the NRF_CLOCK->HFCLKSTAT register changes to 0x00010000, which means the HFCLK source is now RC (16 MHz RC oscillator). Unlike LFCLK, I don't see a task for setting the HFCLK source. Regardless, though, I presume I can't change it once the softdevice has started. Also interesting, if I repeat the above test using RTC1 instead of TIMER1, RTC1 values are accurate. Thoughts? Thx!

Reply
  • Thanks Aryan. The call to SimbleeBLE.begin() starts the softdevice. Unfortunately I don't have access to that code. Before calling SimbleeBLE.begin(), I change the LFCLK source to Xtal and no difference in behaviour. I did notice something interesting though. When I check the NRF_CLOCK->HFCLKSTAT register before calling SimbleeBLE.begin(), I get the value 0x00010001, which, according to the Nordic nRF51822 v3 reference manual, means the HFCLK source is Xtal (16 MHz HFCLK crystal). After calling SimbleeBLE.begin(), the NRF_CLOCK->HFCLKSTAT register changes to 0x00010000, which means the HFCLK source is now RC (16 MHz RC oscillator). Unlike LFCLK, I don't see a task for setting the HFCLK source. Regardless, though, I presume I can't change it once the softdevice has started. Also interesting, if I repeat the above test using RTC1 instead of TIMER1, RTC1 values are accurate. Thoughts? Thx!

Children
No Data
Related