use core::ops::Deref;
cfg_if::cfg_if! {
if #[cfg(any(feature = "h5", feature = "h7"))] {
mod h;
pub use h::*;
} else {
mod baseline;
pub use baseline::*;
}
}
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "c0")] { use crate::{pac::{self, DMA as DMA1}};
} else {
use crate::pac::{self, DMA1};
}
}
#[cfg(any(feature = "f3", feature = "l4"))]
use crate::dma::DmaInput;
#[cfg(not(any(feature = "f4", feature = "l552")))]
use crate::dma::{self, ChannelCfg, DmaChannel};
use crate::{error::Result, util::RccPeriph};
#[macro_export]
macro_rules! check_errors {
($sr:expr) => {
#[cfg(feature = "h7")]
let crc_error = $sr.crce().bit_is_set();
#[cfg(not(feature = "h7"))]
let crc_error = $sr.crcerr().bit_is_set();
if $sr.ovr().bit_is_set() {
return Err(Error::SpiError(SpiError::Overrun));
} else if $sr.modf().bit_is_set() {
return Err(Error::SpiError(SpiError::ModeFault));
} else if crc_error {
return Err(Error::SpiError(SpiError::Crc));
}
};
}
#[non_exhaustive]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SpiError {
Overrun,
ModeFault,
Crc,
DuplexFailed, }
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum BaudRate {
Div2 = 0b000,
Div4 = 0b001,
Div8 = 0b010,
Div16 = 0b011,
Div32 = 0b100,
Div64 = 0b101,
Div128 = 0b110,
Div256 = 0b111,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum ReceptionThresh {
D16 = 0,
D8 = 1,
}
#[derive(Clone, Copy, PartialEq)]
pub enum SpiCommMode {
FullDuplex,
HalfDuplex,
TransmitOnly,
ReceiveOnly,
}
#[derive(Clone, Copy, PartialEq)]
pub enum SlaveSelect {
Software,
HardwareOutEnable,
HardwareOutDisable,
}
cfg_if! {
if #[cfg(feature = "embedded_hal")] {
type SpiModeType = embedded_hal::spi::Mode;
} else {
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum SpiPolarity {
IdleLow = 0,
IdleHigh = 1,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum SpiPhase {
CaptureOnFirstTransition = 0,
CaptureOnSecondTransition = 1,
}
#[derive(Clone, Copy)]
pub struct SpiMode {
pub polarity: SpiPolarity,
pub phase: SpiPhase,
}
impl SpiMode {
pub fn mode0() -> Self {
Self {
polarity: SpiPolarity::IdleLow,
phase: SpiPhase::CaptureOnFirstTransition,
}
}
pub fn mode1() -> Self {
Self {
polarity: SpiPolarity::IdleLow,
phase: SpiPhase::CaptureOnSecondTransition,
}
}
pub fn mode2() -> Self {
Self {
polarity: SpiPolarity::IdleHigh,
phase: SpiPhase::CaptureOnFirstTransition,
}
}
pub fn mode3() -> Self {
Self {
polarity: SpiPolarity::IdleHigh,
phase: SpiPhase::CaptureOnSecondTransition,
}
}
}
type SpiModeType = SpiMode;
}
}
#[derive(Clone)]
pub struct SpiConfig {
pub mode: SpiModeType,
pub comm_mode: SpiCommMode,
pub slave_select: SlaveSelect,
pub data_size: DataSize,
pub fifo_reception_thresh: ReceptionThresh,
}
impl Default for SpiConfig {
fn default() -> Self {
cfg_if! {
if #[cfg(feature = "embedded_hal")] {
let mode0 = embedded_hal::spi::MODE_0;
} else {
let mode0 = SpiModeType::mode0();
}
}
Self {
mode: mode0,
comm_mode: SpiCommMode::FullDuplex,
slave_select: SlaveSelect::Software,
data_size: DataSize::D8,
fifo_reception_thresh: ReceptionThresh::D8,
}
}
}
pub struct Spi<R> {
pub regs: R,
pub cfg: SpiConfig,
}
impl<R> Spi<R>
where
R: Deref<Target = pac::spi1::RegisterBlock> + RccPeriph,
{
#[cfg(not(any(feature = "f4", feature = "l552")))]
pub fn stop_dma(
&mut self,
channel: DmaChannel,
channel2: Option<DmaChannel>,
dma_periph: dma::DmaPeriph,
) -> Result<()> {
dma::stop(dma_periph, channel)?;
if let Some(ch2) = channel2 {
dma::stop(dma_periph, ch2)?;
};
#[cfg(not(feature = "h7"))]
self.regs.cr2().modify(|_, w| {
w.txdmaen().clear_bit();
w.rxdmaen().clear_bit()
});
#[cfg(feature = "h7")]
self.regs.cfg1().modify(|_, w| {
w.txdmaen().clear_bit();
w.rxdmaen().clear_bit()
});
Ok(())
}
#[cfg(not(any(feature = "f4", feature = "l552")))]
pub fn cleanup_dma(
&mut self,
dma_periph: dma::DmaPeriph,
channel_tx: DmaChannel,
channel_rx: Option<DmaChannel>,
) -> Result<()> {
dma::clear_interrupt(dma_periph, channel_tx, dma::DmaInterrupt::TransferComplete)?;
if let Some(ch_rx) = channel_rx {
dma::clear_interrupt(dma_periph, ch_rx, dma::DmaInterrupt::TransferComplete)?;
}
self.stop_dma(channel_tx, channel_rx, dma_periph)
}
pub fn read_status(&self) -> u32 {
unsafe { self.regs.sr().read().bits().into() }
}
}