Using BMI323 with I²C

I realized that after I posted my code. Therefor I wrote a second post that your code should work.

In the 3D world, 0x0000 is next to 0xFFFF, so 0 is next to 65535. The 0xFFFF is also -1 when it would be a signed value.
The range to both sides is also the same. The angle with 16383 is the same (but opposite) angle as 49152. That seems to be the range to deal with.

The code of the Bosch API has lots of structs and code for offsets, but most of the code does not really do much. The basic example shows the raw values.
However, I think those raw values in the example are signed 16 bits values. It uses this struct with signed value for the acceleration.

The datasheet is too long for me to completely understand.

1 Like

Dear @devpierrick

Do you have any progress?
I am starting my project exactly as you did (not all the components arrived so I haven't started yet), the discussion in this post is really helpful.

Hello,
No I don't have any progress because I considere it's working properly for my project :slight_smile:

Dear @devpierrick

I start working on Arduino Nano BLE with BMI323, however, my output data keeps the same even though I move the IMU.

I use the code in post #13, and it works but seems still have problems.
Would you mind sharing some experiences?

Best,
Lixing

What is you schematic ?

Thanks for your quick reply!

I have solved my previous problem, by setting the address to 0x69. For those who connect to VIN, Ground, SCL and SDA, the address is 0x69 not 0x68.

However, my project aimed to collect IMU data with a high sample rate (maybe the max of BMI323: 6400Hz). I use serial connection to my PC but it only achieves 800+Hz now (I have changed the sample rate setting).

From my previous experience, it is possible to access audio data at > 16000Hz, which means the remained problem should be software issue (I guess). Do you have any expertise in it?

I guess there are the following solutions:

  1. change to SPI?
  2. callback is used in PDM library, is it the bottleneck?

Since my question is not so correlated to the original post, I may create a new post later.

Best,
Lixing He

Ok, I'm glad to hear that you've solved your first problem!
Honestly, I don't know, so yes, make another post. :slight_smile:
Regards

I just turned around and found some problems.

Since BMI323 supports -2g/2g range for accelerometer, it is hard to believe that the data type is "uint16_t", I try with short instead, and the results are the following:

However, although the X and Y looks reasonable, the Z always keeps 0. Are you interested in using "short" instead of "uint16_t"?
I have attached my code below:

#include <Wire.h>

#define INC_ADDRESS 0x69
#define ACC_CONF  0x20  //Page 91
#define GYR_CONF  0x21  //Page 93
#define CMD       0x7E  //Page 65

short x, y, z;

void setup(void) {  
  Serial.begin(115200); 
  //Accelerometer
  Wire.begin();  
  Wire.setClock(400000);      // I2C Fast Mode (400kHz)  
  softReset();  
  /*
   * Acc_Conf P.91
   * mode:        0x7000  -> High
   * average:     0x0000  -> No
   * filtering:   0x0080  -> ODR/4
   * range:       0x0000  -> 2G
   * ODR:         0x000B  -> 800Hz
   * Total:       0x708B
   */
  writeRegister16(ACC_CONF,0x708C);//Setting accelerometer  
  /*
   * Gyr_Conf P.93
   * mode:        0x7000  -> High
   * average:     0x0000  -> No
   * filtering:   0x0080  -> ODR/4
   * range:       0x0000  -> 125kdps
   * ODR:         0x000B  -> 800Hz
   * Total:       0x708B
   */
  writeRegister16(GYR_CONF,0x708B);//Setting gyroscope    
}

void softReset(){  
  writeRegister16(CMD, 0xDEAF);
  delay(50);    
}

void loop() {

  if(readRegister16(0x02) == 0x00) {
    //Read ChipID   
    readAllAccel();             // read all accelerometer/gyroscope/temperature data     
    Serial.print(" \tx:");
    Serial.print(x);
    Serial.print(" \ty:");
    Serial.print(y);
    Serial.print(" \tz:");
    Serial.println(z);

  }
}

//Write data in 16 bits
void writeRegister16(uint16_t reg, uint16_t value) {
  Wire.beginTransmission(INC_ADDRESS);
  Wire.write(reg);
  //Low 
  Wire.write((uint16_t)value & 0xff);
  //High
  Wire.write((uint16_t)value >> 8);
  Wire.endTransmission();
}

//Read data in 16 bits
uint16_t readRegister16(uint8_t reg) {
  Wire.beginTransmission(INC_ADDRESS);
  Wire.write(reg);
  Wire.endTransmission(false);
  int n = Wire.requestFrom(INC_ADDRESS, 4);  
  uint16_t data[4];
  int i =0;
  while(Wire.available()){
    data[i] = Wire.read();
    i++;
  }  
  return (data[3]   | data[2] << 8);
}

//Read all axis
void readAllAccel() {
  Wire.beginTransmission(INC_ADDRESS);
  Wire.write(0x03);
  Wire.endTransmission();
  Wire.requestFrom(INC_ADDRESS, 6);
  short data[6];
  int i =0;
  while(Wire.available()){
    data[i] = Wire.read();
    i++;
  }

  //Offset = 2 because the 2 first bytes are dummy (useless)
  int offset = 2;  
  x =             (data[offset + 0]   | (short)data[offset + 1] << 8);  //0x03
  y =             (data[offset + 2]   | (short)data[offset + 3] << 8);  //0x04
  z =             (data[offset + 4]   | (short)data[offset + 5] << 8);  //0x05
}

Hi, I've tested your code and I had the same, Z frozen, but it's because you're not reading enough bytes, the 2 firsts are dummies, so you have to read 8 instead of 6 as follow :slight_smile:

  Wire.requestFrom(INC_ADDRESS, 8);
  short data[8];
  int i =0;
  while(Wire.available()){
    data[i] = Wire.read();
    i++;
  }

  //Offset = 2 because the 2 first bytes are dummy (useless)
  int offset = 2;  

And I don't see the problem to use short instead of int16_t, because it seems the same:
"int16_t is always, by definition an 16-bit signed value (−32,768 to +32,767),"
"A short is a 16-bit data-type. On all Arduinos (ATMega and ARM based) a short stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767"

Thanks for your help. It works.

Besides, I didn't realize that you have changed to int16_t, the last code posted is uint16_t. Seems the data reading is correct now.

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