Author Topic: RFDuino using BLE and I2C IMU at the same time  (Read 127 times)

maxouille

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
RFDuino using BLE and I2C IMU at the same time
« on: October 23, 2017, 12:18:37 AM »
Hi !

I'm using an RFDuino in order to retrieve IMU MPU-9250 values and send them to an Android app via BLE.

Separately, BLE or I2C IMU works fine. However, when I merge the two codes, either the BLE nor the I2C IMU is starting. If BLE is using I2C, it should not be a problem because I2C can have multiple slaves at different addresses.

The IMU pins are GPIO5 and GPIO6 for the I2C. I even tried with differente I2C pin (2, 3 for example) and it is the same result.

Did anyone face this problem before ?

Here is the code I use for the RFDuino :

Code: [Select]
   #include <RFduinoBLE.h>
#include "MPU9250.h"

int connected = 0;
int PRECISION = 1000000;
float PRECISION_F = 1000000.0;

#define LazarusPin 31
#define mySerialDebug true  // Set to true to get mySerial output for debugging
#define NB_SENSORS 4
#define NB_IMUVAL 9

bool imuGo = true;
bool bleGo = true;

int intPin = 12;

// Pin definitions
MPU9250 myIMU;

char strbufIMU[NB_IMUVAL * (2 * 4 + 1 * 1) + (NB_IMUVAL - 1) * (1 * 1) ]; // (NB_IMUVAL * (2 * sizeof(float) + 1 * sizeof(char)) + (NB_VAL - 1) * (1 * 1)  [IMU val %d.%d + ; between]
char strbufFSR[NB_SENSORS * 4 + (NB_SENSORS - 1) * (1 * 1) ]; // NB_SENSORS * sizeof(float) [sensor values] + (NB_SENSORS - 1) * sizeof(float) ";"]

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

  if (imuGo) {
    setupIMU();
  }
  if (bleGo) {
    setupBLE();
  }

}

void setupBLE() {
  pinMode(LazarusPin, INPUT_PULLDOWN);
  NRF_GPIO->PIN_CNF[LazarusPin] =
    (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos);

  RFduinoBLE.advertisementData = "cube";
  RFduinoBLE.advertisementInterval = 1000; // ms
  RFduinoBLE.txPowerLevel = -20; // dBm, possible values: -20, -16, -12, -8, -4, 0, +4

  Serial.println("Waiting for connection...");
  RFduinoBLE.begin();
  RFduino_ULPDelay(INFINITE);
}

void setupIMU() {
  // Set up the interrupt pin, its set as active high, push-pull
  pinMode(intPin, INPUT);
  digitalWrite(intPin, LOW);

  Wire.begin();
  Serial.println("after begin wire");

  // Read the WHO_AM_I register, this is a good test of communication
  byte c = myIMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
  if (mySerialDebug) {
    Serial.print("MPU9250 "); Serial.print("I AM "); Serial.print(c, HEX);
    Serial.print(" I should be "); Serial.println(0x71, HEX);
  }
  if (c == 0x71) // WHO_AM_I should always be 0x68
  {
    if (mySerialDebug) {
      Serial.println("MPU9250 is online...");
    }

    // Start by performing self test and reporting values
    if (mySerialDebug) {
      myIMU.MPU9250SelfTest(myIMU.SelfTest);
      Serial.print("x-axis self test: acceleration trim within : ");
      Serial.print(myIMU.SelfTest[0], 1); Serial.println("% of factory value");
      Serial.print("y-axis self test: acceleration trim within : ");
      Serial.print(myIMU.SelfTest[1], 1); Serial.println("% of factory value");
      Serial.print("z-axis self test: acceleration trim within : ");
      Serial.print(myIMU.SelfTest[2], 1); Serial.println("% of factory value");
      Serial.print("x-axis self test: gyration trim within : ");
      Serial.print(myIMU.SelfTest[3], 1); Serial.println("% of factory value");
      Serial.print("y-axis self test: gyration trim within : ");
      Serial.print(myIMU.SelfTest[4], 1); Serial.println("% of factory value");
      Serial.print("z-axis self test: gyration trim within : ");
      Serial.print(myIMU.SelfTest[5], 1); Serial.println("% of factory value");
    }

    // Calibrate gyro and accelerometers, load biases in bias registers
    myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);

    myIMU.initMPU9250();
    // Initialize device for active mode read of acclerometer, gyroscope, and
    // temperature
    if (mySerialDebug) {
      Serial.println("MPU9250 initialized for active data mode....");
    }

    // Read the WHO_AM_I register of the magnetometer, this is a good test of
    // communication
    byte d = myIMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
    if (mySerialDebug) {
      Serial.print("AK8963 "); Serial.print("I AM "); Serial.print(d, HEX);
      Serial.print(" I should be "); Serial.println(0x48, HEX);
    }

    // Get magnetometer calibration from AK8963 ROM
    myIMU.initAK8963(myIMU.magCalibration);
    // Initialize device for active mode read of magnetometer
    if (mySerialDebug) {
      Serial.println("AK8963 initialized for active data mode....");
      //  mySerial.println("Calibration values: ");
      Serial.print("X-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[0], 2);
      Serial.print("Y-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[1], 2);
      Serial.print("Z-Axis sensitivity adjustment value ");
      Serial.println(myIMU.magCalibration[2], 2);
    }

  } // if (c == 0x71)
  else
  {
    if (mySerialDebug) {
      Serial.print("Could not connect to MPU9250: 0x");
      Serial.println(c, HEX);
    }
    while (1) ; // Loop forever if communication doesn't happen
  }
}

void RFduinoBLE_onConnect() {
  Serial.println("Connected");

  connected = 1;

  // Wake up from RFduino_ULPDelay()
  // http://forum.rfduino.com/index.php?topic=801.msg2682#msg2682
  NRF_GPIO->PIN_CNF[LazarusPin] =
    (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos);
  RFduino_pinWake(LazarusPin, HIGH);
  NRF_GPIO->PIN_CNF[LazarusPin] =
    (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos);
  Serial.println("after wake up");
}

void RFduinoBLE_onDisconnect() {
  Serial.println("Disconnected");
  connected = 0;
}

void loop() {
  if (connected != 0) {
    // If intPin goes high, all data registers have new data
    // On interrupt, check if data ready interrupt
    if (imuGo) {
      if (myIMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) {
        myIMU.readAccelData(myIMU.accelCount);  // Read the x/y/z adc values
        myIMU.getAres();

        // Now we'll calculate the accleration value into actual g's
        // This depends on scale being set
        myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes; // - accelBias[0];
        myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes; // - accelBias[1];
        myIMU.az = (float)myIMU.accelCount[2] * myIMU.aRes; // - accelBias[2];

        myIMU.readGyroData(myIMU.gyroCount);  // Read the x/y/z adc values
        myIMU.getGres();

        // Calculate the gyro value into actual degrees per second
        // This depends on scale being set
        myIMU.gx = (float)myIMU.gyroCount[0] * myIMU.gRes;
        myIMU.gy = (float)myIMU.gyroCount[1] * myIMU.gRes;
        myIMU.gz = (float)myIMU.gyroCount[2] * myIMU.gRes;

        myIMU.readMagData(myIMU.magCount);  // Read the x/y/z adc values
        myIMU.getMres();
        // User environmental x-axis correction in milliGauss, should be
        // automatically calculated
        myIMU.magbias[0] = +470.;
        // User environmental x-axis correction in milliGauss TODO axis??
        myIMU.magbias[1] = +120.;
        // User environmental x-axis correction in milliGauss
        myIMU.magbias[2] = +125.;

        // Calculate the magnetometer values in milliGauss
        // Include factory calibration per data sheet and user environmental
        // corrections
        // Get actual magnetometer value, this depends on scale being set
        myIMU.mx = (float)myIMU.magCount[0] * myIMU.mRes * myIMU.magCalibration[0] -
                   myIMU.magbias[0];
        myIMU.my = (float)myIMU.magCount[1] * myIMU.mRes * myIMU.magCalibration[1] -
                   myIMU.magbias[1];
        myIMU.mz = (float)myIMU.magCount[2] * myIMU.mRes * myIMU.magCalibration[2] -
                   myIMU.magbias[2];
      } // if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)

      // Must be called before updating quaternions!
      myIMU.updateTime();

      unsigned long t = millis();
      myIMU.delt_t = t - myIMU.count;
      if (myIMU.delt_t > 34) {
        float IMUtab[9] = {1000 * myIMU.ax, 1000 * myIMU.ay, 1000 * myIMU.az, myIMU.gx, myIMU.gy, myIMU.gz, myIMU.mx, myIMU.my, myIMU.mz};

        sprintf(strbufIMU, "%d.%d;%d.%d;%d.%d;%d.%d;%d.%d;%d.%d;%d.%d;%d.%d;%d.%d",
                (int) IMUtab[0], (int) (abs(IMUtab[0]) * PRECISION_F) % PRECISION,
                (int) IMUtab[1], (int) (abs(IMUtab[1]) * PRECISION_F) % PRECISION,
                (int) IMUtab[2], (int) (abs(IMUtab[2]) * PRECISION_F) % PRECISION,
                (int) IMUtab[3], (int) (abs(IMUtab[3]) * PRECISION_F) % PRECISION,
                (int) IMUtab[4], (int) (abs(IMUtab[4]) * PRECISION_F) % PRECISION,
                (int) IMUtab[5], (int) (abs(IMUtab[5]) * PRECISION_F) % PRECISION,
                (int) IMUtab[6], (int) (abs(IMUtab[6]) * PRECISION_F) % PRECISION,
                (int) IMUtab[7], (int) (abs(IMUtab[7]) * PRECISION_F) % PRECISION,
                (int) IMUtab[8], (int) (abs(IMUtab[8]) * PRECISION_F) % PRECISION);
        //Serial.println(strbufIMU);

        myIMU.count = millis();
      } // if (myIMU.delt_t > 500)
    } // if (imuGo)

    sprintf(strbufFSR, "%d;%d;%d;%d", analogRead(1), analogRead(2), analogRead(3), analogRead(4));
    //Serial.println(strbufFSR);

    char strbufALL[sizeof(strbufIMU) + 1 * 1 + sizeof(strbufFSR)]; // strbufIMU;strbufFSR (sendBatteryLevel ? 1 : 0) * 4
    sprintf(strbufALL, "%s;%s", strbufIMU, strbufFSR);
    Serial.println(strbufALL);

    if (bleGo) {
      Serial.println("Try send data ble");
      int numRetry = 10;
      while (!RFduinoBLE.send(strbufALL, sizeof(strbufALL)) && numRetry-- > 0) // all tx buffers in use (can't send - try again later)
        delay(100);
    }
  } else { // if (connected)
    Serial.println("Stopping loop");
    RFduino_resetPinWake(LazarusPin);
    RFduino_ULPDelay(INFINITE);
  }
}// end loop

EDIT :
 I updated my code. Seems more clear. The intPin is from the MPU9250 Library. It is the interrupt pin triggered in myIMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01.
Here is the reference of the MPU9250 library : https://github.com/sparkfun/SparkFun_MPU-9250_Breakout_Arduino_Library

Thx for the help !
« Last Edit: October 24, 2017, 01:44:39 AM by maxouille »

tolson

  • Global Moderator
  • *****
  • Posts: 870
  • Karma: +20/-0
    • View Profile
    • Thomas Olson Consulting
Re: RFDuino using BLE and I2C IMU at the same time
« Reply #1 on: October 23, 2017, 09:44:31 AM »
BLE doesn't use I2C at all. It is a software defined radio internal to the Nordic chip. Without getting much into your code, you are using pins that are not available on RFduino, like intPin 12. So some work needs to be done cleaning up.  Not sure why you are using Lazarus. And don't know which MPU9250.h include file is used.

maxouille

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: RFDuino using BLE and I2C IMU at the same time
« Reply #2 on: October 24, 2017, 01:44:59 AM »
I edited my code and provided more infos about the code :) Thx