Skip to content

Instantly share code, notes, and snippets.

@korken89
Created September 19, 2023 10:10
Show Gist options
  • Save korken89/4b06caf5e7cadd320988846274f16030 to your computer and use it in GitHub Desktop.
Save korken89/4b06caf5e7cadd320988846274f16030 to your computer and use it in GitHub Desktop.
//! `rtic_sync::arbiter::Arbiter`-based shared bus `SpiDevice` implementation.
// TODO: upstream to rtic-sync
use embedded_hal::digital::OutputPin;
use embedded_hal_async::{
delay::DelayUs,
spi::{ErrorType, Operation, SpiBus, SpiDevice},
};
use embedded_hal_bus::spi::DeviceError;
use rtic_sync::arbiter::Arbiter;
pub struct ArbiterDevice<BUS, CS, D> {
bus: Arbiter<BUS>,
cs: CS,
delay: D,
}
impl<BUS, CS, D> ArbiterDevice<BUS, CS, D> {
/// Create a new [`ArbiterDevice`].
pub fn new(bus: Arbiter<BUS>, cs: CS, delay: D) -> Self {
Self { bus, cs, delay }
}
}
impl<BUS, CS, D> ErrorType for ArbiterDevice<BUS, CS, D>
where
BUS: ErrorType,
CS: OutputPin,
{
type Error = DeviceError<BUS::Error, CS::Error>;
}
impl<Word, BUS, CS, D> SpiDevice<Word> for ArbiterDevice<BUS, CS, D>
where
Word: Copy + 'static,
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayUs,
{
async fn transaction(
&mut self,
operations: &mut [Operation<'_, Word>],
) -> Result<(), Self::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(())
}
}
impl<BUS, CS, D> crate::ChipSelect for ArbiterDevice<BUS, CS, D>
where
BUS: ErrorType,
CS: OutputPin,
{
type Error = CS::Error;
fn chip_select(&mut self) -> Result<(), Self::Error> {
self.cs.set_low()
}
fn chip_unselect(&mut self) -> Result<(), Self::Error> {
self.cs.set_high()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment