Nano 33 IOT BLE becomes unresponsive and has to be manually rebooted

Hey all, I am pretty new to all this so I am sure my code is bonkers.
I have two Nano 33 IOTs as central and peripheral and they cant stay connected, I think my loops are getting stuck when the Bluetooth signal is weak.

I think I should probably be using else or the watchdog timer in some way, but am not sure I should be forcing them to reboot all the time to fix my issue, especially since I want to have the peripheral sleep since it will be on battery.

I have sleep currently commented out since I am just trying to get the communication reliable

Central

#include <Arduino.h>
#include <ArduinoBLE.h>

const arduino::String nameOfPeripheral = "GaugeReader";
const char *deviceServiceUuid = "19B10000-E8F2-537E-4F6C-D104768A1214";
const char *deviceServiceCharacteristicUuid = "19B10001-E8F2-537E-4F6C-D104768A1214";

const int RELAY_PIN = A0;

void scanForPeripheral()
{
  Serial.print("Scanning for");
  Serial.print(nameOfPeripheral);
  Serial.println("...");
  BLE.scanForUuid(deviceServiceUuid);
}

void printPeripheralInfo(BLEDevice peripheral)
{
  Serial.print("Found ");
  Serial.print(peripheral.address());
  Serial.print(" '");
  Serial.print(peripheral.localName());
  Serial.print("' ");
  Serial.print(peripheral.advertisedServiceUuid());
  Serial.println();
}

void readGageLevel(BLECharacteristic gageLevelChar)
{
  uint8_t gageLevel;

  gageLevelChar.readValue(gageLevel);

  Serial.print("Gage Level % is now: ");
  Serial.println(gageLevel);

  if (gageLevel <= 50)
  {
    digitalWrite(RELAY_PIN, HIGH);
  }
  else
  {
    digitalWrite(RELAY_PIN, LOW);
  }
}

void controlPeripheral(BLEDevice peripheral)
{
  // connect to the peripheral
  Serial.println("Connecting ...");
  if (peripheral.connect())
  {
    Serial.println("Connected");
  }
  else
  {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering peripheral device attributes...");
  if (peripheral.discoverAttributes())
  {
    Serial.println("* Peripheral device attributes discovered!");
  }
  else
  {
    Serial.println("Attribute discovery failed.");
    peripheral.disconnect();
    return;
  }

  Serial.println("Subscribing to gage level characteristic ...");

  // retrieve the BLE Gage Level Characteristic
  BLECharacteristic gageLevelChar = peripheral.characteristic(deviceServiceCharacteristicUuid);

  if (!gageLevelChar)
  {
    Serial.println("No gage level characteristic found!");
    peripheral.disconnect();
    return;
  }
  else if (!gageLevelChar.canRead())
  {
    Serial.println("* Peripheral does not have a readable gageLevel characteristic!");
    peripheral.disconnect();
    return;
  }

  int i = 0;
  while (peripheral.connected() && i < 10)
  {
    // while the peripheral is connected
    readGageLevel(gageLevelChar);
    i++;
  }

  peripheral.disconnect();
  Serial.println("GageLevel Monitor disconnected!");
}

void setup()
{
  Serial.begin(9600);
  // while (!Serial); // wait for serial

  // begin initialization
  if (!BLE.begin())
  {
    Serial.println("starting BLE failed!");
  }

  pinMode(RELAY_PIN, OUTPUT);

  Serial.println("BLE - GageLevel Central");
  scanForPeripheral();
}

void loop()
{
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral)
  {
    // discovered a peripheral, print out address, local name, and advertised service
    printPeripheralInfo(peripheral);

    // Check if the peripheral is a GaugeReader, the local name will be: "GaugeReader"
    if (peripheral.localName() != nameOfPeripheral)
    {
      return;
    }

    BLE.stopScan();
    controlPeripheral(peripheral);
    scanForPeripheral();
  }
}

Peripheral

#include <Arduino.h>
#include <ArduinoBLE.h>
#include <Adafruit_SleepyDog.h>
#include <AS5600.h>
#include <Wire.h>

AMS_5600 ams5600;
int ang, lang = 0;

// BLE Gauge Service
BLEService gaugeLevelService("19B10000-E8F2-537E-4F6C-D104768A1214");

// BLE Gauge Level Characteristic
// standard 16-bit characteristic UUID
// remote clients will be able to get notifications if this characteristic changes
BLEIntCharacteristic gaugeLevelChar("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);

int sleepTime = 500;     // time to sleep in ms
long previousMillis = 0; // last time the battery level was checked, in ms

void blePeripheralConnectHandler(BLEDevice central)
{
  // central connected event handler
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central)
{
  // central disconnected event handler
  digitalWrite(LED_BUILTIN, LOW);
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());

  Serial.println("Good night... (-, - ) ... zzzZZ ...");
  Serial.print("Back in ");
  Serial.print(sleepTime);
  Serial.println("s");

  delay(sleepTime);
  // Watchdog.sleep();
}

void setup()
{
  Serial.begin(9600);
  Wire.begin();                 // initialize an i2c bus for AMS5600 angle encoder
  pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected

  // pinMode(LED_PWR, OUTPUT);
  // digitalWrite(LED_PWR, LOW);
  // digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);
  // digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);

  // begin initialization
  if (!BLE.begin())
  {
    Serial.println("starting BLE failed!");
  }

  BLE.setConnectionInterval(0x0006, 0x0c80);

  /* Set a local name for the BLE device
     This name will appear in advertising packets
     and can be used by remote devices to identify this BLE device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("GaugeReader");
  BLE.setAdvertisedService(gaugeLevelService);
  gaugeLevelService.addCharacteristic(gaugeLevelChar);

  // add service
  BLE.addService(gaugeLevelService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // set initial value for this characteristic
  gaugeLevelChar.writeValue(100);

  // Start advertising BLE. It will start continuously transmitting BLE
  // advertising packets and will be visible to remote BLE central devices
  // until it receives a new connection.
  BLE.setAdvertisingInterval(2 * 320 * 0.625); // 320 * 0.625 ms
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void printDebugGaugeLevel(int gaugeLevel, int gaugeReading = -1)
{
  Serial.print("Gauge is now: "); // print it

  if (gaugeReading >= 0)
  {
    Serial.print("(");
    Serial.print(gaugeReading);
    Serial.print(") ");
  }

  Serial.println(gaugeLevel);
}

int convertToGaugeLevel(int rawAngle)
{
  int value = rawAngle;
  if (rawAngle >= 1000)
  {
    value = max(rawAngle - 1280, 0);
  }
  else
  {
    value = min(rawAngle + 2815, 4095);
  }

  int gaugeLevel = map(value, 3700, 0, 0, 100);
  return gaugeLevel;
}

void updateGaugeLevel()
{
  // Serial.println("Check gauge Level.");
  if (ams5600.detectMagnet() == 0)
  {
    Serial.println("Warning! Cannot detect gauge level magnet!");
    return;
  }

  int gaugeReading = ams5600.getRawAngle();
  int gaugeLevel = convertToGaugeLevel(gaugeReading);

  printDebugGaugeLevel(gaugeLevel, gaugeReading);
  gaugeLevelChar.writeValue(gaugeLevel);
}

void loop()
{
  // Check GaugeLevel
  long currentMillis = millis();

  if (currentMillis - previousMillis >= 500)
  {
    previousMillis = currentMillis;
    updateGaugeLevel();
  }

  // poll for BLE events
  BLE.poll(500);
}

Hello @patricktodd,

Just had a quick look and I would recommend a few things I would try.

When you say it becomes unresponsive, is it both boards and/or how many connections can you achieve before that happens?

Try using setEventHandler, on both central and peripheral as it will make things clearer and maybe take the 500 out of BLE.poll(500).

Also, I would remove the delay(sleepTime) as the BLE can have issues when you don't read from it all the time (i.e. BLE.poll() needs to happen as much as possible). If you need to put it to sleep you might need to consider actually switching the BLE off then turning it back on when it wakes up.

The BLE crashing because of lack of polling is a known issue currently covered in the BLE library GitHub if you want to know more.

Hope that helps,
Matt

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.