Skip to content

Commit

Permalink
spi nb
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Jan 14, 2024
1 parent 8162c5e commit 5d1498e
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 49 deletions.
2 changes: 1 addition & 1 deletion examples/spi-slave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use cortex_m_rt::entry;
use panic_halt as _;

use cortex_m::{asm, singleton};
use embedded_hal_02::spi::{Mode, Phase, Polarity};
use stm32f1xx_hal::spi::{Mode, Phase, Polarity};
pub const MODE: Mode = Mode {
phase: Phase::CaptureOnSecondTransition,
polarity: Polarity::IdleHigh,
Expand Down
82 changes: 77 additions & 5 deletions src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
*/

mod hal_02;
mod hal_1;

use core::ops::Deref;

use crate::pac::{self, RCC};
pub use embedded_hal_02::spi::{Mode, Phase, Polarity};

use crate::afio::MAPR;
use crate::dma::dma1;
Expand All @@ -52,6 +52,33 @@ use crate::time::Hertz;
use core::sync::atomic::{self, Ordering};
use embedded_dma::{ReadBuffer, WriteBuffer};

/// Clock polarity
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Polarity {
/// Clock signal low when idle
IdleLow,
/// Clock signal high when idle
IdleHigh,
}

/// Clock phase
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Phase {
/// Data in "captured" on the first clock transition
CaptureOnFirstTransition,
/// Data in "captured" on the second clock transition
CaptureOnSecondTransition,
}

/// SPI mode
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Mode {
/// Clock polarity
pub polarity: Polarity,
/// Clock phase
pub phase: Phase,
}

/// Interrupt event
pub enum Event {
/// New data has been received
Expand Down Expand Up @@ -192,7 +219,7 @@ impl<REMAP, PINS> Spi<pac::SPI1, REMAP, PINS, u8, Master> {
spi: pac::SPI1,
pins: PINS,
mapr: &mut MAPR,
mode: Mode,
mode: impl Into<Mode>,
freq: Hertz,
clocks: Clocks,
) -> Self
Expand All @@ -213,7 +240,7 @@ impl<REMAP, PINS> Spi<pac::SPI1, REMAP, PINS, u8, Slave> {
You can also use `NoMiso` or `NoMosi` if you don't want to use the pins
*/
pub fn spi1_slave(spi: pac::SPI1, pins: PINS, mapr: &mut MAPR, mode: Mode) -> Self
pub fn spi1_slave(spi: pac::SPI1, pins: PINS, mapr: &mut MAPR, mode: impl Into<Mode>) -> Self
where
REMAP: Remap<Periph = pac::SPI1>,
PINS: Pins<REMAP, Slave>,
Expand Down Expand Up @@ -461,7 +488,8 @@ impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u8, Master>
where
SPI: Instance,
{
fn configure(spi: SPI, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self {
fn configure(spi: SPI, pins: PINS, mode: impl Into<Mode>, freq: Hertz, clocks: Clocks) -> Self {
let mode = mode.into();
// enable or reset SPI
let rcc = unsafe { &(*RCC::ptr()) };
SPI::enable(rcc);
Expand Down Expand Up @@ -521,7 +549,8 @@ impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u8, Slave>
where
SPI: Instance,
{
fn configure(spi: SPI, pins: PINS, mode: Mode) -> Self {
fn configure(spi: SPI, pins: PINS, mode: impl Into<Mode>) -> Self {
let mode = mode.into();
// enable or reset SPI
let rcc = unsafe { &(*RCC::ptr()) };
SPI::enable(rcc);
Expand Down Expand Up @@ -601,6 +630,49 @@ where
}
}

impl<SPI, REMAP, PINS, FrameSize, OP> Spi<SPI, REMAP, PINS, FrameSize, OP>
where
SPI: Instance,
FrameSize: Copy,
{
pub fn read_nonblocking(&mut self) -> nb::Result<FrameSize, Error> {
let sr = self.spi.sr.read();

Err(if sr.ovr().bit_is_set() {
Error::Overrun.into()
} else if sr.modf().bit_is_set() {
Error::ModeFault.into()
} else if sr.crcerr().bit_is_set() {
Error::Crc.into()
} else if sr.rxne().bit_is_set() {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
// reading a half-word)
return Ok(self.read_data_reg());
} else {
nb::Error::WouldBlock
})
}
pub fn write_nonblocking(&mut self, data: FrameSize) -> nb::Result<(), Error> {
let sr = self.spi.sr.read();

// NOTE: Error::Overrun was deleted in #408. Need check
Err(if sr.modf().bit_is_set() {
Error::ModeFault.into()
} else if sr.crcerr().bit_is_set() {
Error::Crc.into()
} else if sr.txe().bit_is_set() {
// NOTE(write_volatile) see note above
self.write_data_reg(data);
return Ok(());
} else {
nb::Error::WouldBlock
})
}
pub fn write(&mut self, words: &[FrameSize]) -> Result<(), Error> {
self.spi_write(words)
}
}

// DMA

pub type SpiTxDma<SPI, REMAP, PINS, OP, CHANNEL> = TxDma<Spi<SPI, REMAP, PINS, u8, OP>, CHANNEL>;
Expand Down
81 changes: 38 additions & 43 deletions src/spi/hal_02.rs
Original file line number Diff line number Diff line change
@@ -1,75 +1,70 @@
use super::*;

pub use embedded_hal_02::spi::{Mode, Phase, Polarity};
use embedded_hal_02::{blocking::spi as blocking, spi};

impl<SPI, REMAP, PINS, FrameSize, OP> spi::FullDuplex<FrameSize>
for Spi<SPI, REMAP, PINS, FrameSize, OP>
impl From<Polarity> for super::Polarity {
fn from(p: Polarity) -> Self {
match p {
Polarity::IdleLow => Self::IdleLow,
Polarity::IdleHigh => Self::IdleHigh,
}
}
}

impl From<Phase> for super::Phase {
fn from(p: Phase) -> Self {
match p {
Phase::CaptureOnFirstTransition => Self::CaptureOnFirstTransition,
Phase::CaptureOnSecondTransition => Self::CaptureOnSecondTransition,
}
}
}

impl From<Mode> for super::Mode {
fn from(m: Mode) -> Self {
Self {
polarity: m.polarity.into(),
phase: m.phase.into(),
}
}
}

impl<SPI, REMAP, PINS, W, OP> spi::FullDuplex<W> for Spi<SPI, REMAP, PINS, W, OP>
where
SPI: Instance,
FrameSize: Copy,
W: Copy,
{
type Error = Error;

fn read(&mut self) -> nb::Result<FrameSize, Error> {
let sr = self.spi.sr.read();

Err(if sr.ovr().bit_is_set() {
Error::Overrun.into()
} else if sr.modf().bit_is_set() {
Error::ModeFault.into()
} else if sr.crcerr().bit_is_set() {
Error::Crc.into()
} else if sr.rxne().bit_is_set() {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
// reading a half-word)
return Ok(self.read_data_reg());
} else {
nb::Error::WouldBlock
})
fn read(&mut self) -> nb::Result<W, Error> {
self.read_nonblocking()
}

fn send(&mut self, data: FrameSize) -> nb::Result<(), Error> {
let sr = self.spi.sr.read();

// NOTE: Error::Overrun was deleted in #408. Need check
Err(if sr.modf().bit_is_set() {
Error::ModeFault.into()
} else if sr.crcerr().bit_is_set() {
Error::Crc.into()
} else if sr.txe().bit_is_set() {
// NOTE(write_volatile) see note above
self.write_data_reg(data);
return Ok(());
} else {
nb::Error::WouldBlock
})
fn send(&mut self, data: W) -> nb::Result<(), Error> {
self.write_nonblocking(data)
}
}

impl<SPI, REMAP, PINS, FrameSize, OP> blocking::transfer::Default<FrameSize>
for Spi<SPI, REMAP, PINS, FrameSize, OP>
impl<SPI, REMAP, PINS, W, OP> blocking::transfer::Default<W> for Spi<SPI, REMAP, PINS, W, OP>
where
SPI: Instance,
FrameSize: Copy,
W: Copy,
{
}

impl<SPI: Instance, REMAP, PINS, OP> blocking::Write<u8> for Spi<SPI, REMAP, PINS, u8, OP> {
type Error = Error;

// Implement write as per the "Transmit only procedure" page 712
// of RM0008 Rev 20. This is more than twice as fast as the
// default Write<> implementation (which reads and drops each
// received value)
fn write(&mut self, words: &[u8]) -> Result<(), Error> {
self.spi_write(words)
self.write(words)
}
}

impl<SPI: Instance, REMAP, PINS, OP> blocking::Write<u16> for Spi<SPI, REMAP, PINS, u16, OP> {
type Error = Error;

fn write(&mut self, words: &[u16]) -> Result<(), Error> {
self.spi_write(words)
self.write(words)
}
}
93 changes: 93 additions & 0 deletions src/spi/hal_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use super::*;
pub use embedded_hal::spi::{ErrorKind, ErrorType, Mode, Phase, Polarity};

impl From<Polarity> for super::Polarity {
fn from(p: Polarity) -> Self {
match p {
Polarity::IdleLow => Self::IdleLow,
Polarity::IdleHigh => Self::IdleHigh,
}
}
}

impl From<Phase> for super::Phase {
fn from(p: Phase) -> Self {
match p {
Phase::CaptureOnFirstTransition => Self::CaptureOnFirstTransition,
Phase::CaptureOnSecondTransition => Self::CaptureOnSecondTransition,
}
}
}

impl From<Mode> for super::Mode {
fn from(m: Mode) -> Self {
Self {
polarity: m.polarity.into(),
phase: m.phase.into(),
}
}
}

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,
}
}
}

impl<SPI: Instance, REMAP, PINS, W, OP> ErrorType for Spi<SPI, REMAP, PINS, W, OP> {
type Error = Error;
}

mod nb {
use super::{Error, Instance, Spi};
use embedded_hal_nb::spi::FullDuplex;

impl<SPI, REMAP, PINS, W, OP> FullDuplex<W> for Spi<SPI, REMAP, PINS, W, OP>
where
SPI: Instance,
W: Copy,
{
fn read(&mut self) -> nb::Result<W, Error> {
self.read_nonblocking()
}

fn write(&mut self, data: W) -> nb::Result<(), Error> {
self.write_nonblocking(data)
}
}
}

mod blocking {
use super::super::{Instance, Spi};
use embedded_hal::spi::SpiBus;

impl<SPI: Instance, REMAP, PINS, W, OP> SpiBus<W> for Spi<SPI, REMAP, PINS, W, OP>
where
SPI: Instance,
W: Copy + 'static,
{
fn transfer_in_place(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
todo!()
}

fn transfer(&mut self, _buff: &mut [W], _data: &[W]) -> Result<(), Self::Error> {
todo!()
}

fn read(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
todo!()
}

fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
self.write(words)
}

fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
}

0 comments on commit 5d1498e

Please sign in to comment.