use core::{convert::Infallible, marker::PhantomData, ops::Deref};
use embedded_hal::spi::{self, Phase, Polarity};
use embedded_hal_0_2::{blocking::spi as blocking_spi02, spi as spi02};
use embedded_hal_nb::spi::FullDuplex;
use fugit::{HertzU32, RateExtU32};
use crate::{
dma::{EndlessReadTarget, EndlessWriteTarget, ReadTarget, WriteTarget},
pac::{self, dma::ch::ch_ctrl_trig::TREQ_SEL_A, RESETS},
resets::SubsystemReset,
typelevel::Sealed,
};
mod pins;
pub use pins::*;
impl From<spi::Mode> for FrameFormat {
fn from(f: spi::Mode) -> Self {
Self::MotorolaSpi(f)
}
}
impl From<&spi::Mode> for FrameFormat {
fn from(f: &spi::Mode) -> Self {
Self::MotorolaSpi(*f)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum FrameFormat {
MotorolaSpi(spi::Mode),
TexasInstrumentsSynchronousSerial,
NationalSemiconductorMicrowire,
}
impl From<&embedded_hal_0_2::spi::Mode> for FrameFormat {
fn from(f: &embedded_hal_0_2::spi::Mode) -> Self {
let embedded_hal_0_2::spi::Mode { polarity, phase } = f;
match (polarity, phase) {
(spi02::Polarity::IdleLow, spi02::Phase::CaptureOnFirstTransition) => {
FrameFormat::MotorolaSpi(spi::MODE_0)
}
(spi02::Polarity::IdleLow, spi02::Phase::CaptureOnSecondTransition) => {
FrameFormat::MotorolaSpi(spi::MODE_1)
}
(spi02::Polarity::IdleHigh, spi02::Phase::CaptureOnFirstTransition) => {
FrameFormat::MotorolaSpi(spi::MODE_2)
}
(spi02::Polarity::IdleHigh, spi02::Phase::CaptureOnSecondTransition) => {
FrameFormat::MotorolaSpi(spi::MODE_3)
}
}
}
}
impl From<embedded_hal_0_2::spi::Mode> for FrameFormat {
fn from(f: embedded_hal_0_2::spi::Mode) -> Self {
From::from(&f)
}
}
pub trait State: Sealed {}
pub struct Disabled {
__private: (),
}
pub struct Enabled {
__private: (),
}
impl State for Disabled {}
impl Sealed for Disabled {}
impl State for Enabled {}
impl Sealed for Enabled {}
pub trait SpiDevice: Deref<Target = pac::spi0::RegisterBlock> + SubsystemReset + Sealed {
const ID: usize;
fn tx_dreq() -> u8;
fn rx_dreq() -> u8;
}
impl Sealed for pac::SPI0 {}
impl SpiDevice for pac::SPI0 {
const ID: usize = 0;
fn tx_dreq() -> u8 {
TREQ_SEL_A::SPI0_TX.into()
}
fn rx_dreq() -> u8 {
TREQ_SEL_A::SPI0_RX.into()
}
}
impl Sealed for pac::SPI1 {}
impl SpiDevice for pac::SPI1 {
const ID: usize = 1;
fn tx_dreq() -> u8 {
TREQ_SEL_A::SPI1_TX.into()
}
fn rx_dreq() -> u8 {
TREQ_SEL_A::SPI1_RX.into()
}
}
pub trait DataSize: Sealed {}
impl DataSize for u8 {}
impl DataSize for u16 {}
impl Sealed for u8 {}
impl Sealed for u16 {}
pub struct Spi<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8 = 8u8> {
device: D,
pins: P,
state: PhantomData<S>,
}
impl<S: State, D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<S, D, P, DS> {
fn transition<To: State>(self, _: To) -> Spi<To, D, P, DS> {
Spi {
device: self.device,
pins: self.pins,
state: PhantomData,
}
}
pub fn free(self) -> (D, P) {
(self.device, self.pins)
}
pub fn set_baudrate<F: Into<HertzU32>, B: Into<HertzU32>>(
&mut self,
peri_frequency: F,
baudrate: B,
) -> HertzU32 {
let freq_in = peri_frequency.into().to_Hz();
let baudrate = baudrate.into().to_Hz();
let mut prescale: u8 = u8::MAX;
let mut postdiv: u8 = 0;
for prescale_option in (2u32..=254).step_by(2) {
if freq_in < ((prescale_option + 2) * 256).saturating_mul(baudrate) {
prescale = prescale_option as u8;
break;
}
}
debug_assert_ne!(prescale, u8::MAX);
for postdiv_option in (1..=255u8).rev() {
if freq_in / (prescale as u32 * postdiv_option as u32) > baudrate {
postdiv = postdiv_option;
break;
}
}
self.device
.sspcpsr()
.write(|w| unsafe { w.cpsdvsr().bits(prescale) });
self.device
.sspcr0()
.modify(|_, w| unsafe { w.scr().bits(postdiv) });
(freq_in / (prescale as u32 * (1 + postdiv as u32))).Hz()
}
pub fn set_format(&mut self, frame_format: FrameFormat) {
self.device.sspcr0().modify(|_, w| unsafe {
w.dss().bits(DS - 1).frf().bits(match &frame_format {
FrameFormat::MotorolaSpi(_) => 0x00,
FrameFormat::TexasInstrumentsSynchronousSerial => 0x01,
FrameFormat::NationalSemiconductorMicrowire => 0x10,
});
if let FrameFormat::MotorolaSpi(ref mode) = frame_format {
w.spo()
.bit(mode.polarity == Polarity::IdleHigh)
.sph()
.bit(mode.phase == Phase::CaptureOnSecondTransition);
}
w
});
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Disabled, D, P, DS> {
pub fn new(device: D, pins: P) -> Spi<Disabled, D, P, DS> {
Spi {
device,
pins,
state: PhantomData,
}
}
fn set_slave(&mut self, slave: bool) {
if slave {
self.device.sspcr1().modify(|_, w| w.ms().set_bit());
} else {
self.device.sspcr1().modify(|_, w| w.ms().clear_bit());
}
}
fn init_spi<F: Into<HertzU32>, B: Into<HertzU32>>(
mut self,
resets: &mut RESETS,
peri_frequency: F,
baudrate: B,
frame_format: FrameFormat,
slave: bool,
) -> Spi<Enabled, D, P, DS> {
self.device.reset_bring_down(resets);
self.device.reset_bring_up(resets);
self.set_baudrate(peri_frequency, baudrate);
self.set_format(frame_format);
self.set_slave(slave);
self.device
.sspdmacr()
.modify(|_, w| w.txdmae().set_bit().rxdmae().set_bit());
self.device.sspcr1().modify(|_, w| w.sse().set_bit());
self.transition(Enabled { __private: () })
}
pub fn init<F: Into<HertzU32>, B: Into<HertzU32>, M: Into<FrameFormat>>(
self,
resets: &mut RESETS,
peri_frequency: F,
baudrate: B,
frame_format: M,
) -> Spi<Enabled, D, P, DS> {
self.init_spi(resets, peri_frequency, baudrate, frame_format.into(), false)
}
pub fn init_slave<M: Into<FrameFormat>>(
self,
resets: &mut RESETS,
frame_format: M,
) -> Spi<Enabled, D, P, DS> {
self.init_spi(
resets,
1000u32.Hz(),
1000u32.Hz(),
frame_format.into(),
true,
)
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>, const DS: u8> Spi<Enabled, D, P, DS> {
fn is_writable(&self) -> bool {
self.device.sspsr().read().tnf().bit_is_set()
}
fn is_readable(&self) -> bool {
self.device.sspsr().read().rne().bit_is_set()
}
pub fn is_busy(&self) -> bool {
self.device.sspsr().read().bsy().bit_is_set()
}
pub fn disable(self) -> Spi<Disabled, D, P, DS> {
self.device.sspcr1().modify(|_, w| w.sse().clear_bit());
self.transition(Disabled { __private: () })
}
}
macro_rules! impl_write {
($type:ident, [$($nr:expr),+]) => {
$(
impl<D: SpiDevice, P: ValidSpiPinout<D>> spi02::FullDuplex<$type> for Spi<Enabled, D, P, $nr> {
type Error = Infallible;
fn read(&mut self) -> Result<$type, nb::Error<Infallible>> {
if !self.is_readable() {
return Err(nb::Error::WouldBlock);
}
Ok(self.device.sspdr().read().data().bits() as $type)
}
fn send(&mut self, word: $type) -> Result<(), nb::Error<Infallible>> {
if !self.is_writable() {
return Err(nb::Error::WouldBlock);
}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(word as u16) });
Ok(())
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> blocking_spi02::write::Default<$type> for Spi<Enabled, D, P, $nr> {}
impl<D: SpiDevice, P: ValidSpiPinout<D>> blocking_spi02::transfer::Default<$type> for Spi<Enabled, D, P, $nr> {}
impl<D: SpiDevice, P: ValidSpiPinout<D>> blocking_spi02::write_iter::Default<$type> for Spi<Enabled, D, P, $nr> {}
impl<D: SpiDevice, P: ValidSpiPinout<D>> spi::ErrorType for Spi<Enabled, D, P, $nr> {
type Error = Infallible;
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> spi::SpiBus<$type> for Spi<Enabled, D, P, $nr> {
fn read(&mut self, words: &mut [$type]) -> Result<(), Self::Error> {
for word in words.iter_mut() {
while !self.is_writable() {}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(0) });
while !self.is_readable() {}
*word = self.device.sspdr().read().data().bits() as $type;
}
Ok(())
}
fn write(&mut self, words: &[$type]) -> Result<(), Self::Error> {
for word in words.iter() {
while !self.is_writable() {}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(*word as u16) });
while !self.is_readable() {}
let _ = self.device.sspdr().read().data().bits();
}
Ok(())
}
fn transfer(&mut self, read: &mut [$type], write: &[$type]) -> Result<(), Self::Error>{
let len = read.len().max(write.len());
for i in 0..len {
let wb = write.get(i).copied().unwrap_or(0);
while !self.is_writable() {}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(wb as u16) });
while !self.is_readable() {}
let rb = self.device.sspdr().read().data().bits() as $type;
if let Some(r) = read.get_mut(i) {
*r = rb;
}
}
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [$type]) -> Result<(), Self::Error>{
for word in words.iter_mut() {
while !self.is_writable() {}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(*word as u16) });
while !self.is_readable() {}
*word = self.device.sspdr().read().data().bits() as $type;
}
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
while self.is_busy() {}
Ok(())
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> FullDuplex<$type> for Spi<Enabled, D, P, $nr> {
fn read(&mut self) -> Result<$type, nb::Error<Infallible>> {
if !self.is_readable() {
return Err(nb::Error::WouldBlock);
}
Ok(self.device.sspdr().read().data().bits() as $type)
}
fn write(&mut self, word: $type) -> Result<(), nb::Error<Infallible>> {
if !self.is_writable() {
return Err(nb::Error::WouldBlock);
}
self.device
.sspdr()
.write(|w| unsafe { w.data().bits(word as u16) });
Ok(())
}
}
unsafe impl<D: SpiDevice, P: ValidSpiPinout<D>> ReadTarget for Spi<Enabled, D, P, $nr> {
type ReceivedWord = $type;
fn rx_treq() -> Option<u8> {
Some(D::rx_dreq())
}
fn rx_address_count(&self) -> (u32, u32) {
(
self.device.sspdr().as_ptr() as u32,
u32::MAX,
)
}
fn rx_increment(&self) -> bool {
false
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> EndlessReadTarget for Spi<Enabled, D, P, $nr> {}
unsafe impl<D: SpiDevice, P: ValidSpiPinout<D>> WriteTarget for Spi<Enabled, D, P, $nr> {
type TransmittedWord = $type;
fn tx_treq() -> Option<u8> {
Some(D::tx_dreq())
}
fn tx_address_count(&mut self) -> (u32, u32) {
(
self.device.sspdr().as_ptr() as u32,
u32::MAX,
)
}
fn tx_increment(&self) -> bool {
false
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> EndlessWriteTarget for Spi<Enabled, D, P, $nr> {}
)+
};
}
impl_write!(u8, [4, 5, 6, 7, 8]);
impl_write!(u16, [9, 10, 11, 12, 13, 14, 15, 16]);