Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - JeffNYC

Pages: [1]
1
Android / Re: Simblee intermittent not found Android 6.0.1
« on: October 29, 2017, 04:56:52 PM »
Hi Nelson,

Thanks for the quick response and the ideas - found the problem.  While I had 'Location' set to 'On' in the Simblee app permissions, somehow my Global 'Location' toggle (under Settings) had gotten turned off.   Oops.

Great to know that the Simblee-Android connection is solid, now just need to ensure my users don't make the same silly mistake I did!

Thanks,
Jeff

2
Android / Simblee intermittent not found Android 6.0.1
« on: October 27, 2017, 12:17:08 AM »
I've been having problems recently getting the Simblee app to find a nearby Simblee on an Android 6.0.1 phone (Blackberry Priv STV100-2). 
When I go to the phone's Bluetooth 'Available Devices' list, the Simblee appears.  But in the Simblee app, there is nothing found at all.
Also, when this occurs, the Simblee device can always be found using the Simblee app on other phones I have handy (iOs in this case).

What's bizarre is that most of the time Simblee finds the device and functions perfectly fine on this Android 6.0.1 device.  It just seems to have 'bad days' sometimes where it just cannot see the Simblee, and I cannot figure out why.  Restarting the phone or the Simblee doesn't change anything.
I've also tried uninstalling and reinstalling the Simblee app from the Android phone, but the problem persists.

Any ideas here?  Planning to use this for a low-volume production product, so need to figure this out asap before we start shipping!

3
Simblee Libraries / Re: SimbleeBLE affects TIMER1/2 accuracy
« on: March 28, 2017, 09:40:35 PM »
Just an update - I did hear back from RF Digital support and good news: they fully endorse this approach, and their prior recommendation to use 2 Simblees was only based on what would be the simplest implementation - here's the essence of what they wrote:

"The code you're using, directly modifying NRF registers and using PPI to communicate directly between peripherals, is much higher-level than most of our customers use. Most of our customers use our libraries in Arduino to program their Simblee. I realize you are still using Arduino, but the code you've used here will offer you an increase in speed.

Having looked at everything, I do think that this code is good to go, and will remain stable. You should still be able to add another encoder without detriment."

So it looks like you've created quite a fantastic solution here Tim!  Thank you very much for sharing this with the community, as it has really saved the day for me, and I'm sure will do the same for many others.

-Jeff

4
Simblee Libraries / Re: SimbleeBLE affects TIMER1/2 accuracy
« on: March 18, 2017, 09:58:16 PM »
Hi Tim,

Thanks so much for taking the time to share this solution!  I didn't initially realize that the 'GPIOTE' and dynamic_attachInterrupt language could be used for multiple ISR's running in the same branch.
I tried an approach like you described below and was quite relieved to see that it worked!  I used slightly different language than what you wrote (as I'd copied an encoder example I found yesterday), and I didn't split the reportTime and encoder pulse stuff into two separate functions, but it seems to work well as-is.  Here's the relevant code that I have that now works:

Code: [Select]
NRF_GPIOTE->CONFIG[2] =  (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
              | (EXTERNAL_ENCODER << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN2_Set << GPIOTE_INTENSET_IN2_Pos;
I'm not exactly sure how the differences in the last line impact operation.  Can you explain?

and here's the expanded reportTime ISR:

Code: [Select]
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;
   
    pwm_value_store = timerValue;
   
  }
 
  if( (NRF_GPIOTE->EVENTS_IN[2] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN2_Msk))  {
    NRF_GPIOTE->EVENTS_IN[2] = 0;
    interruptCount++;
    interruptCalled = true;
  }
 
}



And here's the full (edited-down) code in one piece in case that's helpful to anyone:

Code: [Select]
#include <SimbleeForMobile.h>

// Vars for Input RC throttle PWM Read
int throttlePin = 20;
float pwm_value = 0;
volatile float pwm_value_store = 0;

// Vars for WS2812 LEDs
unsigned long ledUpdateRate = 100;  // in milliseconds - how often to update the LEDs, i.e call ws2812
unsigned long ledLastUpdated = 0;
const int ws2812pin = 15;
const int nPIXELS = 5;
const int nLEDs = nPIXELS * 3;
uint8_t ledBar[nLEDs];
#define LED_DELAY         0         // delay after calling ws2812

// Vars for Simblee UI
unsigned long simbleeMobileUpdateRate = 400; // in milliseconds
unsigned long lastUpdated = 0;
//Lots of unnecessary stuff here

// Vars for UART communication (using UART to control a peripheral device - wouldn't think this would interfere with things, but put it here just in case)
long serialSpeed = 230400;

// Vars for external encoder (that requires external pin interrupts...)  A quadrature encoder but don't care about direction so only using one output.
#define EXTERNAL_ENCODER         14     // Digital pin for input from magnetic encoder
volatile int interruptCount = 0;
volatile boolean interruptCalled = false;  //  was interrupt called?
unsigned long lastTime = 0;
unsigned long currTime = 0;
unsigned long timeDiff = 0;
float eSpeed = 1;


void setup() {

  override_uart_limit = true;
  Serial.begin(serialSpeed, 10, 13);  // RX, TX
  delay(1000);
 
  pinMode(throttlePin,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 = 6;  // overflow is every 2.097152 seconds - modified this to get sufficient resolution
  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 throttlePin changes from digital
  // low to high.
  NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)
              | (throttlePin << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
 
  // Configure GPIOTE channel 1 as event that occurs when throttlePin changes from digital
  // high to low.
  NRF_GPIOTE->CONFIG[1] =  (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
              | (throttlePin << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
 
  //  Configure GPIOTE channel 2 (encoder) as event that occurs when encoder toggles from digital
  // high to low or vice versa
  NRF_GPIOTE->CONFIG[2] =  (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos)
              | (EXTERNAL_ENCODER << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
 
  // Interrupt only on high to low (or toggle?)
  NRF_GPIOTE->INTENCLR = GPIOTE_INTENSET_IN0_Msk;
  NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN1_Msk;
  NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN2_Set << GPIOTE_INTENSET_IN2_Pos;

  // 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);

// Setup for LEDs
  pinMode(ws2812pin, OUTPUT);
  digitalWrite(ws2812pin, LOW);
  // Initialize the ledBar array - all LEDs OFF.
  for(int wsOut = 0; wsOut < nLEDs; wsOut++){
    ledBar[wsOut] = 0x00;
  }
  loadWS2812();
  delay(1);

  pinMode (EXTERNAL_ENCODER, INPUT);

  SimbleeForMobile.deviceName = "Test";
  SimbleeForMobile.advertisementData = "Control";
  SimbleeForMobile.domain = "example.com";
  SimbleeForMobile.baseline = "Feb 22 2017 12:00:00";
  SimbleeForMobile.txPowerLevel = 0;              // txPowerLevel can be any multiple of 4 between -20 and +4, inclusive. +4 is >100ft, -20 is a few feet
  SimbleeForMobile.begin();

  delay(1000);
 
}

void loop() {

  SimbleeForMobile.process();
  delay(1);

// Simblee Update Code
  unsigned long loopTime = millis();
  if (SimbleeForMobile.updatable && simbleeMobileUpdateRate < (loopTime - lastUpdated) ){
    lastUpdated = loopTime;
    // Lots of Simblee UI stuff here
  }

//  Update encoder values
  if (interruptCalled) {
    currTime = micros();
    timeDiff = currTime - lastTime;
    eSpeed = (float)interruptCount * (1000000.0 / 6.0) / (float)timeDiff;   // Calculate RPM from time difference and interrupt count (6 pulses/rev)
    interruptCalled = false;
    interruptCount = 0;
    lastTime = currTime;
  }

// Read Throttle Signal and Convert to Throttle / Brake for VESC
  pwm_value = pwm_value_store / 2.5;    // Do relevant math here to convert pulse width to throttle value

// Update WS2812 if enough time elapsed and Simblee radio not on
if (!SimbleeForMobile.radioActive && ledUpdateRate < (loopTime - ledLastUpdated) ){
    loadWS2812();
    delay(LED_DELAY);
    ledLastUpdated = loopTime;
  }
 
}

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;
   
    pwm_value_store = timerValue;
   
  }
 
  if( (NRF_GPIOTE->EVENTS_IN[2] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN2_Msk))  {
    NRF_GPIOTE->EVENTS_IN[2] = 0;
    interruptCount++;
    interruptCalled = true;
  }
 
}

void loadWS2812(){      // update LEDs using Tolsen's code - doubled NOPs as wasn't working in original form with the WS2812's I had
  noInterrupts();
  for(int wsOut = 0; wsOut < nLEDs; wsOut++){
    for(int x=7; x>=0; x--){
      NRF_GPIO->OUTSET = (1UL << ws2812pin);
      if(ledBar[wsOut] & (0x01 << x)) {
        __ASM ( \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              );
        NRF_GPIO->OUTCLR = (1UL << ws2812pin);
      }else{
        NRF_GPIO->OUTCLR = (1UL << ws2812pin);
        __ASM ( \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              );     
      }
    }
  }
  delayMicroseconds(50); // latch and reset WS2812
  interrupts();
}

void ui(){
// Lots of stuff here
}

void ui_event(event_t &event) {
// Lots of stuff here
}



Anyways, I'm thrilled to have gotten this working, although I wish I knew even a little about what the GPIOTE code above means.  It's clearly not 'newbie-friendly' Arduino ;)

Interestingly, I'd emailed RFDuino Support about this problem prior to discovering the solution, and their response was that a single Simblee will not be able to handle encoder interrupts as well as running BLE and other code, and that my solution would be to add a 2nd Simblee module to handle interrupts and code, and communicating with the first via SimbleeCOM.  This is not a solution that I would like to have to employ!  I shared the functioning code with them and am waiting to hear back whether this is indeed a satisfactory and stable solution.

The only last remaining hiccup is that the data from the encoder is a little bit erratic.  I'm wondering if this is due to the BLE radio interrupts affecting the pulse timing measurements?  Does the internal micros() clock stop counting when the BLE radio activates, rendering some pulse interval measurements to come out shorter than they actually are?   This would be consistent with what I'm observing:  small, irregular errors in RPM measurement that are always higher than they should be (i.e. the pulse time measurements are shorter).  Wondering if anyone has any more insight into this and whether there's a solution?

Thanks again for all the help Tim!!


5
Simblee Libraries / Re: SimbleeBLE affects TIMER1/2 accuracy
« on: March 16, 2017, 12:38:53 AM »
One thing I should clarify regarding my SFM issues - after I upload the code, my phone usually sees the Simblee device initially, then after I try to connect, I get the error message:

'Connection Request to the Simblee timed out'

And after that I no longer see my device show up in the 'Found Simblees' list...

Here's the relevant code - I had to cut out a lot of unrelated code; hopefully I didn't miss anything relevant:



Code: [Select]
#include <SimbleeForMobile.h>

// Vars for Input RC throttle PWM Read
int throttlePin = 20;
float pwm_value = 0;
float pwm_value_store = 0;

// Vars for WS2812 LEDs
unsigned long ledUpdateRate = 100;  // in milliseconds - how often to update the LEDs, i.e call ws2812
unsigned long ledLastUpdated = 0;
const int ws2812pin = 15;
const int nPIXELS = 5;
const int nLEDs = nPIXELS * 3;
uint8_t ledBar[nLEDs];
#define LED_DELAY         0         // delay after calling ws2812

// Vars for Simblee UI
unsigned long simbleeMobileUpdateRate = 400; // in milliseconds
unsigned long lastUpdated = 0;
//Lots of unnecessary stuff here

// Vars for UART communication (using UART to control a peripheral device - wouldn't think this would interfere with things, but put it here just in case)
long serialSpeed = 230400; 

// Vars for external encoder (that requires external pin interrupts...)  A quadrature encoder but don't care about direction so only using one output.
#define EXTERNAL_ENCODER         14     // Digital pin for input from magnetic encoder
volatile int interruptCount = 0;
volatile boolean interruptCalled = false;  //  was interrupt called?
unsigned long lastTime = 0;
unsigned long currTime = 0;
unsigned long timeDiff = 0;
float speed = 1;


void setup() {

  override_uart_limit = true;
  Serial.begin(serialSpeed, 10, 13);  // RX, TX
  delay(1000);
 
  pinMode(throttlePin,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 = 6;  // overflow is every 2.097152 seconds - modified this to get sufficient resolution
  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 throttlePin changes from digital
  // low to high.
  NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)
              | (throttlePin << GPIOTE_CONFIG_PSEL_Pos)
              | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);
 
  // Configure GPIOTE channel 1 as event that occurs when throttlePin changes from digital
  // high to low.
  NRF_GPIOTE->CONFIG[1] =  (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
              | (throttlePin << 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);

// Setup for LEDs
  pinMode(ws2812pin, OUTPUT);
  digitalWrite(ws2812pin, LOW);
  // Initialize the ledBar array - all LEDs OFF.
  for(int wsOut = 0; wsOut < nLEDs; wsOut++){
    ledBar[wsOut] = 0x00;
  }
  loadWS2812();
  delay(1);

  pinMode (EXTERNAL_ENCODER, INPUT);

  SimbleeForMobile.deviceName = "Test";
  SimbleeForMobile.advertisementData = "Control";
  SimbleeForMobile.domain = "example.com";
  SimbleeForMobile.baseline = "Feb 22 2017 12:00:00";
  SimbleeForMobile.txPowerLevel = 0;              // txPowerLevel can be any multiple of 4 between -20 and +4, inclusive. +4 is >100ft, -20 is a few feet
  SimbleeForMobile.begin();

  attachPinInterrupt(EXTERNAL_ENCODER, encoderPulseCount, HIGH);     //  This is the declaration that causes SFM to no longer respond.  Comment this out and SFM functions normally.
  delay(1000);
 
}

void loop() {

  SimbleeForMobile.process();
  delay(1);

// Simblee Update Code
  unsigned long loopTime = millis();
  if (SimbleeForMobile.updatable && simbleeMobileUpdateRate < (loopTime - lastUpdated) ){
    lastUpdated = loopTime;
    // Lots of Simblee UI stuff here
  }

//  Update encoder values
  if (interruptCalled) {
    currTime = micros();
    timeDiff = currTime - lastTime;
    speed = (float)interruptCount * 1000000.0 / (float)timeDiff;   // Calculate RPM from time difference and interrupt count (pulses)
    interruptCalled = false;
    interruptCount = 0;
    lastTime = currTime;
  }

// Read Throttle Signal and Convert to Throttle / Brake for VESC
  pwm_value = pwm_value_store / 2.5;    // Do relevant math here to convert pulse width to throttle value

// Update WS2812 if enough time elapsed and Simblee radio not on
if (!SimbleeForMobile.radioActive && ledUpdateRate < (loopTime - ledLastUpdated) ){
    loadWS2812();
    delay(LED_DELAY);
    ledLastUpdated = loopTime;
  }
 
}

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;
   
    pwm_value_store = timerValue;
   
  }
}

void loadWS2812(){      // update LEDs using Tolsen's code - doubled NOPs as wasn't working in original form with the WS2812's I had
  noInterrupts();
  for(int wsOut = 0; wsOut < nLEDs; wsOut++){
    for(int x=7; x>=0; x--){
      NRF_GPIO->OUTSET = (1UL << ws2812pin);
      if(ledBar[wsOut] & (0x01 << x)) {
        __ASM ( \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              );
        NRF_GPIO->OUTCLR = (1UL << ws2812pin);
      }else{
        NRF_GPIO->OUTCLR = (1UL << ws2812pin);
        __ASM ( \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              " NOP\n\t" \
              );     
      }
    }
  }
  delayMicroseconds(50); // latch and reset WS2812
  interrupts();
}

int encoderPulseCount (uint32_t dummyPin) {   // ISR for encoder pulse read - dummyPin required...
  interruptCount++;
  interruptCalled = true;
  return 0;                               // ...as is 'return 0'
}

void ui(){
// Lots of stuff here
}

void ui_event(event_t &event) {
// Lots of stuff here
}


6
Simblee Libraries / Re: SimbleeBLE affects TIMER1/2 accuracy
« on: March 15, 2017, 10:07:24 PM »
Thanks for the reply Tim - sorry I didn't see it until now.  I rebuilt the code again from an earlier version to be sure I hadn't made a mistake in adding in your Timer code, and lo and behold it worked beautifully the second time around.  I haven't been able to trace exactly what the relevant difference was, but it may have been related to interrupts...

When I first tried to include your code (and it didn't' work), I had several interrupt pins configured using [ attachPinInterrupt(pin, callback, mode); ] as described in the Simblee User Guide v2.06.   I removed these during the rebuild and when the code worked they were not yet added back.

Well, now I just added back one attachPinInterrupt() and SFM has stopped working again.  Literally if I comment out the attachPinInterrupt() line, everything is fine, but I uncomment it and SFM will no longer connect (or even show up in the 'Found Simblees' list).

I wonder if there is a conflict between the attachPinInterrupt() described in the User Guide and the dynamic_attachInterrupt(GPIOTE_IRQn, reportTime) included in your code?  And I can't seem to find any documentation on the use of dynamic_attachInterrupt() for Simblee anywhere, so I'm at a loss here...

I should also add that I'm using the loadWS2812() code from Tolsen to drive a few WS2812 LEDs, and that code includes a very short noInterrupts() loop.  But that has been playing nicely with SFM ever since I put in code to only call it every 100ms and only if the Simblee radio is not active:

if (!SimbleeForMobile.radioActive && ledUpdateRate < (loopTime - ledLastUpdated) ){
    loadWS2812();
}

Unfortunately, I don't have the ability to control when pin interrupts occur to ensure that the radio is not active and thus disrupted (like I do with loadWS2812()).  Perhaps this is where dynamic_attachInterrupt() comes into play?

Anyways, I'll stop speculating beyond my area of expertise and see what others have to say.  And I'll do my best to past all the other relevant code shortly in a subsequent post.

7
Simblee Libraries / Re: SimbleeBLE affects TIMER1/2 accuracy
« on: March 06, 2017, 01:59:27 PM »
Thanks for updating this post Tim.

I'm very new to this platform, and have no prior experience with RFDuino, so forgive my question if it's obvious.  But is there any reason the Timer code you provided would not work with SimbleeForMobile instead of SimbleeBLE? 

I'm trying to use your pulse measuring code (from your first post in this thread) to read an RC PWM signal (1.2-1.8ms pulse width), and it works great as a standalone program.  However, once I add it into a larger program that uses SimbleeForMobile, it stops working and so does SFM.

I've never used Timer-level code before, so perhaps (hopefully) there's a simple tweak to make it work with SimbleeForMobile instead of SimbleeBLE?

And if anyone could point me to some sort of tutorial / documentation on this type of language: NRF_GPIOTE->CONFIG..etc.. it would be a huge help.  I have no idea how to follow it and try to debug...

Thanks!

8
Support / Re: Slider not reliably logging event - SOLUTION
« on: February 22, 2017, 04:45:54 PM »
I figured out what was causing the problem and wanted to share it here in case others encounter this.  The problem was I did not have any delay mechanism in my loop() code so the Simblee-Phone communication was getting overloaded as I added more elements and data exchange.  So while initially with a 'light' interface there were no delay issues or lost actions, as I developed the page the problems began to appear and worsen to point of being unusable.

Here's what you need to be sure to have in your code to avoid this:
Code: [Select]
unsigned long updateRate = 200; // in milliseconds  (200ms worked for me, but I've seen 500ms in other examples)

void loop() {
  unsigned long loopTime = millis();
 
  if (SimbleeForMobile.updatable && updateRate < (loopTime - lastUpdated)){
    lastUpdated = loopTime;

   // put all your SimbleeForMobile.updateValue (or Text) calls inside here

  {
...
}

I wish the documentation had been clearer on this.  But I hope this helps others!

9
Support / Re: Slider not reliably logging event
« on: February 21, 2017, 08:04:46 PM »
Also seeing this problem.  Any solutions?

Pages: [1]