embedded_hal_bus::i2c

Struct AtomicDevice

source
pub struct AtomicDevice<'a, T> { /* private fields */ }
Expand description

Atomics-based shared bus I2c implementation.

Sharing is implemented with a AtomicDevice, which consists of an UnsafeCell and an AtomicBool “locked” flag. This means it has low overhead, like RefCellDevice. Aditionally, it is Send, which allows sharing a single bus across multiple threads (interrupt priority level), like CriticalSectionDevice, while not using critical sections and therefore impacting real-time performance less.

The downside is using a simple AtomicBool for locking doesn’t prevent two threads from trying to lock it at once. For example, the main thread can be doing an I2C transaction, and an interrupt fires and tries to do another. In this case, a Busy error is returned that must be handled somehow, usually dropping the data or trying again later.

Note that retrying in a loop on Busy errors usually leads to deadlocks. In the above example, it’ll prevent the interrupt handler from returning, which will starve the main thread and prevent it from releasing the lock. If this is an issue for your use case, you most likely should use CriticalSectionDevice instead.

This primitive is particularly well-suited for applications that have external arbitration rules that prevent Busy errors in the first place, such as the RTIC framework.

§Examples

Assuming there is a pressure sensor with address 0x42 on the same bus as a temperature sensor with address 0x20; AtomicDevice can be used to give access to both of these sensors from a single i2c instance.

use embedded_hal_bus::i2c;
use embedded_hal_bus::util::AtomicCell;

let i2c = hal.i2c();
let i2c_cell = AtomicCell::new(i2c);
let mut temperature_sensor = TemperatureSensor::new(
  i2c::AtomicDevice::new(&i2c_cell),
  0x20,
);
let mut pressure_sensor = PressureSensor::new(
  i2c::AtomicDevice::new(&i2c_cell),
  0x42,
);

Implementations§

source§

impl<'a, T> AtomicDevice<'a, T>
where T: I2c,

source

pub fn new(bus: &'a AtomicCell<T>) -> Self

Create a new AtomicDevice.

Trait Implementations§

source§

impl<'a, T> ErrorType for AtomicDevice<'a, T>
where T: I2c,

source§

type Error = AtomicError<<T as ErrorType>::Error>

Error type
source§

impl<'a, T> I2c for AtomicDevice<'a, T>
where T: I2c,

source§

fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error>

Reads enough bytes from slave with address to fill read. Read more
source§

fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error>

Writes bytes to slave with address address. Read more
source§

fn write_read( &mut self, address: u8, write: &[u8], read: &mut [u8], ) -> Result<(), Self::Error>

Writes bytes to slave with address address and then reads enough bytes to fill read in a single transaction. Read more
source§

fn transaction( &mut self, address: u8, operations: &mut [Operation<'_>], ) -> Result<(), Self::Error>

Execute the provided operations on the I2C bus. Read more
source§

impl<'a, T> Send for AtomicDevice<'a, T>

Auto Trait Implementations§

§

impl<'a, T> Freeze for AtomicDevice<'a, T>

§

impl<'a, T> !RefUnwindSafe for AtomicDevice<'a, T>

§

impl<'a, T> Sync for AtomicDevice<'a, T>
where T: Send,

§

impl<'a, T> Unpin for AtomicDevice<'a, T>

§

impl<'a, T> !UnwindSafe for AtomicDevice<'a, T>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.