kriswiner / MPU9250

Arduino sketches for MPU9250 9DoF with AHRS sensor fusion
1.03k stars 472 forks source link

MPU-9250 via SPI #62

Open ijunglee opened 8 years ago

ijunglee commented 8 years ago

Hello, I am developing the firmware for TI MSP430F5438A to control MPU-9250 via SPI. However, I found that the result which I received is so strange. This is the result of acceleration when I put the MPU-9250 on the table with Z-axis toward up: accpro But I think the result is (0, 0, 1)g The initial flow of MPU-9250 is as follows: initial The sequence of the parameters is {address of register, value to set the register, delay time in ms} The scale which I set to the MPU-9250 is : Accelerometer: +/- 4g Gyroscope: +/- 2000 dps Magnetometer: 14-bit

Is there any problem in the initial flow? Thanks in advance!

kriswiner commented 8 years ago

I am not quite sure why you are using the I2C_SLV registers for the AK8963C. Why not read it directly? Is this to get the mag data into the FIFO?

Anyway, I recommend you look at the raw register data coming out of the accel read. It is likely there is an integer type error or scale conversion error.

ijunglee commented 8 years ago

Thanks for your reply.

  1. I use I2C_SLV registers because the MCU reads/writes the magnetometer data via I2C. Does it mean I should let the AK8963C be one of the I2C device of MPU-9250? Furthermore, do you have any example of accessing AK8963C directly? (Arduino is OK.) Maybe I used the wrong method to accessing it. I think I am not using the FIFO to get the data.
  2. This is my scale conversion code in the software. accgyromag

I am not sure the calculation of magnetometer data. But I think the data conversion of accelerometer and gyroscope is correct. Would you please check it for me?

Thanks for your help in advance.

kriswiner commented 8 years ago

I have lots of sketches on github showing how to read the mag. The key is to place the MPU9250 in pass through mode by writing 0x22 to the INT_CFG register. Please take a look at the init function in one of my sketches.

-----Original Message----- From: ijunglee [mailto:notifications@github.com] Sent: May 10, 2016 9:07 PM To: kriswiner/MPU-9250 Cc: Kris Winer; Comment Subject: Re: [kriswiner/MPU-9250] MPU-9250 via SPI (#62)

Thanks for your reply.

  1. I use I2C_SLV registers because the MCU reads/writes the magnetometer data via I2C. Does it mean I should let the AK8963C be one of the I2C device of MPU-9250? Furthermore, do you have any example of accessing AK8963C directly? (Arduino is OK.) Maybe I used the wrong method to accessing it. I think I am not using the FIFO to get the data.
  2. This is my scale conversion code in the software. accgyromag https://cloud.githubusercontent.com/assets/12967717/15169541/c4372116-176e- 11e6-8235-10de7edaddb5.PNG

I am not sure the calculation of magnetometer data. But I think the data conversion of accelerometer and gyroscope is correct. Would you please check it for me?

Thanks for your help in advance.

You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/kriswiner/MPU-9250/issues/62#issuecomment-218356740 https://github.com/notifications/beacon/AGY1qmdnjjJGKZz8tvmVeYZ4Xu1fmwb8ks5 qAVX9gaJpZM4Ia1nC.gif

ijunglee commented 8 years ago

Thanks for your kindly help! I got the SPI initialization sequence from invensense. I set 0x22 to INT_CFG, and it finally works!! I found I was set to 0x30 before. When I set 0x30 to INT_CFG, magnetometer seems not so stable. I can get the mag value sometimes but sometimes not. Do you have any idea about this problem? This is my whole initialization: initial

And do you know the difference between Slave 0 and Slave 4? Should I really need to set Slave 4 when magnetometer initialization and Slave 0 for receiving the magnetometer values?

kriswiner commented 8 years ago

I don't know how to configure the MPU9250slave registers which is why I don't do it this way.

-----Original Message----- From: ijunglee [mailto:notifications@github.com] Sent: May 25, 2016 9:46 PM To: kriswiner/MPU-9250 Cc: Kris Winer; Comment Subject: Re: [kriswiner/MPU-9250] MPU-9250 via SPI (#62)

Thanks for your kindly help! I got the SPI initialization sequence from invensense. I set 0x22 to INT_CFG, and it finally works!! I found I was set to 0x30 before. When I set 0x30 to INT_CFG, magnetometer seems not so stable. I can get the mag value sometimes but sometimes not. Do you have any idea about this problem? This is my whole initialization: initial https://cloud.githubusercontent.com/assets/12967717/15563838/14906e8e-233f- 11e6-865d-3bd7f4fc9f8c.PNG

And do you know the difference between Slave 0 and Slave 4? Should I really need to set Slave 4 when magnetometer initialization and Slave 0 for receiving the magnetometer values?

You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/kriswiner/MPU-9250/issues/62#issuecomment-221776321 https://github.com/notifications/beacon/AGY1qtqh3rCQaEOpaOSfc3onTye8B3Yiks5 qFSV0gaJpZM4Ia1nC.gif

ijunglee commented 8 years ago

That's OK. Thanks for your reply.

And do you know why INT_CFG should be set to 0x22 instead of 0x30? (Follow invensense's SPI initialize sample code, it gave me 0x30.) This the description of INT_CFG. int_cfg

If I set to 0x30, does it mean the MPU9250 will clear the interrupt flag when any reading process occurs? This is why I can not get the magnetometer value while reading acc and gyro because the interrupt flag is clear. Is the INT_STATUS register only for I2C? I am not sure if I misunderstood it or not.

Thank you.

kriswiner commented 8 years ago

The important thing about INT_CFG is the pass-through mode. Unless you are using the slave registers of the MPU9250 and letting the MPU9250 manage the AK8963C you need to set the pass through mode to allow the host to talk directly to the AK8963C. This can only be done by setting 0x02 in the INT_CFG. I use 0x22 if I want to latch the interrupt and 0x12 if I want any read to clear the interrupt (which is better for a lot of applications).

-----Original Message----- From: ijunglee [mailto:notifications@github.com] Sent: May 25, 2016 10:18 PM To: kriswiner/MPU-9250 Cc: Kris Winer; Comment Subject: Re: [kriswiner/MPU-9250] MPU-9250 via SPI (#62)

That's OK. Thanks for your reply.

And do you know why INT_CFG should be set to 0x22 instead of 0x30? (Follow invensense's SPI initialize sample code, it gave me 0x30.) This the description of INT_CFG. int_cfg https://cloud.githubusercontent.com/assets/12967717/15564360/f50ec60a-2343- 11e6-8936-d16b897b947a.PNG

If I set to 0x30, does it mean the MPU9250 will clear the interrupt flag when any reading process occurs? This is why I can not get the magnetometer value while reading acc and gyro because the interrupt flag is clear. Is the INT_STATUS register only for I2C? I am not sure if I misunderstood it or not.

Thank you.

You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/kriswiner/MPU-9250/issues/62#issuecomment-221779910 https://github.com/notifications/beacon/AGY1qpK_zpWINeZKGWNqrXIzg6m0cRyDks5 qFSz9gaJpZM4Ia1nC.gif

ijunglee commented 8 years ago

Thanks for your reply. =) Another big question, I can successfully get one sensor's data now which includes acc, gyro and mag. I think the result is fine.

I would like to connect multiple MPU-9250 like the SPI master-slave connection in datasheet: spi

I connect 18 MPU-9250 via SPI. I think it just use the loop to run the same procedure of initialization 18 times like this: http://pastebin.com/ReZumsL9

However, I can get the Who am I ID of each MPU9250 (for acc and gyro), but I can not get the ID of magnetometer. I can not get the data of mag also. The data of acc and gyro from 18 MPU-9250 are fine.

Do you have any idea how to solve this? Thanks in advance.

kriswiner commented 8 years ago

I don't know. There might be a dwell time issue. Maybe if you increases the delay time for mag access. Mag access is via 400 kHz I2C while you are probably running the SPI at 10 MHz, so you might need a delay to allow reading of the mag.

-----Original Message----- From: ijunglee [mailto:notifications@github.com] Sent: May 30, 2016 7:11 AM To: kriswiner/MPU-9250 Cc: Kris Winer; Comment Subject: Re: [kriswiner/MPU-9250] MPU-9250 via SPI (#62)

Thanks for your reply. =) Another big question, I can successfully get one sensor's data now which includes acc, gyro and mag. I think the result is fine.

I would like to connect multiple MPU-9250 like the SPI master-slave connection in datasheet: spi https://cloud.githubusercontent.com/assets/12967717/15651320/5ee8f814-26b1- 11e6-9f8a-9aa725b94e2d.PNG

I connect 18 MPU-9250 via SPI. I think it just use the loop to run the same procedure of initialization 18 times like this: http://pastebin.com/ReZumsL9

However, I can get the Who am I ID of each MPU9250 (for acc and gyro), but I can not get the ID of magnetometer. I can not get the data of mag also. The data of acc and gyro from 18 MPU-9250 are fine.

Do you have any idea how to solve this? Thanks in advance.

You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU-9250/issues/62#issuecomment-222500796 , or mute the thread https://github.com/notifications/unsubscribe/AGY1qotZYahlOlVmikRuGHjYu6HUk- eDks5qGvAIgaJpZM4Ia1nC . https://github.com/notifications/beacon/AGY1qv1p1bZYXmixeRlQ6yFCENR3Hd2Aks5 qGvAIgaJpZM4Ia1nC.gif

MikeFair commented 7 years ago

While I'm sure you've already worked around this or discovered the answer; this is directly a result of using the I2C_BYPASS (INT_CFG 0x02) to access the mag; essentially there are 18 0x0C devices on that bus (one from each MPU) and they are all seeing the request.

While ADO changes the address of the MPU (0x68 vs 0x69), it doesn't alter the address of the MAG on that MPU (which remains 0x0C for all). The I2C bypass (INT_CFG 0x02) gives the host direct access to the MAG, as well as any other devices connected to the EDA/ECL pins of the MPU as one bus. By enabling the BYPASS on all 18 MPUs, all the mags (0x0C) have been connected to the same lines.

INT_CFG 0x30 (b00110000) means both latch the interrupt (keep high until cleared) and clear on any read (so reading anything will trigger a reset of the interrupt); and does not enable the I2C bypass.

When you configure and enable the Slaves, they will constantly put the data they read into the EXT_SENS_DATA registers (0x49-0x60). At least Slaves 0-3 do; Slave 4 is a different case for more immediate execution of one time transactions working with only one byte at a time.

If you're uncomfortable configuring the slaves, you can leave the bypass flag clear on all the MPUs and then enable it on just the one you are talking to at that time; then clear the bypass when you're done. Even easier is to continue with the approach of enabling SLV0 to poll the MAG for you; then the mag data for each MPU will be in its EXT_SENS_DATA registers (starting at 0x49).

Hope that helps.

massenssan commented 7 years ago

hello Dear, I would like to start to interface the MPU9250 via SPI with MSP430G2955, but I find it hard to start as I know nothing even though I have read the datasheet of MPU9250, register map and the user's guide. please any guidance how to set the registers and start receiving the data. thanks

kriswiner commented 7 years ago

https://github.com/kriswiner/MPU9250brianc118

On Sun, Jun 25, 2017 at 10:49 AM, massenssan notifications@github.com wrote:

hello Dear, I would like to start to interface the MPU9250 via SPI with MSP430G2955, but I find it hard to start as I know nothing even though I have read the datasheet of MPU9250, register map and the user's guide. please any guidance how to set the registers and start receiving the data. thanks

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-310917243, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qucYNxW2zVpQCs0As3AVoUEybJnxks5sHp2sgaJpZM4Ia1nC .

massenssan commented 7 years ago

thank you Sir.

massenssan commented 7 years ago

Dear Mr. Kris Winer, i went through your code but i don't find the main c code where i can see how do you call all the function of MPU9250.c. Please can you provide me that main file. best regards

burnsfisher commented 6 years ago

I just want to add something since I think that the above never quite hit on several issues. Perhaps this will save someone some time: 1) Yes, you can read the magnetometer even though you are using SPI. Kris Winer did not explicitly say that; at least at first he is talking about about I2C access. 2) However, despite using SPI to connect to the processor, you must set the bypass bit as Kris says. The documentation is HORRIBLE for this. It sure sounds like this is intended to pass your I2C command directly to the mag and external I2C bus, but it also apparently enables the internal I2C to the mag. 3) Yes, you have to read the mag data from the I2C_SLV registers if you are using SPI. 4) Finally (and this is slightly documented if you read every word) you must read 7 bytes, not just 6 from the mag registers. You must read STS2 in order to unlatch the mag registers; otherwise they are not updated.

kriswiner commented 6 years ago

Thanks Burns,

The reading of 7 bytes from the AK8963C is clear in the AK8963 documentation and applies to both I2C and SPI.

The hard part about SPI it seems to me is setting up the slave registers. But Brian Chen has a pretty good sketch that shows how to do this so for those who need or want to use SPI, there should be enough examples to get this to work. I personally always use I2C when it is available, certainly for the MPU9250.

And yes, the documentation sucks and the MPU9250 can be a very complicated device to use well. I have tried in my sketches to make it somewhat understandable. The MPU9250 is used by the tens of millions in cell phones and Invensense doesn't waste their time with small volume hobbyists and makers. Same as it ever was.

Thanks again for the input.

Kris

On Tue, Jun 12, 2018 at 8:55 AM, Burns Fisher notifications@github.com wrote:

I just want to add something since I think that the above never quite hit on several issues. Perhaps this will save someone some time:

  1. Yes, you can read the magnetometer even though you are using SPI. Kris Winer did not explicitly say that; at least at first he is talking about about I2C access.
  2. However, despite using SPI to connect to the processor, you must set the bypass bit as Kris says. The documentation is HORRIBLE for this. It sure sounds like this is intended to pass your I2C command directly to the mag and external I2C bus, but it also apparently enables the internal I2C to the mag.
  3. Yes, you have to read the mag data from the I2C_SLV registers if you are using SPI.
  4. Finally (and this is slightly documented if you read every word) you must read 7 bytes, not just 6 from the mag registers. You must read STS2 in order to unlatch the mag registers; otherwise they are not updated.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-396641786, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qruLZfM0XHrdPVccghHwcd5Tcr8zks5t7-SFgaJpZM4Ia1nC .

gregbreen commented 6 years ago

I have recently gotten SPI access going, including the mag self-test. This thread was very helpful, but I just want to comment on @burnsfisher 's statement:

However, despite using SPI to connect to the processor, you must set the bypass bit as Kris says. The documentation is HORRIBLE for this. It sure sounds like this is intended to pass your I2C command directly to the mag and external I2C bus, but it also apparently enables the internal I2C to the mag.

I haven't found this to be the case. I used Invensense's 6.12 Motion Driver source code, and minimally changed it to achieve my goals. Although that driver is intended for I2C, it's pretty easy to convert most of it to SPI. I did it like this:

static int i2c_write( unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char const *data )
{
    if( slave_addr == 0x0C )
    {
        // We use slave 4 because the Motion Library only uses slaves 0 and 1
        uint8_t byte;
        byte = slave_addr;
        spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_ADDR, &byte, 1 );

        for( uint8_t i = 0; i < length; i++ )
        {
            byte = reg_addr + i;
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_REG, &reg_addr, 1 );
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_DO, data, length );
            spi_read_register( SPI_DEV_MPU9250, I2C_SLV4_CTRL, &byte, 1 );
            byte |= (1 | 0x80);
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_CTRL, &byte, 1 );
            delay_ms(20);
        }
    }
    else
    {
        spi_write_register( SPI_DEV_MPU9250, reg_addr, (uint8_t *)data, length );
    }

    return 0;
}

And very similar for the i2c_read().

The compass parts of the Motion Drivers still needed a bit more massaging, but the main point is to never call mpu_set_bypass(1). Instead leave bypass off. So with an mpu_set_bypass(0) call, the bypass bit is NOT set in INT_PIN_CFG. Works just fine in my experience. YMMV.

siddarora7 commented 5 years ago

Greg,

I found your comment to be really helpful. I am also using Invensenses's 6.12 Motion driver driver code and like you I am using SPI as well.

However in your snippet above, why are you writing the entire data to the SLV4_REG every single time?

Shouldn't that line be more like - mpu9250_write(0, I2C_SLV4_DO, 1, data[i]); //0 cause you don;'t really need a Device addr

Also, Is it really worth using the DMP especially with SPI?

I am working on an STM32L4, will computing the quaternions and Euler angles using STM itself result in that noticeable difference in performance?

Thanks

kriswiner commented 5 years ago

You could try this https://github.com/kriswiner/MPU9250/tree/master/AK8963_as_slave and see, I use it with success on an STM32L4.

On Thu, Dec 6, 2018 at 10:08 AM Siddhartha Arora notifications@github.com wrote:

Greg,

I found your comment to be really helpful. I am also using Invensenses's 6.12 Motion driver driver code and like you I am using SPI as well.

However in your snippet above, why are you writing the entire data to the SLV4_REG every single time?

Shouldn't that line be more like - mpu9250_write(0, I2C_SLV4_DO, 1, data[i]); //0 cause you don;'t really need a Device addr

Also, Is it really worth using the DMP especially with SPI?

I am working on an STM32L4, will computing the quaternions and Euler angles using STM itself result in that noticeable difference in performance?

Thanks

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-444971166, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qkTeKm64B7Y8n0vDyB9BFAuPQJDqks5u2V0NgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

Thanks, I'll have a look at that.

gregbreen commented 5 years ago

Hi @siddarora7 .

However in your snippet above, why are you writing the entire data to the SLV4_REG every single time?

It's a screw up. Actually I do want to write to that register on every iteration of the loop, but the register value should be incrementing. Also, the write to D0 needs to be a single byte. The only reason my code has worked is because the Motion Driver library only ever writes single bytes to the magnetometer. My function is trying to support writing multiple bytes to contiguous registers.

Furthermore the read-modify-write of the CTRL register is a vestige of when I was using a different slave (0 I think). Not necessary for slave 4. I just changed the function to this, and it works:

static int i2c_write( unsigned char slave_addr, unsigned char reg_addr, unsigned char length, unsigned char const *data )
{
    if( slave_addr == 0x0C )
    {
        // We use slave 4 because the Motion Library only uses slaves 0 and 1
        uint8_t byte;
        byte = slave_addr;
        spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_ADDR, &byte, 1 );

        for( uint8_t i = 0; i < length; i++ )
        {
            byte = reg_addr + i;
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_REG, &byte, 1 );
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_DO, &(data[i]), 1 );
            byte = 0x80;
            spi_write_register( SPI_DEV_MPU9250, I2C_SLV4_CTRL, &byte, 1 );
            delay_ms(20);
        }
    }
    else
    {
        spi_write_register( SPI_DEV_MPU9250, reg_addr, (uint8_t *)data, length );
    }

    return 0;
}

Also, Is it really worth using the DMP especially with SPI?

Depends what you want to do. In my case, I needed a step counter, and the DMP does that with no intervention from the micro. Also accumulates walk time, and a few other things.

Obviously the DMP can reduce the work your MCU does, but I have never actually measured the difference.

siddarora7 commented 5 years ago

Greg,

Thank you for your help. I was away from the project for some time. I am able to talk to the compass now. However, for some reason it is pretty weird.

I do a check for AK8963 WHOAMI at the start of my code. I have noticed that only on a power reset to my board I can get a valid 0x48 from the WHOAMI and then get the raw data(which has it's own issues). But when I just re-program the board through ST-LInk 2, I either get a 0x00 or 0xFF.

Note- Talking to Accel and Gyro works fine regardless.

I did email tech support but so far haven't heard from them.

Do you have any thoughts regarding this?

Thanks again.

BR, Sidd

kriswiner commented 5 years ago

You have to enable passthrough mode to access the AK8963C. if passthrough mode is not enabled (as it is not on power on) you won;t be able to talk with the AK8963C. Just that simple.

On Mon, Dec 17, 2018 at 9:44 AM Siddhartha Arora notifications@github.com wrote:

Greg,

Thank you for your help. I was away from the project for some time. I am able to talk to the compass now. However, for some reason it is pretty weird.

I do a check for AK8963 WHOAMI at the start of my code. I have noticed that only on a power reset to my board I can get a valid 0x48 from the WHOAMI and then get the raw data(which has it's own issues). But when I just re-program the board through ST-LInk 2, I either get a 0x00 or 0xFF.

Note- Talking to Accel and Gyro works fine regardless.

I did email tech support but so far haven't heard from them.

Do you have any thoughts regarding this?

Thanks again.

BR, Sidd

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447933535, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qjyq3CB3gml-yxPPNpJ6VgaQLAxmks5u59ffgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

I am sorry I should have mentioned before but I am using SPI.

I am assuming that pass through does not work with SPI?

kriswiner commented 5 years ago

Why not?

On Mon, Dec 17, 2018 at 10:26 AM Siddhartha Arora notifications@github.com wrote:

I am sorry I should have mentioned before but I am using SPI.

I am assuming that pass through does not work with SPI?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447947632, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qj1DLvnXe3jgWFn7z-6Ucf44l9dGks5u5-HCgaJpZM4Ia1nC .

kriswiner commented 5 years ago

It's true this is an I2C bus passthrough. Are you letting the MPU9250 manage the AK8963C as a slave?

On Mon, Dec 17, 2018 at 10:27 AM Tlera Corporation tleracorp@gmail.com wrote:

Why not?

On Mon, Dec 17, 2018 at 10:26 AM Siddhartha Arora < notifications@github.com> wrote:

I am sorry I should have mentioned before but I am using SPI.

I am assuming that pass through does not work with SPI?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447947632, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qj1DLvnXe3jgWFn7z-6Ucf44l9dGks5u5-HCgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

Yes I am. Do I need to configure CTRL1 and CTRL 2 registers on Ak8963 just to read WHOAMI?

kriswiner commented 5 years ago

No, this should work with no trouble. Maybe you need some delays?

On Mon, Dec 17, 2018 at 10:30 AM Siddhartha Arora notifications@github.com wrote:

Yes I am. Do I need to configure CTRL1 and CTRL 2 registers on Ak8963 just to read WHOAMI?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447949025, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qv4HJFjVpalM7DT-yc4Yn46fDfm3ks5u5-K7gaJpZM4Ia1nC .

siddarora7 commented 5 years ago

This is what I am doing : Register addresses are in Decimal

uint8_t mpu9250_write(uint8_t DevAddr, uint8_t address, uint16_t length, uint8_t *data)

uint8_t t = 0x80;
mpu9250_write(0, PWR_MGMT, 1, &t);              //Pwr MGMT reset
delayUS_DWT(100);

t = 0x00;
mpu9250_write(0, PWR_MGMT, 1, &t);              //Auto select clock source
delayUS_DWT(100);

t = 0x30;
mpu9250_write(0, USER_CTRL, 1, &t);         //Enable 12C master mode
delayUS_DWT(100);

t = 0x00;
mpu9250_write(0, I2C_MST_CTRL, 1, &t);          //I2c Configure multi master
delayUS_DWT(100);

t = 0x00;
mpu9250_write(0, I2C_SLV0_CTRL, 1, &t);         //Disable slave controller
delayMS_DWT(100);

t = 0x0C | 0x80;
mpu9250_write(0x00, I2C_SLV0_ADDR, 1, &t);
delayMS_DWT(100);

t = 0x00;
mpu9250_write(0x00, I2C_SLV0_REG, 1, &t);
delayMS_DWT(100);

t = 0x81;
mpu9250_write(0x00, I2C_SLV0_CTRL, 1, &t);
delayMS_DWT(100);

mpu9250_read(0, EXT_SENS_DATA_00, 1, &pls);

I am pretty sure I am making a stupid error in this. But I can't seem to find it. I have tried various iterations of this.

Thanks

kriswiner commented 5 years ago

This is how I initialize the MPU9250 for master I2C mode:

void initMPU9250() { ... (some MPU9250 specific initialization calls)

writeByte(MPU9250_ADDRESS, USER_CTRL, 0x20); // Enable I2C Master mode writeByte(MPU9250_ADDRESS, I2C_MST_CTRL, 0x1D); // I2C configuration STOP after each transaction, master I2C bus at 400 KHz writeByte(MPU9250_ADDRESS, I2C_MST_DELAY_CTRL, 0x81); // Use blocking data retreival and enable delay for mag sample rate mismatch writeByte(MPU9250_ADDRESS, I2C_SLV4_CTRL, 0x01); // Delay mag data retrieval to once every other accel/gyro data sample }

Then after this MPU9250 init function is called I use this function to get the WHO_AM_I from the AK8963C and it works just fine:

uint8_t MPU9250::getAK8963CID() { // uint8_t c = readByte(AK8963_ADDRESS, WHO_AM_I_AK8963); // Read WHO_AM_I register for MPU-9250 writeByte(MPU9250_ADDRESS, USER_CTRL, 0x20); // Enable I2C Master mode writeByte(MPU9250_ADDRESS, I2C_MST_CTRL, 0x0D); // I2C configuration multi-master I2C 400KHz

writeByte(MPU9250_ADDRESS, I2C_SLV0_ADDR, AK8963_ADDRESS | 0x80); // Set the I2C slave address of AK8963 and set for read. writeByte(MPU9250_ADDRESS, I2C_SLV0_REG, WHO_AM_I_AK8963); // I2C slave 0 register address from where to begin data transfer writeByte(MPU9250_ADDRESS, I2C_SLV0_CTRL, 0x81); // Enable I2C and transfer 1 byte delay(10); uint8_t c = readByte(MPU9250_ADDRESS, EXT_SENS_DATA_00); // Read the WHO_AM_I byte return c; }

Here https://github.com/kriswiner/MPU9250/tree/master/AK8963_as_slave is the repo. of course, I am using I2C in the read/write functions but this all should work just as well when using SPI.

On Mon, Dec 17, 2018 at 10:42 AM Siddhartha Arora notifications@github.com wrote:

This is what I am doing : Register addresses are in Decimal

uint8_t mpu9250_write(uint8_t DevAddr, uint8_t address, uint16_t length, uint8_t *data)

`uint8_t t = 0x80; mpu9250_write(0, PWR_MGMT, 1, &t); //Pwr MGMT reset delayUS_DWT(100);

t = 0x00; mpu9250_write(0, PWR_MGMT, 1, &t); //Auto select clock source delayUS_DWT(100);

t = 0x30; mpu9250_write(0, USER_CTRL, 1, &t); //Enable 12C master mode delayUS_DWT(100);

t = 0x00; mpu9250_write(0, I2C_MST_CTRL, 1, &t); //I2c Configure multi master delayUS_DWT(100);

t = 0x00; mpu9250_write(0, I2C_SLV0_CTRL, 1, &t); //Disable slave controller delayMS_DWT(100);

t = 0x0C | 0x80; mpu9250_write(0x00, I2C_SLV0_ADDR, 1, &t); delayMS_DWT(100);

t = 0x00; mpu9250_write(0x00, I2C_SLV0_REG, 1, &t); delayMS_DWT(100);

t = 0x81; mpu9250_write(0x00, I2C_SLV0_CTRL, 1, &t); delayMS_DWT(100);

mpu9250_read(0, EXT_SENS_DATA_00, 1, &pls); `

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447953321, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qmpjwH62KqX1Z3O1M66fvjPZ0Ojcks5u5-WhgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

Let me check on this.

I have a quick question though. In writeByte(MPU9250_ADDRESS, I2C_SLV4_CTRL, 0x01);

Why are you enabling SLV4?

Are you just using SLV0 for WHOAMI and using SLV4 for data?

kriswiner commented 5 years ago

This sets the decimation for the mag read. The mag will be read every time the accel is read unless you se the decimation. So at 200 Hz accel sample rate I want to read the mag only every other time, i.e., at 100 Hz.

On Mon, Dec 17, 2018 at 11:09 AM Siddhartha Arora notifications@github.com wrote:

Let me check on this.

I have a quick question though. In writeByte(MPU9250_ADDRESS, I2C_SLV4_CTRL, 0x01);

Why are you enabling SLV4?

Are you just using SLV0 for WHOAMI and using SLV4 for data?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447962131, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qqQBlIwD0CwR2g02HhjHTm7DsgJzks5u5-vPgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

Okay.

So I tried porting in your configs into mine but it's still the same issue. I tried a different board as well.

Any other suggestions?

kriswiner commented 5 years ago

Try I2C?

On Mon, Dec 17, 2018 at 11:21 AM Siddhartha Arora notifications@github.com wrote:

Okay.

So I tried porting in your configs into mine but it's still the same issue. I tried a different board as well.

Any other suggestions?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447965938, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qgAkUSBoYiTFsgtInG9ZfLSG6kUeks5u5-6jgaJpZM4Ia1nC .

siddarora7 commented 5 years ago

:). I am left with that choice only. I will have to rework my board though.

Anyhow, Thanks for your help.

I'll post if here If I get a positive update with SPI.

kriswiner commented 5 years ago

Not sure why SPI wouldn't work just as well. Anyway I know I2C works...

On Mon, Dec 17, 2018 at 12:16 PM Siddhartha Arora notifications@github.com wrote:

:). I am left with that choice only. I will have to rework my board though.

Anyhow, Thanks for your help.

I'll post if here If I get a positive update with SPI.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/62#issuecomment-447983667, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1ql94sR8SqL1OU0hKiUJmyjC-YmBcks5u5_uUgaJpZM4Ia1nC .

gregbreen commented 5 years ago

I do a check for AK8963 WHOAMI at the start of my code. I have noticed that only on a power reset to my board I can get a valid 0x48 from the WHOAMI and then get the raw data(which has it's own issues). But when I just re-program the board through ST-LInk 2, I either get a 0x00 or 0xFF.

Note- Talking to Accel and Gyro works fine regardless.

I did email tech support but so far haven't heard from them.

Do you have any thoughts regarding this?

Are you still using the motion sense drivers? I ask because I see some custom code from you in this thread. If you are, I presume you are calling mpu_init() in every reset.

Per my original comment "The compass parts of the Motion Drivers still needed a bit more massaging". Here's my setup_compass() function to get it working with SPI. One modification is to reset the magnetometer every time. This is likely what you need.

See the SPI conditional compilation markers below. I defined SPI in my port.h file.

static int setup_compass(void)
{
    unsigned char data[4], akm_addr;

#ifdef SPI
    // For SPI, we don't want bypass mode - compass is a slave I2C device
    mpu_set_bypass(0);
#else
    mpu_set_bypass(1);
#endif

    /* Find compass. Possible addresses range from 0x0C to 0x0F. */
    for (akm_addr = 0x0C; akm_addr <= 0x0F; akm_addr++) {
        int result;
        result = i2c_read(akm_addr, AKM_REG_WHOAMI, 1, data);
        if (!result && (data[0] == AKM_WHOAMI))
            break;
    }

#ifdef SPI
    // For SPI, we know it's always 0x0C, so enforce it
    if (akm_addr != 0x0C) {
#else
    if (akm_addr > 0x0F) {
#endif
        /* TODO: Handle this case in all compass-related functions. */
        log_e("Compass not found.\n");
        return -1;
    }

    st.chip_cfg.compass_addr = akm_addr;

#ifdef SPI
    // Reset the magnetometer on every startup, to ensure a clean slate
    data[0] = 1;
    if (i2c_write(st.chip_cfg.compass_addr, AKM_REG_CNTL2, 1, data))
        return -1;
    delay_ms(1);
#endif

    data[0] = AKM_POWER_DOWN;
    if (i2c_write(st.chip_cfg.compass_addr, AKM_REG_CNTL, 1, data))
        return -1;
    delay_ms(1);

    data[0] = AKM_FUSE_ROM_ACCESS;
    if (i2c_write(st.chip_cfg.compass_addr, AKM_REG_CNTL, 1, data))
        return -1;
    delay_ms(1);

    /* Get sensitivity adjustment data from fuse ROM. */
    if (i2c_read(st.chip_cfg.compass_addr, AKM_REG_ASAX, 3, data))
        return -1;
    st.chip_cfg.mag_sens_adj[0] = (long)data[0] + 128;
    st.chip_cfg.mag_sens_adj[1] = (long)data[1] + 128;
    st.chip_cfg.mag_sens_adj[2] = (long)data[2] + 128;

    data[0] = AKM_POWER_DOWN;
    if (i2c_write(st.chip_cfg.compass_addr, AKM_REG_CNTL, 1, data))
        return -1;
    delay_ms(1);

#ifndef SPI
    // For SPI, nothing more to do here - we are already not in bypass
    mpu_set_bypass(0);
#endif

    /* Set up master mode, master clock, and ES bit. */
    data[0] = 0x40;
    if (i2c_write(st.hw->addr, st.reg->i2c_mst, 1, data))
        return -1;

    /* Slave 0 reads from AKM data registers. */
    data[0] = BIT_I2C_READ | st.chip_cfg.compass_addr;
    if (i2c_write(st.hw->addr, st.reg->s0_addr, 1, data))
        return -1;

    /* Compass reads start at this register. */
    data[0] = AKM_REG_ST1;
    if (i2c_write(st.hw->addr, st.reg->s0_reg, 1, data))
        return -1;

    /* Enable slave 0, 8-byte reads. */
    data[0] = BIT_SLAVE_EN | 8;
    if (i2c_write(st.hw->addr, st.reg->s0_ctrl, 1, data))
        return -1;

    /* Slave 1 changes AKM measurement mode. */
    data[0] = st.chip_cfg.compass_addr;
    if (i2c_write(st.hw->addr, st.reg->s1_addr, 1, data))
        return -1;

    /* AKM measurement mode register. */
    data[0] = AKM_REG_CNTL;
    if (i2c_write(st.hw->addr, st.reg->s1_reg, 1, data))
        return -1;

    /* Enable slave 1, 1-byte writes. */
    data[0] = BIT_SLAVE_EN | 1;
    if (i2c_write(st.hw->addr, st.reg->s1_ctrl, 1, data))
        return -1;

    /* Set slave 1 data. */
    data[0] = AKM_SINGLE_MEASUREMENT;
    if (i2c_write(st.hw->addr, st.reg->s1_do, 1, data))
        return -1;

    /* Trigger slave 0 and slave 1 actions at each sample. */
    data[0] = 0x03;
    if (i2c_write(st.hw->addr, st.reg->i2c_delay_ctrl, 1, data))
        return -1;

#ifdef MPU9150
    /* For the MPU9150, the auxiliary I2C bus needs to be set to VDD. */
    data[0] = BIT_I2C_MST_VDDIO;
    if (i2c_write(st.hw->addr, st.reg->yg_offs_tc, 1, data))
        return -1;
#endif

    return 0;
}

If you want to get self-test working, I made some similar changes there that I can share. Unfortunately the code is in a private repo, so I can give you only these little samples.

siddarora7 commented 5 years ago

Hi Greg,

So I was using the motion driver code initially to interface with DMP, but have kept that aside for the moment.

But regardless my issue still persists, I made changes according to your code and still it doesn't work.

I am yet to hear from Invensense, I am assuming that the lack in tech support is because they discontinued this chip.

I think it's the chip itself, maybe switching to a different one? I don't know.

gregbreen commented 5 years ago

@siddarora7 , you may want to check out @kriswiner 's quote from earlier (Jun 13) on this thread:

And yes, the documentation sucks and the MPU9250 can be a very complicated device to use well. I have tried in my sketches to make it somewhat understandable. The MPU9250 is used by the tens of millions in cell phones and Invensense doesn't waste their time with small volume hobbyists and makers. Same as it ever was.

In short, don't pin your hopes on customer support to rescue you. Mind you, they did answer me when I was trying to get mag self-test going. Anyways back your problem and your code.

Looking at your code from 4 days ago, I don't see a problem with it, apart from maybe the delays. You only have 100us after resetting the MPU9250, whereas I (and Invensense) have 100ms. I'm not sure that the chip will be ready for any of your register accesses until after you do your first 100ms delay (SLV0_CTRL). In my code, I have a 100ms delay after the reset. The only other delay I have is 20ms before reading from DI.

PJiaHeng commented 4 years ago

Thanks for your reply. =) Another big question, I can successfully get one sensor's data now which includes acc, gyro and mag. I think the result is fine.

I would like to connect multiple MPU-9250 like the SPI master-slave connection in datasheet: spi

I connect 18 MPU-9250 via SPI. I think it just use the loop to run the same procedure of initialization 18 times like this: http://pastebin.com/ReZumsL9

However, I can get the Who am I ID of each MPU9250 (for acc and gyro), but I can not get the ID of magnetometer. I can not get the data of mag also. The data of acc and gyro from 18 MPU-9250 are fine.

Do you have any idea how to solve this? Thanks in advance.

Hello, I try to connect multi MPU9250 via SPI as well. But it works badly. When I connect one MPU9250 via SPI, I can get right data of acc, gyro, mag always. However, when I connect 7 MPU9250 via SPI, the RAW_DATA_RDY_INT don't change to 0x01 after reading 9DOF data from 7 MPU9250 some times. Then, I try to get only mag data from 7 MPU9250 via SPI, it still don't change to 0x01 after reading mag data some times. I wanna know do you suffer this problem? If did, I wish you could give me some advice. Thanks very much.

ijunglee commented 4 years ago

Thanks for your reply. =) Another big question, I can successfully get one sensor's data now which includes acc, gyro and mag. I think the result is fine. I would like to connect multiple MPU-9250 like the SPI master-slave connection in datasheet: spi I connect 18 MPU-9250 via SPI. I think it just use the loop to run the same procedure of initialization 18 times like this: http://pastebin.com/ReZumsL9 However, I can get the Who am I ID of each MPU9250 (for acc and gyro), but I can not get the ID of magnetometer. I can not get the data of mag also. The data of acc and gyro from 18 MPU-9250 are fine. Do you have any idea how to solve this? Thanks in advance.

Hello, I try to connect multi MPU9250 via SPI as well. But it works badly. When I connect one MPU9250 via SPI, I can get right data of acc, gyro, mag always. However, when I connect 7 MPU9250 via SPI, the RAW_DATA_RDY_INT don't change to 0x01 after reading 9DOF data from 7 MPU9250 some times. Then, I try to get only mag data from 7 MPU9250 via SPI, it still don't change to 0x01 after reading mag data some times. I wanna know do you suffer this problem? If did, I wish you could give me some advice. Thanks very much.

Hello, now I can connect and read 18 MPU-9250 via SPI and they works perfectly. I noticed that I had problems like yours if I connected to the TI MSP430 debugger and used the break points to check the data ready flag. But if I didn't connect to the debugger and just sent the data packet with 18 IMUs to my software program, it won't have any problems. Maybe the debugger would get some electricity from the sensors and make them unstable (unsure about this) How do you test your sensor reading?

PJiaHeng commented 4 years ago

Hello, now I can connect and read 18 MPU-9250 via SPI and they works perfectly. I noticed that I had problems like yours if I connected to the TI MSP430 debugger and used the break points to check the data ready flag. But if I didn't connect to the debugger and just sent the data packet with 18 IMUs to my software program, it won't have any problems. Maybe the debugger would get some electricity from the sensors and make them unstable (unsure about this) How do you test your sensor reading?

Thanks for your reply. The same as you, I also connect to a debugger. So I will try to run my project without debugger. To test my sensor reading is right, I let MPU9250 rest on the table and no any motion. And I have some questions: Do you enable by-pass mode at last? Do you have some operations about fsync? Because the INT_STATUS register will change to 0x09, before I don't get RAW_DATA_RDY_INT.

PJiaHeng commented 4 years ago

@ijunglee Did you use FIFO buffer on the MPU9250?