SparkFun NanoBeacon Board - IN100 Hookup Guide

Pages
Contributors: El Duderino
Favorited Favorite 1

BMA400 Qwiic Example

Note: Make sure you are using the latest stable version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

Now that we know the IN100 is working and advertising, let's use a custom config file to send acceleration data from the SparkFun Triple Axis Accelerometer Breakout - BMA400 (Qwiic) to a RedBoard IoT running code to convert the values into a serial printout.

Required Libraries & Board Tools

This example assumes the use of the SparkFun IoT RedBoard board file as well as several libraries that do not come pre-installed with Arduino. Make sure to install both the board files and libraries prior to using this example. The SparkFun IoT RedBoard uses the ESP32 Dev Module board definition included in the "esp32" boards package. For detailed information on installing and using the IoT RedBoard, check out this section of our Hookup Guide for the board. Install the libraries used in this example with the Arduino Library Manager tool by searching for "ESP32 BLE Arduino".

Qwiic BMA400 Config File

With the board files and libraries installed we can move on to loading the Qwiic BMA400 config file from the Examples folder in the GitHub repository. This also contains the Arduino code so go ahead and download both (or the whole repository).

This config file contains all of the I2C commands as well as custom advertising data settings to name the NanoBeacon "BMA400_Data" and have it send voltage and I2C data. You can modify this if necessary but for a quick personal test, these settings should be just fine. You can view the I2C commands in the "I2C" window as shown below:

Screenshot showing I2C settings in Config Tool for BMA400 example.
Having trouble seeing the detail in this image? Click on it for a larger view.

After loading the config file and adjusting anything you see fit, click the "Burn/Program" button. Reminder, this is a one-time use button and there is no confirmation prompt. Any settings here are saved permanently to the IN100 so if you do change anything here, make sure it works before clicking this button.

Arduino Code

With just the config file loaded on the NanoBeacon, you can open up a scanner app and watch the acceleration data print out in hex but that isn't very human-readable. To convert this hex data to a serial print, we wrote a quick Arduino sketch that connects to a NanoBeacon board running the config file we just uploaded and then parses the hex data into a serial print to easily ready acceleration data from all three of the BMA400's axes.

Open the sketch file or copy the code below into a blank Arduino sketch. Select your board (in our case "ESP32 Dev Module") and Port and click the upload button.

language:c
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEEddystoneURL.h>
#include <BLEEddystoneTLM.h>
#include <BLEBeacon.h>

int scanTime = 1;
BLEScan *pBLEScan;

// This class is used for the onResult() callback function
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
  // This function is called each time a new BLE device is found during a scan
  void onResult(BLEAdvertisedDevice advertisedDevice)
  {
    // Some BLE devices don't have names, so we'll ignore the ones that don't
    if (advertisedDevice.haveName())
    {
      // Check if the name of this device matches our beacon
      const char* deviceName = advertisedDevice.getName().c_str();
      if(strncmp(deviceName, "BMA400_Data", strlen(deviceName)) == 0)
      {
        // This is our beacon! Print out the received signal strength
        Serial.printf("RSSI: %i\n", advertisedDevice.getRSSI());

        // Copy the manufacturer data into a buffer
        uint8_t manufacturerData[32];
        std::string manufacturerDataString = advertisedDevice.getManufacturerData();
        manufacturerDataString.copy((char*) manufacturerData, manufacturerDataString.length(), 0);

        // The first 2 bytes are the manufaturer ID, print those out
        uint16_t manufacturerID = (manufacturerData[0] << 8 ) | manufacturerData[1];
        Serial.printf("Manufacturer ID: %04X\n", manufacturerID);

        // The next byte is the battery voltage, units are 31.25mV/LSB
        uint16_t voltageRaw = manufacturerData[2];
        float voltage = voltageRaw * 0.03125;
        Serial.printf("Voltage: %.2f\n", voltage);

        // Last 6 bytes are the raw acceleration data for the x/y/z axes, as specified in the BMA400 datasheet
        int16_t xRaw = ((uint16_t) manufacturerData[4] << 8) | manufacturerData[3];
        int16_t yRaw = ((uint16_t) manufacturerData[6] << 8) | manufacturerData[5];
        int16_t zRaw = ((uint16_t) manufacturerData[8] << 8) | manufacturerData[7];

        // The raw values are 12-bit signed values, so we need to make sure negative values are correctly signed
        if(xRaw > 2047) xRaw -= 4096;
        if(yRaw > 2047) yRaw -= 4096;
        if(zRaw > 2047) zRaw -= 4096;

        // Convert the raw values to acceleration in g's
        // BMA400 defaults to +/- 4g over the whole 12-bit range
        float xAcc = xRaw * 4.0 / pow(2, 11);
        float yAcc = yRaw * 4.0 / pow(2, 11);
        float zAcc = zRaw * 4.0 / pow(2, 11);

        // Now print out the x/y/z acceleration values
        Serial.printf("X: %.2f Y: %.2f Z: %.2f\n\n", xAcc, yAcc, zAcc);

        // Now that we've found our beacon and logged everything, we can stop the scan
        pBLEScan->stop();
      }
    }
  }
};

void setup()
{
  // Set up serial
  Serial.begin(115200);
  Serial.println("BLE scan sketch begin!");

  // Create new BLE scan object
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();

  // Set callback for when new devices are found in the scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());

  // Enable active scanning. It uses more power, but is faster
  pBLEScan->setActiveScan(true);

  // Set the scan interval and window in milliseconds
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
}

void loop()
{
  // Start new scan. This blocks until finished
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);

  // Scan finished, delete results to release memory
  pBLEScan->clearResults();
}

After uploading, open the serial monitor with the baud set to 115200. The code will start to scan for the matching NanoBeacon device (BMA400_Data) and when it succeeds, prints out the data sent by the beacon including Manufacturer ID, voltage measured on Vcc and the acceleration data of the x/y/z axes.

Additional Config Tests

For those who want to go beyond this example or prefer to send I2C data from different devices, InPlay has a growing list of other config tests for other sensors, like the BME280 atmospheric sensor, available from the GitHub repository below: