Author Topic: Waking ULPDelay(INFINITE) in loop() - Lazarus Library - avoid lock up  (Read 2259 times)

anton

  • RFduino Newbie
  • *
  • Posts: 1
  • Karma: +0/-0
    • View Profile
As described in http://forum.rfduino.com/index.php?topic=801.0 we can use Lazarus Library to wake from ULPDelay(INFINITE) in loop(). In case we have two Pins - Lazarus 31 and a real one (let say buttonA=5), Lazarus wake up is only possible, if pin 5 is LOW. But if we hold the button pressed (signal is HIGH), Lazarus doesn't work.
There was also a commed in the first example:

Quote
  // Note if using RGB shield where buttons pullup and resistors pulldown OK. But
  // if you run without the board installed then better have pulldowns on CPU board.
  // Also PinWake will lock up if buttons get stuck on. So make sure input trigger
  // signals always return to normal. 

Why can't we reset after pinWoke on pin 5 in a way, that pinWoke on pin 31 (Lazarus pin) is possible, even during pin 5 remains HIGH?

See below the example I modified to produce the situation. Just press buttonA on RGB shield an hold on. ariseLazurus(); won't wake the ULPDelay(INFINITE) until we release buttonA.

Code: [Select]
/*
*
*  http://forum.rfduino.com/index.php?topic=801.0
*
*/

#include <RFduinoBLE.h>
#include "SPI.h"
#include "SD.h"

#define LazarusPin 31

#define SERIAL

// ISR red mark
const int ButtonA_pin = 5;
int start_time=0;
int end_time=0;
int state = HIGH;

int btnA_ISR(uint32_t ulPin)
{
    end_time = millis();

#ifdef SERIAL
    Serial.print("ISR ");
    Serial.print(ulPin);
    Serial.println(" called");
#endif
    return 1;  // 0 don't exit RFduino_ULPDelay, 1 exit RFduino_ULPDelay
}

void setup() {
  Serial.begin(9600);
 
  pinMode(6, OUTPUT);
 
  RFduinoBLE.deviceName = "BLE_LZRS";
  RFduinoBLE.advertisementData = "Lazurus Test";
  RFduinoBLE.begin();

  pinMode(ButtonA_pin, INPUT);
  RFduino_pinWakeCallback(ButtonA_pin, HIGH, btnA_ISR);
//  RFduino_pinWakeCallback(ButtonA_pin, LOW, btnA_ISR);

  delay(1500);
  Serial.print("setup(): Default: ");
  printL();
  pinMode(LazarusPin,INPUT_PULLDOWN);
  Serial.print("setup(): pinMode to input pulldown: ");
  printL();
  NRF_GPIO->PIN_CNF[LazarusPin] =
      (GPIO_PIN_CNF_PULL_Pulldown<<GPIO_PIN_CNF_PULL_Pos);
  Serial.print("setup(): pulldown ");
  printL(); 

// As long as pinWake is included in the ariseLazarus function... not needed here.
// Uncomment if you wish to see.
//  RFduino_pinWake(LazarusPin,HIGH);
//  Serial.print("setup(): post pinWake HIGH: ");
//  printL();
}

void loop() {
  int diff = 0;

  Serial.println("main loop() going to sleep forever");
  RFduinoBLE_ULPDelay(INFINITE);
  if(lazarusArising()){
    Serial.println("Lazarus has awakened!");
    printL();
    Serial.println("");
    delay(5000); //just waste some time
    Serial.println("Lazarus exit!");
  }
  if (RFduino_pinWoke(ButtonA_pin)) {
    RFduino_resetPinWake(ButtonA_pin);
    RFduino_pinWakeCallback(ButtonA_pin, DISABLE, NULL);
    if (state == LOW) {
      RFduino_pinWakeCallback(ButtonA_pin, HIGH, btnA_ISR);
    } else {
      RFduino_pinWakeCallback(ButtonA_pin, LOW, btnA_ISR);
    }
    state = HIGH - state;
    RFduino_resetPinWake(ButtonA_pin);

    Serial.println("ButtonA has awakened!");
    printL();
    Serial.println("");
   
    delay(5000); //just waste some time
   
    diff = end_time - start_time;
    start_time = end_time;
   
    Serial.print("Differenz [ms]: ");
    Serial.println(diff);   
  }
 
  // Do whatever you have to do while are alive again!
  delay(100); //just waste some time
 
}

bool lazarusArising(){
  if(RFduino_pinWoke(LazarusPin)){
Serial.print("pinWoke Test: ");
printL();
    RFduino_resetPinWake(LazarusPin);
Serial.print("resetPinWake: ");
printL();
    return HIGH;
  }
  return LOW;
}

void ariseLazurus(){
  Serial.print("\n\nAttempting to Wake Lazarus from Infinite Sleep!  \n ");
 Serial.print("arise entry: ");
 printL();

// NOTE: SENSE and Connect not really needed. Just PULL and call to pinWake!
// Uncomment the extra PIN_CNF lines here and below to see..
    NRF_GPIO->PIN_CNF[LazarusPin] =
//        (GPIO_PIN_CNF_INPUT_Connect<<GPIO_PIN_CNF_INPUT_Pos) |
//        (GPIO_PIN_CNF_SENSE_High<<GPIO_PIN_CNF_SENSE_Pos) |
        (GPIO_PIN_CNF_PULL_Pullup<<GPIO_PIN_CNF_PULL_Pos);
 Serial.print("arise post pullup: ");
 printL();

  RFduino_pinWake(LazarusPin,HIGH);
  Serial.print("arise post pinWake: ");
 printL();

    NRF_GPIO->PIN_CNF[LazarusPin] =
//        (GPIO_PIN_CNF_INPUT_Connect<<GPIO_PIN_CNF_INPUT_Pos) |     
//        (GPIO_PIN_CNF_SENSE_High<<GPIO_PIN_CNF_SENSE_Pos) |
        (GPIO_PIN_CNF_PULL_Pulldown<<GPIO_PIN_CNF_PULL_Pos);
 Serial.print("arise post pulldown pre-exiting: ");
 printL();
}

void printL(){
  Serial.print("Lazarus PIN CNF: ");
   printVal(NRF_GPIO->PIN_CNF[LazarusPin]);
   Serial.println("");
}
void printVal(uint32_t val){
 printf("%02x %02x %02x %02x\n",val>>24 & 0xFF,val>>16&0xFF,val>>8&0xFF,val&0xFF);
}

void RFduinoBLE_onConnect() {
  Serial.println("Connected");
//  ariseLazurus();
}

void RFduinoBLE_onReceive(char *data, int len) {
  Serial.println("Received");
  ariseLazurus();
}

void RFduinoBLE_onDisconnect() {
  Serial.println("Disconnected");
}


I have an use case where a signal on a real pin changes to HIGH and remains for some seconds. I would like to receive and handle BLE commands during this time. I appreciate any suggestions, how to solve the issue!
« Last Edit: June 12, 2015, 05:19:05 PM by tolson »

tolson

  • Global Moderator
  • *****
  • Posts: 827
  • Karma: +19/-0
    • View Profile
    • Thomas Olson Consulting
Re: Waking ULPDelay(INFINITE) in loop() - Lazarus Library - avoid lock up
« Reply #1 on: February 07, 2015, 10:23:57 AM »
Hi Anton,

I have to look at your code when I get a chance. But lazarus on pin 31 is not involved anymore with any real pin.

However, you do have to be careful with using real pins for wakeup and not clearing them after the interrupt occurs.
I'm thinking if the pin5 is kept high too long you may be stuck in getting continuous interrupts. I'll have to see how you are handling that in your code. But it is something you can look into and be aware of. Same thing calling lazarus. As the later examples show it gets released quickly. I'll try to look at your code closer later tonight.

Before implementing lazarus for radio wake up, make sure you got your real pin5 wake up handling working reliably so as not to confuse what is really going on.

cioa for now.
Tom

tolson

  • Global Moderator
  • *****
  • Posts: 827
  • Karma: +19/-0
    • View Profile
    • Thomas Olson Consulting
Re: Waking ULPDelay(INFINITE) in loop() - Lazarus Library - avoid lock up
« Reply #2 on: February 08, 2015, 07:12:15 PM »
You are mixing up pinWake and pinWakeCallback. A pinWakeCallback is an interrupt routine which purpose is to respond to button presses independantly of what is going on in the loop(). If yout want to use the pin press to wake up the main loop then use pinWake only... I think!


tolson

  • Global Moderator
  • *****
  • Posts: 827
  • Karma: +19/-0
    • View Profile
    • Thomas Olson Consulting
Re: Waking ULPDelay(INFINITE) in loop() - Lazarus Library - avoid lock up
« Reply #3 on: February 08, 2015, 07:50:54 PM »
Here I have modified the pinWake demo to show that pinWakeCallback is dealt with in subroutine and
does not wake deep sleep in main loop().
Also showing changing the pinWake mode from HIGH to LOW and back to from LOW to HIGH.
So buttonA (pin5) press is greenLED and button release is redLED. And the buttonB (pin6) is blueLED.

Code: [Select]
/*
 Copyright (c) 2014 OpenSourceRF.com.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Modified by Thomas Olson to clarify pinWake vs pinWakeCallback
// effect on ULPDelay in main loop()


int myPinCallback(uint32_t ulPin)
{
  digitalWrite(4, HIGH);
  delay(250);
  digitalWrite(4, LOW);
  return 0;  // don't exit RFduino_ULPDelay
}

void setup() {
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
 
  // processing handled by exiting RFduino_ULPDelay
  pinMode(5, INPUT);
  RFduino_pinWake(5, HIGH);
 
  // processing handled by myPinCallback
  pinMode(6, INPUT);
  RFduino_pinWakeCallback(6, HIGH, myPinCallback);
}

void loop() {
  RFduino_ULPDelay(INFINITE);

  // if pinWakeCallback affects loop() all 3 LEDs with flash.
  // Not expecting this to happen as is dealt with in callback. 
  if(RFduino_pinWoke(6)){
    digitalWrite(2,HIGH);
    digitalWrite(3,HIGH);
    digitalWrite(4,HIGH);
    delay(250);
    digitalWrite(2,LOW);
    digitalWrite(3,LOW);
    digitalWrite(4,LOW);
  }


  if (RFduino_pinWoke(5))
  {

    if(digitalRead(5)){
      //button press flashes greenLED
      digitalWrite(3, HIGH);
      delay(250);
      digitalWrite(3, LOW);
      RFduino_resetPinWake(5);
      //setup pin to wake on LOW now
      delay(1);
      RFduino_pinWake(5,LOW);
    }else{
      // button release flashes redLED
      digitalWrite(2, HIGH);
      delay(250);
      digitalWrite(2, LOW);
      RFduino_resetPinWake(5);
      // setup up pin to wake on HIGH now
      delay(1);
      RFduino_pinWake(5,HIGH);
    }
  }
}

 

anything