Struct shared_bus::BusManager

source ·
pub struct BusManager<M> { /* private fields */ }
Expand description

“Manager” for a shared bus.

The manager owns the original bus peripheral (wrapped inside a mutex) and hands out proxies which can be used by device drivers for accessing the bus. Certain bus proxies can only be created with restrictions (see the individual methods for details).

Usually the type-aliases defined in this crate should be used instead of BusManager directly. Otherwise, the mutex type needs to be specified explicitly. Here is an overview of aliases (some are only available if a certain feature is enabled):

Bus ManagerMutex TypeFeature NameNotes
BusManagerSimpleshared_bus::NullMutexalways availableFor sharing within a single execution context.
BusManagerStdstd::sync::MutexstdFor platforms where std is available.
BusManagerCortexMcortex_m::interrupt::Mutexcortex-mFor Cortex-M platforms; Uses a critcal section (i.e. turns off interrupts during bus transactions).

Constructing a BusManager

There are two ways to instanciate a bus manager. Which one to use depends on the kind of sharing that is intended.

  1. When all bus users live in the same task/thread, a BusManagerSimple can be used:

    // For example:
    // let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 90.khz(), clocks, &mut rcc.apb1);
    
    let bus = shared_bus::BusManagerSimple::new(i2c);
    
    let mut proxy1 = bus.acquire_i2c();
    let mut my_device = MyDevice::new(bus.acquire_i2c());
    
    proxy1.write(0x39, &[0xc0, 0xff, 0xee]);
    my_device.do_something_on_the_bus();
  2. When users are in different execution contexts, a proper mutex type is needed and the manager must be made static to ensure it lives long enough. For this, shared-bus provides a number of macros creating such a static instance:

    // For example:
    // let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 90.khz(), clocks, &mut rcc.apb1);
    
    // The bus is a 'static reference -> it lives forever and references can be
    // shared with other threads.
    let bus: &'static _ = shared_bus::new_std!(SomeI2cBus = i2c).unwrap();
    
    let mut proxy1 = bus.acquire_i2c();
    let mut my_device = MyDevice::new(bus.acquire_i2c());
    
    // We can easily move a proxy to another thread:
    std::thread::spawn(move || {
        my_device.do_something_on_the_bus();
    });

    For other platforms, similar macros exist (e.g. new_cortexm!()).

Implementations§

source§

impl<M: BusMutex> BusManager<M>

source

pub fn new(bus: M::Bus) -> Self

Create a new bus manager for a bus.

See the documentation for BusManager for more details.

source§

impl<M: BusMutex> BusManager<M>

source

pub fn acquire_i2c<'a>(&'a self) -> I2cProxy<'a, M>

Acquire an I2cProxy for this bus.

The returned proxy object can then be used for accessing the bus by e.g. a driver:

let bus = shared_bus::BusManagerSimple::new(i2c);

let mut proxy1 = bus.acquire_i2c();
let mut my_device = MyDevice::new(bus.acquire_i2c());

proxy1.write(0x39, &[0xc0, 0xff, 0xee]);
my_device.do_something_on_the_bus();
source

pub fn acquire_adc<'a>(&'a self) -> AdcProxy<'a, M>

Acquire an AdcProxy for this hardware block.

The returned proxy object can then be used for accessing the bus by e.g. a driver:

// For example:
// let ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);
// let ch1 = gpioa.pa1.into_analog(&mut gpioa.crl);
// let adc = Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);

let adc_bus: &'static _ = shared_bus::new_cortexm!(Adc<ADC1> = adc).unwrap();
let mut proxy1 = adc_bus.acquire_adc();
let mut proxy2 = adc_bus.acquire_adc();

proxy1.read(ch0).unwrap();
proxy2.read(ch1).unwrap();
source§

impl<T> BusManager<NullMutex<T>>

source

pub fn acquire_spi<'a>(&'a self) -> SpiProxy<'a, NullMutex<T>>

Acquire an SpiProxy for this bus.

Note: SPI Proxies can only be created from BusManagerSimple (= bus managers using the NullMutex). See SpiProxy for more details why.

The returned proxy object can then be used for accessing the bus by e.g. a driver:

let bus = shared_bus::BusManagerSimple::new(spi);

let mut proxy1 = bus.acquire_spi();
let mut my_device = MyDevice::new(bus.acquire_spi());

// Chip-select needs to be managed manually
cs1.set_high();
proxy1.write(&[0xc0, 0xff, 0xee]);
cs1.set_low();

my_device.do_something_on_the_bus();

Trait Implementations§

source§

impl<M: Debug> Debug for BusManager<M>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<M> RefUnwindSafe for BusManager<M>where M: RefUnwindSafe,

§

impl<M> Send for BusManager<M>where M: Send,

§

impl<M> Sync for BusManager<M>where M: Sync,

§

impl<M> Unpin for BusManager<M>where M: Unpin,

§

impl<M> UnwindSafe for BusManager<M>where M: UnwindSafe,

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere 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 Twhere 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 Twhere U: Into<T>,

§

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 Twhere U: TryFrom<T>,

§

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.