use core::marker::PhantomData;
use embedded_hal::spi::{ErrorKind, ErrorType, MODE_0, Mode, Phase, Polarity, SpiBus};
use crate::gpio::{Alternate, Pin};
use crate::pac;
use crate::rcu::{Enable, Rcu, Reset};
const DZ_8BIT: u8 = 0b0111;
const DZ_16BIT: u8 = 0b1111;
#[allow(missing_docs)]
pub mod fill {
pub const LOW: u8 = 0x00;
pub const HIGH: u8 = 0xFF;
pub const LOW_WORD: u16 = 0x0000;
pub const HIGH_WORD: u16 = 0xFFFF;
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum SpiPsc {
Div2 = 0b000,
Div4 = 0b001,
Div8 = 0b010,
Div16 = 0b011,
Div32 = 0b100,
Div64 = 0b101,
Div128 = 0b110,
Div256 = 0b111,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BitOrder {
MsbFirst,
LsbFirst,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[must_use]
pub struct SpiConfig {
psc: SpiPsc,
mode: Mode,
bit_order: BitOrder,
}
impl SpiConfig {
pub const fn new(psc: SpiPsc) -> Self {
Self {
psc,
mode: MODE_0,
bit_order: BitOrder::MsbFirst,
}
}
pub const fn mode(mut self, mode: Mode) -> Self {
self.mode = mode;
self
}
pub const fn bit_order(mut self, bit_order: BitOrder) -> Self {
self.bit_order = bit_order;
self
}
}
pub trait SckPin<SPI> {}
pub trait MisoPin<SPI> {}
pub trait MosiPin<SPI> {}
macro_rules! spi_pins {
( $( $SPI:ty:
SCK: [ $($(#[$sck_cfg:meta])? $sck_p:literal $sck_n:literal : $sck_af:literal),* $(,)? ]
MISO: [ $($(#[$miso_cfg:meta])? $miso_p:literal $miso_n:literal : $miso_af:literal),* $(,)? ]
MOSI: [ $($(#[$mosi_cfg:meta])? $mosi_p:literal $mosi_n:literal : $mosi_af:literal),* $(,)? ]
),* $(,)? ) => {
$(
$( $(#[$sck_cfg])? impl SckPin<$SPI> for Pin<$sck_p, $sck_n, Alternate<$sck_af>> {} )*
$( $(#[$miso_cfg])? impl MisoPin<$SPI> for Pin<$miso_p, $miso_n, Alternate<$miso_af>> {} )*
$( $(#[$mosi_cfg])? impl MosiPin<$SPI> for Pin<$mosi_p, $mosi_n, Alternate<$mosi_af>> {} )*
)*
};
}
spi_pins!(
pac::Spi0:
SCK: ['A' 5 : 0, #[cfg(pads_ge_28)] 'B' 3 : 0]
MISO: ['A' 6 : 0, #[cfg(pads_ge_28)] 'B' 4 : 0]
MOSI: ['A' 7 : 0, #[cfg(pads_ge_28)] 'B' 5 : 0]
);
#[cfg(chip_x4)]
spi_pins!(
pac::Spi0:
SCK: [#[cfg(pads_ge_48)] 'B' 13 : 0]
MISO: [#[cfg(pads_ge_48)] 'B' 14 : 0]
MOSI: [#[cfg(pads_ge_48)] 'B' 15 : 0]
);
#[cfg(chip_x8)]
spi_pins!(
pac::Spi1:
SCK: ['B' 1 : 6, #[cfg(pads_ge_48)] 'B' 10 : 7, #[cfg(pads_ge_48)] 'B' 13 : 0]
MISO: ['A' 13 : 6, #[cfg(pads_ge_48)] 'B' 14 : 0]
MOSI: ['A' 14 : 6, #[cfg(pads_ge_48)] 'B' 15 : 0]
);
pub struct Byte;
pub struct Word;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Overrun,
ModeFault,
Crc,
Framing,
}
impl embedded_hal::spi::Error for Error {
fn kind(&self) -> ErrorKind {
match self {
Self::Overrun => ErrorKind::Overrun,
Self::ModeFault => ErrorKind::ModeFault,
Self::Crc => ErrorKind::Other,
Self::Framing => ErrorKind::FrameFormat,
}
}
}
pub trait Instance: Enable + Reset {
fn apply_config(&mut self, config: SpiConfig, wide: bool);
fn tbe(&self) -> bool;
fn rbne(&self) -> bool;
fn write_data(&mut self, word: u16);
fn read_data(&mut self) -> u16;
fn take_error(&mut self) -> Option<Error>;
fn set_rbneie(&mut self, on: bool);
fn rbneie(&self) -> bool;
fn set_tbeie(&mut self, on: bool);
fn tbeie(&self) -> bool;
fn set_errie(&mut self, on: bool);
fn errie(&self) -> bool;
fn shut_down(&mut self);
}
impl Instance for pac::Spi0 {
#[inline]
fn apply_config(&mut self, config: SpiConfig, wide: bool) {
self.ctl0().modify(|_, w| {
let w = w
.mstmod()
.set_bit()
.swnssen()
.set_bit()
.swnss()
.set_bit()
.lf()
.bit(config.bit_order == BitOrder::LsbFirst)
.ff16()
.bit(wide)
.spien()
.set_bit()
.ckpl()
.bit(config.mode.polarity == Polarity::IdleHigh)
.ckph()
.bit(config.mode.phase == Phase::CaptureOnSecondTransition);
unsafe { w.psc().bits(config.psc as u8) }
});
}
#[inline]
fn tbe(&self) -> bool {
self.stat().read().tbe().bit_is_set()
}
#[inline]
fn rbne(&self) -> bool {
self.stat().read().rbne().bit_is_set()
}
#[inline]
fn write_data(&mut self, word: u16) {
self.data().write(|w| unsafe { w.data().bits(word) });
}
#[inline]
fn read_data(&mut self) -> u16 {
self.data().read().data().bits()
}
#[inline]
fn take_error(&mut self) -> Option<Error> {
let stat = self.stat().read();
if stat.rxorerr().bit_is_set() {
Some(Error::Overrun)
} else if stat.conferr().bit_is_set() {
self.ctl0().modify(|_, w| w);
Some(Error::ModeFault)
} else if stat.crcerr().bit_is_set() {
self.stat().modify(|_, w| w.crcerr().clear_bit());
Some(Error::Crc)
} else if stat.ferr().bit_is_set() {
self.stat().modify(|_, w| w.ferr().clear_bit());
Some(Error::Framing)
} else {
None
}
}
#[inline]
fn set_rbneie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.rbneie().bit(on));
}
#[inline]
fn rbneie(&self) -> bool {
self.ctl1().read().rbneie().bit_is_set()
}
#[inline]
fn set_tbeie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.tbeie().bit(on));
}
#[inline]
fn tbeie(&self) -> bool {
self.ctl1().read().tbeie().bit_is_set()
}
#[inline]
fn set_errie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.errie().bit(on));
}
#[inline]
fn errie(&self) -> bool {
self.ctl1().read().errie().bit_is_set()
}
#[inline]
fn shut_down(&mut self) {
while !self.tbe() || self.stat().read().trans().bit_is_set() {}
self.ctl0().modify(|_, w| w.spien().clear_bit());
if self.rbne() {
self.read_data();
}
}
}
impl Instance for pac::Spi1 {
#[inline]
fn apply_config(&mut self, config: SpiConfig, wide: bool) {
self.ctl1().modify(|_, w| {
let w = w.byten().bit(!wide);
unsafe { w.dz().bits(if wide { DZ_16BIT } else { DZ_8BIT }) }
});
self.ctl0().modify(|_, w| {
let w = w
.mstmod()
.set_bit()
.swnssen()
.set_bit()
.swnss()
.set_bit()
.lf()
.bit(config.bit_order == BitOrder::LsbFirst)
.spien()
.set_bit()
.ckpl()
.bit(config.mode.polarity == Polarity::IdleHigh)
.ckph()
.bit(config.mode.phase == Phase::CaptureOnSecondTransition);
unsafe { w.psc().bits(config.psc as u8) }
});
}
#[inline]
fn tbe(&self) -> bool {
self.stat().read().tbe().bit_is_set()
}
#[inline]
fn rbne(&self) -> bool {
self.stat().read().rbne().bit_is_set()
}
#[inline]
fn write_data(&mut self, word: u16) {
self.data().write(|w| unsafe { w.data().bits(word) });
}
#[inline]
fn read_data(&mut self) -> u16 {
self.data().read().data().bits()
}
#[inline]
fn take_error(&mut self) -> Option<Error> {
let stat = self.stat().read();
if stat.rxorerr().bit_is_set() {
Some(Error::Overrun)
} else if stat.conferr().bit_is_set() {
self.ctl0().modify(|_, w| w);
Some(Error::ModeFault)
} else if stat.crcerr().bit_is_set() {
self.stat().modify(|_, w| w.crcerr().clear_bit());
Some(Error::Crc)
} else if stat.ferr().bit_is_set() {
self.stat().modify(|_, w| w.ferr().clear_bit());
Some(Error::Framing)
} else {
None
}
}
#[inline]
fn set_rbneie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.rbneie().bit(on));
}
#[inline]
fn rbneie(&self) -> bool {
self.ctl1().read().rbneie().bit_is_set()
}
#[inline]
fn set_tbeie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.tbeie().bit(on));
}
#[inline]
fn tbeie(&self) -> bool {
self.ctl1().read().tbeie().bit_is_set()
}
#[inline]
fn set_errie(&mut self, on: bool) {
self.ctl1().modify(|_, w| w.errie().bit(on));
}
#[inline]
fn errie(&self) -> bool {
self.ctl1().read().errie().bit_is_set()
}
#[inline]
fn shut_down(&mut self) {
while self.stat().read().txlvl().bits() != 0 || self.stat().read().trans().bit_is_set() {}
self.ctl0().modify(|_, w| w.spien().clear_bit());
while self.stat().read().rxlvl().bits() != 0 {
self.read_data();
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
Rbne,
Tbe,
Error,
}
pub struct Spi<SPIX, SCK, MISO, MOSI, WORD = Byte> {
spi: SPIX,
sck_pin: SCK,
miso_pin: MISO,
mosi_pin: MOSI,
_word: PhantomData<WORD>,
}
impl<SPIX, SCK, MISO, MOSI> Spi<SPIX, SCK, MISO, MOSI, Byte>
where
SPIX: Instance,
SCK: SckPin<SPIX>,
MISO: MisoPin<SPIX>,
MOSI: MosiPin<SPIX>,
{
pub fn new(
rcu: &mut Rcu,
mut spi: SPIX,
sck_pin: SCK,
miso_pin: MISO,
mosi_pin: MOSI,
config: SpiConfig,
) -> Self {
SPIX::enable(rcu);
SPIX::reset(rcu);
spi.apply_config(config, false);
Self {
spi,
sck_pin,
miso_pin,
mosi_pin,
_word: PhantomData,
}
}
}
impl<SPIX, SCK, MISO, MOSI> Spi<SPIX, SCK, MISO, MOSI, Word>
where
SPIX: Instance,
SCK: SckPin<SPIX>,
MISO: MisoPin<SPIX>,
MOSI: MosiPin<SPIX>,
{
pub fn new_word(
rcu: &mut Rcu,
mut spi: SPIX,
sck_pin: SCK,
miso_pin: MISO,
mosi_pin: MOSI,
config: SpiConfig,
) -> Self {
SPIX::enable(rcu);
SPIX::reset(rcu);
spi.apply_config(config, true);
Self {
spi,
sck_pin,
miso_pin,
mosi_pin,
_word: PhantomData,
}
}
}
impl<SPIX, SCK, MISO, MOSI, WORD> Spi<SPIX, SCK, MISO, MOSI, WORD>
where
SPIX: Instance,
{
pub fn read_ready(&self) -> bool {
self.spi.rbne()
}
pub fn write_ready(&self) -> bool {
self.spi.tbe()
}
pub fn take_error(&mut self) -> Option<Error> {
self.spi.take_error()
}
pub fn listen(&mut self, event: Event) {
match event {
Event::Rbne => self.spi.set_rbneie(true),
Event::Tbe => self.spi.set_tbeie(true),
Event::Error => self.spi.set_errie(true),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Rbne => self.spi.set_rbneie(false),
Event::Tbe => self.spi.set_tbeie(false),
Event::Error => self.spi.set_errie(false),
}
}
pub fn is_listening(&self, event: Event) -> bool {
match event {
Event::Rbne => self.spi.rbneie(),
Event::Tbe => self.spi.tbeie(),
Event::Error => self.spi.errie(),
}
}
pub fn release(mut self, rcu: &mut Rcu) -> (SPIX, SCK, MISO, MOSI) {
self.spi.shut_down();
self.unlisten(Event::Rbne);
self.unlisten(Event::Tbe);
self.unlisten(Event::Error);
SPIX::disable(rcu);
(self.spi, self.sck_pin, self.miso_pin, self.mosi_pin)
}
}
impl<SPIX, SCK, MISO, MOSI> Spi<SPIX, SCK, MISO, MOSI, Byte>
where
SPIX: Instance,
{
pub fn write_byte(&mut self, byte: u8) {
self.spi.write_data(byte as u16);
}
pub fn read_byte(&mut self) -> u8 {
self.spi.read_data() as u8
}
pub fn transfer_byte(&mut self, byte: u8) -> Result<u8, Error> {
while !self.write_ready() {}
self.write_byte(byte);
while !self.read_ready() {}
let received = self.read_byte();
match self.take_error() {
Some(e) => Err(e),
None => Ok(received),
}
}
pub fn transfer_bytes(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
assert!(
read.len() == write.len(),
"SPI transfer buffers must be the same length"
);
for (slot, &byte) in read.iter_mut().zip(write) {
*slot = self.transfer_byte(byte)?;
}
Ok(())
}
pub fn transfer_bytes_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
for word in words {
*word = self.transfer_byte(*word)?;
}
Ok(())
}
}
impl<SPIX, SCK, MISO, MOSI> Spi<SPIX, SCK, MISO, MOSI, Word>
where
SPIX: Instance,
{
pub fn write_word(&mut self, word: u16) {
self.spi.write_data(word);
}
pub fn read_word(&mut self) -> u16 {
self.spi.read_data()
}
pub fn transfer_word(&mut self, word: u16) -> Result<u16, Error> {
while !self.write_ready() {}
self.write_word(word);
while !self.read_ready() {}
let received = self.read_word();
match self.take_error() {
Some(e) => Err(e),
None => Ok(received),
}
}
pub fn transfer_words(&mut self, read: &mut [u16], write: &[u16]) -> Result<(), Error> {
assert!(
read.len() == write.len(),
"SPI transfer buffers must be the same length"
);
for (slot, &word) in read.iter_mut().zip(write) {
*slot = self.transfer_word(word)?;
}
Ok(())
}
pub fn transfer_words_in_place(&mut self, words: &mut [u16]) -> Result<(), Error> {
for word in words {
*word = self.transfer_word(*word)?;
}
Ok(())
}
}
impl<SPIX, SCK, MISO, MOSI, WORD> ErrorType for Spi<SPIX, SCK, MISO, MOSI, WORD>
where
SPIX: Instance,
{
type Error = Error;
}
impl<SPIX, SCK, MISO, MOSI> SpiBus<u8> for Spi<SPIX, SCK, MISO, MOSI, Byte>
where
SPIX: Instance,
{
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.transfer_bytes(read, write)
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.transfer_bytes_in_place(words)
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
for slot in words {
*slot = self.transfer_byte(fill::LOW)?;
}
Ok(())
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
for &byte in words {
self.transfer_byte(byte)?;
}
Ok(())
}
}
impl<SPIX, SCK, MISO, MOSI> SpiBus<u16> for Spi<SPIX, SCK, MISO, MOSI, Word>
where
SPIX: Instance,
{
fn transfer(&mut self, read: &mut [u16], write: &[u16]) -> Result<(), Self::Error> {
self.transfer_words(read, write)
}
fn transfer_in_place(&mut self, words: &mut [u16]) -> Result<(), Self::Error> {
self.transfer_words_in_place(words)
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn read(&mut self, words: &mut [u16]) -> Result<(), Self::Error> {
for slot in words {
*slot = self.transfer_word(fill::LOW_WORD)?;
}
Ok(())
}
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
for &word in words {
self.transfer_word(word)?;
}
Ok(())
}
}