Skip to content

Commit

Permalink
feat(spi): Add PanicOnRead and PanicOnWrite for simplex SPI transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
jbeaurivage committed Oct 28, 2024
1 parent d81f1d4 commit ff22e90
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 0 deletions.
70 changes: 70 additions & 0 deletions hal/src/sercom/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,76 @@ where
}
}

/// Wrapper type around a [`Spi`] that allows using
/// [`embedded_hal::spi::SpiBus`] even though it only has RX capability. Will
/// panic if any write-adjacent method is used (ie, `write`, `transfer`,
/// `transfer_in_place`, and `flush`).
///
/// Also implements `Into<Spi>, `AsRef<Spi>` and `AsMut<Spi>` if you need to use
/// `Spi` methods.
///
/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
pub struct PanicOnWrite<T: crate::ehal::spi::ErrorType>(T);

impl<C: ValidConfig, R, T> From<PanicOnWrite<Spi<C, Rx, R, T>>> for Spi<C, Rx, R, T> {
fn from(value: PanicOnWrite<Spi<C, Rx, R, T>>) -> Self {
value.0
}
}

impl<C: ValidConfig, R, T> AsRef<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
fn as_ref(&self) -> &Spi<C, Rx, R, T> {
&self.0
}
}
impl<C: ValidConfig, R, T> AsMut<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
fn as_mut(&mut self) -> &mut Spi<C, Rx, R, T> {
&mut self.0
}
}

impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
/// Turn a [`Tx`] [`Spi`] into a [`PanicOnWrite`]
pub fn into_panic_on_write(self) -> PanicOnWrite<Self> {
PanicOnWrite(self)
}
}

/// Wrapper type around a [`Spi`] that allows using
/// [`embedded_hal::spi::SpiBus`] even though it only has TX capability. Will
/// panic if any write-adjacent method is used (ie, `read`, `transfer`, and
/// `transfer_in_place`).
///
/// Also implements `Into<Spi>, `AsRef<Spi>` and `AsMut<Spi>` if you need to use
/// `Spi` methods.
///
/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
pub struct PanicOnRead<T: crate::ehal::spi::ErrorType>(T);

impl<C: ValidConfig, R, T> From<PanicOnRead<Spi<C, Tx, R, T>>> for Spi<C, Tx, R, T> {
fn from(value: PanicOnRead<Spi<C, Tx, R, T>>) -> Self {
value.0
}
}

impl<C: ValidConfig, R, T> AsRef<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
fn as_ref(&self) -> &Spi<C, Tx, R, T> {
&self.0
}
}

impl<C: ValidConfig, R, T> AsMut<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
fn as_mut(&mut self) -> &mut Spi<C, Tx, R, T> {
&mut self.0
}
}

impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
/// Turn a [`Rx`] [`Spi`] into a [`PanicOnRead`]
pub fn into_panic_on_read(self) -> PanicOnRead<Self> {
PanicOnRead(self)
}
}

#[hal_cfg("sercom0-d5x")]
impl<P, M, A> Spi<Config<P, M, DynLength>, A>
Expand Down
1 change: 1 addition & 0 deletions hal/src/sercom/spi/impl_ehal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use num_traits::PrimInt;

#[cfg(feature = "dma")]
mod dma;
mod panic_on;

#[hal_module(
any("sercom0-d11", "sercom0-d21") => "impl_ehal_thumbv6m.rs",
Expand Down
191 changes: 191 additions & 0 deletions hal/src/sercom/spi/impl_ehal/panic_on.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//! [`SpiBus`] implementations for [`PanicOnWrite`] and [`PanicOnRead`]
use num_traits::{AsPrimitive, PrimInt};

use crate::ehal::spi::{ErrorType, SpiBus};

use super::{
Config, DataWidth, Flags, MasterMode, NoneT, PanicOnRead, PanicOnWrite, Rx, Sercom, Size, Spi,
Tx, ValidConfig, ValidPads, Word,
};

impl<T: ErrorType> ErrorType for PanicOnRead<T> {
type Error = <T as ErrorType>::Error;
}

impl<T: ErrorType> ErrorType for PanicOnWrite<T> {
type Error = <T as ErrorType>::Error;
}

/// [`SpiBus`] implementation for [`PanicOnRead`] using word-by-word transfers
impl<P, M, C> SpiBus<Word<C>> for PanicOnRead<Spi<Config<P, M, C>, Tx>>
where
Config<P, M, C>: ValidConfig<OpMode = M>,
P: ValidPads,
M: MasterMode,
C: Size + 'static,
C::Word: PrimInt + AsPrimitive<DataWidth> + Copy,
DataWidth: AsPrimitive<C::Word>,
{
#[inline]
fn read(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn write(&mut self, words: &[Word<C>]) -> Result<(), Self::Error> {
for word in words {
self.0.block_on_flags(Flags::DRE)?;
unsafe { self.0.write_data(word.as_()) };
}

// No need to check for RX buffer overflows, receiver is always disabled for
// TX-only SPIs
self.0.flush_tx();
Ok(())
}

#[inline]
fn transfer(&mut self, _read: &mut [Word<C>], _write: &[Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn transfer_in_place(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn flush(&mut self) -> Result<(), Self::Error> {
self.0.flush_tx();
Ok(())
}
}

/// [`SpiBus`] implementation for [`PanicOnWrite`] using word-by-word transfers
impl<P, M, C> SpiBus<Word<C>> for PanicOnWrite<Spi<Config<P, M, C>, Rx>>
where
Config<P, M, C>: ValidConfig<OpMode = M>,
P: ValidPads,
M: MasterMode,
C: Size + 'static,
C::Word: PrimInt + AsPrimitive<DataWidth> + Copy,
DataWidth: AsPrimitive<C::Word>,
{
#[inline]
fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> {
self.0.read_word_by_word(words)
}

#[inline]
fn write(&mut self, _words: &[Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn transfer(&mut self, _read: &mut [Word<C>], _write: &[Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn transfer_in_place(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn flush(&mut self) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}
}

#[cfg(feature = "dma")]
mod dma {
use super::*;
use crate::dmac::{AnyChannel, Beat, Ready};

/// [`SpiBus`] implementation for [`PanicOnRead`] using DMA transfers
impl<P, M, C, T, S> SpiBus<Word<C>> for PanicOnRead<Spi<Config<P, M, C>, Tx, NoneT, T>>
where
Config<P, M, C>: ValidConfig<Sercom = S, OpMode = M>,
P: ValidPads,
M: MasterMode,
C: Size + 'static,
C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
S: Sercom,
DataWidth: AsPrimitive<C::Word>,
T: AnyChannel<Status = Ready>,
{
#[inline]
fn read(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn write(&mut self, words: &[Word<C>]) -> Result<(), Self::Error> {
self.0.write_dma(words)?;
Ok(())
}

#[inline]
fn transfer(
&mut self,
_read: &mut [Word<C>],
_write: &[Word<C>],
) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn transfer_in_place(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnRead` panics on SPI reads");
}

#[inline]
fn flush(&mut self) -> Result<(), Self::Error> {
self.0.flush_tx();
Ok(())
}
}

/// [`SpiBus`] implementation for [`PanicOnWrite`] using DMA transfers
impl<P, M, C, R, T> SpiBus<Word<C>> for PanicOnWrite<Spi<Config<P, M, C>, Rx, R, T>>
where
Config<P, M, C>: ValidConfig<OpMode = M>,
P: ValidPads,
M: MasterMode,
C: Size + 'static,
C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
DataWidth: AsPrimitive<C::Word>,
R: AnyChannel<Status = Ready>,
T: AnyChannel<Status = Ready>,
{
#[inline]
fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> {
self.0.read_dma_master(words)
}

#[inline]
fn write(&mut self, _words: &[Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn transfer(
&mut self,
_read: &mut [Word<C>],
_write: &[Word<C>],
) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn transfer_in_place(&mut self, _words: &mut [Word<C>]) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}

#[inline]
fn flush(&mut self) -> Result<(), Self::Error> {
unimplemented!("`PanicOnWrite` panics on SPI writes");
}
}
}

0 comments on commit ff22e90

Please sign in to comment.