diff --git a/CHANGELOG.md b/CHANGELOG.md index fef36c27..b1778295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed + - Support `u16` read/write for SPI - Use `bool` for BIDI mode type - `PwmHz::get_period`: fix computation of return value, prevent division by zero - apply #[inline] attribute to bitbanding functions [#517] diff --git a/src/spi.rs b/src/spi.rs index 0bac88fa..949c87c1 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -131,11 +131,32 @@ impl Ms for Master { const MSTR: bool = true; } +pub trait FrameSize: Copy + Default { + const DFF: bool; +} + +impl FrameSize for u8 { + const DFF: bool = false; +} + +impl FrameSize for u16 { + const DFF: bool = true; +} + +/// The bit format to send the data in +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BitFormat { + /// Least significant bit first + LsbFirst, + /// Most significant bit first + MsbFirst, +} + #[derive(Debug)] -pub struct Spi { +pub struct Spi { spi: SPI, pins: PINS, - _operation: PhantomData, + _operation: PhantomData<(W, OPERATION)>, } // Implemented by all SPI instances @@ -149,8 +170,8 @@ pub trait Instance: // Implemented by all SPI instances macro_rules! spi { ($SPI:ty: $Spi:ident) => { - pub type $Spi = - Spi<$SPI, PINS, BIDI, OPERATION>; + pub type $Spi = + Spi<$SPI, PINS, BIDI, W, OPERATION>; impl Instance for $SPI { fn ptr() -> *const spi1::RegisterBlock { @@ -182,7 +203,7 @@ pub trait SpiExt: Sized + Instance { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins; fn spi_bidi( @@ -191,7 +212,7 @@ pub trait SpiExt: Sized + Instance { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins; fn spi_slave( @@ -200,7 +221,7 @@ pub trait SpiExt: Sized + Instance { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins; fn spi_bidi_slave( @@ -209,7 +230,7 @@ pub trait SpiExt: Sized + Instance { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins; } @@ -221,7 +242,7 @@ impl SpiExt for SPI { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins, { @@ -233,7 +254,7 @@ impl SpiExt for SPI { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins, { @@ -245,7 +266,7 @@ impl SpiExt for SPI { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins, { @@ -257,7 +278,7 @@ impl SpiExt for SPI { mode: impl Into, freq: Hertz, clocks: &Clocks, - ) -> Spi + ) -> Spi where (SCK, MISO, MOSI): Pins, { @@ -265,7 +286,9 @@ impl SpiExt for SPI { } } -impl Spi { +impl + Spi +{ pub fn init(self) -> Self { self.spi.cr1.modify(|_, w| { // bidimode: 2-line or 1-line unidirectional @@ -273,6 +296,8 @@ impl Spi Spi Spi { - pub fn to_bidi_transfer_mode(self) -> Spi { +impl Spi { + pub fn to_bidi_transfer_mode(self) -> Spi { + self.into_mode() + } +} + +impl Spi { + pub fn to_normal_transfer_mode(self) -> Spi { + self.into_mode() + } +} + +impl Spi { + pub fn to_slave_operation(self) -> Spi { self.into_mode() } } -impl Spi { - pub fn to_normal_transfer_mode(self) -> Spi { +impl Spi { + pub fn to_master_operation(self) -> Spi { self.into_mode() } } -impl Spi { - pub fn to_slave_operation(self) -> Spi { +impl Spi +where + SPI: Instance, +{ + /// Converts from 8bit dataframe to 16bit. + pub fn frame_size_16bit(self) -> Spi { self.into_mode() } } -impl Spi { - pub fn to_master_operation(self) -> Spi { +impl Spi +where + SPI: Instance, +{ + /// Converts from 16bit dataframe to 8bit. + pub fn frame_size_8bit(self) -> Spi { self.into_mode() } } -impl Spi { +impl Spi { pub fn new( spi: SPI, mut pins: (SCK, MISO, MOSI), @@ -331,7 +376,7 @@ impl Spi } } -impl Spi { +impl Spi { pub fn new_bidi( spi: SPI, mut pins: (SCK, MISO, MOSI), @@ -357,7 +402,7 @@ impl Spi { } } -impl Spi { +impl Spi { pub fn new_slave( spi: SPI, mut pins: (SCK, MISO, MOSI), @@ -383,7 +428,7 @@ impl Spi { } } -impl Spi { +impl Spi { pub fn new_bidi_slave( spi: SPI, mut pins: (SCK, MISO, MOSI), @@ -421,7 +466,7 @@ where } } -impl Spi { +impl Spi { fn _new(spi: SPI, pins: PINS) -> Self { Self { spi, @@ -431,7 +476,9 @@ impl Spi(self) -> Spi { + fn into_mode( + self, + ) -> Spi { let mut spi = Spi::_new(self.spi, self.pins); spi.enable(false); spi.init() @@ -482,6 +529,14 @@ impl Spi self.spi.cr1.modify(|_, w| w.lsbfirst().set_bit()), + BitFormat::MsbFirst => self.spi.cr1.modify(|_, w| w.lsbfirst().clear_bit()), + } + } + /// Enable interrupts for the given `event`: /// - Received data ready to be read (RXNE) /// - Transmit data register empty (TXE) @@ -550,13 +605,36 @@ impl Spi bool { self.spi.sr.read().ovr().bit_is_set() } +} - pub fn use_dma(self) -> DmaBuilder { - DmaBuilder { spi: self.spi } +trait ReadWriteReg { + fn read_data_reg(&mut self) -> W; + fn write_data_reg(&mut self, data: W); +} + +impl ReadWriteReg + for Spi +where + SPI: Instance, + W: FrameSize, +{ + fn read_data_reg(&mut self) -> W { + // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows + // reading a half-word) + unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const W) } } + fn write_data_reg(&mut self, data: W) { + // NOTE(write_volatile) see note above + unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut W, data) } + } +} + +impl + Spi +{ #[inline(always)] - fn check_read(&mut self) -> nb::Result { + fn check_read(&mut self) -> nb::Result { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { @@ -566,14 +644,14 @@ impl Spi nb::Result<(), Error> { + fn check_send(&mut self, byte: W) -> nb::Result<(), Error> { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { @@ -592,23 +670,19 @@ impl Spi u8 { - // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows reading a half-word) - unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) } - } +// Spi DMA - #[inline(always)] - fn send_u8(&mut self, byte: u8) { - // NOTE(write_volatile) see note above - unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) } +impl Spi { + pub fn use_dma(self) -> DmaBuilder { + DmaBuilder { spi: self.spi } } } diff --git a/src/spi/hal_02.rs b/src/spi/hal_02.rs index bf183f3f..b91e6de3 100644 --- a/src/spi/hal_02.rs +++ b/src/spi/hal_02.rs @@ -28,23 +28,23 @@ impl From for super::Mode { } mod nb { - use super::super::{Error, Instance, Spi}; + use super::super::{Error, FrameSize, Instance, Spi}; use embedded_hal::spi::FullDuplex; - impl FullDuplex for Spi + impl FullDuplex for Spi where SPI: Instance, { type Error = Error; - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { if BIDI { self.spi.cr1.modify(|_, w| w.bidioe().clear_bit()); } self.check_read() } - fn send(&mut self, byte: u8) -> nb::Result<(), Error> { + fn send(&mut self, byte: W) -> nb::Result<(), Error> { if BIDI { self.spi.cr1.modify(|_, w| w.bidioe().set_bit()); } @@ -58,7 +58,7 @@ mod blocking { use embedded_hal::blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}; use embedded_hal::spi::FullDuplex; - impl Transfer for Spi + impl Transfer for Spi where SPI: Instance, { @@ -74,7 +74,23 @@ mod blocking { } } - impl Write for Spi + impl Transfer for Spi + where + SPI: Instance, + { + type Error = Error; + + fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { + for word in words.iter_mut() { + nb::block!(self.send(*word))?; + *word = nb::block!(self.read())?; + } + + Ok(words) + } + } + + impl Write for Spi where SPI: Instance, { @@ -85,7 +101,7 @@ mod blocking { } } - impl WriteIter for Spi + impl WriteIter for Spi where SPI: Instance, { @@ -106,13 +122,46 @@ mod blocking { } } - impl Transactional for Spi + impl Write for Spi + where + SPI: Instance, + { + type Error = Error; + + fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { + self.write_iter(words.iter().copied()) + } + } + + impl WriteIter for Spi + where + SPI: Instance, + { + type Error = Error; + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + for word in words.into_iter() { + nb::block!(self.send(word))?; + if !BIDI { + nb::block!(self.read())?; + } + } + + Ok(()) + } + } + + impl Transactional for Spi where + Self: Transfer + Write, SPI: Instance, { type Error = Error; - fn exec<'a>(&mut self, operations: &mut [Operation<'a, u8>]) -> Result<(), Error> { + fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Error> { for op in operations { match op { Operation::Write(w) => self.write(w)?, diff --git a/src/spi/hal_1.rs b/src/spi/hal_1.rs index c08ce0aa..a2860dcb 100644 --- a/src/spi/hal_1.rs +++ b/src/spi/hal_1.rs @@ -37,26 +37,26 @@ impl Error for super::Error { } } -impl ErrorType for super::Spi { +impl ErrorType for super::Spi { type Error = super::Error; } mod nb { - use super::super::{Error, Instance, Spi}; + use super::super::{Error, FrameSize, Instance, Spi}; use embedded_hal_one::spi::nb::FullDuplex; - impl FullDuplex for Spi + impl FullDuplex for Spi where SPI: Instance, { - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { if BIDI { self.spi.cr1.modify(|_, w| w.bidioe().clear_bit()); } self.check_read() } - fn write(&mut self, byte: u8) -> nb::Result<(), Error> { + fn write(&mut self, byte: W) -> nb::Result<(), Error> { if BIDI { self.spi.cr1.modify(|_, w| w.bidioe().set_bit()); } @@ -66,15 +66,14 @@ mod nb { } mod blocking { - use super::super::{Error, Instance, Spi}; + use super::super::{FrameSize, Instance, Spi}; use embedded_hal_one::spi::{ blocking::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite}, nb::FullDuplex, }; - impl SpiBus for Spi + impl SpiBus for Spi where - Self: FullDuplex + SpiBusWrite, SPI: Instance, { fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> { @@ -98,7 +97,7 @@ mod blocking { } } - impl SpiBusFlush for Spi + impl SpiBusFlush for Spi where SPI: Instance, { @@ -107,9 +106,8 @@ mod blocking { } } - impl SpiBusWrite for Spi + impl SpiBusWrite for Spi where - Self: FullDuplex, SPI: Instance, { fn write(&mut self, words: &[W]) -> Result<(), Self::Error> { @@ -124,10 +122,8 @@ mod blocking { } } - impl SpiBusRead - for Spi + impl SpiBusRead for Spi where - Self: FullDuplex, SPI: Instance, { fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {