embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.15k stars 713 forks source link

STM32F303 I2C `blocking_read_write` works but async `write_read` fails due to a timeout #2884

Open fmckeogh opened 4 months ago

fmckeogh commented 4 months ago

main.rs:

bind_interrupts!(struct Irqs {
    I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
    I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
});

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let p = embassy_stm32::init(Config::default());

    let mut config = i2c::Config::default();

    let mut i2c = I2c::new(
        p.I2C1,
        p.PB6,
        p.PB7,
        Irqs,
        p.DMA1_CH2,
        p.DMA1_CH7,
        Hertz(100_000),
        Default::default(),
    );

    let mut buf = [0u8];
    i2c.blocking_write_read(0x38, &[0u8], &mut buf).unwrap();

    defmt::info!("blocking: {:?}", buf);

    let mut buf = [0u8];
    i2c.write_read(0x38, &[0u8], &mut buf).await.unwrap();

    defmt::info!("async: {:?}", buf);
}

Output:

INFO  blocking: [24]
└─ pd_interceptor::____embassy_main_task::{async_fn#0} @ pd-interceptor/src/main.rs:55  
ERROR panicked at pd-interceptor/src/main.rs:58:50:
called `Result::unwrap()` on an `Err` value: Timeout

Why does the async read-write fail? Have I set up the interrupts/DMA correctly?

jamesmunns commented 4 months ago

@fmckeogh I looked and the F303 doesn't have the errata from #2887, I would suggest adding logs to the poll_fns in the read/write dma internal to figure out which branch was taken, I'm guessing in the hanging case, it's taking one of the branches that DOESN'T re-enable the interrupts.

Since the interrupts self-disable, any non-terminating branch of the poll-fns should re-enable the interrupts.

fmckeogh commented 4 months ago

@jamesmunns Awesome, will do:)

fmckeogh commented 4 months ago

@jamesmunns Yes, seems like you're right. The contents of the poll_fn gets called once, returns pending, then is never called again. I've tried manually re-enabling interrupts but no luck so far, I think I need to take some time to understand the codebase.