MPU-9250 Teensy Library

I ran the scan and it only found 0x68, so I'm going to go with a failure of some sort in the chip. I'll wire up another board and report back. Thanks again for the assistance.

Edit: Interesting, the new board I am having the same problem with. I read something about pin 1 on the 9250 needing to be connected to VDDIO and there was a breakout board that didn't make this connection, but I haven't seen any complaints about the Sparkfun boards. Maybe I'll contact them and see if anyone else has had this issue.

That is odd. The Sparkfun documentation mentions that VDDIO is jumpered to VDD, so that should be fine. You might want to try sending 0x80 to register 0x6B in order to clear the MPU-9250 registers first, then set register 0x37 to enable bypass mode, then cycle the power (you'll need some long delays in between these steps). That way you make sure that it isn't some MPU-9250 setting that is preventing the bypass from working.
 
That is odd. The Sparkfun documentation mentions that VDDIO is jumpered to VDD, so that should be fine. You might want to try sending 0x80 to register 0x6B in order to clear the MPU-9250 registers first, then set register 0x37 to enable bypass mode, then cycle the power (you'll need some long delays in between these steps). That way you make sure that it isn't some MPU-9250 setting that is preventing the bypass from working.

The reset resulted in no change.

The VDDIO issue I had read about on another board is that pin 1 on the 9250 needs to be connected to VDDIO (separately from the normal VDDIO pin), and one manufacturer didn't do this and it caused intermittent failure depending on whether or not the magnetometer reset correctly by chance. I don't think this is the case, though, since I can talk to the magnetometer directly on the aux I2C pins.

I've put in a support request with Invensense, but I don't anticipate every hearing anything back from them.

Thanks for the help, but I think at this point, I'll just use an external bypass (jumper both busses together).
 
Hi Brian, getting back into another project with a MPU9250 in SPI mode. I don't know if this was in the original code but what is the purpose of the initial register read and CS cycle in the readregisters method for SPI? I don't seem to need it--or I should say it seems to read OK when I exclude that part.

if(_useSPIHS){
SPI.beginTransaction(SPISettings(SPI_HS_CLOCK, MSBFIRST, SPI_MODE3));
}
else{
SPI.beginTransaction(SPISettings(SPI_LS_CLOCK, MSBFIRST, SPI_MODE3));
}
digitalWriteFast(_csPin,LOW); // select the MPU9250 chip

SPI.transfer(subAddress | SPI_READ); // specify the starting register address

digitalWriteFast(_csPin,HIGH); // deselect the MPU9250 chip

delayMicroseconds(1);
digitalWriteFast(_csPin,LOW); // select the MPU9250 chip

SPI.transfer(subAddress | SPI_READ); // specify the starting register address

for(uint8_t i = 0; i < count; i++){
dest = SPI.transfer(0x00); // read the data
}

digitalWriteFast(_csPin,HIGH); // deselect the MPU9250 chip
SPI.endTransaction(); // end the transaction



Thanks again for sharing your code.
 
Hi Brian, getting back into another project with a MPU9250 in SPI mode. I don't know if this was in the original code but what is the purpose of the initial register read and CS cycle in the readregisters method for SPI? I don't seem to need it--or I should say it seems to read OK when I exclude that part.



Thanks again for sharing your code.

That's a relatively recent addition. We had multiple, different sensors on the same SPI bus with the MPU-9250 and during de-bugging found that MPU-9250 data with the original code was always one frame old. This addition fixes that issue, so the data that you collect when calling something like getMotion10() is from the current frame. The performance impact is just a 1us increase in the time data collection takes.
 
Should I ask how you found that issue? :)

When you say multiple sensors on the same bus, was that multiple MPU-9250 or just a mix of devices, or both? Do you think it's an issue with a single MPU-9250 device on a dedicated bus?

Either way I'm glad I asked the question because I was thinking of putting 2+ MPU-9250 on a single bus to get extended precision in the lower ranges and still have the wider range data too.
 
Should I ask how you found that issue? :)

When you say multiple sensors on the same bus, was that multiple MPU-9250 or just a mix of devices, or both? Do you think it's an issue with a single MPU-9250 device on a dedicated bus?

Either way I'm glad I asked the question because I was thinking of putting 2+ MPU-9250 on a single bus to get extended precision in the lower ranges and still have the wider range data too.

It was a mix of devices, specifically a MPU-9250 and BME-280. We were using the MPU-9250 generated interrupt to drive a data acquisition function which was collecting data from both sensors. We found that we never got data from the MPU-9250 and when we started diving deep into the details, we discovered that even running the MPU-9250 by itself, that the initial frame of data was not valid.

This was never discovered running multiple MPU-9250's on the same bus. I think this is because the BME-280 ran at a different clock setting.

Let me be clear that, although the original code worked fine for the MPU-9250 running on its own or multiple MPU-9250's on the same SPI bus, the data was 1 frame delayed. For applications that are latency critical, this wouldn't be great, so I'm glad we found the bug and a fix for it. Especially that the performance impact isn't large.

Sounds like a neat application! I've thought of similar concepts and have seen it done with pressure transducers for measuring airspeed on aircraft.
 
... I was thinking of putting 2+ MPU-9250 on a single bus to get extended precision in the lower ranges and still have the wider range data too.

That caught my eye ... how do you plan to get that "extended precision"? thanks
 
That caught my eye ... how do you plan to get that "extended precision"? thanks

You get 16 bits of precision on the accelerometer and gyro. On the accelerometer for example, you can set the range to 2g, 4g or 8g. So if you're reading a 2g range with 16 bits the g/(2^bits-1) precision is going to be finer than reading a 8g range with 16 bits. If I set one device to 8g and one device to 2g I will get the full 8g range plus finer increments in the 2g range. Theoretically 4 times more precision in the lower range. I guess I'll find out when I start doing side-by-side comparisons.
 
Last edited:
ah I see. In my application I'm only reading around 0 - 1.2 g so 2g range is obvious choice. So sadly this idea has no advantage, but I see how it works for you.
 
FYI, I've updated this library to use the new SPIClass available in Teensyduino 1.37 and newer. The main difference is that SPI declaration can now indicate directly which SPI bus is used. Additionally the setMOSI, setMISO, and setSCK functions can be used to set the alternate pins.

For example, using SPI bus 0, the default pins, and pin 10 as the chip select, the object declaration can be simplified to:
Code:
MPU9250 IMU(10);

Using SPI bus 1 and switching to pin 20 for SCK would be:
Code:
MPU9250 IMU(10,&SPI1);
void setup() {
  SPI1.setSCK(20);
  IMU.begin(ACCEL_RANGE_8G,GYRO_RANGE_250DPS);
}

Best,
Brian
 
Wake on motion interrupt

Hi Fyod, I haven't had a need to implement the wake on interrupt yet. If there's a need for it, I may be able to roll it into the next library update.

Hi! I'm a novice here working on a project that requires the use of the Wake-On Motion interrupt from the MPU9250 wired via I2C to a Teensy LC. I'm using onehorse's SENtral Ultimate Sensor Fusion board and have found really very little resources on how to implement this. Did you ever get around to experimenting with it?
 
Hi! I'm a novice here working on a project that requires the use of the Wake-On Motion interrupt from the MPU9250 wired via I2C to a Teensy LC. I'm using onehorse's SENtral Ultimate Sensor Fusion board and have found really very little resources on how to implement this. Did you ever get around to experimenting with it?

I'll be doing a lot of work on the MPU-9250 library within the next couple weeks and will look into adding the wake on motion interrupt feature.

Brian
 
Some news on the MPU-9250 library. It's been updated and should work with non-Teensy devices. In addition to Teensy, I'm also testing the library with the Ladybug STM32 board. The library methods have changed to better encapsulate the data that the library is using, grab all of the required memory at declaration, and make its use more straightforward.

In addition to those changes, I've added Wake on Motion interrupt and FIFO capability. This is all documented in detail on GitHub along with examples.

I'll be working on adding calibration routines and filters in the coming weeks.
 
Nice, glad to see this. Using the onehorse MPU9250 hardware is good - and the examples worked - but were not 'pretty'. Looking forward to getting back to that - especially to work with your code and ladybug.
 
Some news on the MPU-9250 library. It's been updated and should work with non-Teensy devices. In addition to Teensy, I'm also testing the library with the Ladybug STM32 board. The library methods have changed to better encapsulate the data that the library is using, grab all of the required memory at declaration, and make its use more straightforward.

In addition to those changes, I've added Wake on Motion interrupt and FIFO capability. This is all documented in detail on GitHub along with examples.

I'll be working on adding calibration routines and filters in the coming weeks.

Yay to this!
 
Minor update. The MPU-9250 library now estimates the gyro biases during the begin function and removes them during sensor reading. Additionally, you can call estimateGyroBias() to estimate and use new gyro biases. There are also getGyroBiasX_rads, getGyroBiasY_rads, and getGyroBiasZ_rads functions for getting the current gyro biases in use. Finally, there are setGyroBiasX_rads, setGyroBiasY_rads, and setGyroBiasZ_rads functions for setting the gyro biases to the input value if you're estimating them from another source, such as the output from a kalman filter.

The gyro biases are not saved to the MPU-9250 registers. I made this decision based on my experience that gyro bias tends to need to be estimated every power cycle. But using the get and set functions, it would be easy to save the biases to Teensy EEPROM and load them during future uses of the library.
 
One more update, I've added methods to calibrate the accelerometer and magnetometer. Methods to get and set the estimated bias and scale factor for each axis have also been added, which should make it easy to store your accelerometer or magnetometer calibration data in EEPROM and use them during future uses of the library.

Please let me know if you end up with any questions or issues as you use the new functionality of the library.

Cheers!
Brian
 
Breakout Mods

Brian:

Thanks for the time put into this library. I wanted this functionality 3 years ago for a project and there was nothing worthwhile to start from for the hobbyist... so I shelved it.

I bought an inexpensive 9250 breakout board to revisit this functionality after finding this thread. https://www.amazon.com/gp/product/B01I1J0Z7Y/ref=oh_aui_detailpage_o03_s00?ie=UTF8&psc=1 which was $8.49 + prime when I bought it. If the link is busted in the future, google image search 'MPU9250' - blue board with MPU-92/65 or MPU-9250/6500 written on the edge, 10 pin interface, advertised for I2C interface only. Schematic will show 10K resistors on the outputs.

I'm not a master programmer or hardware designer, so there's a couple things in this thread and elsewhere on related pages that slowed me down when it came to making Teensy work with this type breakout. Definitely wasn't plug and play for my Teensy 3.6. You need to make a couple simple modification to make it work with Teensy or other 3.3V boards:

1) Bridge the solder jumper next to the voltage regulator to bypass the regulator and just push 3.3V straight into the board @ VCC.
2) Remove all the resistors. There are 5 SMD 10K resistors that need to go. 3 on the SDA end and 2 on the INT end. Clean up your solder pads afterwards to make sure nothing is jumped! These are all pull up or down resistors that might work for 5V integration, but did not work for me on 3.3V.

If you want to use the I2C, then you'll need to add 2 4.7K pull up resistors into your project. Easiest place is to add where the I2C interface is going into 18 & 19. Connect the resistors there and then to 3.3V for the pull up.

For SPI, just wire it direct using the chart in the library's readme. Nothing extra needed.

I ran examples Basic_I2C, Advanced_I2C, Basic_SPI, and added the interrupt wire and got Interrupt_SPI running as well with no other changes. I didn't try the other examples. I haven't integrated it in my project yet so I don't know if the data coming out is good, I just breadboarded this to see if I could get something that looks correct out of it. I get 10/-10-ish on the G readout when flipping it around so it looks like I'm on the right track.

Hopefully this helps someone else along the way.

DD
 
One more update, I've added methods to calibrate the accelerometer and magnetometer. Methods to get and set the estimated bias and scale factor for each axis have also been added, which should make it easy to store your accelerometer or magnetometer calibration data in EEPROM and use them during future uses of the library.

Please let me know if you end up with any questions or issues as you use the new functionality of the library.

Cheers!
Brian

Hi Brian

thanks for the new libraries and all the improvements you made this year.

Could you please spend a few words about the calibration process and what your routines expect me to do ? (CalibrateMPU9250)
 
Hi Brian

thanks for the new libraries and all the improvements you made this year.

Could you please spend a few words about the calibration process and what your routines expect me to do ? (CalibrateMPU9250)

Sure, I keep meaning to make a video of it, but haven't gotten around yet with the holidays.

First, the gyros are calibrated during the begin function. All that's needed for a good gyro calibration is that the IMU is stationary. If you would like to redo the calibration at any time, simply call calibrateGyro. Due to the nature of gyro errors and the way they are currently modeled (simply as a bias), the gyro should be calibrated every time the IMU is used, which is why it's included in the begin function.

The accelerometers only need to be calibrated once. The error model I'm currently using for the accelerometers is a bias and a scale factor. To calibrate them, call the calibrateAccel function 6 times, once for each orientation of the IMU (+X, -X, +Y, -Y, +Z, -Z) facing up. This is because we're using the gravity vector to calibrate the accelerometers. The IMU should be stationary when calibrateAccel is called. You can find an example here:
https://github.com/bolderflight/uNa...MPU9250/CalibrateMPU9250/CalibrateMPU9250.ino

You'll notice I'm using the terminal to tell me when to change the IMU orientation and have a delay before calling calibrateAccel so I have time to orient and get the IMU stationary before the calibration starts. Once you're done with the calibration, you'll want to get the calibration biases and scale factors with the get functions, store them in EEPROM, and then use the set functions to use them in the future.

Finally, the magnetometers only need to be calibrated when their magnetic or electrical environment changes. The error model I'm currently using is a bias and a scale factor. To calibrate them, call the calibrateMag function and slowly move the IMU in a figure 8. This is a good gif of the motion:
https://lh3.googleusercontent.com/e...zStQhhbs1FImcgOEmUYoeijg-tS4xNh6Kmd234n4=w350

You can also slowly flip IMU in each axis in each direction. We're using the Earth's magnetic field to calibrate the magnetometer and trying to show all 6 magnetometer axis the maximum and minimum magnetic field. The calibrateMag function returns when it gets enough data for a good calibration; although, it relies on you persistently exciting the IMU to try to show it new information. Once you're done with the calibration, you'll want to get the calibration biases and scale factors with the get functions, store them in EEPROM, and then use the set functions to use them in the future.
 
The accelerometers only need to be calibrated once. The error model I'm currently using for the accelerometers is a bias and a scale factor. To calibrate them, call the calibrateAccel function 6 times, once for each orientation of the IMU (+X, -X, +Y, -Y, +Z, -Z) facing up. This is because we're using the gravity vector to calibrate the accelerometers. The IMU should be stationary when calibrateAccel is called. You can find an example here:
https://github.com/bolderflight/uNa...MPU9250/CalibrateMPU9250/CalibrateMPU9250.ino

You'll notice I'm using the terminal to tell me when to change the IMU orientation and have a delay before calling calibrateAccel so I have time to orient and get the IMU stationary before the calibration starts. Once you're done with the calibration, you'll want to get the calibration biases and scale factors with the get functions, store them in EEPROM, and then use the set functions to use them in the future.

Hi Brian, of course I noticed the terminal messages. A couple of times telling me "switch". I coded a calibration routine for the 9250 as well - quite dumb with instructions how to position the sensor. I suspected in your calibration must be some magic that does the calibration without positioning the sensor. Have the impression just switching the light on and off does the trick. (please don't take my comment too serious).

By the way - why six times ? x-axis positive/negative etc ? I did three measurements - one for each axis, positive or negative did not matter.
 
Last edited:
You'll notice I'm using the terminal to tell me when to change the IMU orientation and have a delay before calling calibrateAccel so I have time to orient and get the IMU stationary before the calibration starts. Once you're done with the calibration, you'll want to get the calibration biases and scale factors with the get functions, store them in EEPROM, and then use the set functions to use them in the future.

Hi Brian,
One of the things that the AP Groundstation does for accel calibration is let you know what axis to do then does the switch. Was thinking about adding that to the switch prints just so I remember what axis is just did.

Prevous postings from Paul and Nox771 (creator of the alternative i2c library, i2c_t3.h) have said that the internal pull-ups for Teensy 3.x/LC are too weak to be usable in general.

What I found is that most of the reputable breakout boards have 4.7k resistors on the board for SDA/SCL pull ups. Would always check the schematic to see if you really need them. Also most of these boards allow for Vin of 5v but convert it to 3.3v first, they also have a separate pin for 3.3v. Like was 4.7k is good for most cases. Haven't run into a problem yet with these, but there may be cases.....

Mike
 
Back
Top