Nano 33 BLE Sense: libraries are flaky

On the Nano 33 BLE Sense, I am trying to read most sensors in the same program. This worked well until I tried to read the APDS9960 sensor.

The ColorSensor.ino example that comes with the Arduino_APDS9960 library works fine with my Nano board. But as soon as I try to use that library in a more complex code, that loads a bunch of Sense libraries, it stops working. The r, g, b variables are 0, and half the time the APDS.readColor() call fails.

Not sure what else to do. The logic is correct - I am following the example from GitHub. The APDS library, when used alone in a program, works. But as soon as I try to move beyond "hello world", it does not work anymore.

Something's wrong somewhere, and I'm out of ideas for troubleshooting.

This is my current code:

#include <Arduino_HTS221.h>
#include <Arduino_LPS22HB.h>
#include <Arduino_LSM9DS1.h>
#include <Arduino_APDS9960.h>

float temperature, humidity, pressure;
float acc_x, acc_y, acc_z;
float gyro_x, gyro_y, gyro_z;
float magnet_x, magnet_y, magnet_z;

char linebuf_atm[80];
char linebuf_acc[80];
char linebuf_gyro[80];
char linebuf_magnet[80];
char linebuf_color[80];

int r, g, b, w;

int ledState = LOW;

void setup() {
  Serial.begin(9600);
  delay(100);

  HTS.begin();
  delay(100);

  BARO.begin();
  delay(100);
  // The baro sensor reads wrong first time after init
  // so let's do a throw-away read here.
  pressure = BARO.readPressure(MILLIBAR);

  IMU.begin();
  delay(100);

  APDS.begin();
  delay(100);

  pinMode(LED_BUILTIN, OUTPUT);

  // Let's allow things to settle down.
  delay(1000);
}

void loop() {
  Serial.println();

  if (APDS.colorAvailable()) {
    int r, g, b, w;
    APDS.readColor(r, g, b, w);
  } else {
    Serial.println("APDS fail");
  }
  temperature = HTS.readTemperature();
  humidity = HTS.readHumidity();
  pressure = BARO.readPressure(MILLIBAR);
  IMU.readAcceleration(acc_x, acc_y, acc_z);
  IMU.readGyroscope(gyro_x, gyro_y, gyro_z);
  IMU.readMagneticField(magnet_x, magnet_y, magnet_z);

  sprintf(linebuf_atm,
    "atmo:\t\ttemp=%.1fC\thumid=%.1f%%\tpress=%umb",
    temperature, humidity, int(pressure));
  sprintf(linebuf_acc,
    "accel (g):\tx=%.3f\ty=%.3f\tz=%.3f",
    acc_x, acc_y, acc_z);
  sprintf(linebuf_gyro,
    "gyro (deg/sec):\tx=%.3f\t\ty=%.3f\tz=%.3f",
    gyro_x, gyro_y, gyro_z);
  sprintf(linebuf_magnet,
    "magneto (uT):\tx=%.2f\t\ty=%.2f\t\tz=%.2f",
    magnet_x, magnet_y, magnet_z);
  sprintf(linebuf_color,
    "light:\t\tred=%u\t\tgreen=%u\tblue=%u\t\tall=%u",
    r, g, b, w);

  Serial.println(linebuf_atm);
  Serial.println(linebuf_acc);
  Serial.println(linebuf_gyro);
  Serial.println(linebuf_magnet);
  Serial.println(linebuf_color);

  ledState = ledState ? LOW: HIGH;
  digitalWrite(LED_BUILTIN,  ledState);
  
  delay(1000);
}

What seems to fix the APDS reading is this:

while (! APDS.colorAvailable()) {
  delay(5);
}
APDS.readColor(r, g, b, w);

In other words, some pause is mandatory between colorAvailable() and readColor(). With this change, my code appears to reliably read all sensors I care about, in one loop. I'll keep testing it for a while.

The code that uses the delay() is in the example from the Adafruit version of the library. Looks like the Arduino library is modeled after it, but that example was changed without realizing what the delay() was for. Well, this is what it is for - preventing nasty bugs such as this.

I will make a pull request on GitHub with this code change for the example.

Pull request created:

If that example had the correct logic (using delay() between those function calls), it would have saved me an afternoon of head-scratching.

Have found also that reading temperature with also reading humidity causes the HTS221.h library to fail.

#include <Arduino_HTS221.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!HTS.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }
}

void loop() {
  // read all the sensor values
  float temperature = HTS.readTemperature();
  //float humidity    = HTS.readHumidity();

  // print each of the sensor values
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" °C");

  //Serial.print("Humidity    = ");
  //Serial.print(humidity);
  //Serial.println(" %");

  // print an empty line
  Serial.println();

  // wait 1 second to print again
  //delay(1000);
}

Work around is to acquire a humidity reading, even if you do not require it.