eldruin / mlx9061x-rs

Platform-agnostic Rust driver for MLX90614/MLX90615 Infrarred thermometer
Apache License 2.0
6 stars 5 forks source link

STM32, I2C, and SMBUS #1

Closed David-OConnor closed 3 years ago

David-OConnor commented 3 years ago

Hi. Is there a trick to getting this to work over I2C, vice SMBUS? What could cause it to work on Raspberry Pi, but not STM32? I've tried F3 and L4, with no luck, but it works on Pi using this drive. I notice that the example is Linux / Raspberry Pi. Thank you.

eldruin commented 3 years ago

I always write an example for the Raspberry Pi because of its popularity but I usually rather use the F1 BluePill or F4 "USB-C pill" boards.

I hope it helps :)

David-OConnor commented 3 years ago

Thank you. Your post really helps - I now know there's no extra config required. I'm now working off the F3 discovery board, since you have a known working solution there (Was using L4 Nucleo before). Still no luck. This is perplexing, given the sensor works on Pi with the same drivers, and other I2C devices work on the STM32s.

This is the program, on F3 discovery:

#![no_main]
#![no_std]

use cortex_m_rt::entry;

use core::sync::atomic::{AtomicUsize, Ordering};
use defmt_rtt as _;
use panic_probe as _;

use stm32f3xx_hal::{
    clocks,
    delay::Delay,
    i2c::I2c,
    interrupt,
    pac,
    prelude::*,
};

use mlx9061x::{Mlx9061x, SlaveAddr};

#[entry]
fn main() -> ! {
    let cp = cortex_m::Peripherals::take().unwrap();
    let mut dp = pac::Peripherals::take().unwrap();

    let mut clocks_1 = clocks::Clocks::full_speed();

    if clocks_1.setup(&mut dp.RCC, &mut dp.FLASH).is_err() {
        defmt::error!("Unable to configure clocks due to a speed error.")
    };

    // `rcc.rs` clock config we pass to other fns that need the speeds. For compatibility.
    let clocks = clocks_1.make_rcc_clocks();

    let mut rcc = dp.RCC.constrain();

    // todo temp mut
    let mut delay = Delay::new(cp.SYST, clocks);

    let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);

    let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
    let sda = gpiob.pb7.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
    let i2c = I2c::new(dp.I2C1, (scl, sda), 100.khz(), clocks, &mut rcc.apb1);

    let sensor_addr = SlaveAddr::default();
    let mut sensor = Mlx9061x::new_mlx90614(i2c, sensor_addr, 5).unwrap();

    loop {
        let temp = sensor.object1_temperature().unwrap_or(69.);
        defmt::warn!("TEMP: {:?}", &temp);

        delay.delay_ms(1_000_u16);
    }
}
geomatsi commented 3 years ago

Hi @David-OConnor

Could you please clarify what do you mean by 'no luck' ? What are the symptoms ?

Based on my experience, my guess is that there might be some issues with i2c implementation in f3 crate. I had to fix i2c implementation in stm32l1xx _hal to make it work with mlx9061x. IIRC I had to adapt some bits from stm32f1xx-hal related to termination of read operation: see https://github.com/stm32-rs/stm32l1xx-hal/pull/7.

Regards, Sergey

David-OConnor commented 3 years ago

Hi. I receive a CheckSumMismatch error from the crate, which is caused by Calculate SMBus Packet Error Code. I'm suspicious of a HAL I2C issue too. I'll try to port your PR to F3 and L4. I wonder if it's significant this is SMBUS and not I2C. I tried enabling most of the SMBus related bits on the I2C register, without success.

@eldruin : Have you tested the F3 example? Thank you. It appears that @geomatsi's changes are present in F1 only; not L4, F3, nor F4.

David-OConnor commented 3 years ago

Unable to git it working on F4 discovery either, using its HAL on Github. (NACK)

David-OConnor commented 3 years ago

Getting Err value: I2C(Acknowledge) on a STM32F103 Blue Pill board using that example code.

geomatsi commented 3 years ago

Hi @David-OConnor ,

Could you please check another usual suspect and play with clocks. As a first check, I would suggest to try release build rather than default debug: build your program using --release switch for cargo.

Regards, Sergey

eldruin commented 3 years ago

I only tested this on the F1. For the F3 I only adapted it. I will try the examples again as soon as I find some time. Do you have pull-up resistors on the I2C lines? 4.7k is a classic value. IIRC the RPi uses 10k.

David-OConnor commented 3 years ago

I'm using 10K hardware Pullups. Have been release building. I'll experiment with the clocks and report back. Thank you.

David-OConnor commented 3 years ago

What version of F1 HAL did you use? I tried v0.7.0 (Current published) and Github master.

eldruin commented 3 years ago

I am unsure which exact version I have used when I tried it. As per Cargo.toml it must have been the 0.6.x version, though.

David-OConnor commented 3 years ago

I appreciate the update. Unable on 0.6.0 either. This is so weird - I just plugged it back into the Rpi, and using this driver, it still works fine. I'm pretty sure this has nothing to do with your crate here btw. I'm leaning towards @geomatsi's comment about it being an issue with the HALs and SMBUS.

My next step is to try to edit the HAL I2C config, but was hoping to start with a working config to work back from, which is why I was trying to get it working on F1. I'm still unable to make it work on F1, F3, F4, or L4.

From here, I'll try using a logic analyzer, learn the I2C protocol, and see what's going on.

What we know:

David-OConnor commented 3 years ago

Fixed. This was due to none of the STM32 HALs other than H7 supporting repeating start on I2C. Many devices don't care, but some, like this, due. The fix was copy+pasting the read_write method from H7's I2C module into L4.

Issue on L4: https://github.com/stm32-rs/stm32l4xx-hal/issues/189 PR on L4: https://github.com/stm32-rs/stm32l4xx-hal/pull/186

eldruin commented 3 years ago

I see. I fixed the same issue in linux-embedded-hal a while ago because the VEML6030 also cared about it. I guess this one would also have not worked on the RPi without it then. Thanks @David-OConnor and @geomatsi!