shared-bus
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 = i2c1;
let bus = new;
let mut proxy1 = bus.acquire_i2c;
let mut my_device = new;
proxy1.write;
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 = i2c1;
// The bus is a 'static reference -> it lives forever and references can be
// shared with other threads.
let bus: &'static _ = new_std!.unwrap;
let mut proxy1 = bus.acquire_i2c;
let mut my_device = new;
// We can easily move a proxy to another thread:
# let t =
spawn;
# t.join.unwrap;
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 |
NA | BusManagerAtomicCheck |
new_atomic_check!() |
cortex-m |
Supported Busses
Currently, the following busses can be shared with shared-bus:
Bus | 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() |
License
shared-bus is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.