Skip to content

Commit da90532

Browse files
committed
Add blocking version of rtic_sync::arbiter::spi::ArbiterDevice
1 parent 861a63d commit da90532

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

rtic-sync/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ For each category, _Added_, _Changed_, _Fixed_ add new entries at the top!
1616

1717
- `defmt v0.3` derives added and forwarded to `embedded-hal(-x)` crates.
1818
- signal structure
19+
- Add `arbiter::spi::BlockingArbiterDevice` that helps during initialization of RTIC apps. After initialization is complete, convert an `BlockingArbiterDevice` into an `ArbiterDevice` using `BlockingArbiterDevice::into_non_blocking()`
1920

2021
## v1.2.0 - 2024-01-10
2122

rtic-sync/src/arbiter.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,10 @@ impl<'a, T> DerefMut for ExclusiveAccess<'a, T> {
195195
pub mod spi {
196196
use super::Arbiter;
197197
use embedded_hal::digital::OutputPin;
198+
use embedded_hal::spi::SpiBus as BlockingSpiBus;
198199
use embedded_hal_async::{
199200
delay::DelayNs,
200-
spi::{ErrorType, Operation, SpiBus, SpiDevice},
201+
spi::{ErrorType, Operation, SpiBus as AsyncSpiBus, SpiDevice},
201202
};
202203
use embedded_hal_bus::spi::DeviceError;
203204

@@ -226,7 +227,7 @@ pub mod spi {
226227
impl<'a, Word, BUS, CS, D> SpiDevice<Word> for ArbiterDevice<'a, BUS, CS, D>
227228
where
228229
Word: Copy + 'static,
229-
BUS: SpiBus<Word>,
230+
BUS: AsyncSpiBus<Word>,
230231
CS: OutputPin,
231232
D: DelayNs,
232233
{
@@ -271,6 +272,89 @@ pub mod spi {
271272
Ok(())
272273
}
273274
}
275+
276+
/// [`Arbiter`]-based shared bus implementation.
277+
pub struct BlockingArbiterDevice<'a, BUS, CS, D> {
278+
bus: &'a Arbiter<BUS>,
279+
cs: CS,
280+
delay: D,
281+
}
282+
283+
impl<'a, BUS, CS, D> BlockingArbiterDevice<'a, BUS, CS, D> {
284+
/// Create a new [`BlockingArbiterDevice`].
285+
pub fn new(bus: &'a Arbiter<BUS>, cs: CS, delay: D) -> Self {
286+
Self { bus, cs, delay }
287+
}
288+
289+
/// Create an `ArbiterDevice` from an `BlockingArbiterDevice`.
290+
pub fn into_non_blocking(self) -> ArbiterDevice<'a, BUS, CS, D>
291+
where
292+
BUS: AsyncSpiBus,
293+
{
294+
ArbiterDevice {
295+
bus: self.bus,
296+
cs: self.cs,
297+
delay: self.delay,
298+
}
299+
}
300+
}
301+
302+
impl<'a, BUS, CS, D> ErrorType for BlockingArbiterDevice<'a, BUS, CS, D>
303+
where
304+
BUS: ErrorType,
305+
CS: OutputPin,
306+
{
307+
type Error = DeviceError<BUS::Error, CS::Error>;
308+
}
309+
310+
impl<'a, Word, BUS, CS, D> SpiDevice<Word> for BlockingArbiterDevice<'a, BUS, CS, D>
311+
where
312+
Word: Copy + 'static,
313+
BUS: BlockingSpiBus<Word>,
314+
CS: OutputPin,
315+
D: DelayNs,
316+
{
317+
async fn transaction(
318+
&mut self,
319+
operations: &mut [Operation<'_, Word>],
320+
) -> Result<(), DeviceError<BUS::Error, CS::Error>> {
321+
let mut bus = self.bus.access().await;
322+
323+
self.cs.set_low().map_err(DeviceError::Cs)?;
324+
325+
let op_res = 'ops: {
326+
for op in operations {
327+
let res = match op {
328+
Operation::Read(buf) => bus.read(buf),
329+
Operation::Write(buf) => bus.write(buf),
330+
Operation::Transfer(read, write) => bus.transfer(read, write),
331+
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
332+
Operation::DelayNs(ns) => match bus.flush() {
333+
Err(e) => Err(e),
334+
Ok(()) => {
335+
self.delay.delay_ns(*ns).await;
336+
Ok(())
337+
}
338+
},
339+
};
340+
if let Err(e) = res {
341+
break 'ops Err(e);
342+
}
343+
}
344+
Ok(())
345+
};
346+
347+
// On failure, it's important to still flush and deassert CS.
348+
let flush_res = bus.flush();
349+
let cs_res = self.cs.set_high();
350+
351+
op_res.map_err(DeviceError::Spi)?;
352+
flush_res.map_err(DeviceError::Spi)?;
353+
cs_res.map_err(DeviceError::Cs)?;
354+
355+
Ok(())
356+
}
357+
}
274358
}
275359

276360
/// I2C bus sharing using [`Arbiter`]

0 commit comments

Comments
 (0)