Expand description
shared-bus is a crate to allow sharing bus peripherals safely between multiple devices.
In the embedded-hal
ecosystem, it is convention for drivers to “own” the bus peripheral they
are operating on. This implies that only one driver can have access to a certain bus. That,
of course, poses an issue when multiple devices are connected to a single bus.
shared-bus solves this by giving each driver a bus-proxy to own which internally manages access to the actual bus in a safe manner. For a more in-depth introduction of the problem this crate is trying to solve, take a look at the blog post.
There are different ‘bus managers’ for different use-cases:
§Sharing within a single task/thread
As long as all users of a bus are contained in a single task/thread, bus sharing is very
simple. With no concurrency possible, no special synchronization is needed. This is where
a BusManagerSimple
should 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();
The BusManager::acquire_*()
methods can be called as often as needed; each call will yield
a new bus-proxy of the requested type.
§Sharing across multiple tasks/threads
For sharing across multiple tasks/threads, synchronization is needed to ensure all bus-accesses
are strictly serialized and can’t race against each other. The synchronization is handled by
a platform-specific BusMutex
implementation. shared-bus already contains some
implementations for common targets. For each one, there is also a macro for easily creating
a bus-manager with 'static
lifetime, which is almost always a requirement when sharing across
task/thread boundaries. As an example:
// 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();
});
Those platform-specific bits are guarded by a feature that needs to be enabled. Here is an overview of what’s already available:
Mutex | Bus Manager | 'static Bus Macro | Feature Name |
---|---|---|---|
std::sync::Mutex | BusManagerStd | new_std!() | std |
cortex_m::interrupt::Mutex | BusManagerCortexM | new_cortexm!() | cortex-m |
shared_bus::XtensaMutex (spin::Mutex in critical section) | BusManagerXtensa | new_xtensa!() | xtensa |
None (Automatically Managed) | BusManagerAtomicCheck | new_atomic_check!() | cortex-m |
§Supported buses and hardware blocks
Currently, the following buses/blocks can be shared with shared-bus:
Bus/Block | Proxy Type | Acquire Method | Comments |
---|---|---|---|
I2C | I2cProxy | .acquire_i2c() | |
SPI | SpiProxy | .acquire_spi() | SPI can only be shared within a single task (See SpiProxy for details). |
ADC | AdcProxy | .acquire_adc() |
Macros§
- new_
atomic_ check - Construct a statically allocated bus manager.
- new_
cortexm - Macro for creating a Cortex-M bus manager with
'static
lifetime. - new_std
- Macro for creating a
std
-based bus manager with'static
lifetime. - new_
xtensa - Macro for creating a Xtensa-lx6 bus manager with
'static
lifetime.
Structs§
- AdcProxy
- Proxy type for ADC sharing.
- Atomic
Check Mutex - A simple coherency checker for sharing across multiple tasks/threads.
- BusManager
- “Manager” for a shared bus.
- I2cProxy
- Proxy type for I2C bus sharing.
- Null
Mutex - “Dummy” mutex for sharing in a single task/thread.
- SpiProxy
- Proxy type for SPI bus sharing.
- Xtensa
Mutex - Wrapper for an interrupt free spin mutex.
Traits§
- BusMutex
- Common interface for mutex implementations.
Type Aliases§
- BusManager
Atomic Check - A bus manager for safely sharing the bus when using concurrency frameworks (such as RTIC).
- BusManager
CortexM - A bus manager for safely sharing between tasks on Cortex-M.
- BusManager
Simple - A bus manager for sharing within a single task/thread.
- BusManager
Std - A bus manager for safely sharing between threads on a platform with
std
support. - BusManager
Xtensa - A bus manager for safely sharing between tasks on Xtensa-lx6.
- CortexM
Mutex - Alias for a Cortex-M mutex.