use core::marker::PhantomData;
pub use crate::traits::wg::spi::{
FullDuplex,
Mode,
Phase,
Polarity,
};
use crate::typestates::pin::{
flexcomm::{
Spi,
SpiPins,
ChipSelect,
},
PinId,
};
use crate::time::{
Hertz,
};
pub mod prelude {
pub use super::SpiMaster;
pub use super::Error as SpiError;
pub use super::Result as SpiResult;
}
#[derive(Debug)]
pub enum Error {
Overrun,
ModeFault,
Crc,
#[doc(hidden)]
_Extensible,
}
pub type Result<T> = nb::Result<T, Error>;
pub struct SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
where
SCK: PinId,
MOSI: PinId,
MISO: PinId,
CS: PinId,
SPI: Spi,
PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
{
spi: SPI,
pins: PINS,
_sck: PhantomData<SCK>,
_mosi: PhantomData<MOSI>,
_miso: PhantomData<MISO>,
_cs: PhantomData<CS>,
cs: ChipSelect,
}
impl<SCK, MOSI, MISO, CS, SPI, PINS> SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
where
SCK: PinId,
MOSI: PinId,
MISO: PinId,
CS: PinId,
SPI: Spi,
PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
{
pub fn new<Speed: Into<Hertz>>(spi: SPI, pins: PINS, speed: Speed, mode: Mode) -> Self {
let speed: Hertz = speed.into();
let speed: u32 = speed.0;
while spi.stat.read().mstidle().bit_is_clear() { continue; }
spi.fifocfg.modify(|_, w| w
.enabletx().disabled()
.enablerx().disabled()
);
spi.cfg.modify(|_, w| w
.enable().disabled()
.master().master_mode()
.lsbf().standard()
.cpha().bit(mode.phase == Phase::CaptureOnSecondTransition)
.cpol().bit(mode.polarity == Polarity::IdleHigh)
.loop_().disabled()
);
let div: u32 = 12_000_000 / speed - 1;
debug_assert!(div <= 0xFFFF);
spi.div.modify(|_, w| unsafe { w.divval().bits(div as u16) } );
spi.fifocfg.modify(|_, w| w
.enabletx().enabled()
.enablerx().enabled()
);
spi.cfg.modify(|_, w| w
.enable().enabled()
);
Self {
spi,
pins,
_sck: PhantomData,
_mosi: PhantomData,
_miso: PhantomData,
_cs: PhantomData,
cs: PINS::CS,
}
}
pub fn release(self) -> (SPI, PINS) {
(self.spi, self.pins)
}
fn return_on_error(&self) -> Result<()> {
Ok(())
}
}
impl<SCK, MOSI, MISO, CS, SPI, PINS> FullDuplex<u8> for SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
where
SCK: PinId,
MOSI: PinId,
MISO: PinId,
CS: PinId,
SPI: Spi,
PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
{
type Error = Error;
fn read(&mut self) -> Result<u8> {
if self.spi.fifostat.read().rxnotempty().bit_is_set() {
let byte = self.spi.fiford.read().rxdata().bits();
Ok(byte as u8)
} else {
Err(nb::Error::WouldBlock)
}
}
fn send(&mut self, byte: u8) -> Result<()> {
self.return_on_error()?;
if self.spi.fifostat.read().txnotfull().bit_is_set() {
use ChipSelect::*;
match self.cs {
Chip0 => {
self.spi.fifowr.write(|w| unsafe { w
.len().bits(7)
.txssel0_n().asserted()
.txdata().bits(byte as u16)
});
},
Chip1 => {
self.spi.fifowr.write(|w| unsafe { w
.len().bits(7)
.txssel1_n().asserted()
.txdata().bits(byte as u16)
});
},
Chip2 => {
self.spi.fifowr.write(|w| unsafe { w
.len().bits(7)
.txssel2_n().asserted()
.txdata().bits(byte as u16)
});
},
Chip3 => {
self.spi.fifowr.write(|w| unsafe { w
.len().bits(7)
.txssel3_n().asserted()
.txdata().bits(byte as u16)
});
},
NoChips => {
self.spi.fifowr.write(|w| unsafe { w
.len().bits(7)
.txdata().bits(byte as u16)
});
},
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<SCK, MOSI, MISO, CS, SPI, PINS> crate::traits::wg::blocking::spi::transfer::Default<u8>
for
SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
where
SCK: PinId,
MOSI: PinId,
MISO: PinId,
CS: PinId,
SPI: Spi,
PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
{}
impl<SCK, MOSI, MISO, CS, SPI, PINS> crate::traits::wg::blocking::spi::write::Default<u8>
for
SpiMaster<SCK, MOSI, MISO, CS, SPI, PINS>
where
SCK: PinId,
MOSI: PinId,
MISO: PinId,
CS: PinId,
SPI: Spi,
PINS: SpiPins<SCK, MOSI, MISO, CS, SPI>,
{}