Skip to content

Commit 54408f1

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

File tree

2 files changed

+54
-15
lines changed

2 files changed

+54
-15
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: 52 additions & 14 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,11 +685,21 @@ impl<SPI: Instance> Inner<SPI> {
685685
Self { spi }
686686
}
687687

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

@@ -734,6 +744,19 @@ impl<SPI: Instance> Inner<SPI> {
734744
self.spi.sr().read().ovr().bit_is_set()
735745
}
736746

747+
fn check_errors(&self) -> Result<(), Error> {
748+
let sr = self.spi.sr().read();
749+
if sr.ovr().bit_is_set() {
750+
Err(Error::Overrun)
751+
} else if sr.modf().bit_is_set() {
752+
Err(Error::ModeFault)
753+
} else if sr.crcerr().bit_is_set() {
754+
Err(Error::Crc)
755+
} else {
756+
Ok(())
757+
}
758+
}
759+
737760
#[inline]
738761
fn bidi_output(&mut self) {
739762
self.spi.cr1().modify(|_, w| w.bidioe().set_bit());
@@ -798,23 +821,38 @@ impl<SPI: Instance> Inner<SPI> {
798821
})
799822
}
800823

824+
// Implement write as per the "Transmit only procedure"
825+
// RM SPI::3.5. This is more than twice as fast as the
826+
// default Write<> implementation (which reads and drops each
827+
// received value)
801828
fn spi_write<const BIDI: bool, W: FrameSize>(
802829
&mut self,
803830
words: impl IntoIterator<Item = W>,
804831
) -> Result<(), Error> {
805832
if BIDI {
806833
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>())?;
834+
}
835+
// Write each word when the tx buffer is empty
836+
for word in words {
837+
loop {
838+
let sr = self.spi.sr().read();
839+
if sr.txe().bit_is_set() {
840+
self.write_data_reg(word);
841+
if sr.modf().bit_is_set() {
842+
return Err(Error::ModeFault);
843+
}
844+
break;
845+
}
814846
}
815847
}
816-
817-
Ok(())
848+
// Wait for final TXE
849+
while !self.is_tx_empty() {}
850+
if !BIDI {
851+
// Clear OVR set due to dropped received values
852+
let _: W = self.read_data_reg();
853+
}
854+
let _ = self.spi.sr().read();
855+
self.check_errors()
818856
}
819857

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

0 commit comments

Comments
 (0)