Sleep function disrupts functions (I think)

I am using a Pololu A-Star 328PB running 8MHz at 3.3V.
I have a RN4871 BLE module connected to the Serial1 ports.
I include the “avr/sleep.h” to enable me to run in Low Power by putting the 328PB to sleep (set_sleep_mode(SLEEP_MODE_PWR_DOWN);).
My sketch “sleeps” for three cycles of 8 seconds each.
On third sleep cycle, I call, amongst other functions, “scanBLE();” which starts the BLE scanning.
However, although “scanBLE()” function is called, I do not receive any data on the Serial1.
I suspect that either the “sleep” function or something else is preventing this.
I cannot, after a few days, fathom why this is happening.

I have written a “test” sketch which does not have any sleep functions and it runs fine when “scanBLE()” is called from setup().

My “Test” sketch:

int beaconcount;
String beaconMAC;
String beaconName;
boolean scanning = false;
#define INTERVAL_SCAN 5000
unsigned long scantime = 0;

void setup() {
  Serial.begin(9600); 
  Serial1.begin(9600); // Enable Serial1 (BLE)

  delay(500);
  scanBLE();
}

void loop() {
  if (Serial1.available()) {
    String s = Serial1.readStringUntil('\n');
    //    Serial.println(s);

    if (scanning == true) {
      int posCMD = s.indexOf("D>");
      if (posCMD > 0) {
        Serial1.println("F");
        Serial1.print('\r');
      }
    }

    scantime = millis();

    int posName = s.indexOf("45434F");
    if (posName > 0) {
      beaconcount = beaconcount + 1;
      int posMAC = s.indexOf(",");
      beaconMAC = s.substring(posMAC - 12, posMAC);
      beaconName = s.substring(posName + 6, posName);
    }
  }

  if ((millis() - scantime) >= INTERVAL_SCAN)
  {
    scantime = millis();
    scanning = false;
    if (beaconcount >= 1) {
      Serial.print("Beacon MAC: ");
      Serial.println(beaconMAC);
    }
    if (beaconcount <= 0) {
      Serial.println("NO Beacon Found");
    }
    Serial1.print("R,1");// RESET BLE Module
    Serial1.print('\r');
  }
}

void scanBLE() {
  scanning = true;
  Serial1.print("$$");
  Serial.println("Scanning.......");
}

Serial Monitor output:

Scanning.......
Beacon MAC: B752B81093D7

My “Full” Sketch with “Sleep”:

#include <SoftwareSerial.h>

#include <avr/wdt.h>            // library for default watchdog functions
#include <avr/interrupt.h>      // library for interrupts handling
#include <avr/sleep.h>          // library for sleep
#include <avr/POWER.h>          // library for POWER_3V control
#include <Vcc.h>                // library to read battery voltage

const float VccMin   = 0.0;           // Minimum expected Vcc level, in Volts.
const float VccMax   = 3.6;           // Maximum expected Vcc level, in Volts.
const float VccCorrection = 1.0 / 1.0; // Measured Vcc by multimeter divided by reported Vcc
Vcc vcc(VccCorrection);

int myVolts;

const byte pinGPS_Power = 5;
const byte pinSIG_Sleep = 6;
const byte pinBLE_Sleep = 7;

int beaconcount = 0;
String beaconMAC;
String beaconName;
boolean scanning = false;
#define INTERVAL_SCAN 5000
unsigned long scantime = 0;

double lastLAT;
double lastLON;

// how many times remain to sleep before wake up
int nbr_remaining;

// how long to sleep for - n x 8 seconds
int sleep_time;

// count sleep_periods
int sleep_periods_count = 0;

// count sleep periods for check sensors
int check_sensor_count = 0;

// count sleep periods for transmit
int check_transmit_count = 0;


// interrupt raised by the watchdog firing
// when the watchdog fires during sleep, this function will be executed
// remember that interrupts are disabled in ISR functions
ISR(WDT_vect)
{
  // not hanging, just waiting
  // reset the watchdog
  wdt_reset();
}

// function to configure the watchdog: let it sleep 8 seconds before firing
// when firing, configure it for resuming program execution
void configure_wdt(void)
{

  cli();                           // disable interrupts for changing the registers

  MCUSR = 0;                       // reset status register flags

  // Put timer in interrupt-only mode:
  WDTCSR |= 0b00011000;            // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
  // using bitwise OR assignment (leaves other bits unchanged).
  WDTCSR =  0b01000000 | 0b100001; // set WDIE: interrupt enabled
  // clr WDE: reset disabled
  // and set delay interval (right side of bar) to 8 seconds

  sei();                           // re-enable interrupts

  // reminder of the definitions for the time before firing
  // delay interval patterns:
  //  16 ms:     0b000000
  //  500 ms:    0b000101
  //  1 second:  0b000110
  //  2 seconds: 0b000111
  //  4 seconds: 0b100000
  //  8 seconds: 0b100001

}

// Put the Arduino to deep sleep. Only an interrupt can wake it up.
void sleep(int ncycles)
{
  nbr_remaining = ncycles; // defines how many cycles should sleep

  // Set sleep to full POWER down.  Only external interrupts or
  // the watchdog timer can wake the CPU!
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  //  // Turn off the ADC while asleep.
  //    POWER_adc_disable();

  while (nbr_remaining > 0) { // while some cycles left, sleep!

    // Enable sleep and enter sleep mode.
    sleep_mode();

    // CPU is now asleep and program execution completely halts!
    // Once awake, execution will resume at this point if the
    // watchdog is configured for resume rather than restart

    // When awake, disable sleep mode
    sleep_disable();

    // we have slept one time more
    nbr_remaining = nbr_remaining - 1;

  }

  //  // put everything on again
  //  POWER_3V_all_enable();

}

SoftwareSerial sigSerial(8, 9); // RX, TX


void setup() {

  Serial.begin(9600);
  Serial1.begin(9600); // Enable Serial1 (BLE)
  sigSerial.begin(9600); // Enable SoftwareSerial sigSerial

  // configure the watchdog
  configure_wdt();

  pinMode      (pinGPS_Power, OUTPUT);
  digitalWrite (pinGPS_Power, HIGH); // MAKE SURE GPS IS OFF
}

void loop() {
  //    sleep_time = 225;// 30 minutes
  //    sleep_time = 112.5;// 15 minutes
  //  sleep_time = 30;// 5 minutes THIS IS DEFAULT
  //  sleep_time = 5;// 40 seconds
  //    sleep_time = 2.5;// 20 seconds
  sleep_time = 1;// 8 seconds


  // BLE:**********************************************************************
  if (Serial1.available()) {
    String s = Serial1.readStringUntil('\n');
    Serial.print("BLE Sent: ");
    Serial.println(s);

    if (scanning == true) {
      int posCMD = s.indexOf("D>");
      if (posCMD > 0) {
        Serial1.print("F");
        Serial1.print('\r');
      }
    }

    scantime = millis();

    int posName = s.indexOf("45434F");
    if (posName > 0) {
      beaconcount = beaconcount + 1;
      int posMAC = s.indexOf(",");
      beaconMAC = s.substring(posMAC - 12, posMAC);
      beaconName = s.substring(posName + 6, posName);
    }
  }

  if ((millis() - scantime) >= INTERVAL_SCAN)
  {
    scantime = millis();
    scanning = false;
    if (beaconcount >= 1) {
      Serial.print("Beacon MAC: ");
      Serial.println(beaconMAC);
    }
    if (beaconcount <= 0) {
      Serial.println("NO Beacon Found");
    }
    Serial1.println("R,1");// RESET BLE Module
    Serial1.print('\r');

  }
  //END BLE**********************************************************************


  //CHECK SENSORS AFTER COUNT == N
  check_sensor_count++;
  Serial.print("Sleep Count: ");
  Serial.println(check_sensor_count);

  if (check_sensor_count >= 3)// time to check sensors
  {
    Serial.print("Time to do BLE Stuff: ");
    Serial.println(check_sensor_count);

    scanBLE(); // Start BLE scan

    readBattery();
    Serial.print("My Voltage: ");
    Serial.println(myVolts);
    delay(50);

    check_sensor_count = 0;
  }

  //TRANSMIT AFTER COUNT == N
  check_transmit_count++;
  Serial.print("Transmit counts: ");
  Serial.println(check_transmit_count);
  delay(50);
  Serial.println("-----------------------------------------");
  delay(50);

  if (check_transmit_count >= 10)// time to transmit
  {
    Serial.println("Time to Transmit");
    delay(50);

    check_transmit_count = 0;

  }
  sleep(sleep_time);
}

void scanBLE() {
  scanning = true;
  Serial1.print("$$");
  Serial.println("Scanning.......");
}


void readBattery()
{
  float v = vcc.Read_Volts();
  myVolts = v * 10;

}

Serial Monitor output:

Sleep Count: 1
Transmit counts: 1
-----------------------------------------
Sleep Count: 2
Transmit counts: 2
-----------------------------------------
Sleep Count: 3
Time to do BLE Stuff: 3
Scanning.......
My Voltage: 32
Transmit counts: 3
-----------------------------------------

Going back to sleep while scanning is true makes it impossible to receive date from SoftwareSerial.

I set scanning = false here:

  if ((millis() - scantime) >= INTERVAL_SCAN)
  {
    scantime = millis();
    scanning = false;
    if (beaconcount >= 1) {
      Serial.print("Beacon MAC: ");
      Serial.println(beaconMAC);
    }
    if (beaconcount <= 0) {
      Serial.println("NO Beacon Found");
    }
    Serial1.print("R,1");// RESET BLE Module
    Serial1.print('\r');
  }

Declan:
I set scanning = false here:

Reread my post. This time put some thought and care into the effort.

Thanks CB.
I have gone through my code for hours and cannot find the problem OR where exactly I must disable sleep while scanning is true.

I tried:

  if (!scanning){
  sleep(sleep_time);
  }

but no joy.
This is driving me nuts.
I have compared my "Test" sketch with my "Full" sketch and cannot get to grips with the problem of preventing returning to sleep while scanning.

After making changes, repost your entire sketch.

This is my updated sketch:

#include <SoftwareSerial.h>

#include <avr/wdt.h>            // library for default watchdog functions
#include <avr/interrupt.h>      // library for interrupts handling
#include <avr/sleep.h>          // library for sleep
#include <avr/POWER.h>          // library for POWER_3V control
#include <Vcc.h>                // library to read battery voltage

const float VccMin   = 0.0;           // Minimum expected Vcc level, in Volts.
const float VccMax   = 3.6;           // Maximum expected Vcc level, in Volts.
const float VccCorrection = 1.0 / 1.0; // Measured Vcc by multimeter divided by reported Vcc
Vcc vcc(VccCorrection);

int myVolts;

const byte pinGPS_Power = 5;
const byte pinSIG_Sleep = 6;
const byte pinBLE_Sleep = 7;

int beaconcount = 0;
String beaconMAC;
String beaconName;
boolean scanning = false;
#define INTERVAL_SCAN 5000
unsigned long scantime = 0;

double lastLAT;
double lastLON;

// how many times remain to sleep before wake up
int nbr_remaining;

// how long to sleep for - n x 8 seconds
int sleep_time;

// count sleep_periods
int sleep_periods_count = 0;

// count sleep periods for check sensors
int check_sensor_count = 0;

// count sleep periods for transmit
int check_transmit_count = 0;


// interrupt raised by the watchdog firing
// when the watchdog fires during sleep, this function will be executed
// remember that interrupts are disabled in ISR functions
ISR(WDT_vect)
{
  // not hanging, just waiting
  // reset the watchdog
  wdt_reset();
}

// function to configure the watchdog: let it sleep 8 seconds before firing
// when firing, configure it for resuming program execution
void configure_wdt(void)
{

  cli();                           // disable interrupts for changing the registers

  MCUSR = 0;                       // reset status register flags

  // Put timer in interrupt-only mode:
  WDTCSR |= 0b00011000;            // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
  // using bitwise OR assignment (leaves other bits unchanged).
  WDTCSR =  0b01000000 | 0b100001; // set WDIE: interrupt enabled
  // clr WDE: reset disabled
  // and set delay interval (right side of bar) to 8 seconds

  sei();                           // re-enable interrupts

  // reminder of the definitions for the time before firing
  // delay interval patterns:
  //  16 ms:     0b000000
  //  500 ms:    0b000101
  //  1 second:  0b000110
  //  2 seconds: 0b000111
  //  4 seconds: 0b100000
  //  8 seconds: 0b100001

}

// Put the Arduino to deep sleep. Only an interrupt can wake it up.
void sleep(int ncycles)
{
  nbr_remaining = ncycles; // defines how many cycles should sleep

  // Set sleep to full POWER down.  Only external interrupts or
  // the watchdog timer can wake the CPU!
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  //  // Turn off the ADC while asleep.
  //    POWER_adc_disable();

  while (nbr_remaining > 0) { // while some cycles left, sleep!

    // Enable sleep and enter sleep mode.
    sleep_mode();

    // CPU is now asleep and program execution completely halts!
    // Once awake, execution will resume at this point if the
    // watchdog is configured for resume rather than restart

    // When awake, disable sleep mode
    sleep_disable();

    // we have slept one time more
    nbr_remaining = nbr_remaining - 1;

  }

  //  // put everything on again
  //  POWER_3V_all_enable();

}

SoftwareSerial sigSerial(8, 9); // RX, TX


void setup() {

  Serial.begin(9600);
  Serial1.begin(9600); // Enable Serial1 (BLE)
  sigSerial.begin(9600); // Enable SoftwareSerial sigSerial

  // configure the watchdog
  configure_wdt();

  pinMode      (pinGPS_Power, OUTPUT);
  digitalWrite (pinGPS_Power, HIGH); // MAKE SURE GPS IS OFF
}

void loop() {
  //    sleep_time = 225;// 30 minutes
  //    sleep_time = 112.5;// 15 minutes
  //  sleep_time = 30;// 5 minutes THIS IS DEFAULT
  //  sleep_time = 5;// 40 seconds
  //    sleep_time = 2.5;// 20 seconds
  sleep_time = 1;// 8 seconds


  // BLE:**********************************************************************
  if (Serial1.available()) {
    String s = Serial1.readStringUntil('\n');
    Serial.print("BLE Sent: ");
    Serial.println(s);

    if (scanning == true) {
      int posCMD = s.indexOf("D>");
      if (posCMD > 0) {
        Serial1.print("F");
        Serial1.print('\r');
      }
    }

    scantime = millis();

    int posName = s.indexOf("45434F");
    if (posName > 0) {
      beaconcount = beaconcount + 1;
      int posMAC = s.indexOf(",");
      beaconMAC = s.substring(posMAC - 12, posMAC);
      beaconName = s.substring(posName + 6, posName);
    }
  }

  if ((millis() - scantime) >= INTERVAL_SCAN)
  {
    scantime = millis();
    scanning = false;
    if (beaconcount >= 1) {
      Serial.print("Beacon MAC: ");
      Serial.println(beaconMAC);
    }
    if (beaconcount <= 0) {
      Serial.println("NO Beacon Found");
    }
    Serial1.println("R,1");// RESET BLE Module
    Serial1.print('\r');

  }
  //END BLE**********************************************************************


  //CHECK SENSORS AFTER COUNT == N
  check_sensor_count++;
  Serial.print("Sleep Count: ");
  Serial.println(check_sensor_count);

  if (check_sensor_count >= 3)// time to check sensors
  {
    Serial.print("Time to do BLE Stuff: ");
    Serial.println(check_sensor_count);

    scanBLE(); // Start BLE scan

    readBattery();
    Serial.print("My Voltage: ");
    Serial.println(myVolts);
    delay(50);

    check_sensor_count = 0;
  }

  //TRANSMIT AFTER COUNT == N
  check_transmit_count++;
  Serial.print("Transmit counts: ");
  Serial.println(check_transmit_count);
  delay(50);
  Serial.println("-----------------------------------------");
  delay(50);

  if (check_transmit_count >= 10)// time to transmit
  {
    Serial.println("Time to Transmit");
    delay(50);

    check_transmit_count = 0;

  }
  
  if (!scanning) {
    sleep(sleep_time);
  }
}

void scanBLE() {
  scanning = true;
  Serial1.print("$$");
  Serial.println("Scanning.......");
}


void readBattery()
{
  float v = vcc.Read_Volts();
  myVolts = v * 10;

}

The only change from the “Full” code in post 1 is:

sleep(sleep_time);

has been changed to:

  if (!scanning) {
    sleep(sleep_time);
  }

I am aging radidly :frowning:

It looks like you are sending the reset sequence to the BLE module, and then going to sleep. Is the BLE module then sending the data while the Arduino is asleep, and you are expecting the data to be buffered so that you can parse the data when the Arduino wakes up?

I don't think you can receive more than one character while the Arduino is in power down mode.

Thanks,
Yes, it looks like the BLE module is sending the data while the Arduino is asleep.
No, I am not expecting the data to be buffered so that I can parse the data when the Arduino wakes up.
I am sure I need to DISABLE sleep while the scanning==true.
I have attempted many, many scenarios to achieve this, but no joy.

Does your code work if you don't try to sleep?

Yes, the code works if no sleep.
The code "Test" in post #1 works fine.

Declan:
Yes, the code works if no sleep.
The code “Test” in post #1 works fine.

Then, you added code to sleep. You KNOW when you try to go to sleep. It is not difficult to determine, when you want to sleep, whether or not you CAN go to sleep.

// how long to sleep for - n x 8 seconds
int sleep_time;

So, you want to sleep for 0 seconds… If that is not true, then why is there no initial value?

// count sleep_periods
int sleep_periods_count = 0;

You use an int so that you can have a negative number of sleep times. Is that even possible? Do you really plan to sleep 32000+ times?

Using appropriate types IS important.

What do your serial prints tell you is happening? Specifically, when is scanning set to true? When is it set to false? When, with respect to those times, does it get told to go to sleep?