1use crate::port;
3use core::marker::PhantomData;
4use embedded_hal::spi::{self, SpiBus};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum SerialClockRate {
28 OscfOver2 = 1,
29 OscfOver4 = 2,
30 OscfOver8 = 3,
31 OscfOver16 = 4,
32 OscfOver32 = 5,
33 OscfOver64 = 6,
34 OscfOver128 = 7,
35}
36
37impl SerialClockRate {
38 pub fn into_divider(self) -> u8 {
39 2u8.pow(self as u32)
40 }
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub enum DataOrder {
46 MostSignificantFirst,
47 LeastSignificantFirst,
48}
49
50#[derive(Clone, PartialEq, Eq)]
56pub struct Settings {
57 pub data_order: DataOrder,
58 pub clock: SerialClockRate,
59 pub mode: spi::Mode,
60}
61
62impl Default for Settings {
63 fn default() -> Self {
64 Settings {
65 data_order: DataOrder::MostSignificantFirst,
66 clock: SerialClockRate::OscfOver4,
67 mode: spi::MODE_1,
68 }
69 }
70}
71
72pub trait SpiOps<H, SCLK, MOSI, MISO, CS> {
78 fn raw_setup(&mut self, settings: &Settings);
80 fn raw_release(&mut self);
82
83 fn raw_check_iflag(&self) -> bool;
87 fn raw_read(&self) -> u8;
89 fn raw_write(&mut self, byte: u8);
92 fn raw_transaction(&mut self, byte: u8) -> u8;
94}
95
96pub struct ChipSelectPin<CSPIN>(port::Pin<port::mode::Output, CSPIN>);
103
104impl<CSPIN: port::PinOps> ChipSelectPin<CSPIN> {
105 pub unsafe fn into_pin_unchecked(self) -> port::Pin<port::mode::Output, CSPIN> {
113 self.0
114 }
115
116 pub unsafe fn from_pin(pin: port::Pin<port::mode::Output, CSPIN>) -> Self {
121 Self(pin)
122 }
123}
124
125impl<CSPIN: port::PinOps> embedded_hal_v0::digital::v2::OutputPin for ChipSelectPin<CSPIN> {
126 type Error = core::convert::Infallible;
127 fn set_low(&mut self) -> Result<(), Self::Error> {
128 self.0.set_low();
129 Ok(())
130 }
131 fn set_high(&mut self) -> Result<(), Self::Error> {
132 self.0.set_high();
133 Ok(())
134 }
135}
136
137impl<CSPIN: port::PinOps> embedded_hal_v0::digital::v2::StatefulOutputPin for ChipSelectPin<CSPIN> {
138 fn is_set_low(&self) -> Result<bool, Self::Error> {
139 Ok(self.0.is_set_low())
140 }
141 fn is_set_high(&self) -> Result<bool, Self::Error> {
142 Ok(self.0.is_set_high())
143 }
144}
145
146impl<CSPIN: port::PinOps> embedded_hal_v0::digital::v2::ToggleableOutputPin
147 for ChipSelectPin<CSPIN>
148{
149 type Error = core::convert::Infallible;
150 fn toggle(&mut self) -> Result<(), Self::Error> {
151 self.0.toggle();
152 Ok(())
153 }
154}
155
156impl<CSPIN: port::PinOps> embedded_hal::digital::ErrorType for ChipSelectPin<CSPIN> {
157 type Error = core::convert::Infallible;
158}
159
160impl<CSPIN: port::PinOps> embedded_hal::digital::OutputPin for ChipSelectPin<CSPIN> {
161 fn set_high(&mut self) -> Result<(), Self::Error> {
162 self.0.set_high();
163 Ok(())
164 }
165
166 fn set_low(&mut self) -> Result<(), Self::Error> {
167 self.0.set_low();
168 Ok(())
169 }
170}
171
172impl<CSPIN: port::PinOps> embedded_hal::digital::StatefulOutputPin for ChipSelectPin<CSPIN> {
173 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
174 Ok(self.0.is_set_high())
175 }
176
177 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
178 Ok(self.0.is_set_low())
179 }
180}
181
182pub struct Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> {
194 p: SPI,
195 sclk: port::Pin<port::mode::Output, SCLKPIN>,
196 mosi: port::Pin<port::mode::Output, MOSIPIN>,
197 miso: port::Pin<port::mode::Input, MISOPIN>,
198 write_in_progress: bool,
199 _cs: PhantomData<CSPIN>,
200 _h: PhantomData<H>,
201}
202
203impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
204where
205 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
206 SCLKPIN: port::PinOps,
207 MOSIPIN: port::PinOps,
208 MISOPIN: port::PinOps,
209 CSPIN: port::PinOps,
210{
211 pub fn new(
219 p: SPI,
220 sclk: port::Pin<port::mode::Output, SCLKPIN>,
221 mosi: port::Pin<port::mode::Output, MOSIPIN>,
222 miso: port::Pin<port::mode::Input<port::mode::PullUp>, MISOPIN>,
223 cs: port::Pin<port::mode::Output, CSPIN>,
224 settings: Settings,
225 ) -> (Self, ChipSelectPin<CSPIN>) {
226 let mut spi = Self {
227 p,
228 sclk,
229 mosi,
230 miso: miso.forget_imode(),
231 write_in_progress: false,
232 _cs: PhantomData,
233 _h: PhantomData,
234 };
235 spi.p.raw_setup(&settings);
236 (spi, ChipSelectPin(cs))
237 }
238
239 pub fn with_external_pullup(
246 p: SPI,
247 sclk: port::Pin<port::mode::Output, SCLKPIN>,
248 mosi: port::Pin<port::mode::Output, MOSIPIN>,
249 miso: port::Pin<port::mode::Input<port::mode::Floating>, MISOPIN>,
250 cs: port::Pin<port::mode::Output, CSPIN>,
251 settings: Settings,
252 ) -> (Self, ChipSelectPin<CSPIN>) {
253 let mut spi = Self {
254 p,
255 sclk,
256 mosi,
257 miso: miso.forget_imode(),
258 write_in_progress: false,
259 _cs: PhantomData,
260 _h: PhantomData,
261 };
262 spi.p.raw_setup(&settings);
263 (spi, ChipSelectPin(cs))
264 }
265
266 pub fn reconfigure(&mut self, settings: Settings) -> nb::Result<(), core::convert::Infallible> {
268 self.flush()?;
270 self.p.raw_setup(&settings);
271 Ok(())
272 }
273
274 pub fn release(
278 mut self,
279 cs: ChipSelectPin<CSPIN>,
280 ) -> (
281 SPI,
282 port::Pin<port::mode::Output, SCLKPIN>,
283 port::Pin<port::mode::Output, MOSIPIN>,
284 port::Pin<port::mode::Input, MISOPIN>,
285 port::Pin<port::mode::Output, CSPIN>,
286 ) {
287 self.p.raw_release();
288 (self.p, self.sclk, self.mosi, self.miso, cs.0)
289 }
290
291 fn flush(&mut self) -> nb::Result<(), core::convert::Infallible> {
292 if self.write_in_progress {
293 if self.p.raw_check_iflag() {
294 self.write_in_progress = false;
295 } else {
296 return Err(nb::Error::WouldBlock);
297 }
298 }
299 Ok(())
300 }
301
302 fn receive(&mut self) -> u8 {
303 self.p.raw_read()
304 }
305
306 fn write(&mut self, byte: u8) {
307 self.write_in_progress = true;
308 self.p.raw_write(byte);
309 }
310}
311
312impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal_v0::spi::FullDuplex<u8>
316 for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
317where
318 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
319 SCLKPIN: port::PinOps,
320 MOSIPIN: port::PinOps,
321 MISOPIN: port::PinOps,
322 CSPIN: port::PinOps,
323{
324 type Error = core::convert::Infallible;
325
326 fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
328 self.flush()?;
329 self.write(byte);
330 Ok(())
331 }
332
333 fn read(&mut self) -> nb::Result<u8, Self::Error> {
335 self.flush()?;
336 Ok(self.receive())
337 }
338}
339
340impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal::spi::ErrorType
341 for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
342where
343 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
344 SCLKPIN: port::PinOps,
345 MOSIPIN: port::PinOps,
346 MISOPIN: port::PinOps,
347 CSPIN: port::PinOps,
348{
349 type Error = core::convert::Infallible;
350}
351
352impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> SpiBus
353 for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
354where
355 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
356 SCLKPIN: port::PinOps,
357 MOSIPIN: port::PinOps,
358 MISOPIN: port::PinOps,
359 CSPIN: port::PinOps,
360{
361 fn flush(&mut self) -> Result<(), Self::Error> {
362 if self.write_in_progress {
363 while !self.p.raw_check_iflag() {}
364 self.write_in_progress = false;
365 }
366
367 Ok(())
368 }
369 fn read(&mut self, read: &mut [u8]) -> Result<(), Self::Error> {
370 SpiBus::flush(self)?;
373
374 for b in read.iter_mut() {
375 *b = self.p.raw_transaction(0x00);
377 }
378
379 Ok(())
380 }
381
382 fn write(&mut self, write: &[u8]) -> Result<(), Self::Error> {
383 SpiBus::flush(self)?;
386
387 for b in write.iter() {
388 self.p.raw_transaction(*b);
389 }
390
391 Ok(())
392 }
393
394 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
395 SpiBus::flush(self)?;
398
399 let longest = read.len().max(write.len());
400 for i in 0..longest {
401 let r = self.p.raw_transaction(*write.get(i).unwrap_or(&0x00));
402 if i < read.len() {
403 read[i] = r;
404 }
405 }
406
407 Ok(())
408 }
409
410 fn transfer_in_place(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
411 SpiBus::flush(self)?;
414
415 for b in buffer.iter_mut() {
416 *b = self.p.raw_transaction(*b)
417 }
418
419 Ok(())
420 }
421}
422
423impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal_v0::blocking::spi::transfer::Default<u8>
425 for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
426where
427 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
428 SCLKPIN: port::PinOps,
429 MOSIPIN: port::PinOps,
430 MISOPIN: port::PinOps,
431 CSPIN: port::PinOps,
432{
433}
434
435impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal_v0::blocking::spi::write::Default<u8>
437 for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
438where
439 SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
440 SCLKPIN: port::PinOps,
441 MOSIPIN: port::PinOps,
442 MISOPIN: port::PinOps,
443 CSPIN: port::PinOps,
444{
445}
446
447#[macro_export]
449macro_rules! impl_spi {
450 (
451 hal: $HAL:ty,
452 peripheral: $SPI:ty,
453 sclk: $sclkpin:ty,
454 mosi: $mosipin:ty,
455 miso: $misopin:ty,
456 cs: $cspin:ty,
457 ) => {
458 impl $crate::spi::SpiOps<$HAL, $sclkpin, $mosipin, $misopin, $cspin> for $SPI {
459 fn raw_setup(&mut self, settings: &Settings) {
460 use $crate::hal::spi;
461
462 self.spcr.write(|w| {
464 w.spe().set_bit();
466 w.mstr().set_bit();
468 match settings.data_order {
470 DataOrder::MostSignificantFirst => w.dord().clear_bit(),
471 DataOrder::LeastSignificantFirst => w.dord().set_bit(),
472 };
473 match settings.mode.polarity {
475 spi::Polarity::IdleHigh => w.cpol().set_bit(),
476 spi::Polarity::IdleLow => w.cpol().clear_bit(),
477 };
478 match settings.mode.phase {
480 spi::Phase::CaptureOnFirstTransition => w.cpha().clear_bit(),
481 spi::Phase::CaptureOnSecondTransition => w.cpha().set_bit(),
482 };
483 match settings.clock {
485 SerialClockRate::OscfOver2 => w.spr().fosc_4_2(),
486 SerialClockRate::OscfOver4 => w.spr().fosc_4_2(),
487 SerialClockRate::OscfOver8 => w.spr().fosc_16_8(),
488 SerialClockRate::OscfOver16 => w.spr().fosc_16_8(),
489 SerialClockRate::OscfOver32 => w.spr().fosc_64_32(),
490 SerialClockRate::OscfOver64 => w.spr().fosc_64_32(),
491 SerialClockRate::OscfOver128 => w.spr().fosc_128_64(),
492 }
493 });
494 self.spsr.write(|w| match settings.clock {
496 SerialClockRate::OscfOver2 => w.spi2x().set_bit(),
497 SerialClockRate::OscfOver4 => w.spi2x().clear_bit(),
498 SerialClockRate::OscfOver8 => w.spi2x().set_bit(),
499 SerialClockRate::OscfOver16 => w.spi2x().clear_bit(),
500 SerialClockRate::OscfOver32 => w.spi2x().set_bit(),
501 SerialClockRate::OscfOver64 => w.spi2x().clear_bit(),
502 SerialClockRate::OscfOver128 => w.spi2x().clear_bit(),
503 });
504 }
505
506 fn raw_release(&mut self) {
507 self.spcr.write(|w| w.spe().clear_bit());
508 }
509
510 fn raw_check_iflag(&self) -> bool {
511 self.spsr.read().spif().bit_is_set()
512 }
513
514 fn raw_read(&self) -> u8 {
515 self.spdr.read().bits()
516 }
517
518 fn raw_write(&mut self, byte: u8) {
519 self.spdr.write(|w| unsafe { w.bits(byte) });
520 }
521
522 fn raw_transaction(&mut self, byte: u8) -> u8 {
523 self.raw_write(byte);
524 while !self.raw_check_iflag() {}
525 self.raw_read()
526 }
527 }
528 };
529}