embedded-hal icon indicating copy to clipboard operation
embedded-hal copied to clipboard

How do I share an I2c bus between tasks?

Open Maldus512 opened this issue 1 year ago • 1 comments

I'm trying to setup an embedded project with the async/await approach (using a simple executor, no big framework like Embassy). I have two modules which need to asynchronously manage two i2c devices on the same bus, so they need ownership of an I2c instance.

When I try to create two RefCellDevices and move them to the respective modules I incur in the following compilation error:

    // 12c0 is the original I2c bus
    let i2c_bus = RefCell::new(i2c0);

    // First RefCellDevice, to be owned by the main thread
    let mut rtc = Rx8010sj::new(embedded_hal_bus::i2c::RefCellDevice::new(&i2c_bus));
    log::info!("RTC stopped: {}", rtc.is_stopped().unwrap());
    rtc.set_stopped(false).unwrap();

    // Second RefCellDevice, to be sent to a different task
    let (mut leds, task) = leds::Driver::start(
        embedded_hal_bus::i2c::RefCellDevice::new(&i2c_bus),
    );
    spawner.spawn_local(task).unwrap();

    local_executor.run();
error[E0597]: `i2c_bus` does not live long enough
  --> src/lib.rs:68:51
   |
49 |     let i2c_bus = RefCell::new(i2c0);
   |         ------- binding `i2c_bus` declared here
...
68 |         embedded_hal_bus::i2c::RefCellDevice::new(&i2c_bus),
   |         ------------------------------------------^^^^^^^^-
   |         |                                         |
   |         |                                         borrowed value does not live long enough
   |         argument requires that `i2c_bus` is borrowed for `'static`
...
89 | }
   | - `i2c_bus` dropped here while still borrowed

I think understand the problem: i2c_bus is owned by the main function and the compiler thinks it will be dropped at the end even if the main function never returns. Thus I cannot send the i2c_bus reference to the leds task because it doesn't live long enough.

I can create a (late initialized) static instance for i2c_bus and it works but obviously it uses unsafe code.

Alternatively I can Box the RefCellDevice and immediately leak it, but again it doesn't seem a perfect solution.

What is the preferred way to fix this?

Maldus512 avatar Apr 18 '24 07:04 Maldus512

you can use shared-bus however the support for embedded-hal 1.0 is not complete, but for 0.2 it worked perfectly for me (stm32f4 and freeRTOS-rust)

hacknus avatar Jun 21 '24 11:06 hacknus