use crate::hal::spi;
use crate::{pac::SPI0, pac::SPI1, HALExt};
use core::marker::PhantomData;
use embedded_time::rate::*;
pub struct Spi<SPI, Disabled, Pins> {
peripheral: SPI,
_state: PhantomData<Disabled>,
_pins: PhantomData<Pins>,
}
pub struct Disabled;
pub struct Enabled<T> {
_state: PhantomData<T>,
}
pub struct DontCare;
pub struct Controller;
pub struct Peripheral;
pub struct DefaultPins;
pub struct AltPins;
use crate::gpio::gpioa::{PTB2, PTB3, PTB4, PTB5};
use crate::gpio::gpiob::{PTE0, PTE1, PTE2, PTE3};
impl HALExt for SPI0 {
type T = Spi<SPI0, Disabled, DefaultPins>;
fn split(self) -> Self::T {
Spi {
peripheral: self,
_state: PhantomData,
_pins: PhantomData,
}
}
}
use crate::gpio::gpioa::{PTD0, PTD1, PTD2, PTD3};
impl HALExt for SPI1 {
type T = Spi<SPI1, Disabled, DefaultPins>;
fn split(self) -> Spi<SPI1, Disabled, DefaultPins> {
Spi {
peripheral: self,
_state: PhantomData,
_pins: PhantomData,
}
}
}
impl Spi<SPI0, Disabled, DefaultPins> {
pub fn into_alt_pins(self) -> Spi<SPI0, Disabled, AltPins> {
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
pub fn enable_as_controller<T2, T3, T4, T5>(
self,
clock: PTB2<T2>,
sdo: PTB3<T3>,
sdi: PTB4<T4>,
cs: Option<PTB5<T5>>,
manage_cs: bool,
mode: spi::Mode,
) -> Spi<SPI0, Controller, DefaultPins> {
let sim = unsafe { &(*pac::SIM::ptr()) };
sim.pinsel.modify(|_, w| w.spi0ps()._0());
sim.scgc.modify(|_, w| w.spi0()._1());
self.enable_spi(true, false, cs.is_some(), manage_cs, mode);
let _ = (clock, sdo, sdi, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
pub fn enable_as_peripheral<T2, T3, T4, T5>(
self,
clock: PTB2<T2>,
sdi: PTB3<T3>,
sdo: PTB4<T4>,
cs: PTB5<T5>,
mode: spi::Mode,
) -> Spi<SPI0, Enabled<Peripheral>, DefaultPins> {
let sim = unsafe { &(*pac::SIM::ptr()) };
sim.pinsel.modify(|_, w| w.spi0ps()._0());
sim.scgc.modify(|_, w| w.spi0()._1());
self.enable_spi(false, false, true, true, mode);
let _ = (clock, sdo, sdi, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
}
impl Spi<SPI0, Disabled, AltPins> {
pub fn enable_as_controller<T0, T1, T2, T3>(
self,
clock: PTE0<T0>,
sdo: PTE1<T1>,
sdi: PTE2<T2>,
cs: Option<PTE3<T3>>,
manage_cs: bool,
mode: spi::Mode,
) -> Spi<SPI0, Controller, AltPins> {
let sim = unsafe { &(*pac::SIM::ptr()) };
sim.pinsel.modify(|_, w| w.spi0ps()._1());
sim.scgc.modify(|_, w| w.spi0()._1());
self.enable_spi(true, false, cs.is_some(), manage_cs, mode);
let _ = (clock, sdo, sdi, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
pub fn enable_as_peripheral<T0, T1, T2, T3>(
self,
clock: PTE0<T0>,
sdi: PTE1<T1>,
sdo: PTE2<T2>,
cs: PTE3<T3>,
mode: spi::Mode,
) -> Spi<SPI0, Enabled<Peripheral>, AltPins> {
let sim = unsafe { &(*pac::SIM::ptr()) };
sim.pinsel.modify(|_, w| w.spi0ps()._1());
sim.scgc.modify(|_, w| w.spi0()._1());
self.enable_spi(false, false, true, true, mode);
let _ = (clock, sdi, sdo, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
}
impl Spi<SPI1, Disabled, DefaultPins> {
pub fn enable_as_controller<T0, T1, T2, T3>(
self,
clock: PTD0<T0>,
sdo: PTD1<T1>,
sdi: PTD2<T2>,
cs: Option<PTD3<T3>>,
manage_cs: bool,
mode: spi::Mode,
) -> Spi<SPI1, Enabled<Controller>, DefaultPins> {
unsafe { (*pac::SIM::ptr()).scgc.modify(|_, w| w.spi1()._1()) };
self.enable_spi(true, false, cs.is_some(), manage_cs, mode);
let _ = (clock, sdo, sdi, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
pub fn enable_as_peripheral<T0, T1, T2, T3>(
self,
clock: PTD0<T0>,
sdi: PTD1<T1>,
sdo: PTD2<T2>,
cs: PTD3<T3>,
mode: spi::Mode,
) -> Spi<SPI1, Enabled<Peripheral>, DefaultPins> {
unsafe { (*pac::SIM::ptr()).scgc.modify(|_, w| w.spi1()._1()) };
self.enable_spi(false, false, true, true, mode);
let _ = (clock, sdi, sdo, cs);
Spi {
peripheral: self.peripheral,
_state: PhantomData,
_pins: PhantomData,
}
}
}
macro_rules! spi_builder {
( $($SpiRegister:ident,)+ ) => {
$(
impl<Pins> Spi<$SpiRegister, Disabled, Pins> {
fn enable_spi(
&self,
is_controller: bool,
is_bidirectional: bool,
use_cs: bool,
manage_cs: bool,
mode: spi::Mode
) {
self.peripheral.c1.write(|w| {
w.lsbfe()._0() .ssoe()
.bit(use_cs && manage_cs)
.cpha()
.bit(match mode.phase {
spi::Phase::CaptureOnFirstTransition => false,
spi::Phase::CaptureOnSecondTransition => true,
})
.cpol()
.bit(match mode.polarity {
spi::Polarity::IdleLow => false,
spi::Polarity::IdleHigh => true,
})
.mstr()
.bit(is_controller)
.sptie()._0() .spe()
._1()
.spie()._0() });
self.peripheral.c2.modify(|_, w| {
w.spc0().bit(is_bidirectional)
.spiswai()._0() .bidiroe().bit(is_controller) .modfen().bit(use_cs)
.spmie()._0() });
}
}
impl<Pins, Mode> Spi<$SpiRegister, Enabled<Mode>, Pins> {
pub fn set_baudrate(&self, baudrate: Hertz, bus_freq: Hertz) {
let divisor = bus_to_baudrate_divisor(bus_freq.integer(), baudrate.integer());
self.set_baudrate_divisor(&divisor);
}
pub fn set_baudrate_divisor(&self, divisor: &BaudrateDivisor) {
self.peripheral
.br
.write(|w| unsafe { w.sppr().bits(divisor.scale).spr().bits(divisor.power) });
}
pub fn baudrate_divisor(&self) -> BaudrateDivisor {
let reader = self.peripheral.br.read();
BaudrateDivisor {
scale: reader.sppr().bits(),
power: reader.spr().bits(),
}
}
pub fn mode_fault(&self) -> bool {
self.peripheral.s.read().modf().bit()
}
}
impl<Mode, Pins> Spi<$SpiRegister, Mode, Pins> {
pub fn read_ready(&self) -> bool {
self.peripheral.s.read().sprf().bit()
}
pub fn read_matches(&self) -> bool {
self.peripheral.s.read().spmf().bit()
}
pub fn send_ready(&self) -> bool {
self.peripheral.s.read().sptef().bit()
}
pub fn set_hw_match(&self, value: u8) {
self.peripheral.m.write(|w| unsafe { w.bits(value) });
}
}
impl<Pins, Mode> spi::FullDuplex<u8> for Spi<$SpiRegister, Enabled<Mode>, Pins> {
type Error = core::convert::Infallible;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if !self.read_ready() {
return Err(nb::Error::WouldBlock);
}
Ok(self.peripheral.d.read().bits())
}
fn send(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if !self.send_ready() {
return Err(nb::Error::WouldBlock);
}
self.peripheral.d.write(|w| unsafe { w.bits(word) });
Ok(())
}
}
)+
};
}
spi_builder!(SPI0, SPI1,);
pub struct BaudrateDivisor {
pub scale: u8,
pub power: u8,
}
impl BaudrateDivisor {
pub const fn divisor(&self) -> Result<u32, ()> {
if (self.scale > 7) || (self.power > 8) {
return Err(());
}
Ok((self.scale as u32 + 1) << (self.power + 1))
}
}
const fn bus_to_baudrate_divisor(bus_freq: u32, baudrate: u32) -> BaudrateDivisor {
let target: u32 = bus_freq / baudrate;
divisor_to_baudrate_divisor(target)
}
const fn divisor_to_baudrate_divisor(divisor: u32) -> BaudrateDivisor {
let mut best: BaudrateDivisor = BaudrateDivisor { scale: 7, power: 9 };
let mut scale: u8 = 0;
let mut power: u8 = 0;
let mut old_error: u32 = u32::max_value();
while scale <= 7 {
while power <= 8 {
let new = BaudrateDivisor { scale, power };
let new_div = match new.divisor() {
Ok(f) => f,
Err(_) => 8 << 9,
};
let error: u32 = (new_div as i32 - divisor as i32).unsigned_abs();
if error <= old_error {
old_error = error;
best.scale = scale;
best.power = power;
}
power += 1;
}
power = 0;
scale += 1;
}
best
}
pub enum Errors {
DivsorOutOfRange,
BadInput,
}