nrf-rs / microbit

A Rust crate for BBC micro:bit development
BSD Zero Clause License
276 stars 61 forks source link

How to use `i2c_external` with microbit-v2? #121

Open felipebalbi opened 1 year ago

felipebalbi commented 1 year ago

Hi,

I'm attempting to read from shtc3 sensor connected to microbit-v2 via i2c external pins. For testing, I'm using a minimal RTIC app with one task which received a local context containing the Twim:<TWIM0> instance which it uses to instantiate shtc3. When attempting to build the application, it results in unsatisfied trait bounds:

error[E0599]: the method `device_identifier` exists for struct `ShtCx<Sht2Gen, &mut Twim<TWIM0>>`, but its trait bounds were not satisfied
   --> app\src\main.rs:157:29
    |
157 |         let device_id = sht.device_identifier().unwrap();
    |                             ^^^^^^^^^^^^^^^^^ method cannot be called on `ShtCx<Sht2Gen, &mut Twim<TWIM0>>` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
            `<&mut microbit::nrf52833_hal::Twim<microbit::nrf52833_pac::TWIM0> as _embedded_hal_blocking_i2c_Read>::Error = _`
            `<&mut microbit::nrf52833_hal::Twim<microbit::nrf52833_pac::TWIM0> as _embedded_hal_blocking_i2c_Write>::Error = _`
            `&mut microbit::nrf52833_hal::Twim<microbit::nrf52833_pac::TWIM0>: _embedded_hal_blocking_i2c_Read`
            `&mut microbit::nrf52833_hal::Twim<microbit::nrf52833_pac::TWIM0>: _embedded_hal_blocking_i2c_Write`

If I move the code to init(), then it compiles fine, but there is no activity on the i2c external pins (checked with an oscilloscope) and every transaction results in a Nack.

Is there anything else I need to do to get i2c_external to work? Here's a minimal version of my code:


#[app(device = microbit::hal::pac)]
mod app {
    use super::*;

    #[shared]
    struct Shared {}

    #[local]
    struct Local {
        led: P0_21<Output<PushPull>>,
        // i2c: Twim<TWIM0>,
        gpiote: Gpiote,
        state: bool,
    }

    #[init]
    fn init(cx: init::Context) -> (Shared, Local) {
        info!("Hello from RTIC on micro:bit v2");

        let mut board = Board::new(cx.device, cx.core);
        let i2c = Twim::new(board.TWIM0, board.i2c_external.into(), FREQUENCY_A::K100);
        let mut sht = shtcx::shtc3(i2c);
        let device_id = sht.device_identifier().unwrap(); // Fails here with Nack

        (
            Shared {},
            Local {},
        )
    }
BartMassey commented 8 months ago

You'll probably want to put the sht in your locals, not i2c. The shtc3 driver takes ownership of the i2c.

This sounds like maybe an shtcx issue. I've driven external i2c devices in roughly the way you describe before, but have never used this crate.

It's weird that you're not seeing any activity on the external pins with a scope: especially since you're getting a NACK, which I think should only happen when a bus transaction was tried and failed.

Not sure how to help further without an SHTC device, I'm afraid.

felipebalbi commented 8 months ago

You'll probably want to put the sht in your locals, not i2c. The shtc3 driver takes ownership of the i2c.

I'll give that a go when I have some free time on a weekend.

This sounds like maybe an shtcx issue. I've driven external i2c devices in roughly the way you describe before, but have never used this crate.

It's weird that you're not seeing any activity on the external pins with a scope: especially since you're getting a NACK, which I think should only happen when a bus transaction was tried and failed.

If we have bogus pin-muxing, the I2C controller thinks it has driven the correct signals, but they have not propagated to external balls on the die. When waiting for an ACK, there was also no activity, then it signals a NAK and asserts interrupt signal. It can happen :)

BartMassey commented 3 months ago

Any status on this?

qwandor commented 3 months ago

Does using TWIM1 rather than TWIM0 make a difference?