From 1ad18aa09a8f6aefafab0b9e29c2c31dc614a320 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 5 May 2021 14:50:28 +0100 Subject: [PATCH 1/3] 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 d6b9ee8d8..d233a8af8 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::*; From 9de12a0a7a3dc3bb95a3bdc09817ead8e8130269 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 5 May 2021 18:25:14 +0100 Subject: [PATCH 2/3] Address issues in PR. --- embassy-nrf/src/spim.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index d233a8af8..3b5f7a070 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -232,7 +232,6 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> compiler_fence(Ordering::SeqCst); let r = T::regs(); - let s = T::state(); // Set up the DMA write. r.txd @@ -250,23 +249,20 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spim<'d, T> .maxcnt .write(|w| unsafe { w.maxcnt().bits(words.len() as _) }); - // Reset and enable the event + // Disable the end event since we are busy-polling. r.events_end.reset(); - r.intenset.write(|w| w.end().set()); // Start SPI transaction. r.tasks_start.write(|w| unsafe { w.bits(1) }); + // Wait for 'end' event. + while r.events_end.read().bits() == 0 {} + // 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) } } From 212e83aa221c1838e7da7617d08110580c53bfd2 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 5 May 2021 19:18:57 +0100 Subject: [PATCH 3/3] Make changes to `Write` as well as `Transfer` --- embassy-nrf/src/spim.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 3b5f7a070..3370e1243 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -280,7 +280,6 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { compiler_fence(Ordering::SeqCst); let r = T::regs(); - let s = T::state(); // Set up the DMA write. r.txd @@ -298,23 +297,20 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spim<'d, T> { .maxcnt .write(|w| unsafe { w.maxcnt().bits(recv.len() as _) }); - // Reset and enable the event + // Disable the end event since we are busy-polling. r.events_end.reset(); - r.intenset.write(|w| w.end().set()); // Start SPI transaction. r.tasks_start.write(|w| unsafe { w.bits(1) }); + // Wait for 'end' event. + while r.events_end.read().bits() == 0 {} + // 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(()) } }