embassy_embedded_hal/shared_bus/blocking/
spi.rs1use core::cell::RefCell;
21
22use embassy_sync::blocking_mutex::raw::RawMutex;
23use embassy_sync::blocking_mutex::Mutex;
24use embedded_hal_1::digital::OutputPin;
25use embedded_hal_1::spi::{self, Operation, SpiBus};
26
27use crate::shared_bus::SpiDeviceError;
28use crate::SetConfig;
29
30pub struct SpiDevice<'a, M: RawMutex, BUS, CS> {
32 bus: &'a Mutex<M, RefCell<BUS>>,
33 cs: CS,
34}
35
36impl<'a, M: RawMutex, BUS, CS> SpiDevice<'a, M, BUS, CS> {
37 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS) -> Self {
39 Self { bus, cs }
40 }
41}
42
43impl<'a, M: RawMutex, BUS, CS> spi::ErrorType for SpiDevice<'a, M, BUS, CS>
44where
45 BUS: spi::ErrorType,
46 CS: OutputPin,
47{
48 type Error = SpiDeviceError<BUS::Error, CS::Error>;
49}
50
51impl<BUS, M, CS, Word> embedded_hal_1::spi::SpiDevice<Word> for SpiDevice<'_, M, BUS, CS>
52where
53 M: RawMutex,
54 BUS: SpiBus<Word>,
55 CS: OutputPin,
56 Word: Copy + 'static,
57{
58 fn transaction(&mut self, operations: &mut [embedded_hal_1::spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
59 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
60 return Err(SpiDeviceError::DelayNotSupported);
61 }
62
63 self.bus.lock(|bus| {
64 let mut bus = bus.borrow_mut();
65 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
66
67 let op_res = operations.iter_mut().try_for_each(|op| match op {
68 Operation::Read(buf) => bus.read(buf),
69 Operation::Write(buf) => bus.write(buf),
70 Operation::Transfer(read, write) => bus.transfer(read, write),
71 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
72 #[cfg(not(feature = "time"))]
73 Operation::DelayNs(_) => unreachable!(),
74 #[cfg(feature = "time")]
75 Operation::DelayNs(ns) => {
76 embassy_time::block_for(embassy_time::Duration::from_nanos(*ns as _));
77 Ok(())
78 }
79 });
80
81 let flush_res = bus.flush();
83 let cs_res = self.cs.set_high();
84
85 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
86 flush_res.map_err(SpiDeviceError::Spi)?;
87 cs_res.map_err(SpiDeviceError::Cs)?;
88
89 Ok(op_res)
90 })
91 }
92}
93
94pub struct SpiDeviceWithConfig<'a, M: RawMutex, BUS: SetConfig, CS> {
100 bus: &'a Mutex<M, RefCell<BUS>>,
101 cs: CS,
102 config: BUS::Config,
103}
104
105impl<'a, M: RawMutex, BUS: SetConfig, CS> SpiDeviceWithConfig<'a, M, BUS, CS> {
106 pub fn new(bus: &'a Mutex<M, RefCell<BUS>>, cs: CS, config: BUS::Config) -> Self {
108 Self { bus, cs, config }
109 }
110
111 pub fn set_config(&mut self, config: BUS::Config) {
113 self.config = config;
114 }
115}
116
117impl<'a, M, BUS, CS> spi::ErrorType for SpiDeviceWithConfig<'a, M, BUS, CS>
118where
119 M: RawMutex,
120 BUS: spi::ErrorType + SetConfig,
121 CS: OutputPin,
122{
123 type Error = SpiDeviceError<BUS::Error, CS::Error>;
124}
125
126impl<BUS, M, CS, Word> embedded_hal_1::spi::SpiDevice<Word> for SpiDeviceWithConfig<'_, M, BUS, CS>
127where
128 M: RawMutex,
129 BUS: SpiBus<Word> + SetConfig,
130 CS: OutputPin,
131 Word: Copy + 'static,
132{
133 fn transaction(&mut self, operations: &mut [embedded_hal_1::spi::Operation<'_, Word>]) -> Result<(), Self::Error> {
134 if cfg!(not(feature = "time")) && operations.iter().any(|op| matches!(op, Operation::DelayNs(_))) {
135 return Err(SpiDeviceError::DelayNotSupported);
136 }
137
138 self.bus.lock(|bus| {
139 let mut bus = bus.borrow_mut();
140 bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
141 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
142
143 let op_res = operations.iter_mut().try_for_each(|op| match op {
144 Operation::Read(buf) => bus.read(buf),
145 Operation::Write(buf) => bus.write(buf),
146 Operation::Transfer(read, write) => bus.transfer(read, write),
147 Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
148 #[cfg(not(feature = "time"))]
149 Operation::DelayNs(_) => unreachable!(),
150 #[cfg(feature = "time")]
151 Operation::DelayNs(ns) => {
152 embassy_time::block_for(embassy_time::Duration::from_nanos(*ns as _));
153 Ok(())
154 }
155 });
156
157 let flush_res = bus.flush();
159 let cs_res = self.cs.set_high();
160
161 let op_res = op_res.map_err(SpiDeviceError::Spi)?;
162 flush_res.map_err(SpiDeviceError::Spi)?;
163 cs_res.map_err(SpiDeviceError::Cs)?;
164 Ok(op_res)
165 })
166 }
167}