Skip to content

Commit 84f34da

Browse files
committed
optimized Spi::write
1 parent 6a05a0e commit 84f34da

File tree

2 files changed

+51
-39
lines changed

2 files changed

+51
-39
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
- complete and rework Dma Stream API [#666]
1111
- add `.set_count()` for QEI, add `.write_count()` for TIM [#677]
1212
- add "Fast start" section in README [#678]
13+
- Optimized version of blocking SPI write [#523]
1314
- SPI bidi takes 2 pins [#526]
1415

16+
[#523]: https://github.com/stm32-rs/stm32f4xx-hal/pull/523
1517
[#526]: https://github.com/stm32-rs/stm32f4xx-hal/pull/526
1618
[#666]: https://github.com/stm32-rs/stm32f4xx-hal/pull/666
1719
[#677]: https://github.com/stm32-rs/stm32f4xx-hal/pull/677

src/spi.rs

+49-39
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,19 @@ impl<SPI: Instance> Inner<SPI> {
726726
self.spi.sr.read().ovr().bit_is_set()
727727
}
728728

729+
fn check_errors(&self) -> Result<(), Error> {
730+
let sr = self.spi.sr.read();
731+
if sr.ovr().bit_is_set() {
732+
Err(Error::Overrun)
733+
} else if sr.modf().bit_is_set() {
734+
Err(Error::ModeFault)
735+
} else if sr.crcerr().bit_is_set() {
736+
Err(Error::Crc)
737+
} else {
738+
Ok(())
739+
}
740+
}
741+
729742
#[inline]
730743
fn bidi_output(&mut self) {
731744
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
@@ -787,6 +800,39 @@ impl<SPI: Instance> Inner<SPI> {
787800
nb::Error::WouldBlock
788801
})
789802
}
803+
804+
// Implement write as per the "Transmit only procedure"
805+
// RM SPI::3.5. This is more than twice as fast as the
806+
// default Write<> implementation (which reads and drops each
807+
// received value)
808+
fn spi_write<const BIDI: bool, W: FrameSize>(&mut self, words: impl IntoIterator<Item = W>) -> Result<(), Error> {
809+
if BIDI {
810+
self.bidi_output();
811+
}
812+
// Write each word when the tx buffer is empty
813+
for word in words {
814+
loop {
815+
let sr = self.spi.sr.read();
816+
if sr.txe().bit_is_set() {
817+
self.write_data_reg(word);
818+
if sr.modf().bit_is_set() {
819+
return Err(Error::ModeFault);
820+
}
821+
break;
822+
}
823+
}
824+
}
825+
// Wait for final TXE
826+
while !self.is_tx_empty() {}
827+
// Wait for final !BSY
828+
while self.is_busy() {}
829+
if !BIDI {
830+
// Clear OVR set due to dropped received values
831+
let _: W = self.read_data_reg();
832+
}
833+
let _ = self.spi.sr.read();
834+
self.check_errors()
835+
}
790836
}
791837

792838
// Spi DMA
@@ -907,35 +953,11 @@ impl<SPI: Instance, const BIDI: bool, W: FrameSize> Spi<SPI, BIDI, W> {
907953
}
908954

909955
pub fn write(&mut self, words: &[W]) -> Result<(), Error> {
910-
if BIDI {
911-
self.bidi_output();
912-
for word in words {
913-
nb::block!(self.check_send(*word))?;
914-
}
915-
} else {
916-
for word in words {
917-
nb::block!(self.check_send(*word))?;
918-
nb::block!(self.check_read::<W>())?;
919-
}
920-
}
921-
922-
Ok(())
956+
self.spi_write::<BIDI, W>(words.iter().copied())
923957
}
924958

925959
pub fn write_iter(&mut self, words: impl IntoIterator<Item = W>) -> Result<(), Error> {
926-
if BIDI {
927-
self.bidi_output();
928-
for word in words.into_iter() {
929-
nb::block!(self.check_send(word))?;
930-
}
931-
} else {
932-
for word in words.into_iter() {
933-
nb::block!(self.check_send(word))?;
934-
nb::block!(self.check_read::<W>())?;
935-
}
936-
}
937-
938-
Ok(())
960+
self.spi_write::<BIDI, W>(words)
939961
}
940962

941963
pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
@@ -995,19 +1017,7 @@ impl<SPI: Instance, const BIDI: bool, W: FrameSize> SpiSlave<SPI, BIDI, W> {
9951017
}
9961018

9971019
pub fn write(&mut self, words: &[W]) -> Result<(), Error> {
998-
if BIDI {
999-
self.bidi_output();
1000-
for word in words {
1001-
nb::block!(self.check_send(*word))?;
1002-
}
1003-
} else {
1004-
for word in words {
1005-
nb::block!(self.check_send(*word))?;
1006-
nb::block!(self.check_read::<W>())?;
1007-
}
1008-
}
1009-
1010-
Ok(())
1020+
self.spi_write::<BIDI, W>(words.iter().copied())
10111021
}
10121022

10131023
pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> {

0 commit comments

Comments
 (0)