juliangaal / mpu6050

MPU6050 embedded-hal driver written in Rust
https://crates.io/crates/mpu6050
MIT License
50 stars 31 forks source link

Issue using MPU6050 with ESP32 and esp-hal #53

Closed truppelito closed 1 year ago

truppelito commented 1 year ago

First of all, I realise this may not be the best place to ask this question. I know this crate is for a general hal, not specifically for ESP32 and esp-hal, but maybe someone will have some intuition about this and help me find a solution. Or feel free to remove this issue.

Problem:

I'm trying to use an MPU6050 with an ESP32 using the esp-hal and this crate.

Hardware:

I'm using a breakout board like this one. Connections are very easy: power, GND, SDA and SCL connected directly to the ESP32.

I can confirm this hardware works perfectly when using the Arduino environment and the Adafruit MPU6050 library. The I2C address used is the default (0x68).

Rust software:

Using the aforementioned esp-hal crate, along with this one, I wrote this test code:

#![no_std]
#![no_main]

use core::fmt::Write;
use esp32_hal::{
    clock::ClockControl, i2c::I2C, pac::Peripherals, prelude::*, timer::TimerGroup, Rtc, Serial, IO,
};
use esp_backtrace as _;
use mpu6050::Mpu6050;

#[xtensa_lx_rt::entry]
fn main() -> ! {
    let peripherals = Peripherals::take().unwrap();
    let mut system = peripherals.DPORT.split();
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    // Disable the RTC and TIMG watchdog timers
    let mut rtc = Rtc::new(peripherals.RTC_CNTL);
    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let mut wdt0 = timer_group0.wdt;
    let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
    let mut wdt1 = timer_group1.wdt;

    rtc.rwdt.disable();
    wdt0.disable();
    wdt1.disable();

    let mut usb = Serial::new(peripherals.UART0);
    let mut delay = esp32_hal::Delay::new(&clocks);

    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    let i2c = I2C::new(
        peripherals.I2C0,
        io.pins.gpio21,
        io.pins.gpio22,
        100u32.kHz(),
        &mut system.peripheral_clock_control,
        &clocks,
    )
    .unwrap();

    let mut mpu = Mpu6050::new(i2c);
    mpu.init(&mut delay).unwrap();
    writeln!(usb, "Got here!").unwrap();

    let mut count: u64 = 0;
    loop {
        writeln!(usb, "Serial output #{count}. This works!").unwrap();

        // get roll and pitch estimate
        let acc = mpu.get_acc_angles().unwrap();
        writeln!(usb, "r/p: {:?}", acc).unwrap();

        // get sensor temp
        let temp = mpu.get_temp().unwrap();
        writeln!(usb, "temp: {:?}c", temp).unwrap();

        // get gyro data, scaled with sensitivity
        let gyro = mpu.get_gyro().unwrap();
        writeln!(usb, "gyro: {:?}", gyro).unwrap();

        // get accelerometer data, scaled with sensitivity
        let acc = mpu.get_acc().unwrap();
        writeln!(usb, "acc: {:?}", acc).unwrap();

        delay.delay_ms(10u32);
        count += 1;
    }
}

This code is based on the cargo generate from here with the I2C additions from the example code in the esp-hal crate.

Error:

The code from above, on the exact same hardware that works on the Arduino environment, gives the following error:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0048,len:12
ho 0 tail 12 room 4
load:0x3fff0054,len:4800
load:0x40078000 [_stack_end_cpu0:??:??],len:17448
load:0x4007c428 [_stack_end_cpu0:??:??],len:4840
entry 0x4007c6a0 [_stack_end_cpu0:??:??]

!! A panic occured in 'src/main.rs', at line 44, column 26

PanicInfo {
    payload: Any { .. },
    message: Some(
        called `Result::unwrap()` on an `Err` value: I2c(AckCheckFailed),
    ),
    location: Location {
        file: "src/main.rs",
        line: 44,
        col: 26,
    },
    can_unwind: true,
}

Backtrace:

0x400f1d85 [core::result::unwrap_failed:[...]/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/result.rs:1814]
0x400d95e2 [core::result::Result<T,E>::unwrap:[...]/.rustup/toolchains/esp/lib/rustlib/src/rust/library/core/src/result.rs:1107]
0x400d9a2f [esp32_rust_test::__xtensa_lx_rt_main:[...]/src/main.rs:44]
0x400e1678 [Reset:[...]/.cargo/registry/src/github.com-1ecc6299db9ec823/xtensa-lx-rt-0.13.0/src/lib.rs:77]
0x400dde39 [ESP32Reset:[...]/.cargo/registry/src/github.com-1ecc6299db9ec823/esp32-hal-0.5.0/src/lib.rs:78]

Line 44 is mpu.init(&mut delay).unwrap();. I know that the very first command being sent to the MPU (self.write_byte(PWR_MGMT_1::ADDR, 0x01)?;) is not working (I tested that command specifically).

The weirdest part is that, over 100+ tries, it actually worked exactly once, randomly, with no code changes (or any other reason for it to start working, for that matter). The loop started running and outputting values. Although I didn't check the MEMS values, the temperature printed was around 25ºC, which is completely correct for where I am. After this one time it worked, it never worked again.

I feel like I must be missing something very obvious, but for the life of me I cannot figure it out, and ESP32 Rust examples are sparse on the internet. Any help is appreciated!

truppelito commented 1 year ago

After discussing for a bit here it seems the issue is with the esp-hal. I will leave this open in case anyone wants to comment further, but also feel free to close it.

juliangaal commented 1 year ago

How about tagging the question with [SOLVED], for visibility?