Skip to content

Commit 0d1319a

Browse files
committed
Add blocking version of ArbiterDevice
1 parent 861a63d commit 0d1319a

File tree

4 files changed

+284
-197
lines changed

4 files changed

+284
-197
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: 13 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,21 @@
2323
//! }
2424
//! ```
2525
26-
use core::cell::UnsafeCell;
27-
use core::future::poll_fn;
28-
use core::ops::{Deref, DerefMut};
29-
use core::pin::Pin;
30-
use core::task::{Poll, Waker};
26+
use core::{
27+
cell::UnsafeCell,
28+
future::poll_fn,
29+
ops::{Deref, DerefMut},
30+
pin::Pin,
31+
task::{Poll, Waker},
32+
};
3133
use portable_atomic::{fence, AtomicBool, Ordering};
34+
use rtic_common::{
35+
dropper::OnDrop,
36+
wait_queue::{Link, WaitQueue},
37+
};
3238

33-
use rtic_common::dropper::OnDrop;
34-
use rtic_common::wait_queue::{Link, WaitQueue};
39+
pub mod i2c;
40+
pub mod spi;
3541

3642
/// This is needed to make the async closure in `send` accept that we "share"
3743
/// the link possible between threads.
@@ -191,196 +197,6 @@ impl<'a, T> DerefMut for ExclusiveAccess<'a, T> {
191197
}
192198
}
193199

194-
/// SPI bus sharing using [`Arbiter`]
195-
pub mod spi {
196-
use super::Arbiter;
197-
use embedded_hal::digital::OutputPin;
198-
use embedded_hal_async::{
199-
delay::DelayNs,
200-
spi::{ErrorType, Operation, SpiBus, SpiDevice},
201-
};
202-
use embedded_hal_bus::spi::DeviceError;
203-
204-
/// [`Arbiter`]-based shared bus implementation.
205-
pub struct ArbiterDevice<'a, BUS, CS, D> {
206-
bus: &'a Arbiter<BUS>,
207-
cs: CS,
208-
delay: D,
209-
}
210-
211-
impl<'a, BUS, CS, D> ArbiterDevice<'a, BUS, CS, D> {
212-
/// Create a new [`ArbiterDevice`].
213-
pub fn new(bus: &'a Arbiter<BUS>, cs: CS, delay: D) -> Self {
214-
Self { bus, cs, delay }
215-
}
216-
}
217-
218-
impl<'a, BUS, CS, D> ErrorType for ArbiterDevice<'a, BUS, CS, D>
219-
where
220-
BUS: ErrorType,
221-
CS: OutputPin,
222-
{
223-
type Error = DeviceError<BUS::Error, CS::Error>;
224-
}
225-
226-
impl<'a, Word, BUS, CS, D> SpiDevice<Word> for ArbiterDevice<'a, BUS, CS, D>
227-
where
228-
Word: Copy + 'static,
229-
BUS: SpiBus<Word>,
230-
CS: OutputPin,
231-
D: DelayNs,
232-
{
233-
async fn transaction(
234-
&mut self,
235-
operations: &mut [Operation<'_, Word>],
236-
) -> Result<(), DeviceError<BUS::Error, CS::Error>> {
237-
let mut bus = self.bus.access().await;
238-
239-
self.cs.set_low().map_err(DeviceError::Cs)?;
240-
241-
let op_res = 'ops: {
242-
for op in operations {
243-
let res = match op {
244-
Operation::Read(buf) => bus.read(buf).await,
245-
Operation::Write(buf) => bus.write(buf).await,
246-
Operation::Transfer(read, write) => bus.transfer(read, write).await,
247-
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await,
248-
Operation::DelayNs(ns) => match bus.flush().await {
249-
Err(e) => Err(e),
250-
Ok(()) => {
251-
self.delay.delay_ns(*ns).await;
252-
Ok(())
253-
}
254-
},
255-
};
256-
if let Err(e) = res {
257-
break 'ops Err(e);
258-
}
259-
}
260-
Ok(())
261-
};
262-
263-
// On failure, it's important to still flush and deassert CS.
264-
let flush_res = bus.flush().await;
265-
let cs_res = self.cs.set_high();
266-
267-
op_res.map_err(DeviceError::Spi)?;
268-
flush_res.map_err(DeviceError::Spi)?;
269-
cs_res.map_err(DeviceError::Cs)?;
270-
271-
Ok(())
272-
}
273-
}
274-
}
275-
276-
/// I2C bus sharing using [`Arbiter`]
277-
///
278-
/// An Example how to use it in RTIC application:
279-
/// ```text
280-
/// #[app(device = some_hal, peripherals = true, dispatchers = [TIM16])]
281-
/// mod app {
282-
/// use core::mem::MaybeUninit;
283-
/// use rtic_sync::{arbiter::{i2c::ArbiterDevice, Arbiter},
284-
///
285-
/// #[shared]
286-
/// struct Shared {}
287-
///
288-
/// #[local]
289-
/// struct Local {
290-
/// ens160: Ens160<ArbiterDevice<'static, I2c<'static, I2C1>>>,
291-
/// }
292-
///
293-
/// #[init(local = [
294-
/// i2c_arbiter: MaybeUninit<Arbiter<I2c<'static, I2C1>>> = MaybeUninit::uninit(),
295-
/// ])]
296-
/// fn init(cx: init::Context) -> (Shared, Local) {
297-
/// let i2c = I2c::new(cx.device.I2C1);
298-
/// let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c));
299-
/// let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52);
300-
///
301-
/// i2c_sensors::spawn(i2c_arbiter).ok();
302-
///
303-
/// (Shared {}, Local { ens160 })
304-
/// }
305-
///
306-
/// #[task(local = [ens160])]
307-
/// async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c<'static, I2C1>>) {
308-
/// use sensor::Asensor;
309-
///
310-
/// loop {
311-
/// // Use scope to make sure I2C access is dropped.
312-
/// {
313-
/// // Read from sensor driver that wants to use I2C directly.
314-
/// let mut i2c = i2c.access().await;
315-
/// let status = Asensor::status(&mut i2c).await;
316-
/// }
317-
///
318-
/// // Read ENS160 sensor.
319-
/// let eco2 = cx.local.ens160.eco2().await;
320-
/// }
321-
/// }
322-
/// }
323-
/// ```
324-
pub mod i2c {
325-
use super::Arbiter;
326-
use embedded_hal::i2c::{AddressMode, ErrorType, Operation};
327-
use embedded_hal_async::i2c::I2c;
328-
329-
/// [`Arbiter`]-based shared bus implementation for I2C.
330-
pub struct ArbiterDevice<'a, BUS> {
331-
bus: &'a Arbiter<BUS>,
332-
}
333-
334-
impl<'a, BUS> ArbiterDevice<'a, BUS> {
335-
/// Create a new [`ArbiterDevice`] for I2C.
336-
pub fn new(bus: &'a Arbiter<BUS>) -> Self {
337-
Self { bus }
338-
}
339-
}
340-
341-
impl<'a, BUS> ErrorType for ArbiterDevice<'a, BUS>
342-
where
343-
BUS: ErrorType,
344-
{
345-
type Error = BUS::Error;
346-
}
347-
348-
impl<'a, BUS, A> I2c<A> for ArbiterDevice<'a, BUS>
349-
where
350-
BUS: I2c<A>,
351-
A: AddressMode,
352-
{
353-
async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
354-
let mut bus = self.bus.access().await;
355-
bus.read(address, read).await
356-
}
357-
358-
async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
359-
let mut bus = self.bus.access().await;
360-
bus.write(address, write).await
361-
}
362-
363-
async fn write_read(
364-
&mut self,
365-
address: A,
366-
write: &[u8],
367-
read: &mut [u8],
368-
) -> Result<(), Self::Error> {
369-
let mut bus = self.bus.access().await;
370-
bus.write_read(address, write, read).await
371-
}
372-
373-
async fn transaction(
374-
&mut self,
375-
address: A,
376-
operations: &mut [Operation<'_>],
377-
) -> Result<(), Self::Error> {
378-
let mut bus = self.bus.access().await;
379-
bus.transaction(address, operations).await
380-
}
381-
}
382-
}
383-
384200
#[cfg(test)]
385201
mod tests {
386202
use super::*;

rtic-sync/src/arbiter/i2c.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//! I2C bus sharing using [`Arbiter`]
2+
//!
3+
//! An Example how to use it in RTIC application:
4+
//! ```text
5+
//! #[app(device = some_hal, peripherals = true, dispatchers = [TIM16])]
6+
//! mod app {
7+
//! use core::mem::MaybeUninit;
8+
//! use rtic_sync::{arbiter::{i2c::ArbiterDevice, Arbiter},
9+
//!
10+
//! #[shared]
11+
//! struct Shared {}
12+
//!
13+
//! #[local]
14+
//! struct Local {
15+
//! ens160: Ens160<ArbiterDevice<'static, I2c<'static, I2C1>>>,
16+
//! }
17+
//!
18+
//! #[init(local = [
19+
//! i2c_arbiter: MaybeUninit<Arbiter<I2c<'static, I2C1>>> = MaybeUninit::uninit(),
20+
//! ])]
21+
//! fn init(cx: init::Context) -> (Shared, Local) {
22+
//! let i2c = I2c::new(cx.device.I2C1);
23+
//! let i2c_arbiter = cx.local.i2c_arbiter.write(Arbiter::new(i2c));
24+
//! let ens160 = Ens160::new(ArbiterDevice::new(i2c_arbiter), 0x52);
25+
//!
26+
//! i2c_sensors::spawn(i2c_arbiter).ok();
27+
//!
28+
//! (Shared {}, Local { ens160 })
29+
//! }
30+
//!
31+
//! #[task(local = [ens160])]
32+
//! async fn i2c_sensors(cx: i2c_sensors::Context, i2c: &'static Arbiter<I2c<'static, I2C1>>) {
33+
//! use sensor::Asensor;
34+
//!
35+
//! loop {
36+
//! // Use scope to make sure I2C access is dropped.
37+
//! {
38+
//! // Read from sensor driver that wants to use I2C directly.
39+
//! let mut i2c = i2c.access().await;
40+
//! let status = Asensor::status(&mut i2c).await;
41+
//! }
42+
//!
43+
//! // Read ENS160 sensor.
44+
//! let eco2 = cx.local.ens160.eco2().await;
45+
//! }
46+
//! }
47+
//! }
48+
//! ```
49+
50+
use super::Arbiter;
51+
use embedded_hal::i2c::{AddressMode, ErrorType, Operation};
52+
use embedded_hal_async::i2c::I2c;
53+
54+
/// [`Arbiter`]-based shared bus implementation for I2C.
55+
pub struct ArbiterDevice<'a, BUS> {
56+
bus: &'a Arbiter<BUS>,
57+
}
58+
59+
impl<'a, BUS> ArbiterDevice<'a, BUS> {
60+
/// Create a new [`ArbiterDevice`] for I2C.
61+
pub fn new(bus: &'a Arbiter<BUS>) -> Self {
62+
Self { bus }
63+
}
64+
}
65+
66+
impl<'a, BUS> ErrorType for ArbiterDevice<'a, BUS>
67+
where
68+
BUS: ErrorType,
69+
{
70+
type Error = BUS::Error;
71+
}
72+
73+
impl<'a, BUS, A> I2c<A> for ArbiterDevice<'a, BUS>
74+
where
75+
BUS: I2c<A>,
76+
A: AddressMode,
77+
{
78+
async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> {
79+
let mut bus = self.bus.access().await;
80+
bus.read(address, read).await
81+
}
82+
83+
async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
84+
let mut bus = self.bus.access().await;
85+
bus.write(address, write).await
86+
}
87+
88+
async fn write_read(
89+
&mut self,
90+
address: A,
91+
write: &[u8],
92+
read: &mut [u8],
93+
) -> Result<(), Self::Error> {
94+
let mut bus = self.bus.access().await;
95+
bus.write_read(address, write, read).await
96+
}
97+
98+
async fn transaction(
99+
&mut self,
100+
address: A,
101+
operations: &mut [Operation<'_>],
102+
) -> Result<(), Self::Error> {
103+
let mut bus = self.bus.access().await;
104+
bus.transaction(address, operations).await
105+
}
106+
}

0 commit comments

Comments
 (0)