rtic_sync/arbiter/
spi.rs

1//! SPI bus sharing using [`Arbiter`]
2
3use super::Arbiter;
4use embedded_hal::digital::OutputPin;
5use embedded_hal::spi::SpiBus as BlockingSpiBus;
6use embedded_hal_async::{
7    delay::DelayNs,
8    spi::{ErrorType, Operation, SpiBus as AsyncSpiBus, SpiDevice},
9};
10use embedded_hal_bus::spi::DeviceError;
11
12/// [`Arbiter`]-based shared bus implementation.
13pub struct ArbiterDevice<'a, BUS, CS, D> {
14    bus: &'a Arbiter<BUS>,
15    cs: CS,
16    delay: D,
17}
18
19impl<'a, BUS, CS, D> ArbiterDevice<'a, BUS, CS, D> {
20    /// Create a new [`ArbiterDevice`].
21    pub fn new(bus: &'a Arbiter<BUS>, cs: CS, delay: D) -> Self {
22        Self { bus, cs, delay }
23    }
24}
25
26impl<BUS, CS, D> ErrorType for ArbiterDevice<'_, BUS, CS, D>
27where
28    BUS: ErrorType,
29    CS: OutputPin,
30{
31    type Error = DeviceError<BUS::Error, CS::Error>;
32}
33
34impl<Word, BUS, CS, D> SpiDevice<Word> for ArbiterDevice<'_, BUS, CS, D>
35where
36    Word: Copy + 'static,
37    BUS: AsyncSpiBus<Word>,
38    CS: OutputPin,
39    D: DelayNs,
40{
41    async fn transaction(
42        &mut self,
43        operations: &mut [Operation<'_, Word>],
44    ) -> Result<(), DeviceError<BUS::Error, CS::Error>> {
45        let mut bus = self.bus.access().await;
46
47        self.cs.set_low().map_err(DeviceError::Cs)?;
48
49        let op_res = 'ops: {
50            for op in operations {
51                let res = match op {
52                    Operation::Read(buf) => bus.read(buf).await,
53                    Operation::Write(buf) => bus.write(buf).await,
54                    Operation::Transfer(read, write) => bus.transfer(read, write).await,
55                    Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await,
56                    Operation::DelayNs(ns) => match bus.flush().await {
57                        Err(e) => Err(e),
58                        Ok(()) => {
59                            self.delay.delay_ns(*ns).await;
60                            Ok(())
61                        }
62                    },
63                };
64                if let Err(e) = res {
65                    break 'ops Err(e);
66                }
67            }
68            Ok(())
69        };
70
71        // On failure, it's important to still flush and deassert CS.
72        let flush_res = bus.flush().await;
73        let cs_res = self.cs.set_high();
74
75        op_res.map_err(DeviceError::Spi)?;
76        flush_res.map_err(DeviceError::Spi)?;
77        cs_res.map_err(DeviceError::Cs)?;
78
79        Ok(())
80    }
81}
82
83/// [`Arbiter`]-based shared bus implementation.
84pub struct BlockingArbiterDevice<'a, BUS, CS, D> {
85    bus: &'a Arbiter<BUS>,
86    cs: CS,
87    delay: D,
88}
89
90impl<'a, BUS, CS, D> BlockingArbiterDevice<'a, BUS, CS, D> {
91    /// Create a new [`BlockingArbiterDevice`].
92    pub fn new(bus: &'a Arbiter<BUS>, cs: CS, delay: D) -> Self {
93        Self { bus, cs, delay }
94    }
95
96    /// Create an `ArbiterDevice` from an `BlockingArbiterDevice`.
97    pub fn into_non_blocking(self) -> ArbiterDevice<'a, BUS, CS, D>
98    where
99        BUS: AsyncSpiBus,
100    {
101        ArbiterDevice {
102            bus: self.bus,
103            cs: self.cs,
104            delay: self.delay,
105        }
106    }
107}
108
109impl<'a, BUS, CS, D> ErrorType for BlockingArbiterDevice<'a, BUS, CS, D>
110where
111    BUS: ErrorType,
112    CS: OutputPin,
113{
114    type Error = DeviceError<BUS::Error, CS::Error>;
115}
116
117impl<'a, Word, BUS, CS, D> SpiDevice<Word> for BlockingArbiterDevice<'a, BUS, CS, D>
118where
119    Word: Copy + 'static,
120    BUS: BlockingSpiBus<Word>,
121    CS: OutputPin,
122    D: DelayNs,
123{
124    async fn transaction(
125        &mut self,
126        operations: &mut [Operation<'_, Word>],
127    ) -> Result<(), DeviceError<BUS::Error, CS::Error>> {
128        let mut bus = self.bus.access().await;
129
130        self.cs.set_low().map_err(DeviceError::Cs)?;
131
132        let op_res = 'ops: {
133            for op in operations {
134                let res = match op {
135                    Operation::Read(buf) => bus.read(buf),
136                    Operation::Write(buf) => bus.write(buf),
137                    Operation::Transfer(read, write) => bus.transfer(read, write),
138                    Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
139                    Operation::DelayNs(ns) => match bus.flush() {
140                        Err(e) => Err(e),
141                        Ok(()) => {
142                            self.delay.delay_ns(*ns).await;
143                            Ok(())
144                        }
145                    },
146                };
147                if let Err(e) = res {
148                    break 'ops Err(e);
149                }
150            }
151            Ok(())
152        };
153
154        // On failure, it's important to still flush and deassert CS.
155        let flush_res = bus.flush();
156        let cs_res = self.cs.set_high();
157
158        op_res.map_err(DeviceError::Spi)?;
159        flush_res.map_err(DeviceError::Spi)?;
160        cs_res.map_err(DeviceError::Cs)?;
161
162        Ok(())
163    }
164}