Skip to content

Commit 691ee91

Browse files
committed
optimized Spi::write & move BSY to Spi::disable
1 parent d4e41b1 commit 691ee91

File tree

2 files changed

+53
-18
lines changed

2 files changed

+53
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2121
- Use `stm32f4-staging` until `stm32f4` is released [#706]
2222
- RTIC2 monotonics fix: CC1 instead of CC3
2323
- Allow different lengths of buffers in hal_1 SpiBus impl [#566]
24-
- Clean SPI write impls
24+
- Optimized version of blocking SPI write [#523]
2525
- `steal` UART peripheral on `Rx::new`
2626

2727
[#248]: https://github.com/stm32-rs/stm32f4xx-hal/pull/248
28+
[#523]: https://github.com/stm32-rs/stm32f4xx-hal/pull/523
2829
[#566]: https://github.com/stm32-rs/stm32f4xx-hal/pull/566
2930
[#706]: https://github.com/stm32-rs/stm32f4xx-hal/pull/706
3031
[#731]: https://github.com/stm32-rs/stm32f4xx-hal/pull/731

src/spi.rs

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ impl<SPI: Instance, const BIDI: bool, W> Spi<SPI, BIDI, W> {
589589
/// Convert the spi to another mode.
590590
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> Spi<SPI, BIDI2, W2> {
591591
let mut spi = Spi::_new(self.inner.spi, self.pins);
592-
spi.enable(false);
592+
spi.disable();
593593
spi.init()
594594
}
595595
}
@@ -606,7 +606,7 @@ impl<SPI: Instance, const BIDI: bool, W> SpiSlave<SPI, BIDI, W> {
606606
/// Convert the spi to another mode.
607607
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> SpiSlave<SPI, BIDI2, W2> {
608608
let mut spi = SpiSlave::_new(self.inner.spi, self.pins);
609-
spi.enable(false);
609+
spi.disable();
610610
spi.init()
611611
}
612612
}
@@ -685,12 +685,18 @@ impl<SPI: Instance> Inner<SPI> {
685685
Self { spi }
686686
}
687687

688-
/// Enable/disable spi
689-
pub fn enable(&mut self, enable: bool) {
690-
self.spi.cr1().modify(|_, w| {
691-
// spe: enable the SPI bus
692-
w.spe().bit(enable)
693-
});
688+
/// Enable SPI
689+
pub fn enable(&mut self) {
690+
// spe: enable the SPI bus
691+
self.spi.cr1().modify(|_, w| w.spe().set_bit());
692+
}
693+
694+
/// Disable SPI
695+
pub fn disable(&mut self) {
696+
// Wait for !BSY
697+
while self.is_busy() {}
698+
// spe: disable the SPI bus
699+
self.spi.cr1().modify(|_, w| w.spe().clear_bit());
694700
}
695701

696702
/// Select which frame format is used for data transfers
@@ -734,6 +740,19 @@ impl<SPI: Instance> Inner<SPI> {
734740
self.spi.sr().read().ovr().bit_is_set()
735741
}
736742

743+
fn check_errors(&self) -> Result<(), Error> {
744+
let sr = self.spi.sr().read();
745+
if sr.ovr().bit_is_set() {
746+
Err(Error::Overrun)
747+
} else if sr.modf().bit_is_set() {
748+
Err(Error::ModeFault)
749+
} else if sr.crcerr().bit_is_set() {
750+
Err(Error::Crc)
751+
} else {
752+
Ok(())
753+
}
754+
}
755+
737756
#[inline]
738757
fn bidi_output(&mut self) {
739758
self.spi.cr1().modify(|_, w| w.bidioe().set_bit());
@@ -798,23 +817,38 @@ impl<SPI: Instance> Inner<SPI> {
798817
})
799818
}
800819

820+
// Implement write as per the "Transmit only procedure"
821+
// RM SPI::3.5. This is more than twice as fast as the
822+
// default Write<> implementation (which reads and drops each
823+
// received value)
801824
fn spi_write<const BIDI: bool, W: FrameSize>(
802825
&mut self,
803826
words: impl IntoIterator<Item = W>,
804827
) -> Result<(), Error> {
805828
if BIDI {
806829
self.bidi_output();
807-
for word in words.into_iter() {
808-
nb::block!(self.check_send(word))?;
809-
}
810-
} else {
811-
for word in words.into_iter() {
812-
nb::block!(self.check_send(word))?;
813-
nb::block!(self.check_read::<W>())?;
830+
}
831+
// Write each word when the tx buffer is empty
832+
for word in words {
833+
loop {
834+
let sr = self.spi.sr().read();
835+
if sr.txe().bit_is_set() {
836+
self.write_data_reg(word);
837+
if sr.modf().bit_is_set() {
838+
return Err(Error::ModeFault);
839+
}
840+
break;
841+
}
814842
}
815843
}
816-
817-
Ok(())
844+
// Wait for final TXE
845+
while !self.is_tx_empty() {}
846+
if !BIDI {
847+
// Clear OVR set due to dropped received values
848+
let _: W = self.read_data_reg();
849+
}
850+
let _ = self.spi.sr().read();
851+
self.check_errors()
818852
}
819853

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

0 commit comments

Comments
 (0)