0

I want to read the data from an IMU (MPU9250) periodically. To do that I use a ticker as shown in the following code:

#include <Ticker.h>
#include "MPU9250.h"

constexpr int SERIAL_BAUDRATE = 115200;
constexpr float SAMPLING_FREQUENCY = 1.0;

Ticker TimerIMU;
MPU9250 IMU(Wire, 0x68);

void readIMU()
{
    // read the sensor
  IMU.readSensor();
  // display the data
  Serial.print(IMU.getAccelX_mss(),6);
  Serial.print("\t");
  Serial.print(IMU.getAccelY_mss(),6);
  Serial.print("\t");
  Serial.print(IMU.getAccelZ_mss(),6);
  Serial.print("\t");
  Serial.print(IMU.getGyroX_rads(),6);
  Serial.print("\t");
  Serial.print(IMU.getGyroY_rads(),6);
  Serial.print("\t");
  Serial.println(IMU.getGyroZ_rads(),6);
}


void setup()
{
  // serial to display data
  Serial.begin(115200);
  while(!Serial) {}
  // start communication with IMU 
  int retVal = IMU.begin();
  if(retVal < 0)
    Serial.println("IMU initialization unsuccessful: check your wiring or try resetting power to the sensor.");
   // start ticker
  TimerIMU.attach(1.0 / SAMPLING_FREQUENCY, readIMU);
}

void loop()
{
}

This approach does not produce the expected results: the IMU returns always the same values. Putting the readIMU function in the main loop and commenting the Ticker works well. I use an ESP32-WROVER.

Where is my error? Any suggestion would be appreciated.

1 Answer 1

1

readIMU() is called by the library from an ISR (Interrupt Service Routine). While the ISR runs, other interrupts cannot be handled. The IMU sensor works over I2C, which relies on interrupts being serviced. So, when initiating the communication inside an ISR, the transmission can never be finished correctly, since the needed ISRs are not executed. At least the library doesn't seem to block in that case, so the code runs, but the values are never updated.

You should not do interrupt dependent things inside of an ISR. Instead you can define a global flag variable, which you set inside the ISR. Then in your main code you just constantly check this flag and execute the ISR dependent code, if the flag is set. After the execution you reset the flag.

The response time is dependent on the speed, that your loop runs in. But this shouldn't be a problem here, since you don't have any other code in loop() and your frequency is just 1Hz, so a delay of a few microseconds should not be relevant.


Note, that using Serial is also interrupt dependent. So writing or printing to Serial inside an ISR is also not very good. Though you can get away with it, when you make sure, that you never send more data, than the Serial buffer can hold, and that you leave enough time between the interrupts for the actual transmission. Inside an ISR the printing and writing statements will just fill the buffer. The data will then gets send in the background via interrupts.


Note, that doing this with a Ticker (aka via interrupts) is really not necessary. Instead you can execute the code directly in loop() in a non-blocking style via millis(). Have a look at the BlinkWithoutDelay example, that comes with the Arduino IDE. It demonstrates how to do timed things without blocking with delay calls.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.