0

I have a MPU6050 hooked up to a raspberry pi pico, I am trying to read the data using the i2c protocol. But it only gives 0's, I assume this is due to the fact that its in sleep mode because from what I can tell everything is connected as it should be.

`

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
//mpu address
const static uint8_t MPU_ADDRESS = 0x68;

static void mpu6050_reset() {
    // Two byte reset. First byte register, second byte data
    // There are a load more options to set up the device in different ways that could be added here
    //uint8_t buffer [] = {(uint8_t)65, (uint8_t)66};
    //i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
    //i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
    //printf("b1: %d b2: %d \n", buffer[0], buffer[1]);

    uint8_t buf[] = {0x6B, 0x00};
    i2c_write_blocking(i2c_default, MPU_ADDRESS, buf, 1, false);
    //i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[0], 8, false);
    //i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer[1], 8, false);
    
}

static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
    // For this particular device, we send the device the register we want to read
    // first, then subsequently read from the device. The register is auto incrementing
    // so we don't need to keep sending the register we want, just the first.

    uint8_t buffer[6];

    // Start reading acceleration registers from register 0x3B for 6 bytes
    uint8_t val = 0x3B;
    i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true); // true to keep master control of bus
    i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false);
    printf("buffer accel, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
    for (int i = 0; i < 3; i++) {
        accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
    }

    // Now gyro data from reg 0x43 for 6 bytes
    // The register is auto incrementing on each read
    val = 0x43;
    i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
    i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 6, false);  // False - finished with bus

    for (int i = 0; i < 3; i++) {
        gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
    }
    printf("buffer gyro, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d \n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);

    val = 0x41;
    i2c_write_blocking(i2c_default, MPU_ADDRESS, &val, 1, true);
    i2c_read_blocking(i2c_default, MPU_ADDRESS, buffer, 2, false);  // False - finished with bus

    *temp = buffer[0] << 8 | buffer[1];
}

int main() {

    //check that pico is powered and running
    const uint LED = PICO_DEFAULT_LED_PIN;
    gpio_init(LED);
    gpio_set_dir(LED, GPIO_OUT);
    gpio_put(LED, 1);

    //check that pico can use serial output
    stdio_init_all();
    printf("hello world \n");
    

    //setup i2c buffer address stuff
    uint8_t MPU_ACCELRATION_BUFFER = 0x3B;
    uint8_t MPU_GRYOSCOPE_BUFFER = 0x43;

    //turn on MPU power
    const uint MPU_POWER = 1;
    gpio_init(MPU_POWER);
    gpio_set_dir(MPU_POWER, GPIO_OUT);
    gpio_put(MPU_POWER, 1);

    i2c_init(i2c_default, 400 * 1000);


    gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
    gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
    // Make the I2C pins available to picotool
    bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));

    //while (1){
    mpu6050_reset();
    //}
    int16_t acceleration[3], gyro[3], temp;
    
    while (1) {
        mpu6050_reset();
        mpu6050_read_raw(acceleration, gyro, &temp);

        // These are the raw numbers from the chip, so will need tweaking to be really useful.
        // See the datasheet for more information
        printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
        printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
        printf("Temp. = %f\n", (temp / 340.0) + 36.53);
        sleep_ms(100);
        
    }
    return 0;
}


`

This is the code, using the raspberry pi c/cpp sdk. A large chunk of it is simply the example for the mpu6050 which all seems to be valid, and there is code included meant to wake up the mpu6050. So are there any other methods of waking the MPU6050 up or does the issue appear to be something else within the code?

  • Your problem is `uint8_t buffer[6];` needs to be `uint8_t buffer[14];` because there are 2-bytes High/Low per reading and it's easier to read all values accel, temp, gyro in a single read. The temperature value is in between the Accel and Gyro registers. Here is a quick and dirty [Pico MPU9250/6050](https://github.com/drankinatty/pico-mpu9250) implementation (just don't `#define MPU9250` and it will work for the `MPU6050`). – David C. Rankin Oct 26 '22 at 04:52
  • Also, for testing the Pico-SDK `pico-examples/i2c/mpu6050_i2c` should run right out of the box, but scrolls down the screen. The code above uses ANSI escapes to overwrite values in-place on the terminal. – David C. Rankin Oct 26 '22 at 04:58
  • Technically the code also invokes *UB* due to the mismatch between `printf ("%d" ..., buffer[0], ...)` and `uint8_t buffer[6];`. The proper conversion specifier is `"%hhu"` for unsigned 8-bit values. `"%d"` is for signed 32-bit values. You only need `bi_decl (..)` if using PicoTool and don't `mpu6050_reset();` inside the loop. Just once before entering the loop and `sleep_ms(20);` after the reset. The repeated calls to reset may be causing timing issues. Otherwise, other than what is noted, it looks like your code should run. – David C. Rankin Oct 26 '22 at 05:14
  • Double-check your wiring i2c-data goes to Pin6 (from top-left) and i2c-clock goes on pin7. The order of the clock and data pins are reversed on the MPU6050, so you have clock, then data. – David C. Rankin Oct 26 '22 at 08:05
  • @DavidC.Rankin `uint8_t buffer[14];` doesn't seem to be a solution, as both the `pico-examples/i2c/mpu6050` use `[6]` and it still prints 0's. And for some reason the mpu6050 example in the pico examples package doesn't work either. Also removing bi_decl doesn't change anything. And Just incase you wanted to see output: `18:30:45.655 -> buffer accel, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 18:30:45.655 -> buffer gyro, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 18:30:45.655 -> Acc. X = 0, Y = 0, Z = 0 18:30:45.655 -> Gyro. X = 0, Y = 0, Z = 0 18:30:45.655 -> Temp. = 36.530000` – frozenNeptune Oct 27 '22 at 01:31
  • Yes, you can read `6`, `2` and `6` from `ACCEL_XOUT_H`, `TEMP_OUT_H` and `GYRO_XOUT_H` registers or simply read `14` beginning at `ACCEL_XOUT_H`. Sorry your chip isn't behaving. I've run into a few bad MPUs, but always have gotten output on a couple of axis. One of the best resources for the 6050/9250 is the github repo by [Kris Winer](https://github.com/kriswiner). Well worth poking around. However, if you are reading the chip temperature correctly, (your accel and gyro reg addresses are correct), that tends to point to a potential chip problem. I2c is working. – David C. Rankin Oct 27 '22 at 02:01
  • You are correct removing `bi_decl()` doesn't change anything -- unless you are using picotool. All it does is enable output for that. If you are not using the picotool software (I don't), then you won't notice any difference. My point for bringing it up was simply to point out it wasn't necessary unless you were using picotool (I try and eliminate all unnecessary code, but at least wrapping it in a `#ifdef .. #endif` preprocessor conditional). – David C. Rankin Oct 27 '22 at 02:05
  • @DavidC.Rankin At the moment the chip isn't reading temperature correctly either, as I believe that is the default output for the chip. So does that imply the chip is broken or would the temperature working imply a broken chip? As all 5 chips I am testing with output the same way. So it seems unlikely that all the chips are broken unless the seller sold dud chips. – frozenNeptune Oct 27 '22 at 03:08
  • Also I'll look at that git repository to see if I can find anything useful in there. – frozenNeptune Oct 27 '22 at 03:10
  • If the default pico-SDK example doesn't work -- that implies very strongly that your chip is bad. I've probably bought a dozen or so MPU chips from Amazon, etc.. The first two chips I bought were bad with either one or more dead axis. or dead chips (magnetometor was completely dead on 2nd). So it's not out of the question you have a bad chip. If you didn't buy it new, then there is no telling whether it had been zapped. Right now you can get the 6050 for about $3 each (if I recall correctly you can get 4 for $12) For peace-of-mind, I'd order a new set and solder them together. – David C. Rankin Oct 27 '22 at 03:31
  • I just confirmed by copying your code (removing `bi_decl()`) and changing the format specifiers to `"%hd"`) and built and ran your code -- it works fine, all axis look reasonable (though it flies by so fast it's hard to pick out each axis). Swiveling the MPU around the numbers change as they are supposed to. If you don't see that -- your chip is fried. One good trick for controlling output rate is to `add_repeating_timer_ms (200 ...)` and have that do output to screen. You can read at 100Hz, in `main()` set the `user_data` for the timer to point to you data and print at 5Hz. – David C. Rankin Oct 27 '22 at 03:43
  • @DavidC.Rankin Alright then, if the code does actually run correctly then I'll buy a new chip set and see if it works, also I didn't actually solder the electronics together and instead am just holding the wires against each-other in a breadboard in such a way that they connect, Could that possibly be the cause of the lacking of proper data? – frozenNeptune Oct 27 '22 at 04:56
  • The no solder technique is very likely your problem. Your code runs fine. I do solder all my pin-headers and board (pico is a real bitch 43 individual pins to solder with the SWI 3-pin too) If you are going to do much of this, go ahead and get a good solder station like the X-Tronic 3020-XTS and a good roll of 1mm solder (don't forget the paste flux). Roughly $50 -- but well worth it for digital solder-tip temp control (490-500 deg F is fine). If you have little alligator clips, that can work on the MPU until you can solder the headers in. – David C. Rankin Oct 27 '22 at 06:23
  • @DavidC.Rankin , thanks for the soldering tip recommendation, this one is actually really nice. But also it appears that both purchasing new MPU sensors and soldering on the pins to the sensors doesn't help. Can you send the modified code to me that you made so then I can sanity check myself. Because if it worked for you but doesn't for me I'm simply just stumped on how that's the case. – frozenNeptune Nov 01 '22 at 03:38
  • Sure, here is your example that I tweaked and ran here [MPU Example](https://paste.opensuse.org/17070376). (good until Mon 28 Nov 2022) Very little has changed. Same advice, if this or the pico-examples i2c/mpu6050 examples won't run, it's not the code that is the problem. You build out-of-source in some new directory right? Like `mkdir -p bld && cd bld` then `cmake ../path/to/source/dir` and then `make` right? If you don't use another PI or pico to load the `.elf` file, you are loading the `.f2u` file after holding the bootsel button right? – David C. Rankin Nov 01 '22 at 04:58
  • @DavidC.Rankin , I build it in the VSCode environment, in a separate file from the SDK, and a load the UF2 file onto the pico in bootsel mode. I'm using a windows computer to do this and GPIO does work correctly on the pico. – frozenNeptune Nov 02 '22 at 02:26
  • Okay, that's fine. I have a Win10 build environment for the pico setup too. I just use Msys2 and build and load from the command line. Works fine on either OS. I use 2 Picos, one with `picoprobe` that functions as the debug probe connects to the other over the 3-pin SWI header. Then just use `openocd` to flash the `.elf` file through the first pico. Never have to disconnect the USB and never have to worry about bootsel. (it will spoil you once you try it that way). I use PuTTY for the terminal on windows and xterm on Linux. Both work equally well with the ANSI escapes to display in-place. – David C. Rankin Nov 02 '22 at 02:42
  • Have you double-tripple checked the [MPU/Pico connection diagram](https://github.com/raspberrypi/pico-examples/blob/master/i2c/mpu6050_i2c/mpu6050_i2c_bb.png)? That's the only other thing I can think of that may be messing you up. ALWAYS keep a common-ground between the pico and MPU. So make sure you connect the MPU `gnd` to the pico ground as well. When you get this problem fixed, grab the [Fusion](https://github.com/drankinatty/Fusion) code. That is a fantastic way to incorporate the gyro and accelerometer (no magnetometer) into a precise attitude. – David C. Rankin Nov 02 '22 at 02:45
  • @DavidC.Rankin I've got VCC on pin 36, GND on pin 38, SCL on pin 7, and SDA is on pin 6, Ive set it up to be the same as the pinout. Unless the pico H have different hardware for this type of stuff I don't belive that is an issue. – frozenNeptune Nov 02 '22 at 03:06
  • That's definitely right. No difference between any of the picos as far as pinout goes. No reason why your config won't work. No reason your code won't work -- I ran it. If you are still running unsoldered, just note, it just take one slight bump to cause a momentary disconnect in, e.g. one of the i2c wires. That can result in i2c just doing nothing until it is reset/initialized. From what I can see, you have it all right. Only thing to do is a step-by-step review. Try another i2c example like `i2c/bus_scan` just to make sure all is seen on the i2c bus. – David C. Rankin Nov 02 '22 at 04:37
  • I do an i2c check as part of my `mpu_init` code in the first github link I posted. You can see the `bool mpu_i2c_check (void)` function for how to check the mpu using the `MPU_WHO_AM_I_DATA` (`0x71`) – David C. Rankin Nov 02 '22 at 04:40
  • @DavidC.Rankin I just did both the `bus_scan` and the `WHO_AM_I` both give a `0x68` or a 104 in decimal, which appears to be correct. Unless the chip is supposed to have a `0x71` like you put in the `WHO_AM_I_DATA`? – frozenNeptune Nov 04 '22 at 04:10
  • The Register is the same between the MPU6050 and MPU9250 but the values are different. MPU6050 returns `0x68` (properly the default value is `0x34` as only bits 1:6 are considered) while the MPU9250 returns `0x71` See MPU6000 Register Map, pg. 45 for the 6050 and the MPU9250 Register Map pg. 44. The MPU9255 has a default value of `73`. MPU9255 Register Map also pg. 44. In your case `0x34 << 1 == 0x68`. – David C. Rankin Nov 04 '22 at 04:24
  • @DavidC.Rankin So then the registers are correct, Do you have any idea what other things could be wrong with the I2C connection because I'm stumped. Could it be something to do with the SCL clock? Or something along those lines, because I've got new chips, soldered the parts, tested the bus, and more. – frozenNeptune Nov 04 '22 at 04:37
  • If you can read the `WHO_AM_I` register and get `0x68` (or `0x68 >> 1 == 0x34`) then the MPU6050 is seen and is communicating over i2c. If you have tried 2 MPU6050s and you get zero for all accel and gyro axis values -- it seems unlikely you would have 2 dead MPUs (you could still read `WHO_AM_I` and the accel and gyro be dead, but unlikely all axis would be dead). I am flummoxed. Having run your code here, I know the code works. You simply write `0x0` to the `Reset` register and then read raw values. No checks that would exit early. I still suspect chip issues, another $4 may be worth it.. – David C. Rankin Nov 04 '22 at 04:55
  • We will need to clean up these comments (delete them), for extended conversation, shoot me an e-mail at drankinatty at gmail. – David C. Rankin Nov 04 '22 at 04:58

0 Answers0