Author Topic: SimbleeBLE affects TIMER1/2 accuracy  (Read 2391 times)

Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
SimbleeBLE affects TIMER1/2 accuracy
« on: May 17, 2016, 06:37:04 PM »
Hi all ...

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.

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. Is there a way to use a different clock source for TIMER1/2 to eliminate the impact of BLE? Any other possibilities to get accurate timers with BLE use?

Code is here:
Code: [Select]
#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);
   
  }
}

Thanks for any thoughts, feedback.

Tim

wookie1

  • RFduino Jr. Member
  • **
  • Posts: 23
  • Karma: +0/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #1 on: May 17, 2016, 09:43:40 PM »
I gave up on trying to use timers with Bluetooth on. The bt radio takes precedence over all other functions and interrupts. I ended up using an ATTiny85 to handle some frequency counting and communicate with it over I2C.

Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #2 on: May 18, 2016, 07:21:35 AM »
Thanks wookie1. I understand the precedent the BT radio has over code and interrupts, but my understanding was that by using peripherals with PPI they just do their thing on their own without relying on other system resources. Interestingly, I'm also using RTC1 (again, with PPI) and it appears to be solid and accurate when BLE is on.

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #3 on: May 18, 2016, 05:51:39 PM »
Yep, Tim has got it down!

Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #4 on: May 18, 2016, 09:57:28 PM »
Thanks Tolson. Any ideas why the extra cycles when BLE is on? It's a significant issue if I can't get accurate timing with TIMER1+PPI+GPIOTE.

Thanks. -Tim

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #5 on: May 19, 2016, 12:25:52 AM »
I have no way of figuring it out without source code of the firmware itself.

bsiever

  • RFduino Full Member
  • ***
  • Posts: 89
  • Karma: +4/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #6 on: May 19, 2016, 06:14:58 AM »
Tim,

First, a little more data may be helpful.  For example, if you double the pulse width is the "overrun" about the same (still about 31589-31250 = 339)? And what if you leave the width the same, but halve the frequency (a 1s pulse ever 4s)?

Second, can you try using the PPI to trigger the capture task rather than doing it in the interrupt/callback?  That way the actual capture should be done via PPI and independent of the software stack.

  Bill


Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #7 on: May 19, 2016, 08:20:49 AM »
Thanks Bill. I appreciate your reply. I will get real numbers when I can (hopefully later today), but I can offer this additional info:

This is a simplified test to look at timer accuracy with BLE on. In my actual application I'm using TIMER1, TIMER2, GPIOTE and PPI, along with Maxim's DS3231 RTC (±2ppm accuracy) to implement an accurate clock that offers millisecond accuracy over a couple hours of use. TIMER1 is a counter that increments when the 1 Hz square wave output of the DS3231 pulses. TIMER2 is a free running timer that is cleared on each DS3231 pulse. So TIMER1 counts seconds and TIMER2 times time between the 1-second pulses. This is all implemented with PPI.

I started noticing TIMER2 values greater than 31250 whereas they should always be 0-31250 because its value is always cleared at t=1.0 second.

When a sensor event occurs (that's being timed), I use PPI to capture the values of both TIMER1 and TIMER2, then an interrupt routine is called where capture registers are read and actual time (seconds) is calculated (TIMER1 value + (TIMER2 value / 31250)).

So, I can say, for this simple timer test here, capturing the TIMER1 value with PPI instead of in the interrupt routine, I don't believe, would change the outcome.

I can also say that the error magnitude increases as the pulse increases. Without further testing, I cannot say for sure if the result will change  if the period is increased (4 s instead of 2, as you suggest), but I speculate that it won't.

If anyone is able to implement this simple TIMER1 test and confirm similar results, that would be helpful information that I can offer RF Digital support. I have contacted them about this but so far no response.

I'll post real numbers regarding your suggested tests, Bill, once I have them.

Many, many thanks - with much hope this can be resolved.

Tim

Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #8 on: May 19, 2016, 11:07:01 AM »
Hi again,

Did the tests you suggested Bill, and as expected:

1s pulse over 4s period -> same results as 1s pulse over 2s period, overrun by about the same 339
2s pulse over 4s period -> double the overrun, about 675

Also tried capturing the timer value with PPI instead of in the interrupt routine. No change in results.

Still hopeful ...

Thx,

Tim

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #9 on: May 19, 2016, 02:55:21 PM »
Hi all ...

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.

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. Is there a way to use a different clock source for TIMER1/2 to eliminate the impact of BLE? Any other possibilities to get accurate timers with BLE use?

Code is here:
Code: [Select]
#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);
   
  }
}

Thanks for any thoughts, feedback.

Tim

Hey Tim,
I set my DS3231 SQW to 1HZ output and used that as input into your sketch.

USING Arduino 1.6.9 Simblee 1.0.3... - uses dynamic_attachInterrupt().

//SimbleeBLE.begin();
I get 15625 (half 31250)

SimbleeBLE.begin();
I get 15658 (half 31316).

A difference of 33(half of 66). Why so much less than yours, I don't know.

So Downgrade to Arduino 1.6.5 and downgrade to Simblee 1.0.0... - uses attachInterrupt().

//SimbleeBLE.begin();
I get 15625

SimbleeBLE.begin();
I get 15625

A difference of ZERO!!!! Hmmm! OK, so is it Arduino IDE version or Simblee Library version issue.

So back to Arduino 1.6.9; but downgrade to Simblee 1.0.1 - uses attachInterrupt().

//SimbleeBLE.begin();
I get 15625

SimbleeBLE.begin();
I get 15625

A difference of ZERO!!!

So stick with Arduino 1.6.9; upgrade to Simblee 1.0.2 - uses attacheInterrupt().

//SimbleeBLE.begin();
I get 15625

SimbleeBLE.begin();
I get 15657

A difference of 32.

OK, so the problem seems to have been introduced in Simblee 1.0.2 even before the change to dynamic_attachInterrupts. So exactly what changed? Wish we had the source code to Simblee. We could find and fix as a community and RFD would sell a ton of the Simblee chips sooner.




Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #10 on: May 19, 2016, 03:34:59 PM »
Wow Tolson, that is so kind of you to test. Thank you my friend.

I've never downgraded Simblee library. I think I started at 1.0.2 and later upgraded to 1.0.3. Would you be so kind to offer steps to downgrade? How to obtain the earlier versions of the library?

I heard from RF Digital today and they are looking at the issue. Maybe they'll identify an issue with 1.0.2/3 and resolve to fix in 1.0.4?

Many, many thanks.

Tim

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #11 on: May 19, 2016, 03:52:10 PM »
Wow Tolson, that is so kind of you to test. Thank you my friend.
I'm have similar problems and not getting expediant help.
Quote
I've never downgraded Simblee library. I think I started at 1.0.2 and later upgraded to 1.0.3. Would you be so kind to offer steps to downgrade? How to obtain the earlier versions of the library?
Tools->Boards: "xxxx" ->Boards Manager...

Boards Manager window pops up. Scroll to Simblee Boards by Simblee. It should say what version is INSTALLED.
Click anywhere in the box.  A button should appear in lower right to REMOVE. Don't need to do that. There should also be a selector to 'Select version' in the lower left corner. Choose a version and click on Install.
Voila!

Quote
I heard from RF Digital today and they are looking at the issue. Maybe they'll identify an issue with 1.0.2/3 and resolve to fix in 1.0.4?
Would be nice if it happened real soon and included boocoo other fixes.
« Last Edit: May 19, 2016, 03:54:00 PM by tolson »

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #12 on: May 19, 2016, 08:21:53 PM »
More info that might help track it down...

SimbleeBLE.begin() // 15658
SimbleeCOM.begin() // 15625
Simblee.dualModeBegin() // 15625

SimbleeGZLL.begin() ROLE= HOST // 15625
SimbleeGZLL.begin() ROLE=DEVICEx // 15662

SimbleeForMobile.begin() // 15658
SimbleeCloud and friends // 15658

tolson

  • Global Moderator
  • *****
  • Posts: 806
  • Karma: +18/-0
    • View Profile
    • Thomas Olson Consulting
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #13 on: May 19, 2016, 08:27:12 PM »
I've done the CAPTURE on event and get the same results. I've changed the PPI channels up up and away from PWM channels, etc... no change. I think the code is correct. The results would indicate that somehow the ticks feeding the timers is running slightly faster when something in BLE and apparently GZLL DEVICE role activates. We need help from the guy that actually developed the hidden routines.


Tim

  • RFduino Full Member
  • ***
  • Posts: 98
  • Karma: +2/-0
    • View Profile
Re: SimbleeBLE affects TIMER1/2 accuracy
« Reply #14 on: May 19, 2016, 10:21:11 PM »
Ongoing thanks Tolson. I have more information.

First, I don't see 1.0.1 as an installable version. Only options for me are 1.0.0, 1.0.2 and 1.0.3. When I downgrade to 1.0.0, problem solved. When I look at the change log, there are things in 1.0.2 and 1.0.3 that I expect I need, in particular, the fix for flash erase and write.

CHANGELOG

v 1.0.3
  - Fix for pinWake LOW
  - Fix for SimbleeCloud for supporting other Ethernet/WiFi clients
  - SPI Transaction and useInterrupt support for better compatibility
  - support for both SPI and Wire peripherals
  - Simblee_pinWakeVoidCallback() support for better attachInterrupt() compatibility
    note: prior calls to attachInterrupt() need to be changed to dynamic_attachInterrupt()!
  - WString added support for standard c_str()

v 1.0.2
  - Fix for flash erase and flash write
  - Fix for Simblee BLE power consumption
  - RFDLoader support for other toolchains

v 1.0.1
  - Changes for Arduino 1.6.6
  - Fix for osx/linux permissions

v 1.0.0
  - Initial release

Here's new information:

I inserted code to look at the NRF_CLOCK->HFCLKSTAT register value before and after calling SimbleeBLE.begin(). Here's what I found:

Library 1.0.0:

Before call to SimbleeBLE.begin(): 0x00010001 (SRC=Xtal)
After call to SimbleeBLE.begin(): 0x00010001 (SRC=Xtal)

I see correct results.

Library 1.0.2:

Before call to SimbleeBLE.begin(): 0x00010001 (SRC=Xtal)
After call to SimbleeBLE.begin(): 0x00010000 (SRC=RC)

I see incorrect results.

Maybe the issue is related to the source for the HFCLK? Unlike LFCLK, I don't see an event to select the clock source for the HFCLK. Plus, I imagine that after starting BLE (SimbleeBLE.begin()), it's probably not wise to stop and start the HFCLK. I wonder if the "Fix for Simblee BLE power consumption" in 1.0.2 was to use RC instead of Xtal for the HFCLK source. Maybe the consequence is inaccuracy of TIMERs? I wonder what the cost in power consumption is in using Xtal instead of RC. For our product, accuracy is required even if we have to sacrifice battery life.

Thoughts anyone?

Many thanks,

Tim

 

anything