Waking up from deep sleep prevents Artemis from connecting to BLE.

I’ve been working on a device using the Artemis Nano that can be put to sleep and woken up with a pushbutton. I’m now adding BLE to the mix to broadcast data and such. The problem I’m running into now is that once the device has been put to sleep and wakes up again, I can’t get it to connect to BLE. It connects to nRF connect just fine prior to going to sleep, but can’t connect to it afterwards.

void sleepModeSwitch()
{
  
  if (millis() - debounce < DEBOUNCETIME ) 
  {
    return;
  }
  
  if(sleep_mode_status == false)
  {
    debounce = millis();
    sleep_mode_status = true;
  }
  else
  {
    wakeFromSleep();
    debounce = millis();
    sleep_mode_status = false;
  }
}

void goToSleep()
{
  if (millis() - debounce < DEBOUNCETIME ) 
  {
    return;
  }
#ifdef DEBUG
  Serial.println("Going to sleep");
  delay(50);  //Wait for serial to finish
  Serial.end(); //Power down UART(s)
#endif
  // turn off the led.
  digitalWrite(LED_BUILTIN, LOW);
  //digitalWrite(BATTERY_LED, HIGH);

  // Stop the BLE advertising.
  BLE.stopAdvertise() ;

  powerControlADC(false);
  
  for(int x = 0; x < 50; x++)
  {
    if(x != SLEEP_INTERRUPT && x != BATTERY_LED)
    {
      //am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down Flash, SRAM, cache
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); //Turn off CACHE
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)

  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); //Turn off everything but lower 512k
  //am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); //Turn off everything but lower 64k
  //am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover)
  
  // // Enable interrupts to the core.
  am_hal_interrupt_master_enable();
  
  // //Enable the timer interrupt in the NVIC.
  // NVIC_EnableIRQ(STIMER_CMPR6_IRQn);

  //Go to Deep Sleep.
  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
}

void wakeFromSleep()
{
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
  
  // Renable UART0 pins
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);

  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  initializeADC();

#ifdef DEBUG
  Serial.begin(115200);
  delay(10);
  Serial.println("Waking up! Hello world!");
#endif
  BLE.advertise();
  deepSleepTimer = millis() ;
  sleep_mode_status = false;
  //digitalWrite(BATTERY_LED, LOW);
  //digitalWrite(LED_BUILTIN, HIGH);
}

Is there something being disabled by the sleep mode that I haven’t re-enabled in the wakeup? I tried running BLE.end() after BLE.stopAdvertise() (to put to sleep) then running BLE.begin() before BLE.advertise() (while waking up), and that got me a hardfault, so chances are I just did it wrong, but I’m not quite sure how.

some time ago I wrote the attached deepsleep sketch with BLE. Works on V1.x.x and V2.x.x

example24_ph_deepsleep_BME280.zip (16 KB)

Working on implementing it. I get the sense that I’m missing most of your modifications, so I’ll try to get caught up on that. I will also note that the last time I tried to run BLE.end() to prepare for sleep and BLE.begin() in wakeup, I got a hardfault. Is that also a library/driver modification I’m missing?

If you perform BLE.begin() and BLE.end() more than about 20 to 25 times within a sketch… it can/will crash. Issue in Mbed/Cordio driver where it tries every time at BLE.begin() to get a new “handle” / entry pointer to the HAL. The handle-table has 15 entries and at BLE-end() that handle is not released (as there is NO call in Cordio to do so). On a certain moment, there is a table overrun, as the check whether all the table entries have been fully utilized is missing. It needs modification in the AP3CordioHCITransportDriver.cpp and then a recompile of the MBED-library

paulvha:
some time ago I wrote the attached deepsleep sketch with BLE. Works on V1.x.x and V2.x.x

I tried adding the BLE code to the sleep mode example I got working with GPIO earlier, and I think I’ve found the problem, sort of…

below is the code I got working for GPIO sleep and wakeup. The I’m running into is that, and I need to triple check that the BLE is what’s causing this, when I press the button the first time, it starts to loop through the interrupt, seemingly as soon as the software debounce has run its course. What’s more, the built-in LED doesn’t illuminate after it wakes up the first time.

#include "RTC.h"
#include <ArduinoBLE.h>
#define BUTTON_CTRL 14
#define DEBOUNCETIME 1000   // number of milli seconds needed between pushes

void BLE_Setup();
void setSleepMode();
void goToSleep();
void peripheralSleep();

const char BLE_PERIPHERAL_NAME[] = "Peripheral Sleep Test BLE";

BLEService SleepService("19B10010-E8F2-537E-4F6C-D104768A1214");

BLECharacteristic rxCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 8);

bool sleep_mode_set = false;
unsigned long debounce;     // Stores the last millis()
unsigned long count = 0;
unsigned int loop_count = 0;

void BLE_Setup()
{
  Serial.println("Starting BLE");

  if(!BLE.begin())
  {
    delay(30);
  }

  BLE.setLocalName(BLE_PERIPHERAL_NAME);
  BLE.setAdvertisedService(SleepService);
  SleepService.addCharacteristic(rxCharacteristic);
  BLE.addService(SleepService);
  BLE.advertise();
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON_CTRL, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("SparkFun RTC Low-power Alarm Example");

  BLE_Setup();

  // // Easily set RTC using the system __DATE__ and __TIME__ macros from compiler
  //RTC.setToCompilerTime();

  // Manually set RTC date and time
  rtc.setTime(0, 50, 59, 12, 3, 6, 20); // 12:59:50.000, June 3rd, 2020 (hund, ss, mm, hh, dd, mm, yy)

  // Set the RTC's alarm
  //rtc.setAlarm(0, 0, 0, 13, 3, 6); // 13:00:00.000, June 3rd (hund, ss, mm, hh, dd, mm). Note: No year alarm register

  // Set the RTC alarm mode
  /*
    0: Alarm interrupt disabled
    1: Alarm match every year   (hundredths, seconds, minutes, hour, day, month)
    2: Alarm match every month  (hundredths, seconds, minutes, hours, day)
    3: Alarm match every week   (hundredths, seconds, minutes, hours, weekday)
    4: Alarm match every day    (hundredths, seconds, minute, hours)
    5: Alarm match every hour   (hundredths, seconds, minutes)
    6: Alarm match every minute (hundredths, seconds)
    7: Alarm match every second (hundredths)
  */
  //rtc.setAlarmMode(6); // Set the RTC alarm to match on minutes rollover
  //rtc.attachInterrupt(); // Attach RTC alarm interrupt
  debounce = millis();
  attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), setSleepMode, FALLING);
}

void loop()
{
  BLEDevice central = BLE.central();
  // Print date and time of RTC alarm trigger
  if(central)
  {
    while(central.connected())
    {
      if(loop_count >= 200000)
      {
        Serial.print("count: "); Serial.println(count);//printDateTime();
        count++;
        loop_count = 0;
        rxCharacteristic.writeValue(count);
      }
      else
      {
        loop_count++;
      }
      // Enter deep sleep and await RTC alarm interrupt
    }
  }
  if(sleep_mode_set == true)
  {
    peripheralSleep();
  }
}

// Print the RTC's current date and time
void printDateTime()
{
  rtc.getTime();

  Serial.printf("20%02d-%02d-%02d %02d:%02d:%02d.%03d\n",
          rtc.year, rtc.month, rtc.dayOfMonth,
          rtc.hour, rtc.minute, rtc.seconds, rtc.hundredths);
  Serial.println();
}

void setSleepMode()
{
  if(sleep_mode_set == false)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    if (millis() - debounce < DEBOUNCETIME ) 
    {
      debounce = millis();
      return;
    }
    //detachInterrupt(digitalPinToInterrupt(BUTTON_CTRL));
    //attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), wakeUp, FALLING);
    sleep_mode_set = true;
    return;
  }
  else
  {
    wakeUp();
    sleep_mode_set = false;  
  }
}

void peripheralSleep()
{
  BLE.stopAdvertise();
  //Wire.end();
  BLE.end();

  goToSleep();
}

// Power down gracefully
void goToSleep()
{
  // Disable UART
  Serial.println("Going to sleep...");
  delay(100);
  Serial.end();

  // Disable ADC
  powerControlADC(false);

  // Force the peripherals off
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);

  // Disable all pads (except UART TX/RX)
  for (int x = 0 ; x < 50 ; x++)
  {
    if(x != LED_BUILTIN && x != BUTTON_CTRL)
    {
      am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down CACHE, flashand SRAM
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Turn off CACHE and flash
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)
  
  // Keep the 32kHz clock running for RTC
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ);

  am_hal_interrupt_master_enable();


  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever

  // And we're back!
  wakeUp();
}

// Power up gracefully
void wakeUp()
{
  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // Power up SRAM, turn on entire Flash
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);

  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // Renable UART0 pins
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);

  // Renable power to UART0
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  am_hal_ctimer_start(7, AM_HAL_CTIMER_TIMERB);

  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  
  // Enable ADC
  powerControlADC(true);
  
  initializeADC();

  // Enable Serial
  Serial.begin(115200);
  digitalWrite(LED_BUILTIN, LOW);
  debounce = millis();
  delay(100);
  Serial.println("Waking up! Hello world!");
  BLE_Setup();
}

This is the output, though I should also add that the “Waking up! Hello world!” line has a backwards question mark in front of it.

SparkFun RTC Low-power Alarm Example
Starting BLE
Going to sleep...
Waking up! Hello world!
Starting BLE
Going to sleep...
Waking up! Hello world!
Starting BLE
Going to sleep...
Waking up! Hello world!
Starting BLE
Going to sleep...
Waking up! Hello world!
Starting BLE
Going to sleep...

I’m only guessing, but I think the interrupt flag isn’t being cleared properly. I’m still researching and testing though, so if you have any suggestions or ideas, my ears are wide open

Check the other forum post for the button… you need to define BUTTON-CTRL different !

I made the change you suggested and it didn’t break anything this time! Must have been something else that’s slipped my mind. In the meantime, I noticed I was missing that timer7 shutdown (though I don’t think I missed restarting it?), and now I’m getting a hardfault when I try to wake up and it starts trying to run BLE.begin. I’m assuming this is that cordio library you mentioned that needs to be fixed and precompiled? That said, it’s happening on the first go, rather than 20-25 minutes, but it’s worth noting I think

It fails only after about 20 times… if it fails first time around… you have another problem… then share the sketch as you use it…

paulvha:
It fails only after about 20 times… if it fails first time around… you have another problem… then share the sketch as you use it…

Here’s the sketch, with the Serial output after it (I’ve updated this to switch out if(!BLE.begin()) for while(!BLE.begin()). BLE is now rediscoverable after sleeping and waking up, but the characteristics won’t update data. Also of note, if I set nRF connect to constantly read the characteristic, the program pauses until I tell nRF to stop. Then it goes on like normal)

#include "RTC.h"
#include <ArduinoBLE.h>

#define DEBOUNCETIME 1000   // number of milli seconds needed between pushes

#define BUTTON_CTRL D14
const char BLE_PERIPHERAL_NAME[] = "Peripheral Sleep Test BLE";

BLEService SleepService("19B10010-E8F2-537E-4F6C-D104768A1214");

BLECharacteristic rxCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 8);

bool sleep_mode_set = false;
unsigned long debounce;     // Stores the last millis()
unsigned long count = 0;
unsigned int loop_count = 0;

void BLE_Setup()
{
  Serial.println("Starting BLE");

  while(!BLE.begin())
  {
    delay(30);
  }
  Serial.print("setting device name"); Serial.println(BLE_PERIPHERAL_NAME);
  BLE.setLocalName(BLE_PERIPHERAL_NAME);
  BLE.setAdvertisedService(SleepService);
  SleepService.addCharacteristic(rxCharacteristic);
  BLE.addService(SleepService);
  Serial.println("Beginning Advertising");
  BLE.advertise();
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON_CTRL, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("SparkFun RTC Low-power Alarm Example");

  // // Easily set RTC using the system __DATE__ and __TIME__ macros from compiler
  //RTC.setToCompilerTime();

  // Manually set RTC date and time
  rtc.setTime(0, 50, 59, 12, 3, 6, 20); // 12:59:50.000, June 3rd, 2020 (hund, ss, mm, hh, dd, mm, yy)

  // Set the RTC's alarm
  //rtc.setAlarm(0, 0, 0, 13, 3, 6); // 13:00:00.000, June 3rd (hund, ss, mm, hh, dd, mm). Note: No year alarm register

  // Set the RTC alarm mode
  /*
    0: Alarm interrupt disabled
    1: Alarm match every year   (hundredths, seconds, minutes, hour, day, month)
    2: Alarm match every month  (hundredths, seconds, minutes, hours, day)
    3: Alarm match every week   (hundredths, seconds, minutes, hours, weekday)
    4: Alarm match every day    (hundredths, seconds, minute, hours)
    5: Alarm match every hour   (hundredths, seconds, minutes)
    6: Alarm match every minute (hundredths, seconds)
    7: Alarm match every second (hundredths)
  */

  BLE_Setup();
  //rtc.setAlarmMode(6); // Set the RTC alarm to match on minutes rollover
  //rtc.attachInterrupt(); // Attach RTC alarm interrupt
  debounce = millis();
  attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), setSleepMode, FALLING);
}

void loop()
{
  BLEDevice central = BLE.central();
  // Print date and time of RTC alarm trigger
    if(loop_count >= 75000)
    {
      Serial.print("count: "); Serial.println(count);//printDateTime();
      count++;
      loop_count = 0;
    }
    else
    {
      loop_count++;
      rxCharacteristic.writeValue(count);
    }
    
    // Enter deep sleep and await RTC alarm interrupt
    if(sleep_mode_set == true)
    {
      peripheralSleep();
    }
}

// Print the RTC's current date and time
void printDateTime()
{
  rtc.getTime();

  Serial.printf("20%02d-%02d-%02d %02d:%02d:%02d.%03d\n",
          rtc.year, rtc.month, rtc.dayOfMonth,
          rtc.hour, rtc.minute, rtc.seconds, rtc.hundredths);
  Serial.println();
}

void setSleepMode()
{
  if(sleep_mode_set == false)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    if (millis() - debounce < DEBOUNCETIME ) 
    {
      debounce = millis();
      return;
    }
    //detachInterrupt(digitalPinToInterrupt(BUTTON_CTRL));
    //attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), wakeUp, FALLING);
    sleep_mode_set = true;
    return;
  }
  else
  {
    //wakeUp();
    sleep_mode_set = false;  
  }
}

void peripheralSleep()
{
  BLE.stopAdvertise();
  //Wire.end();
  BLE.end();

  goToSleep();
}

// Power down gracefully
void goToSleep()
{
  // Disable UART
  Serial.end();

  // Disable ADC
  powerControlADC(false);

  // Force the peripherals off
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);

  am_hal_ctimer_stop(7, AM_HAL_CTIMER_TIMERB); 

  // Disable all pads (except UART TX/RX)
  for (int x = 0 ; x < 50 ; x++)
  {
    if(x != LED_BUILTIN && x != BUTTON_CTRL)
    {
      am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down CACHE, flashand SRAM
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Turn off CACHE and flash
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K);    // keep 512K memory powered given the size of the binary
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)
  
  // Keep the 32kHz clock running for RTC
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ);

  am_hal_interrupt_master_enable();


  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever

  // And we're back!
  wakeUp();
}

// Power up gracefully
void wakeUp()
{
  // Power up SRAM, turn on entire Flash
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
  
  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // Renable UART0 pins
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);

  // Renable power to UART0
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  am_hal_ctimer_start(7, AM_HAL_CTIMER_TIMERB);
  
  // Enable ADC
  initializeADC();

  // Enable Serial
  Serial.begin(115200);
  digitalWrite(LED_BUILTIN, LOW);
  BLE_Setup();
  debounce = millis();
}

To note, when it gets to Starting BLE the second time (after count: 12), I have to press the button twice. The first press puts it to sleep no problem, but the second one causes it to wake up and go through most of the wakeup function until it reaches BLE.begin(), whereupon it enters that loop and keeps going until it hard-faults.

SparkFun RTC Low-power Alarm Example
Starting BLE
setting device namePeripheral Sleep Test BLE
Beginning Advertising
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
count: 10
count: 11
count: 12
Starting BLE

++ MbedOS Error Info ++
Error Status: 0x80010133 Code: 307 Module: 1
Error Message: Mutex: 0x100046E4, Not allowed in ISR context
Location: 0x2807B
Error Value: 0x100046E4
Current Thread: main Id: 0x10004708 Entry: 0x27F4D StackSize: 0x1000 StackMem: 0x100061E0 SP: 0x1005FE04 
For more info, visit: https://mbed.com/s/error?error=0x80010133&tgt=SFE_ARTEMIS_ATP
-- MbedOS Error Info --

Ugh, I’m an idiot. I missed that while I usually do while(!BLE.begin(), I instead did if(!BLE.begin()). Some progress has been made. Now it’s rediscoverable, but when I check in nRF connect, normally there’s two characteristics instead of just one, and I can’t read that first one’s data.

update: Okay, so my understanding is that the second characteristic is related to BLE notifications. I removed BLENotify from rxCharacteristic and while I still can’t get nRF connect to display the data normally, if I request a read then go to change how the data is displayed (raw hex, UTF-8, unsigned int, signed in, etc), I can see the number updating. So, I’m assuming whatever this weirdness is, it’s related to the Artemis, but it could also involve nRF connect too. Not sure what the ratio of responsibility for this weirdness is

this example works ( see below). You try to do TOO many things… keep it simple

Also you mix for BLE CENTRAL and PERIPHERAL. Study the BLE examples…

#include "RTC.h"
#include <ArduinoBLE.h>

#define DEBOUNCETIME 1000   // number of milli seconds needed between pushes

#define BUTTON_CTRL D14
const char BLE_PERIPHERAL_NAME[] = "Peripheral Sleep Test BLE";

BLEService SleepService("19B10010-E8F2-537E-4F6C-D104768A1214");

BLECharacteristic txCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLEWrite | BLERead | BLENotify, 8);

volatile bool Set_To_Sleep = false;
unsigned long debounce;     // Stores the last millis()
unsigned long count = 0;
unsigned int loop_count = 0;

void BLE_Setup()
{
  Serial.println("Starting BLE");

  while(!BLE.begin())
  {
    delay(30);
  }
  Serial.print("setting device name"); Serial.println(BLE_PERIPHERAL_NAME);
  BLE.setLocalName(BLE_PERIPHERAL_NAME);
  BLE.setAdvertisedService(SleepService);
  SleepService.addCharacteristic(txCharacteristic);
  BLE.addService(SleepService);
  Serial.println("Beginning Advertising");
  BLE.advertise();
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON_CTRL, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("SparkFun RTC Low-power Alarm Example");

   // Manually set RTC date and time
  rtc.setTime(0, 50, 59, 12, 3, 6, 20); // 12:59:50.000, June 3rd, 2020 (hund, ss, mm, hh, dd, mm, yy)

  // Set the RTC's alarm
  rtc.setAlarm(0, 0, 0, 13, 3, 6); // 13:00:00.000, June 3rd (hund, ss, mm, hh, dd, mm). Note: No year alarm register

  // Set the RTC alarm mode
  /*
    0: Alarm interrupt disabled
    1: Alarm match every year   (hundredths, seconds, minutes, hour, day, month)
    2: Alarm match every month  (hundredths, seconds, minutes, hours, day)
    3: Alarm match every week   (hundredths, seconds, minutes, hours, weekday)
    4: Alarm match every day    (hundredths, seconds, minute, hours)
    5: Alarm match every hour   (hundredths, seconds, minutes)
    6: Alarm match every minute (hundredths, seconds)
    7: Alarm match every second (hundredths)
  */

  BLE_Setup();
  rtc.setAlarmMode(6); // Set the RTC alarm to match on minutes rollover
  
  // uncomment to start RTC interrupt
  //rtc.attachInterrupt(); // Attach RTC alarm interrupt
  debounce = millis();
  attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), setSleepMode, FALLING);
}

void loop()
{
  BLEDevice central = BLE.central();
  //   This wrong... A central connects to a peripheral, not the other way around 
  // study the BLE examples !!
    
  if(loop_count >= 35000)
  {
    Serial.println(count);  //printDateTime();
    count++;
    loop_count = 0;
  }
  else
  {
    loop_count++;
    txCharacteristic.writeValue(count);
  }
  
  // Enter deep sleep and await RTC alarm interrupt
  if(Set_To_Sleep == true)
  {
    peripheralSleep();
  }
}

// Print the RTC's current date and time
void printDateTime()
{
  rtc.getTime();

  Serial.printf("20%02d-%02d-%02d %02d:%02d:%02d.%03d\n",
          rtc.year, rtc.month, rtc.dayOfMonth,
          rtc.hour, rtc.minute, rtc.seconds, rtc.hundredths);
  Serial.println();
}

/**
 * interrupt when button has been pressed
 */
void setSleepMode()
{
  // debounce / detect jitter
  if (millis() - debounce < DEBOUNCETIME ) return;
  debounce = millis();
  
  digitalWrite(LED_BUILTIN, HIGH); // info only

  // if button is the only toggle it should EITHER set to 
  // sleep or keep running.

  if (Set_To_Sleep == false) Set_To_Sleep = true;
  else Set_To_Sleep = false;
}

/**
 * prepare sleep with BLE
 */
void peripheralSleep()
{
  BLE.stopAdvertise();
  BLE.end();
  goToSleep();
}

// Power down gracefully
void goToSleep()
{
  // Disable UART
  Serial.end();

  // Disable ADC
  powerControlADC(false);

  // Force the peripherals off
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);

  // needed for BLE
  am_hal_ctimer_stop(7, AM_HAL_CTIMER_TIMERB); 

  // Disable all pads (except UART TX/RX)
  for (int x = 0 ; x < 50 ; x++)
  {
    if(x != LED_BUILTIN && x != BUTTON_CTRL)
    {
      am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down CACHE, flashand SRAM
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Turn off CACHE and flash
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)
  
  // Keep the 32kHz clock running for RTC
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ);

  am_hal_interrupt_master_enable();

  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever

  // And we're back!
  wakeUp();
}

// Power up gracefully
void wakeUp()
{
  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // Renable UART0 pins
  am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
  am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);

  // Renable power to UART0
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);

  // restart BLE timer
  am_hal_ctimer_start(7, AM_HAL_CTIMER_TIMERB);
  
  // Enable ADC
  initializeADC();  // really needed ???

  // Enable Serial
  Serial.begin(115200);
  digitalWrite(LED_BUILTIN, LOW); // indicate we are back 
  BLE_Setup();
  debounce = millis();
}

Okay, gave it a try and it turned out the same as the one I posted. Yeah, it works in that it doesn’t screw up the BLE connection, but it also has that same problem I mentioned before of it showing up wonky when I check it with nRF connect. I can connect to it, a characteristic shows up, but its value is displayed as NA, and doesn’t change no matter how much I press the read button. That said, the value does seem to be updating since when I go to change how the value is displayed (hex, unsigned int, UTF-8, etc) the value is updating correctly.

Also, can I just say you have the patience of a saint, even as I know I’m undoubtedly trying it?

Of course there is no update :

There is NO BLE.poll() regular called, which needs to be done with ArduinoBLE.

Next to the characteristic update was planned every loop count instead of every count. Thus BLE got hammered.

And an update is only necessary to the characteristic when a central is connected.

Try attached and enable notifications in NRF.

ble_t.zip (2.23 KB)