Using I2C to read the onboard IMU of the Nano33BLE without using the Arduino_LSM9DS1 library

Hi,

I am new in Arduino and need help with I2C.

I want to read the acceleration in the LSM9DS1 module from Arduino 33 BLE. This task is easy with the Arduino_LSM9DS1.h library but want to learn how Wire.h works properly. This is the last step of my objectives but I can't seem to get it running.

I converted the library in the last reply but I can't seem to get it working.

What on earth is that? Please go back and read the forum instructions and rework your post to include all the relevant information.

study the source code of the library ➜ https://github.com/arduino-libraries/Arduino_LSM9DS1/blob/master/src/LSM9DS1.cpp

You may be overthinking this…
Check the code size when you use the library…
Only the functions you call, or are needed by the library will be compiled - unless they are specifically forced by the linker.

School assignment?

No, but I need to learn how this works because I will use this extensively next semester.

I converted the library into this but I'm having trouble reading the values, I only need the third byte.

#include <Arduino.h>
#include <Wire.h>
#define LSM9DS1_ADDRESS            0x6b
#define LSM9DS1_CTRL_REG6_XL       0x20
#define LSM9DS1_CTRL_REG8          0x22
#define LSM9DS1_OUT_X_XL           0x28

void setup() {
  Serial.begin(9600);
  
  Wire.begin(LSM9DS1_ADDRESS);
  Wire.beginTransmission(LSM9DS1_CTRL_REG8);
  Wire.write(0x05);
  Wire.endTransmission();
  delay(10);
  Wire.beginTransmission(LSM9DS1_CTRL_REG6_XL); 
  Wire.write(0x70);             
  Wire.endTransmission();      

  Wire.beginTransmission(LSM9DS1_CTRL_REG6_XL);
  Wire.write(0x00);
  Wire.endTransmission();

}

Sorry, but that is not a clear problem description.

"doesn't run"???? Really???

Impossible. Please take some time to formulate an exact description.

I don't know how register addressing is done on that IC. You must know, so how about some insights from you? Is is strictly sequential, or can you address individual registers?

If it's sequential, just do two dummy reads...

I now understand how to read the third byte, thanks!
The code compiles and uploads it to Arduino, however, when I have the read function like this I can't open the Serial Monitor after uploading, it's my first time working with wire.h so I'm not exactly sure what is causing this. The port just disconnects and I have to reset the Arduino.

That will be more complicated. Have you definitely isolated that problem to your sketch?

Some Wire functions return error codes. Have you checked those, in code?

You can start by calling Wire.begin() in the setup() function and never call Wire.end().
You don't have to #include <Arduino.h> Please remove that.

Wire.begin() assigns certain pins to SDA and SCL and sets the hardware and software into I2C mode.
Wire.end() releases those pins and the software, so those pins can be used for something else. No one uses that, but it might be needed very rarely in some situations.

Can you start with a simple I2C sensor ? Do you have other I2C modules ?

Which Arduino board do you use and which sensor module ? I want to know if you have a 5V board with a 3.3V sensor without level shifter for SDA and SCL.

Manufacturer's page of the LSM9DS1 sensor: https://www.st.com/en/mems-and-sensors/lsm9ds1.html.

Have you tried to run a I2C Scanner sketch ? That is the first step. Can you show the output to us ?
The next step is reading the WHO_AM_I and the WHO_AM_I_M register. Can you show a sketch that does that ?

I wrote an alternative explanation of the functions of the Wire library, that might be helpful.

I'm having some trouble getting the error codes with arduino.

I only have an Arduino 33 BLE Sense, that's why I I'm using this example. The Module is the LSM9DS1 accelerometer in the Arduino platform. It runs fine using the library but not using this code.

Do I need to run the scanner even when the module is in the Arduino itself?
I ran one and it didn't found any device.

I am more familiar with the Wire functions but now I can't even run this code.

#include <Wire.h>
#define LSM9DS1_ADDRESS            0x6b
#define LSM9DS1_CTRL_REG8          0x22

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

  Wire.begin(LSM9DS1_ADDRESS);
  Wire.beginTransmission(LSM9DS1_CTRL_REG8);
  Wire.write(0x05);
  Wire.endTransmission();
}


void loop() {
  delay(10);
}

Is there something I'm missing? The port just disconnects after the upload.

Yes, you need to run a I2C Scanner sketch. Then you know that the I2C bus is working. Use the newest Arduino IDE with all the updates for the boards and the libraries.

I remember vaguely that someone had troubles with a Portenta and a I2C Scanner that did not see any I2C devices, it might have to do that the Arduino software layer is based on Mbed. Your Arduino Nano 33 BLE Sense also based on Mbed.

The port should not disconnect. Can you try with a other USB cable and other USB port ?
Can you buy a other Arduino board ? I don't know what is going on :woozy_face:

I had the legacy but updated and I have the same problem. I also changed port and cable.

The I2C scanner doesn't detect anything.

The I2C bus must be working because the Arduino_LSM9DS1.h.

That means the I2C Scanner conflict with Mbed has not been solved yet :sob:

Can you keep that working sketch and try to add your own code to that ? Try to read those WHO_AM_I and WHO_AM_I_M registers in the loop(). Show your new sketch.

But I can use the library just fine, doesn't that mean that the problem is in my current code and not with Mbed?

I can't keep that sketch and try to get the WHO_AM_I values because "readRegister(uint8_t, uint8_t)' is private within this context".

The code isn't printing anything? It is my interpretation and attempt to adapt the LSM9DS1.cpp from the same library.

LSM9DS1.cpp (6.0 KB)
LSM9DS1.h (2.3 KB)

@user9894581

If you want to know how the Wire.h Library works, then connect two Arduinos together using I2C bus and play with register level codes. You will discover soon that the Wire.h Library just contains the same codes in the High Level Format which hides all the Register Level details from the users.

If it does not work, go back to the example that did work, and use the functions of the Wire library to get the two WHO_AM_I and WHO_AM_I_M bytes.
Every time that it stops working, go back to the example. I think you are throwing away too much. For example this:

while (!Serial);
Serial.println("Started");

The function "readRegister()" is part of the LSM9DS1 library. I thought you wanted to use the Arduino Wire library ?

There are issues with reading the IMU with Wire.h which are discussed here
https://forum.arduino.cc/t/advice-i2c-communication-with-internal-sensors-ble-ble-sense/613815

You need to use Wire1 from TwoWire.

Indeed, at the very end of the library source LSM9DS1..cpp you can see these magic words.

#ifdef ARDUINO_ARDUINO_NANO33BLE
LSM9DS1Class IMU_LSM9DS1(Wire1);
#else
LSM9DS1Class IMU_LSM9DS1(Wire);
#endif

A scanner program is given here and as expected shows the two addresses 0x1e and 0x6b.

Here is a sketch which finds the two Who Am I values found in the library begin( ).

From 0x6b Who Am I = 68
From 0x1e Who Am I = 3D

#include <Wire.h>
extern TwoWire Wire1;

#define LSM9DS1_ADDRESS            0x6b
#define LSM9DS1_ADDRESS_M          0x1e

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started"); 
  Wire1.begin();
  delay(1000);
}
  

void loop() {
 
 Wire1.beginTransmission(LSM9DS1_ADDRESS);
 Wire1.write(0x0f);//Who am I register
 Wire1.endTransmission();
 Wire1.requestFrom(LSM9DS1_ADDRESS, 1);
 Serial.print("From 0x6b Who Am I = ");
 Serial.println(Wire1.read(),HEX);
 delay(2000);
 Wire1.beginTransmission(LSM9DS1_ADDRESS_M);
 Wire1.write(0x0f); //Who am I register
 Wire1.endTransmission();
 Wire1.requestFrom(LSM9DS1_ADDRESS_M, 1);
 Serial.print("From 0x1e Who Am I = ");
 Serial.println(Wire1.read(),HEX);
 delay(2000);
}
2 Likes

Thank you cattledog, for bringing some light in this.

Is this line really needed ? Can you try without ?

extern TwoWire Wire1;

The WIRE_HOWMANY is set to 2 here and that defines Wire1 here.