diff --git a/CHANGELOG.md b/CHANGELOG.md index e57e72a7..0e90d506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Update to `stm32f1` v0.16.0 [#503] [#534] - `Spi` now takes `Option` for `SCK`, `MISO`, `MOSI` [#514], add `SPIx::NoSck`, etc. [#537] +- `spi::FrameSize` and `embedded-hal` 1.0 implementations - move `Qei` mod inside `pwm_input` mod [#516] ### Changed diff --git a/src/spi.rs b/src/spi.rs index 19d64d75..b21cf823 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -66,7 +66,6 @@ mod hal_02; mod hal_1; use core::ops::{Deref, DerefMut}; -use core::ptr; use crate::pac::{self, RCC}; @@ -109,6 +108,36 @@ pub struct Mode { pub phase: Phase, } +type SpiRB = pac::spi1::RegisterBlock; + +pub trait FrameSize: Copy + Default { + const DFF: bool; + #[doc(hidden)] + fn read_data(spi: &SpiRB) -> Self; + #[doc(hidden)] + fn write_data(self, spi: &SpiRB); +} + +impl FrameSize for u8 { + const DFF: bool = false; + fn read_data(spi: &SpiRB) -> Self { + spi.dr8().read().dr().bits() + } + fn write_data(self, spi: &SpiRB) { + spi.dr8().write(|w| w.dr().set(self)); + } +} + +impl FrameSize for u16 { + const DFF: bool = true; + fn read_data(spi: &SpiRB) -> Self { + spi.dr().read().dr().bits() + } + fn write_data(self, spi: &SpiRB) { + spi.dr().write(|w| w.dr().set(self)); + } +} + /// Interrupt event pub enum Event { /// New data has been received @@ -519,24 +548,7 @@ impl SpiSlave { } } -pub trait SpiReadWrite { - fn read_data_reg(&mut self) -> T; - fn write_data_reg(&mut self, data: T); - fn spi_write(&mut self, words: &[T]) -> Result<(), Error>; -} - -impl SpiReadWrite for SpiInner { - 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_ptr() 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_ptr() as *mut W, data) } - } - +impl SpiInner { // 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 @@ -547,7 +559,7 @@ impl SpiReadWrite for SpiInner { loop { let sr = self.spi.sr().read(); if sr.txe().bit_is_set() { - self.write_data_reg(*word); + (*word).write_data(&self.spi); if sr.modf().bit_is_set() { return Err(Error::ModeFault); } @@ -560,13 +572,13 @@ impl SpiReadWrite for SpiInner { // Wait for final !BSY while self.is_busy() {} // Clear OVR set due to dropped received values - let _ = self.read_data_reg(); + let _ = W::read_data(&self.spi); let _ = self.spi.sr().read(); Ok(()) } } -impl SpiInner { +impl SpiInner { /// Select which frame format is used for data transfers pub fn bit_format(&mut self, format: SpiBitFormat) { self.spi @@ -676,9 +688,9 @@ impl SpiSlave { impl SpiInner where SPI: Instance, - W: Copy, + W: FrameSize, { - pub fn read_nonblocking(&mut self) -> nb::Result { + pub(crate) fn check_read(&mut self) -> nb::Result { let sr = self.spi.sr().read(); Err(if sr.ovr().bit_is_set() { @@ -690,12 +702,13 @@ where } 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()); + return Ok(W::read_data(&self.spi)); } else { nb::Error::WouldBlock }) } - pub fn write_nonblocking(&mut self, data: W) -> nb::Result<(), Error> { + + pub(crate) fn check_send(&mut self, data: W) -> nb::Result<(), Error> { let sr = self.spi.sr().read(); // NOTE: Error::Overrun was deleted in #408. Need check @@ -705,15 +718,83 @@ where Error::Crc.into() } else if sr.txe().bit_is_set() { // NOTE(write_volatile) see note above - self.write_data_reg(data); + data.write_data(&self.spi); return Ok(()); } else { nb::Error::WouldBlock }) } + + #[inline(always)] + pub fn read_nonblocking(&mut self) -> nb::Result { + // TODO: bidimode + self.check_read() + } + + #[inline(always)] + pub fn write_nonblocking(&mut self, data: W) -> nb::Result<(), Error> { + // TODO: bidimode + self.check_send(data) + } + + #[inline(always)] pub fn write(&mut self, words: &[W]) -> Result<(), Error> { self.spi_write(words) } + + pub fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> { + for word in words { + nb::block!(self.write_nonblocking(*word))?; + *word = nb::block!(self.read_nonblocking())?; + } + + Ok(()) + } + + pub fn transfer(&mut self, buff: &mut [W], data: &[W]) -> Result<(), Error> { + if data.len() == buff.len() { + for (d, b) in data.iter().cloned().zip(buff.iter_mut()) { + nb::block!(self.write_nonblocking(d))?; + *b = nb::block!(self.read_nonblocking())?; + } + } else { + let mut iter_r = buff.iter_mut(); + let mut iter_w = data.iter().cloned(); + loop { + match (iter_r.next(), iter_w.next()) { + (Some(r), Some(w)) => { + nb::block!(self.write_nonblocking(w))?; + *r = nb::block!(self.read_nonblocking())?; + } + (Some(r), None) => { + nb::block!(self.write_nonblocking(W::default()))?; + *r = nb::block!(self.read_nonblocking())?; + } + (None, Some(w)) => { + nb::block!(self.write_nonblocking(w))?; + let _ = nb::block!(self.read_nonblocking())?; + } + (None, None) => break, + } + } + } + + Ok(()) + } + + pub fn flush(&mut self) -> Result<(), Error> { + Ok(()) + } + + pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> { + // TODO: bidimode + for word in words { + nb::block!(self.check_send(W::default()))?; + *word = nb::block!(self.check_read())?; + } + + Ok(()) + } } // DMA diff --git a/src/spi/hal_02.rs b/src/spi/hal_02.rs index 2e410153..2c1ce88f 100644 --- a/src/spi/hal_02.rs +++ b/src/spi/hal_02.rs @@ -33,7 +33,7 @@ impl From for super::Mode { impl spi::FullDuplex for Spi where SPI: Instance, - W: Copy, + W: FrameSize, { type Error = Error; @@ -49,7 +49,7 @@ where impl blocking::transfer::Default for Spi where SPI: Instance, - W: Copy, + W: FrameSize, { } diff --git a/src/spi/hal_1.rs b/src/spi/hal_1.rs index f038ac72..d9be5cb3 100644 --- a/src/spi/hal_1.rs +++ b/src/spi/hal_1.rs @@ -43,13 +43,13 @@ impl ErrorType for Spi { } mod nb { - use super::{Error, Instance, Spi}; + use super::{Error, FrameSize, Instance, Spi}; use embedded_hal_nb::spi::FullDuplex; impl FullDuplex for Spi where SPI: Instance, - W: Copy, + W: FrameSize, { fn read(&mut self) -> nb::Result { self.read_nonblocking() @@ -62,25 +62,25 @@ mod nb { } mod blocking { - use super::super::{Instance, Spi}; + use super::super::{FrameSize, Instance, Spi}; use core::ops::DerefMut; use embedded_hal::spi::SpiBus; impl SpiBus for Spi where SPI: Instance, - W: Copy + 'static, + W: FrameSize + 'static, { - fn transfer_in_place(&mut self, _words: &mut [W]) -> Result<(), Self::Error> { - todo!() + fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> { + self.deref_mut().transfer_in_place(words) } - fn transfer(&mut self, _buff: &mut [W], _data: &[W]) -> Result<(), Self::Error> { - todo!() + fn transfer(&mut self, buff: &mut [W], data: &[W]) -> Result<(), Self::Error> { + self.deref_mut().transfer(buff, data) } - fn read(&mut self, _words: &mut [W]) -> Result<(), Self::Error> { - todo!() + fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> { + self.deref_mut().read(words) } fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {