From 1ad18aa09a8f6aefafab0b9e29c2c31dc614a320 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 5 May 2021 14:50:28 +0100 Subject: [PATCH] Implement the blocking hal api for SPIM. --- embassy-nrf/src/spim.rs | 105 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index d6b9ee8d..d233a8af 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -218,6 +218,111 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { } } +// Blocking functions are provided by implementing `embedded_hal` traits. +// +// Code could be shared between traits to reduce code size. +impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> { + type Error = Error; + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?; + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started. + compiler_fence(Ordering::SeqCst); + + let r = T::regs(); + let s = T::state(); + + // Set up the DMA write. + r.txd + .ptr + .write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); + + // Set up the DMA read. + r.rxd + .ptr + .write(|w| unsafe { w.ptr().bits(words.as_mut_ptr() as u32) }); + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); + + // Reset and enable the event + r.events_end.reset(); + r.intenset.write(|w| w.end().set()); + + // Start SPI transaction. + r.tasks_start.write(|w| unsafe { w.bits(1) }); + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // after all possible DMA actions have completed. + compiler_fence(Ordering::SeqCst); + + // Wait for 'end' event. + while r.events_end.read().bits() == 0 { + continue; + } + + Ok(words) + } +} + +impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { + type Error = Error; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?; + let mut recv: &mut [u8] = &mut []; + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started. + compiler_fence(Ordering::SeqCst); + + let r = T::regs(); + let s = T::state(); + + // Set up the DMA write. + r.txd + .ptr + .write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); + + // Set up the DMA read. + r.rxd + .ptr + .write(|w| unsafe { w.ptr().bits(recv.as_mut_ptr() as u32) }); + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(recv.len() as _) }); + + // Reset and enable the event + r.events_end.reset(); + r.intenset.write(|w| w.end().set()); + + // Start SPI transaction. + r.tasks_start.write(|w| unsafe { w.bits(1) }); + + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // after all possible DMA actions have completed. + compiler_fence(Ordering::SeqCst); + + // Wait for 'end' event. + while r.events_end.read().bits() == 0 { + continue; + } + + Ok(()) + } +} + mod sealed { use super::*;