1pub use embedded_hal::spi::{MODE_0, MODE_1, MODE_2, MODE_3};
17
18use embedded_hal::digital::v2::{InputPin, OutputPin};
19use embedded_hal::spi::{FullDuplex, Mode, Polarity};
20use embedded_hal::timer::{CountDown, Periodic};
21use nb::block;
22
23#[derive(Debug)]
25pub enum Error<E> {
26 Bus(E),
28 NoData,
30}
31
32#[derive(Debug)]
34pub enum BitOrder {
35 MSBFirst,
37 LSBFirst,
39}
40
41impl Default for BitOrder {
42 fn default() -> Self {
44 BitOrder::MSBFirst
45 }
46}
47
48pub struct SPI<Miso, Mosi, Sck, Timer>
51where
52 Miso: InputPin,
53 Mosi: OutputPin,
54 Sck: OutputPin,
55 Timer: CountDown + Periodic,
56{
57 mode: Mode,
58 miso: Miso,
59 mosi: Mosi,
60 sck: Sck,
61 timer: Timer,
62 read_val: Option<u8>,
63 bit_order: BitOrder,
64}
65
66impl<Miso, Mosi, Sck, Timer, E> SPI<Miso, Mosi, Sck, Timer>
67where
68 Miso: InputPin<Error = E>,
69 Mosi: OutputPin<Error = E>,
70 Sck: OutputPin<Error = E>,
71 Timer: CountDown + Periodic,
72{
73 pub fn new(mode: Mode, miso: Miso, mosi: Mosi, sck: Sck, timer: Timer) -> Self {
75 let mut spi = SPI {
76 mode,
77 miso,
78 mosi,
79 sck,
80 timer,
81 read_val: None,
82 bit_order: BitOrder::default(),
83 };
84
85 match mode.polarity {
86 Polarity::IdleLow => spi.sck.set_low(),
87 Polarity::IdleHigh => spi.sck.set_high(),
88 }
89 .unwrap_or(());
90
91 spi
92 }
93
94 pub fn set_bit_order(&mut self, order: BitOrder) {
96 self.bit_order = order;
97 }
98
99 pub fn access_timer<F>(&mut self, f: F)
115 where
116 F: FnOnce(Timer) -> Timer,
117 {
118 let timer = unsafe { core::mem::zeroed() };
121 let timer = core::mem::replace(&mut self.timer, timer);
123 self.timer = f(timer);
125 }
126
127 fn read_bit(&mut self) -> nb::Result<(), crate::spi::Error<E>> {
128 let is_miso_high = self.miso.is_high().map_err(Error::Bus)?;
129 let shifted_value = self.read_val.unwrap_or(0) << 1;
130 if is_miso_high {
131 self.read_val = Some(shifted_value | 1);
132 } else {
133 self.read_val = Some(shifted_value);
134 }
135 Ok(())
136 }
137
138 #[inline]
139 fn set_clk_high(&mut self) -> Result<(), crate::spi::Error<E>> {
140 self.sck.set_high().map_err(Error::Bus)
141 }
142
143 #[inline]
144 fn set_clk_low(&mut self) -> Result<(), crate::spi::Error<E>> {
145 self.sck.set_low().map_err(Error::Bus)
146 }
147
148 #[inline]
149 fn wait_for_timer(&mut self) {
150 block!(self.timer.wait()).ok();
151 }
152}
153
154impl<Miso, Mosi, Sck, Timer, E> FullDuplex<u8> for SPI<Miso, Mosi, Sck, Timer>
155where
156 Miso: InputPin<Error = E>,
157 Mosi: OutputPin<Error = E>,
158 Sck: OutputPin<Error = E>,
159 Timer: CountDown + Periodic,
160{
161 type Error = crate::spi::Error<E>;
162
163 #[inline]
164 fn read(&mut self) -> nb::Result<u8, Self::Error> {
165 match self.read_val {
166 Some(val) => Ok(val),
167 None => Err(nb::Error::Other(crate::spi::Error::NoData)),
168 }
169 }
170
171 fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
172 for bit_offset in 0..8 {
173 let out_bit = match self.bit_order {
174 BitOrder::MSBFirst => (byte >> (7 - bit_offset)) & 0b1,
175 BitOrder::LSBFirst => (byte >> bit_offset) & 0b1,
176 };
177
178 if out_bit == 1 {
179 self.mosi.set_high().map_err(Error::Bus)?;
180 } else {
181 self.mosi.set_low().map_err(Error::Bus)?;
182 }
183
184 match self.mode {
185 MODE_0 => {
186 self.wait_for_timer();
187 self.set_clk_high()?;
188 self.read_bit()?;
189 self.wait_for_timer();
190 self.set_clk_low()?;
191 }
192 MODE_1 => {
193 self.set_clk_high()?;
194 self.wait_for_timer();
195 self.read_bit()?;
196 self.set_clk_low()?;
197 self.wait_for_timer();
198 }
199 MODE_2 => {
200 self.wait_for_timer();
201 self.set_clk_low()?;
202 self.read_bit()?;
203 self.wait_for_timer();
204 self.set_clk_high()?;
205 }
206 MODE_3 => {
207 self.set_clk_low()?;
208 self.wait_for_timer();
209 self.read_bit()?;
210 self.set_clk_high()?;
211 self.wait_for_timer();
212 }
213 }
214 }
215
216 Ok(())
217 }
218}
219
220impl<Miso, Mosi, Sck, Timer, E> embedded_hal::blocking::spi::transfer::Default<u8>
221 for SPI<Miso, Mosi, Sck, Timer>
222where
223 Miso: InputPin<Error = E>,
224 Mosi: OutputPin<Error = E>,
225 Sck: OutputPin<Error = E>,
226 Timer: CountDown + Periodic,
227{
228}
229
230impl<Miso, Mosi, Sck, Timer, E> embedded_hal::blocking::spi::write::Default<u8>
231 for SPI<Miso, Mosi, Sck, Timer>
232where
233 Miso: InputPin<Error = E>,
234 Mosi: OutputPin<Error = E>,
235 Sck: OutputPin<Error = E>,
236 Timer: CountDown + Periodic,
237{
238}