From 77e885d6b888756a424de5820a602b861f985670 Mon Sep 17 00:00:00 2001 From: Tim Docker Date: Wed, 12 Feb 2020 22:16:50 +1100 Subject: [PATCH] Replace default blocking spi Write implementation with an optimized one --- CHANGELOG.md | 1 + src/spi.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a7355e9..b4bb970c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Replace default blocking spi Write implementation with an optimized one - Use `Deref` for SPI generic implementations instead of macros - Make traits `rcc::Enable` and `rcc::Reset` public, but `RccBus` sealed - Add `QeiOptions` struct to configure slave mode and auto reload value of QEI interface diff --git a/src/spi.rs b/src/spi.rs index 686bee37..e1f888ba 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -35,7 +35,7 @@ use core::ptr; use nb; -pub use crate::hal::spi::{Mode, Phase, Polarity}; +pub use crate::hal::spi::{Mode, Phase, Polarity, FullDuplex}; #[cfg(feature = "high")] use crate::pac::SPI3; use crate::pac::{SPI1, SPI2}; @@ -334,9 +334,52 @@ impl crate::hal::blocking::spi::transfer::Default for Spi< { } -impl crate::hal::blocking::spi::write::Default for Spi where +impl crate::hal::blocking::spi::Write for Spi where SPI: Deref { + type Error = Error; + + // Implement write as per the "Transmit only procedure" page 712 + // of RM0008 Rev 20. This is more than twice as fast as the + // default Write<> implementation (which reads and drops each + // received value) + fn write(&mut self, words: &[u8]) -> Result<(), Error> { + // Write each word when the tx buffer is empty + for word in words { + loop { + let sr = self.spi.sr.read(); + if sr.txe().bit_is_set() { + // NOTE(write_volatile) see note above + unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) } + if sr.modf().bit_is_set() { + return Err(Error::ModeFault); + } + break; + } + } + } + // Wait for final TXE + loop { + let sr = self.spi.sr.read(); + if sr.txe().bit_is_set() { + break; + } + } + // Wait for final !BSY + loop { + let sr = self.spi.sr.read(); + if !sr.bsy().bit_is_set() { + break; + } + } + // Clear OVR set due to dropped received values + // NOTE(read_volatile) see note aboev + unsafe { + let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8); + } + let _ = self.spi.sr.read(); + Ok(()) + } } // DMA