MPU 9250 SPI - Error in wiring or code ?

Hi all,
In past 2 weeks I’m banging my head around, connecting MPU-9250 on SPI protocol to Arduino Due. No luck so far. I read all documentation from Invesenses. IMO in theory this code should work perfectly but I got only 0xFF value.
The wiring is straight forward using this connectors:

For CS pin I’m using pin 52. No pull-up resistors. Wires are standard 30cm long for prototyping.
I have two identical boards, like this one:

Both are operational and fully working over I2C. The thing is they have only two adresses over I2C but I want faster response rate and chaining more then 10 sensors together.

If some one will have answer to my problem I’ll be very thankful.

/************************************************************************/
// Use SPI interface to talk to MPU9250
// Due version
/************************************************************************/

#include <SPI.h>
#include <Wire.h>

/************************************************************************/

#define NCS_PIN   52
#define MISO_PIN  74
#define MOSI_PIN  75
#define SCK_PIN   76

/************************************************************************/

const int nCS = NCS_PIN;

/************************************************************************/

uint8_t SPI_read_register( uint8_t reg )
{
  digitalWrite( nCS, LOW);
  SPI.transfer( nCS, reg | 0x80, SPI_CONTINUE ); // reg | 0x80 to denote read
  uint8_t read_value = SPI.transfer( nCS, 0x00 ); // write 8-bits zero
  digitalWrite( nCS, HIGH);
  return read_value;
}

/************************************************************************/

void SPI_write_register( uint8_t reg, uint8_t value )
{
  digitalWrite( nCS, LOW);
  SPI.transfer( nCS, reg, SPI_CONTINUE );
  SPI.transfer( nCS, value );
  digitalWrite( nCS, HIGH);
}

/************************************************************************/

void setup()
{
  byte id;
  
  Serial.begin( 115200 );
  
  pinMode( NCS_PIN, OUTPUT );
  pinMode( MOSI_PIN, OUTPUT );
  pinMode( MISO_PIN, INPUT );
  pinMode( SCK_PIN, OUTPUT );

  SPI.begin( nCS );
  SPI.setDataMode( nCS, SPI_MODE0 );
  SPI.setBitOrder( nCS, MSBFIRST );
  SPI.setClockDivider( nCS, 84 ); // 1MHz
  digitalWrite(nCS, HIGH);
  delay( 100 );

  Serial.println( "mpu9250 spi" );

  // reset the device
  SPI_write_register( 0x6B, 0x80 );
  delay( 100 );

  // reset acc, gyro and temp
  SPI_write_register( 0x68, 0x07 );
  delay( 100 );

  // disable I2C protocol
  SPI_write_register( 0x6A, 0x10 );
  delay( 100 );


  if(SPI_read_register(0x75) == 0x71) {
      Serial.println("Good to GO");
    } else {
      Serial.println("No connection");
    }
  delay( 100 );
}

/************************************************************************/

void loop()
{
  uint8_t id = SPI_read_register( 0x75 );
  Serial.println( id );
  delay(1000);
}

/************************************************************************/

Your code wouldn't even compile for me. There's a missing file.

And based on your photos I'd guess that the problem is that your boards are sitting on a table without any wires connected to them.

Nope, pretty sure thay are connected :wink:
Sorry for code in first post.

/************************************************************************/
// Use SPI interface to talk to MPU9250
// Due version
/************************************************************************/

#include <SPI.h>
#include <Wire.h>

/************************************************************************/

#define NCS_PIN   52
#define MISO_PIN  74
#define MOSI_PIN  75
#define SCK_PIN   76

/************************************************************************/

const int nCS = NCS_PIN;

/************************************************************************/

uint8_t SPI_read_register( uint8_t reg )
{
  digitalWrite( nCS, LOW);
  SPI.transfer( nCS, reg | 0x80, SPI_CONTINUE ); // reg | 0x80 to denote read
  uint8_t read_value = SPI.transfer( nCS, 0x00 ); // write 8-bits zero
  digitalWrite( nCS, HIGH);
  return read_value;
}

/************************************************************************/

void SPI_write_register( uint8_t reg, uint8_t value )
{
  digitalWrite( nCS, LOW);
  SPI.transfer( nCS, reg, SPI_CONTINUE );
  SPI.transfer( nCS, value );
  digitalWrite( nCS, HIGH);
}

/************************************************************************/

void setup()
{
  byte id;
  
  Serial.begin( 115200 );
  
  pinMode( NCS_PIN, OUTPUT );
  pinMode( MOSI_PIN, OUTPUT );
  pinMode( MISO_PIN, INPUT );
  pinMode( SCK_PIN, OUTPUT );

  SPI.begin( nCS );
  SPI.setDataMode( nCS, SPI_MODE0 );
  SPI.setBitOrder( nCS, MSBFIRST );
  SPI.setClockDivider( nCS, 84 ); // 1MHz
  digitalWrite(nCS, HIGH);
  delay( 100 );

  Serial.println( "mpu9250 spi" );

  // reset the device
  SPI_write_register( 0x6B, 0x80 );
  delay( 100 );

  // reset acc, gyro and temp
  SPI_write_register( 0x68, 0x07 );
  delay( 100 );

  // disable I2C protocol
  SPI_write_register( 0x6A, 0x10 );
  delay( 100 );


  if(SPI_read_register(0x75) == 0x71) {
      Serial.println("Good to GO");
    } else {
      Serial.println("No connection");
    }
  delay( 100 );
}

/************************************************************************/

void loop()
{
  uint8_t id = SPI_read_register( 0x75 );
  Serial.println( id );
  delay(1000);
}

/************************************************************************/

Sorry about begin snarky. I can't actually compile your code as I don't have the Due core. :-) But I was hoping you'd show your wiring, either by diagram or photo. Maybe you made some silly mistake.

A quick look at the datasheet and I noticed this:

To prevent switching into I2C mode when using SPI, the I2C interface should be disabled by setting the I2C_IF_DIS configuration bit. Setting this bit should be performed immediately after waiting for the time specified by the "Start-Up Time for Register Read/Write" in Section 6.3.

But there is no Section 6.3 and no explanation of when exactly you're supposed to set this bit. How did you decide when to set it?

Same code for Nano v3.0:

/************************************************************************/
// Use SPI interface to talk to MPU9250
// Arduino Nano v3.0 version
/************************************************************************/

#include <SPI.h>
#include <Wire.h>

/************************************************************************/

#define NCS_PIN   10
#define MOSI_PIN  11
#define MISO_PIN  12
#define SCK_PIN   13

/************************************************************************/

const int NCS = NCS_PIN;

/************************************************************************/

uint8_t SPI_read_register( uint8_t reg )
{
  digitalWrite( NCS, LOW);
  SPI.transfer( reg | 0x80 ); // reg | 0x80 to denote read
  uint8_t read_value = SPI.transfer( 0x00 ); // write 8-bits zero
  digitalWrite( NCS, HIGH);
  return read_value;
}

/************************************************************************/

void SPI_write_register( uint8_t reg, uint8_t value )
{
  digitalWrite( NCS, LOW);
  SPI.transfer( reg );
  SPI.transfer( value );
  digitalWrite( NCS, HIGH);
}

/************************************************************************/

void setup()
{
  byte id;
  
  Serial.begin( 115200 );
  
  pinMode( NCS_PIN, OUTPUT );
  pinMode( MOSI_PIN, OUTPUT );
  pinMode( MISO_PIN, INPUT );
  pinMode( SCK_PIN, OUTPUT );

  SPI.begin( );
  SPI.setDataMode( SPI_MODE0 );
  SPI.setBitOrder( MSBFIRST );
  SPI.setClockDivider( 16 ); // 1MHz
  digitalWrite(NCS, HIGH);
  delay( 1000 );

  Serial.println( "MPU9250 SPI" );

  // reset the device
  SPI_write_register( 0x6B, 0x80 );
  delay( 100 );

  // disable I2C protocol
  SPI_write_register( 0x6A, 0x10 );
  delay( 100 );

  // reset acc, gyro and temp
  SPI_write_register( 0x68, 0x07 );
  delay( 100 );

  if(SPI_read_register(0x75) == 0x71) {
      Serial.println("Good to GO");
    } else {
      Serial.println("No connection");
    }
  delay( 100 );
}

/************************************************************************/

void loop()
{
  uint8_t id = SPI_read_register( 0x75 );
  Serial.println( id );
  delay(1000);
}

/************************************************************************/

Address 0x6A, bit 0x10 is I2C_IF_DIS. In many examples (invensense examples to), the I2C_IF_DIS are set right after reseting the IMU. In many cases I2C_IF_DIS is not present in code and people still reports working SPI communication.

similar to Due version:
Arduino Nano wiring photos

Well maybe that's not it. It's weird that the datasheet makes mention of it but then never goes any further. Also weird is that you ask if there might be an error in your wiring but never show it. If it's so trivial then why ask?

Looking at the datasheet again, the SPI timing diagram is for mode 1,1. But they never explicitly say what the mode is, so who knows.

Have you tried sending an email to the vendor?

Link to wiring are in post #4. No email to vendor yet, but now this is probably the best option.

According to the timing diagram on the datasheet, it is SPI mode 2. SCLK HIGH with LOW transitions and capturing on the rising edge.

Isn't that mode 3 (CPOL=1, CPOH=1) ?

Szorti: Link to wiring are in post #4.

Okay, have it your way.

jboyton: Isn't that mode 3 (CPOL=1, CPOH=1) ?

You are correct. It is mode 3. https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

Are the SPI_MODE0 and SPI_MODE3 are'nt the same ?

CPOL=0 & CPHA=0 -> data are captured on the clock's rising edge (low→high transition) and data is propagated on a falling edge (high→low clock transition).

CPOL=1 & CPHA=1 -> data are captured on clock's rising edge and data is propagated on a falling edge.

Either way this dosn't do anything. Problem is lying somewhere else.

Have you used the Due's SPI bus before? If you use the Due's style of SPI transfer, you don't have to mess with the CS pin.

uint8_t SPI_read_register( uint8_t reg )
{
  SPI.transfer( nCS, reg | 0x80, SPI_CONTINUE ); // reg | 0x80 to denote read
  uint8_t read_value = SPI.transfer( nCS, 0x00 ); // write 8-bits zero
  return read_value;
}

/************************************************************************/

void SPI_write_register( uint8_t reg, uint8_t value )
{
  SPI.transfer( nCS, reg, SPI_CONTINUE );
  SPI.transfer( nCS, value );
}

Also, my Due had problems if I set the CS pin as OUTPUT and HIGH, but I was using D10 as the CS. It did ok if I set it to HIGH only (not as an OUTPUT). I haven't tried D52.

I have successfully gotten the MPU-9250 working 100% via the SPI protocol. There is a little trick to it. Unfortunately for you, my code is wrote in the Propeller Spin language, but the same commands are required.

Once you push the initial setup values for the MPU-6050 (Accel & Gyro) and have valid data, the next step is to configure your first external sensor (AK8963). I set mine to operate on Slave0 but you can use any of Slave’s 0-4.

When you read x bytes, it is reading registers from the start point, so to get above 16 (F) you start at register you wish to begin, then read x registers (bytes). This is how you have to get the ASA values from the Fuse ROM.

For both sensors, the Read Mask is %1000_0000 and the Write Mask is %0000_0000.

You must set the Slave# Address register to Read/Write before completing the action.

Hopefully you can use this as a guide to get yours working.

SPI INIT CODE.txt (7.28 KB)

SPI_SPIN.txt (6.31 KB)

MPU Loop.txt (3.99 KB)

Hi Guys,
I am trying to communicate with mpu 9250 through spi. I am using due and I can read gyro and acc data just fine. but no luck with magnetometer. I cannot even read its fixed who am i reg. Since I am reading the acc & gyro data, I assume my connections should be okey (I am using 6 pin SPI in the middle of Due). I have been struggling with this issue for almost two weeks now. At this point, any help is really really appreciated. I have also attached the files I have been working on. basically I got a library for another chip and started to changing it.

AE_MPU9250.cpp (20 KB)

AE_MPU9250.h (19.3 KB)

MPU9250.ino (1.47 KB)

I would love if you can send me the wiring diagram / photo from the MPU to the Due.

I don't get the names on the MPU.

Thanks, Yossi

Hello,

i buy a 9255, but i use a 9250 sketch to access.
Here my sketch if it can help you:

regards
Thomas

Hello,

Has anyone had any luck getting MPU-9250s' magnetometer to work with SPI? I've followed @IllExtractors steps but I get absolutely nothing. I can't even read the the WhoAmI register.

Thanks.