|
@@ -109,10 +109,11 @@ pins_impl!(
|
|
|
(MISO, SCK, MOSI), (Miso, Sck, Mosi), (_Miso, _Sck, _Mosi);
|
|
|
);
|
|
|
|
|
|
-pub struct Spi<SPI, REMAP, PINS> {
|
|
|
+pub struct Spi<SPI, REMAP, PINS, FRAMESIZE> {
|
|
|
spi: SPI,
|
|
|
pins: PINS,
|
|
|
_remap: PhantomData<REMAP>,
|
|
|
+ _framesize: PhantomData<FRAMESIZE>,
|
|
|
}
|
|
|
|
|
|
/// A filler type for when the SCK pin is unnecessary
|
|
@@ -147,9 +148,9 @@ remap!(Spi3NoRemap, SPI3, false, PB3, PB4, PB5);
|
|
|
#[cfg(feature = "connectivity")]
|
|
|
remap!(Spi3Remap, SPI3, true, PC10, PC11, PC12);
|
|
|
|
|
|
-impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
|
|
|
+impl<REMAP, PINS> Spi<SPI1, REMAP, PINS, u8> {
|
|
|
/**
|
|
|
- Constructs an SPI instance using SPI1.
|
|
|
+ Constructs an SPI instance using SPI1 in 8bit dataframe mode.
|
|
|
|
|
|
The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
|
|
|
|
|
@@ -170,13 +171,13 @@ impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
|
|
|
PINS: Pins<REMAP, POS>,
|
|
|
{
|
|
|
mapr.modify_mapr(|_, w| w.spi1_remap().bit(REMAP::REMAP));
|
|
|
- Spi::<SPI1, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
+ Spi::<SPI1, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
|
|
|
+impl<REMAP, PINS> Spi<SPI2, REMAP, PINS, u8> {
|
|
|
/**
|
|
|
- Constructs an SPI instance using SPI2.
|
|
|
+ Constructs an SPI instance using SPI2 in 8bit dataframe mode.
|
|
|
|
|
|
The pin parameter tuple (sck, miso, mosi) should be `(PB13, PB14, PB15)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
|
|
|
|
|
@@ -195,14 +196,14 @@ impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
|
|
|
REMAP: Remap<Periph = SPI2>,
|
|
|
PINS: Pins<REMAP, POS>,
|
|
|
{
|
|
|
- Spi::<SPI2, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
+ Spi::<SPI2, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[cfg(any(feature = "high", feature = "connectivity"))]
|
|
|
-impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
|
|
|
+impl<REMAP, PINS> Spi<SPI3, REMAP, PINS, u8> {
|
|
|
/**
|
|
|
- Constructs an SPI instance using SPI3.
|
|
|
+ Constructs an SPI instance using SPI3 in 8bit dataframe mode.
|
|
|
|
|
|
The pin parameter tuple (sck, miso, mosi) should be `(PB3, PB4, PB5)` or `(PC10, PC11, PC12)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
|
|
|
|
|
@@ -221,13 +222,94 @@ impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
|
|
|
REMAP: Remap<Periph = SPI3>,
|
|
|
PINS: Pins<REMAP, POS>,
|
|
|
{
|
|
|
- Spi::<SPI3, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
+ Spi::<SPI3, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub type SpiRegisterBlock = crate::pac::spi1::RegisterBlock;
|
|
|
|
|
|
-impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS>
|
|
|
+pub trait SpiReadWrite<T> {
|
|
|
+ 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<SPI, REMAP, PINS, FrameSize> SpiReadWrite<FrameSize> for Spi<SPI, REMAP, PINS, FrameSize>
|
|
|
+where
|
|
|
+ SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+ FrameSize: Copy,
|
|
|
+{
|
|
|
+ fn read_data_reg(&mut self) -> FrameSize {
|
|
|
+ // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
|
|
|
+ // reading a half-word)
|
|
|
+ return unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const FrameSize) };
|
|
|
+ }
|
|
|
+
|
|
|
+ fn write_data_reg(&mut self, data: FrameSize) {
|
|
|
+ // NOTE(write_volatile) see note above
|
|
|
+ unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut FrameSize, data) }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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 spi_write(&mut self, words: &[FrameSize]) -> Result<(), Error> {
|
|
|
+ // Write each word when the tx buffer is empty
|
|
|
+ for word in words {
|
|
|
+ loop {
|
|
|
+ let sr = self.spi.sr.read();
|
|
|
+ if sr.txe().bit_is_set() {
|
|
|
+ // NOTE(write_volatile) see note above
|
|
|
+ // unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
|
|
|
+ self.write_data_reg(*word);
|
|
|
+ if sr.modf().bit_is_set() {
|
|
|
+ return Err(Error::ModeFault);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Wait for final TXE
|
|
|
+ loop {
|
|
|
+ let sr = self.spi.sr.read();
|
|
|
+ if sr.txe().bit_is_set() {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Wait for final !BSY
|
|
|
+ loop {
|
|
|
+ let sr = self.spi.sr.read();
|
|
|
+ if !sr.bsy().bit_is_set() {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Clear OVR set due to dropped received values
|
|
|
+ // NOTE(read_volatile) see note above
|
|
|
+ // unsafe {
|
|
|
+ // let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
|
|
|
+ // }
|
|
|
+ let _ = self.read_data_reg();
|
|
|
+ let _ = self.spi.sr.read();
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<SPI, REMAP, PINS, FrameSize> Spi<SPI, REMAP, PINS, FrameSize>
|
|
|
+where
|
|
|
+ SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+ FrameSize: Copy,
|
|
|
+{
|
|
|
+ #[deprecated(since = "0.6.0", note = "Please use release instead")]
|
|
|
+ pub fn free(self) -> (SPI, PINS) {
|
|
|
+ self.release()
|
|
|
+ }
|
|
|
+ pub fn release(self) -> (SPI, PINS) {
|
|
|
+ (self.spi, self.pins)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u8>
|
|
|
where
|
|
|
SPI: Deref<Target = SpiRegisterBlock> + Enable + Reset,
|
|
|
SPI::Bus: GetBusFreq,
|
|
@@ -300,25 +382,50 @@ where
|
|
|
spi,
|
|
|
pins,
|
|
|
_remap: PhantomData,
|
|
|
+ _framesize: PhantomData,
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- #[deprecated(since = "0.6.0", note = "Please use release instead")]
|
|
|
- pub fn free(self) -> (SPI, PINS) {
|
|
|
- self.release()
|
|
|
+ /// Converts from 8bit dataframe to 16bit.
|
|
|
+ pub fn frame_size_16bit(self) -> Spi<SPI, REMAP, PINS, u16> {
|
|
|
+ self.spi.cr1.modify(|_, w| w.spe().clear_bit());
|
|
|
+ self.spi.cr1.modify(|_, w| w.dff().set_bit());
|
|
|
+ self.spi.cr1.modify(|_, w| w.spe().set_bit());
|
|
|
+ Spi {
|
|
|
+ spi: self.spi,
|
|
|
+ pins: self.pins,
|
|
|
+ _remap: PhantomData,
|
|
|
+ _framesize: PhantomData,
|
|
|
+ }
|
|
|
}
|
|
|
- pub fn release(self) -> (SPI, PINS) {
|
|
|
- (self.spi, self.pins)
|
|
|
+}
|
|
|
+
|
|
|
+impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u16>
|
|
|
+where
|
|
|
+ SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+{
|
|
|
+ /// Converts from 16bit dataframe to 8bit.
|
|
|
+ pub fn frame_size_8bit(self) -> Spi<SPI, REMAP, PINS, u8> {
|
|
|
+ self.spi.cr1.modify(|_, w| w.spe().clear_bit());
|
|
|
+ self.spi.cr1.modify(|_, w| w.dff().clear_bit());
|
|
|
+ self.spi.cr1.modify(|_, w| w.spe().set_bit());
|
|
|
+ Spi {
|
|
|
+ spi: self.spi,
|
|
|
+ pins: self.pins,
|
|
|
+ _remap: PhantomData,
|
|
|
+ _framesize: PhantomData,
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<SPI, REMAP, PINS> crate::hal::spi::FullDuplex<u8> for Spi<SPI, REMAP, PINS>
|
|
|
+impl<SPI, REMAP, PINS, FrameSize> crate::hal::spi::FullDuplex<FrameSize>
|
|
|
+ for Spi<SPI, REMAP, PINS, FrameSize>
|
|
|
where
|
|
|
SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+ FrameSize: Copy,
|
|
|
{
|
|
|
type Error = Error;
|
|
|
|
|
|
- fn read(&mut self) -> nb::Result<u8, Error> {
|
|
|
+ fn read(&mut self) -> nb::Result<FrameSize, Error> {
|
|
|
let sr = self.spi.sr.read();
|
|
|
|
|
|
Err(if sr.ovr().bit_is_set() {
|
|
@@ -330,13 +437,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(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
|
|
|
+ return Ok(self.read_data_reg());
|
|
|
} else {
|
|
|
nb::Error::WouldBlock
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
|
|
|
+ fn send(&mut self, data: FrameSize) -> nb::Result<(), Error> {
|
|
|
let sr = self.spi.sr.read();
|
|
|
|
|
|
Err(if sr.ovr().bit_is_set() {
|
|
@@ -347,7 +454,7 @@ where
|
|
|
nb::Error::Other(Error::Crc)
|
|
|
} else if sr.txe().bit_is_set() {
|
|
|
// NOTE(write_volatile) see note above
|
|
|
- unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
|
|
|
+ self.write_data_reg(data);
|
|
|
return Ok(());
|
|
|
} else {
|
|
|
nb::Error::WouldBlock
|
|
@@ -355,12 +462,15 @@ where
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<SPI, REMAP, PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<SPI, REMAP, PINS> where
|
|
|
- SPI: Deref<Target = SpiRegisterBlock>
|
|
|
+impl<SPI, REMAP, PINS, FrameSize> crate::hal::blocking::spi::transfer::Default<FrameSize>
|
|
|
+ for Spi<SPI, REMAP, PINS, FrameSize>
|
|
|
+where
|
|
|
+ SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+ FrameSize: Copy,
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS>
|
|
|
+impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS, u8>
|
|
|
where
|
|
|
SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
{
|
|
@@ -371,48 +481,25 @@ where
|
|
|
// default Write<> implementation (which reads and drops each
|
|
|
// received value)
|
|
|
fn write(&mut self, words: &[u8]) -> Result<(), Error> {
|
|
|
- // Write each word when the tx buffer is empty
|
|
|
- for word in words {
|
|
|
- loop {
|
|
|
- let sr = self.spi.sr.read();
|
|
|
- if sr.txe().bit_is_set() {
|
|
|
- // NOTE(write_volatile) see note above
|
|
|
- unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
|
|
|
- if sr.modf().bit_is_set() {
|
|
|
- return Err(Error::ModeFault);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- // Wait for final TXE
|
|
|
- loop {
|
|
|
- let sr = self.spi.sr.read();
|
|
|
- if sr.txe().bit_is_set() {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- // Wait for final !BSY
|
|
|
- loop {
|
|
|
- let sr = self.spi.sr.read();
|
|
|
- if !sr.bsy().bit_is_set() {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- // Clear OVR set due to dropped received values
|
|
|
- // NOTE(read_volatile) see note above
|
|
|
- unsafe {
|
|
|
- let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
|
|
|
- }
|
|
|
- let _ = self.spi.sr.read();
|
|
|
- Ok(())
|
|
|
+ self.spi_write(words)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u16> for Spi<SPI, REMAP, PINS, u16>
|
|
|
+where
|
|
|
+ SPI: Deref<Target = SpiRegisterBlock>,
|
|
|
+{
|
|
|
+ type Error = Error;
|
|
|
+
|
|
|
+ fn write(&mut self, words: &[u16]) -> Result<(), Error> {
|
|
|
+ self.spi_write(words)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// DMA
|
|
|
|
|
|
pub struct SpiPayload<SPI, REMAP, PINS> {
|
|
|
- spi: Spi<SPI, REMAP, PINS>,
|
|
|
+ spi: Spi<SPI, REMAP, PINS, u8>,
|
|
|
}
|
|
|
|
|
|
pub type SpiTxDma<SPI, REMAP, PINS, CHANNEL> = TxDma<SpiPayload<SPI, REMAP, PINS>, CHANNEL>;
|
|
@@ -424,7 +511,7 @@ macro_rules! spi_dma {
|
|
|
type ReceivedWord = u8;
|
|
|
}
|
|
|
|
|
|
- impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS> {
|
|
|
+ impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS, u8> {
|
|
|
pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
|
|
|
let payload = SpiPayload { spi: self };
|
|
|
SpiTxDma { payload, channel }
|