diff options
author | 2023-11-24 12:00:16 +0200 | |
---|---|---|
committer | 2023-11-28 06:42:05 +0000 | |
commit | 8bb084ebbb35f11d3bbeffc56520eb4de7405e67 (patch) | |
tree | 31a37c12c9d18cbc9a3de4138c27a125ee54d84e | |
parent | ff5cad9cd2a3d6c6618bf54e0b126ed9d68ef71a (diff) | |
download | rtic-8bb084ebbb35f11d3bbeffc56520eb4de7405e67.tar.gz rtic-8bb084ebbb35f11d3bbeffc56520eb4de7405e67.tar.zst rtic-8bb084ebbb35f11d3bbeffc56520eb4de7405e67.zip |
rtic-sync: add Arbiter for I2C
-rw-r--r-- | rtic-sync/src/arbiter.rs | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/rtic-sync/src/arbiter.rs b/rtic-sync/src/arbiter.rs index 5683f93d..615a7ed7 100644 --- a/rtic-sync/src/arbiter.rs +++ b/rtic-sync/src/arbiter.rs @@ -274,6 +274,95 @@ pub mod spi { } } +#[cfg(feature = "unstable")] +/// I2C bus sharing using [`Arbiter`] +/// +/// An Example how to use it in RTIC application: +/// ```ignore +/// #[app(device = some_hal, peripherals = true, dispatchers = [TIM16])] +/// mod app { +/// use core::mem::MaybeUninit; +/// use rtic_sync::{arbiter::{i2c::ArbiterDevice, Arbiter}, +/// +/// #[shared] +/// struct Shared {} +/// +/// #[local] +/// struct Local { +/// ens160: Ens160<ArbiterDevice<'static, I2c<'static, I2C1>>>, +/// } +/// +/// #[init(local = [ +/// i2c_arbiter: MaybeUninit<Arbiter<I2c<'static, I2C1>>> = MaybeUninit::uninit(), +/// ])] +/// fn init(cx: init::Context) -> (Shared, Local) { +/// let i2c = I2c::new(cx.device.I2C1); +/// let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c)); +/// let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52); +/// +/// i2c_sensors::spawn(i2c_arbiter).ok(); +/// +/// (Shared {}, Local { ens160 }) +/// } +/// +/// #[task(local = [ens160])] +/// async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c<'static, I2C1>>) { +/// use sensor::Asensor; +/// +/// loop { +/// // Use scope to make sure I2C access is dropped. +/// { +/// // Read from sensor driver that wants to use I2C directly. +/// let mut i2c = i2c.access().await; +/// let status = Asensor::status(&mut i2c).await; +/// } +/// +/// // Read ENS160 sensor. +/// let eco2 = cx.local.ens160.eco2().await; +/// } +/// } +/// } +/// ``` +pub mod i2c { + use super::Arbiter; + use embedded_hal::i2c::{AddressMode, ErrorType, Operation}; + use embedded_hal_async::i2c::I2c; + + /// [`Arbiter`]-based shared bus implementation for I2C. + pub struct ArbiterDevice<'a, BUS> { + bus: &'a Arbiter<BUS>, + } + + impl<'a, BUS> ArbiterDevice<'a, BUS> { + /// Create a new [`ArbiterDevice`] for I2C. + pub fn new(bus: &'a Arbiter<BUS>) -> Self { + Self { bus } + } + } + + impl<'a, BUS> ErrorType for ArbiterDevice<'a, BUS> + where + BUS: ErrorType, + { + type Error = BUS::Error; + } + + impl<'a, BUS, A> I2c<A> for ArbiterDevice<'a, BUS> + where + BUS: I2c<A>, + A: AddressMode, + { + async fn transaction( + &mut self, + address: A, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + let mut bus = self.bus.access().await; + bus.transaction(address, operations).await + } + } +} + #[cfg(test)] mod tests { use super::*; |