Skip to content

Commit bcdf55c

Browse files
committed
optimized Spi::write & move BSY to Spi::disable
1 parent ed88ea1 commit bcdf55c

File tree

2 files changed

+54
-17
lines changed

2 files changed

+54
-17
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
## [Unreleased]
99

1010
- Bump `stm32f4-staging`
11+
- Optimized version of blocking SPI write [#523]
12+
13+
[#523]: https://github.com/stm32-rs/stm32f4xx-hal/pull/523
1114

1215
## [v0.22.1] - 2024-11-03
1316

src/spi.rs

+51-17
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ impl<SPI: Instance, const BIDI: bool, W> Spi<SPI, BIDI, W> {
607607
/// Convert the spi to another mode.
608608
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> Spi<SPI, BIDI2, W2> {
609609
let mut spi = Spi::_new(self.inner.spi, self.pins);
610-
spi.enable(false);
610+
spi.disable();
611611
spi.init()
612612
}
613613
}
@@ -624,7 +624,7 @@ impl<SPI: Instance, const BIDI: bool, W> SpiSlave<SPI, BIDI, W> {
624624
/// Convert the spi to another mode.
625625
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> SpiSlave<SPI, BIDI2, W2> {
626626
let mut spi = SpiSlave::_new(self.inner.spi, self.pins);
627-
spi.enable(false);
627+
spi.disable();
628628
spi.init()
629629
}
630630
}
@@ -703,12 +703,18 @@ impl<SPI: Instance> Inner<SPI> {
703703
Self { spi }
704704
}
705705

706-
/// Enable/disable spi
707-
pub fn enable(&mut self, enable: bool) {
708-
self.spi.cr1().modify(|_, w| {
709-
// spe: enable the SPI bus
710-
w.spe().bit(enable)
711-
});
706+
/// Enable SPI
707+
pub fn enable(&mut self) {
708+
// spe: enable the SPI bus
709+
self.spi.cr1().modify(|_, w| w.spe().set_bit());
710+
}
711+
712+
/// Disable SPI
713+
pub fn disable(&mut self) {
714+
// Wait for !BSY
715+
while self.is_busy() {}
716+
// spe: disable the SPI bus
717+
self.spi.cr1().modify(|_, w| w.spe().clear_bit());
712718
}
713719

714720
/// Select which frame format is used for data transfers
@@ -752,6 +758,19 @@ impl<SPI: Instance> Inner<SPI> {
752758
self.spi.sr().read().ovr().bit_is_set()
753759
}
754760

761+
fn check_errors(&self) -> Result<(), Error> {
762+
let sr = self.spi.sr().read();
763+
if sr.ovr().bit_is_set() {
764+
Err(Error::Overrun)
765+
} else if sr.modf().bit_is_set() {
766+
Err(Error::ModeFault)
767+
} else if sr.crcerr().bit_is_set() {
768+
Err(Error::Crc)
769+
} else {
770+
Ok(())
771+
}
772+
}
773+
755774
#[inline]
756775
fn bidi_output(&mut self) {
757776
self.spi.cr1().modify(|_, w| w.bidioe().set_bit());
@@ -811,23 +830,38 @@ impl<SPI: Instance> Inner<SPI> {
811830
})
812831
}
813832

833+
// Implement write as per the "Transmit only procedure"
834+
// RM SPI::3.5. This is more than twice as fast as the
835+
// default Write<> implementation (which reads and drops each
836+
// received value)
814837
fn spi_write<const BIDI: bool, W: FrameSize>(
815838
&mut self,
816839
words: impl IntoIterator<Item = W>,
817840
) -> Result<(), Error> {
818841
if BIDI {
819842
self.bidi_output();
820-
for word in words.into_iter() {
821-
nb::block!(self.check_send(word))?;
822-
}
823-
} else {
824-
for word in words.into_iter() {
825-
nb::block!(self.check_send(word))?;
826-
nb::block!(self.check_read::<W>())?;
843+
}
844+
// Write each word when the tx buffer is empty
845+
for word in words {
846+
loop {
847+
let sr = self.spi.sr().read();
848+
if sr.txe().bit_is_set() {
849+
self.write_data_reg(word);
850+
if sr.modf().bit_is_set() {
851+
return Err(Error::ModeFault);
852+
}
853+
break;
854+
}
827855
}
828856
}
829-
830-
Ok(())
857+
// Wait for final TXE
858+
while !self.is_tx_empty() {}
859+
if !BIDI {
860+
// Clear OVR set due to dropped received values
861+
let _: W = self.read_data_reg();
862+
}
863+
let _ = self.spi.sr().read();
864+
self.check_errors()
831865
}
832866

833867
fn listen_event(&mut self, disable: Option<BitFlags<Event>>, enable: Option<BitFlags<Event>>) {

0 commit comments

Comments
 (0)