Skip to content

Commit 36349c3

Browse files
committed
optimized Spi::write
1 parent b2636de commit 36349c3

File tree

4 files changed

+54
-18
lines changed

4 files changed

+54
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Changed
1111

12+
- Optimized version of blocking SPI write
1213
- Support `u16` read/write for SPI
1314
- Use `bool` for BIDI mode type
1415
- `PwmHz::get_period`: fix computation of return value, prevent division by zero

src/spi.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,19 @@ impl<SPI: Instance, PINS, const BIDI: bool, W, OPERATION> Spi<SPI, PINS, BIDI, W
605605
pub fn is_overrun(&self) -> bool {
606606
self.spi.sr.read().ovr().bit_is_set()
607607
}
608+
609+
fn check_errors(&self) -> Result<(), Error> {
610+
let sr = self.spi.sr.read();
611+
if sr.ovr().bit_is_set() {
612+
Err(Error::Overrun)
613+
} else if sr.modf().bit_is_set() {
614+
Err(Error::ModeFault)
615+
} else if sr.crcerr().bit_is_set() {
616+
Err(Error::Crc)
617+
} else {
618+
Ok(())
619+
}
620+
}
608621
}
609622

610623
trait ReadWriteReg<W> {
@@ -676,6 +689,42 @@ impl<SPI: Instance, PINS, const BIDI: bool, W: FrameSize, OPERATION>
676689
nb::Error::WouldBlock
677690
})
678691
}
692+
693+
// Implement write as per the "Transmit only procedure"
694+
// RM SPI::3.5. This is more than twice as fast as the
695+
// default Write<> implementation (which reads and drops each
696+
// received value)
697+
fn spi_write<WI>(&mut self, words: WI) -> Result<(), Error>
698+
where
699+
WI: IntoIterator<Item = W>,
700+
{
701+
if BIDI {
702+
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
703+
}
704+
// Write each word when the tx buffer is empty
705+
for word in words {
706+
loop {
707+
let sr = self.spi.sr.read();
708+
if sr.txe().bit_is_set() {
709+
self.write_data_reg(word);
710+
if sr.modf().bit_is_set() {
711+
return Err(Error::ModeFault);
712+
}
713+
break;
714+
}
715+
}
716+
}
717+
// Wait for final TXE
718+
while !self.is_tx_empty() {}
719+
// Wait for final !BSY
720+
while self.is_busy() {}
721+
if !BIDI {
722+
// Clear OVR set due to dropped received values
723+
let _ = self.read_data_reg();
724+
}
725+
let _ = self.spi.sr.read();
726+
self.check_errors()
727+
}
679728
}
680729

681730
// Spi DMA

src/spi/hal_02.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ mod blocking {
9797
type Error = Error;
9898

9999
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
100-
self.write_iter(words.iter().copied())
100+
self.spi_write(words.iter().copied())
101101
}
102102
}
103103

@@ -111,14 +111,7 @@ mod blocking {
111111
where
112112
WI: IntoIterator<Item = u8>,
113113
{
114-
for word in words.into_iter() {
115-
nb::block!(self.send(word))?;
116-
if !BIDI {
117-
nb::block!(self.read())?;
118-
}
119-
}
120-
121-
Ok(())
114+
self.spi_write(words)
122115
}
123116
}
124117

@@ -129,7 +122,7 @@ mod blocking {
129122
type Error = Error;
130123

131124
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
132-
self.write_iter(words.iter().copied())
125+
self.spi_write(words.iter().copied())
133126
}
134127
}
135128

src/spi/hal_1.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,7 @@ mod blocking {
111111
SPI: Instance,
112112
{
113113
fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
114-
for word in words {
115-
nb::block!(<Self as FullDuplex<W>>::write(self, *word))?;
116-
if !BIDI {
117-
nb::block!(<Self as FullDuplex<W>>::read(self))?;
118-
}
119-
}
120-
121-
Ok(())
114+
self.spi_write(words.iter().copied())
122115
}
123116
}
124117

0 commit comments

Comments
 (0)