aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Nils Fitinghoff <nils.fitinghoff@mobilaris.se> 2023-10-09 16:55:55 +0200
committerGravatar Emil Fresk <emil.fresk@gmail.com> 2023-11-22 19:42:46 +0000
commitff5cad9cd2a3d6c6618bf54e0b126ed9d68ef71a (patch)
tree4a8a8d04cd41a707aa875be8a9baca32d47a728b
parent96e7704487a58ea57972f15986b0ca0a64f144c6 (diff)
downloadrtic-ff5cad9cd2a3d6c6618bf54e0b126ed9d68ef71a.tar.gz
rtic-ff5cad9cd2a3d6c6618bf54e0b126ed9d68ef71a.tar.zst
rtic-ff5cad9cd2a3d6c6618bf54e0b126ed9d68ef71a.zip
rtic-sync: Add SPI bus sharing with arbiter
-rw-r--r--rtic-sync/CHANGELOG.md2
-rw-r--r--rtic-sync/Cargo.toml4
-rw-r--r--rtic-sync/src/arbiter.rs83
-rw-r--r--xtask/src/argument_parsing.rs1
4 files changed, 90 insertions, 0 deletions
diff --git a/rtic-sync/CHANGELOG.md b/rtic-sync/CHANGELOG.md
index 465f0de5..7047378b 100644
--- a/rtic-sync/CHANGELOG.md
+++ b/rtic-sync/CHANGELOG.md
@@ -9,6 +9,8 @@ For each category, _Added_, _Changed_, _Fixed_ add new entries at the top!
### Added
+- `arbiter::spi::ArbiterDevice` for sharing SPI buses using `embedded-hal-async`
+
### Changed
### Fixed
diff --git a/rtic-sync/Cargo.toml b/rtic-sync/Cargo.toml
index 064b9fa4..39f62dc8 100644
--- a/rtic-sync/Cargo.toml
+++ b/rtic-sync/Cargo.toml
@@ -21,6 +21,9 @@ heapless = "0.7"
critical-section = "1"
rtic-common = { version = "1.0.0", path = "../rtic-common" }
portable-atomic = { version = "1", default-features = false }
+embedded-hal = { version = "1.0.0-rc.1", optional = true }
+embedded-hal-async = { version = "1.0.0-rc.1", optional = true }
+embedded-hal-bus = { version = "0.1.0-rc.1", optional = true, features = ["async"] }
[dev-dependencies]
tokio = { version = "1", features = ["rt", "macros", "time"] }
@@ -29,3 +32,4 @@ tokio = { version = "1", features = ["rt", "macros", "time"] }
[features]
default = []
testing = ["critical-section/std", "rtic-common/testing"]
+unstable = ["embedded-hal", "embedded-hal-async", "embedded-hal-bus"]
diff --git a/rtic-sync/src/arbiter.rs b/rtic-sync/src/arbiter.rs
index 2d66a677..5683f93d 100644
--- a/rtic-sync/src/arbiter.rs
+++ b/rtic-sync/src/arbiter.rs
@@ -191,6 +191,89 @@ impl<'a, T> DerefMut for ExclusiveAccess<'a, T> {
}
}
+#[cfg(feature = "unstable")]
+/// SPI bus sharing using [`Arbiter`]
+pub mod spi {
+ use super::Arbiter;
+ use embedded_hal::digital::OutputPin;
+ use embedded_hal_async::{
+ delay::DelayUs,
+ spi::{ErrorType, Operation, SpiBus, SpiDevice},
+ };
+ use embedded_hal_bus::spi::DeviceError;
+
+ /// [`Arbiter`]-based shared bus implementation.
+ pub struct ArbiterDevice<'a, BUS, CS, D> {
+ bus: &'a Arbiter<BUS>,
+ cs: CS,
+ delay: D,
+ }
+
+ impl<'a, BUS, CS, D> ArbiterDevice<'a, BUS, CS, D> {
+ /// Create a new [`ArbiterDevice`].
+ pub fn new(bus: &'a Arbiter<BUS>, cs: CS, delay: D) -> Self {
+ Self { bus, cs, delay }
+ }
+ }
+
+ impl<'a, BUS, CS, D> ErrorType for ArbiterDevice<'a, BUS, CS, D>
+ where
+ BUS: ErrorType,
+ CS: OutputPin,
+ {
+ type Error = DeviceError<BUS::Error, CS::Error>;
+ }
+
+ impl<'a, Word, BUS, CS, D> SpiDevice<Word> for ArbiterDevice<'a, BUS, CS, D>
+ where
+ Word: Copy + 'static,
+ BUS: SpiBus<Word>,
+ CS: OutputPin,
+ D: DelayUs,
+ {
+ async fn transaction(
+ &mut self,
+ operations: &mut [Operation<'_, Word>],
+ ) -> Result<(), DeviceError<BUS::Error, CS::Error>> {
+ let mut bus = self.bus.access().await;
+
+ self.cs.set_low().map_err(DeviceError::Cs)?;
+
+ let op_res = 'ops: {
+ for op in operations {
+ let res = match op {
+ Operation::Read(buf) => bus.read(buf).await,
+ Operation::Write(buf) => bus.write(buf).await,
+ Operation::Transfer(read, write) => bus.transfer(read, write).await,
+ Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await,
+ Operation::DelayUs(us) => match bus.flush().await {
+ Err(e) => Err(e),
+ Ok(()) => {
+ self.delay.delay_us(*us).await;
+ Ok(())
+ }
+ },
+ };
+ if let Err(e) = res {
+ break 'ops Err(e);
+ }
+ }
+ Ok(())
+ };
+
+ // On failure, it's important to still flush and deassert CS.
+ let flush_res = bus.flush().await;
+ let cs_res = self.cs.set_high();
+
+ op_res.map_err(DeviceError::Spi)?;
+ flush_res.map_err(DeviceError::Spi)?;
+ cs_res.map_err(DeviceError::Cs)?;
+
+ Ok(())
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/xtask/src/argument_parsing.rs b/xtask/src/argument_parsing.rs
index 88ac1e5d..b4dcd904 100644
--- a/xtask/src/argument_parsing.rs
+++ b/xtask/src/argument_parsing.rs
@@ -89,6 +89,7 @@ impl Package {
.chain(std::iter::once(None))
.collect()
}
+ Package::RticSync => vec![Some("unstable".to_string()), None],
_ => vec![None],
}
}