SparkFun Thing Plus - NINA-B306 Hookup Guide

Pages
Contributors: El Duderino
Favorited Favorite 0

BLE Data Pipe Arduino Example

With everything installed in Arduino we can move on to an example sketch that sets up the Thing Plus - NINA-B306 as a BLE device to package and send data recorded by the sensors to a paired device.

Example Code

You can find the example in the Examples folder in the GitHub repository or you can copy the code below into a blank sketch in Arduino. Select your Board (SparkFun Thing Plus - NINA-B306) and Port and click the Upload button.

language:c
/*
  BLE Data Pipe

  This example creates a BLE peripheral with a sensor service using the 
  SparkFun NINA-B306 Thing Plus. The sensor service notifies (push data to) the
  central.

  The sensor service contains the following characteristics:
  Acceleration X,Y,Z
  Gyro X,Y,Z
  Temperature (degC), Humidity, Pressure
  MIT License
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
  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.

*/

#include <Wire.h>
#include <Adafruit_TinyUSB.h>

#include <SparkFunBME280.h>
#include <SparkFun_ISM330DHCX.h>
#include <SparkFun_MAX1704x_Fuel_Gauge_Arduino_Library.h>

#include "bluefruit.h"
#include "SparkFunBLEService.h"
#include "services/SparkFunBLE_ISM330DHCX.h"
#include "services/SparkFunBLE_BME280.h"


/* Battery Monitor */
SFE_MAX1704X              lipo(MAX1704X_MAX17048);

long curr_millis    = 0;
long prev_millis    = 0;
long batt_interval  = 5000; // 5s in ms

/* BME280 Environmental Sensor */
BME280                    envSensor;

/* ISM330DHCX 6-DoF IMU Sensor */
SparkFun_ISM330DHCX       imuSensor;

sfe_ism_data_t _accelData;
sfe_ism_data_t _gyroData;

/* IMU BLE Service */
SparkFunBLE_ISM330DHCX    bleIMU;

/* ENV BLE Service */
SparkFunBLE_BME280        bleENV;

/* BLE Device Information
 * Name - Thing Plus NINA-B306 Data Pipe
 * Manufacturer - SparkFun Electronics
 * Model - SparkFun Thing Plus NINA-B306
 */
BLEDis                    bledis;

/* BLE Battery Service helper class */
BLEBas                    blebas;

void setup() {
  Serial.begin(115200);
  //while(!Serial) delay(10);

  Serial.println(F("SparkFun BLE Data Pipe Example"));
  Serial.println(F("------------------------------\n"));

  Wire.begin();

  // Initialize Sensors
  initFuelGauge();

  initBME280();

  initISM330DHCX();

  //Initialize BLE things
  Bluefruit.begin();
  Bluefruit.setTxPower(8); // +8 dBm, max power.
  Bluefruit.setName("Data Pipe Example");

  // Configure and start Device Information Service
  Serial.println(F("Configuring the Device Information Service..."));
  bledis.setManufacturer("SparkFun Electronics");
  bledis.setModel("Thing Plus NINA-B306");
  bledis.setHardwareRev("v10");
  bledis.setSoftwareRev("0.1.0");
  bledis.begin();

  // Configure and start BLE Battery Service and initialize to 100%
  Serial.println(F("Configuring the Battery Service..."));
  blebas.begin();
  blebas.write(100);

  // Configure and start BLE Environmental Sensor Service
  // Make sure to give enough room between sensor IDs, the BME280 uses 3 IDs.
  Serial.println(F("Configuring the Environmental Sensor Service..."));
  bleENV.begin(&envSensor, 100); // Sensor, ID.


  // Configure and start the IMU Sensor Service
  // Make sure to give enough room between sensor IDs, the IMU uses 2 IDs.
  Serial.println(F("Configuring the IMU Data Service..."));
  bleIMU.begin(&imuSensor, 200); // Sensor, ID.


  Serial.println(F("Setup complete."));

  /*  Start advertising BLE. It will start continuously transmitting BLE
      advertising packets and will be visible to remote BLE central devices
      until it receives a connection.  
  */
  startAdv();

  Serial.println(F("BLE device active, waiting for connections..."));

}

void loop() {

  // Battery service handler
  curr_millis = millis();
  if ((curr_millis - prev_millis) > batt_interval) { // check every batt_interval ms
    prev_millis = curr_millis;
    if ( lipo.isChange(true) ) {  // only update if battery SOC is > +/- 1%
      blebas.write(lipo.getSOC());
    }
  }

}

void startAdv() {
  Serial.println(F("Begin advertising."));
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();

  // Add services
  Bluefruit.Advertising.addService(bleENV, bleIMU);

  Bluefruit.ScanResponse.addName();

  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval: fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);       // units of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);         // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                   // 0 = Don't stop advertising unless connected

}

void initFuelGauge() {
  Serial.println(F("Initializing MAX17048 Battery Fuel Gauge..."));

  if (!lipo.begin()) {
    Serial.println(F("MAX17048 not detected. Please check wiring. Freezing."));
    while(1);
  }

  // Read and print the battery threshold
  Serial.print(F("Battery empty threshold is currently: "));
  Serial.print(lipo.getThreshold());
  Serial.println(F("%"));

    // We can set an interrupt to alert when the battery SoC gets too low.
    // We can alert at anywhere between 1% and 32%:
    lipo.setThreshold(20); // Set alert threshold to 20%.

  // Read and print the battery empty threshold
  Serial.print(F("Battery empty threshold is now: "));
  Serial.print(lipo.getThreshold());
  Serial.println(F("%"));

  // Clear any alert that might already be generated.
  lipo.clearAlert();

}

void initBME280() {
  Serial.println("Initializing BME280 Environmental Sensor...");
  envSensor.setI2CAddress(0x76); // Default address on NINA-B306

  if (!envSensor.beginI2C()) {
    Serial.println("The BME280 did not respond. Please check address and wiring.");
    while(1);
  }
  Serial.println("BME280 initialization successful.");
}

void initISM330DHCX() {
  Serial.println("Initializing ISM330DHCX...");

  if (!imuSensor.begin()) {
    Serial.println("The ISM330DHCX did not respond. Please check address and wiring.");
    while(1);
  }

  Serial.println("ISM330DHCX Initialization successful. Resetting device settings...");

  imuSensor.deviceReset();

  while(!imuSensor.getDeviceReset()){
    delay(1);
  }

  Serial.println("Device reset complete. Configuring ISM330DHCX...");
  delay(100);

  imuSensor.setDeviceConfig();
  imuSensor.setBlockDataUpdate();

  // Set accelerometer output data rate and data precision
  imuSensor.setAccelDataRate(ISM_XL_ODR_104Hz);
  imuSensor.setAccelFullScale(ISM_4g);

  // Set gyro output data rate and data precision
  imuSensor.setGyroDataRate(ISM_GY_ODR_104Hz);
  imuSensor.setGyroFullScale(ISM_500dps);

  // Turn on accelerometer's filter and apply settings.
  imuSensor.setAccelFilterLP2();
  imuSensor.setAccelSlopeFilter(ISM_LP_ODR_DIV_100);

  // Turn on gyro's filter and apply settings.
  imuSensor.setGyroFilterLP1();
  imuSensor.setGyroLP1Bandwidth(ISM_MEDIUM);

  Serial.println("ISM330DHCX successfully configured.");
}

uint16_t measureCallBack(uint8_t* buf, uint16_t bufsize) {
  float imu_data[6];
  imuSensor.getAccel(&_accelData);
  imuSensor.getGyro(&_gyroData);

  imu_data[0] = _accelData.xData * 0.0098067;
  imu_data[1] = _accelData.yData * 0.0098067;
  imu_data[2] = _accelData.zData * 0.0098067;
  imu_data[3] = _gyroData.xData * 0.017453;
  imu_data[4] = _gyroData.yData * 0.017453;
  imu_data[5] = _gyroData.zData * 0.017453;

  memcpy(buf, &imu_data, 24);

  return 24;
}    

Device Pairing & Data Reading

Once the code finishes uploading, open the Serial Monitor in Arduino to watch the printout to check if everything initializes and configures properly. After configuring the device information and BLE services for the sensors, the code will wait for a connection. You'll need a device to pair with the Thing Plus NINA-B306 like your phone or computer. We recommend using a phone with a BLE application like nRF Connect for Mobile from Nordic Semiconductor®. Other apps should work as well so feel free to use whichever you prefer.

The example sets the SparkFun service/characteristic UUID128 to the base UUID of 5FE0xxxx-005E-4761-9A7E-947AA3C505FE. The sensor services have UUIDs unique to the 3-4ths octets. The BME280 service ID is 0100 and its sensor output characteristic is 0101. The ISM330DHCX sensor service ID is 0200 and its sensor output characteristic is 0201.

Open your BLE app and scan for devices in range and look for the Thing Plus UUID or name. Pair with this device and then enable notify for the sensor service(s) you wish to view. After selecting the service, you should start seeing hex values for data from the sensor. Unfortunately, this is not very human readable but you should be able to see the values change as you move the board or breathe on the BME280.

Extra Examples

The GitHub repository also includes several other examples for the Thing Plus NINA-B306 in the examples folder to use other components on the board like the RGB LED and µSD card.