atsamd_hal/sercom/spi/impl_ehal/
mod.rs

1use super::*;
2use crate::ehal::spi::{self, SpiBus};
3#[allow(unused_imports)]
4use crate::ehal_02::{blocking, serial};
5use crate::ehal_nb;
6use num_traits::PrimInt;
7
8#[cfg(feature = "dma")]
9mod dma;
10mod panic_on;
11
12#[hal_module(
13    any("sercom0-d11", "sercom0-d21") => "thumbv6m.rs",
14    "sercom0-d5x" => "thumbv7em.rs")]
15pub mod impl_ehal_02 {}
16
17impl spi::Error for Error {
18    #[allow(unreachable_patterns)]
19    #[inline]
20    fn kind(&self) -> crate::ehal::spi::ErrorKind {
21        match self {
22            Error::Overflow => crate::ehal::spi::ErrorKind::Overrun,
23            Error::LengthError => crate::ehal::spi::ErrorKind::Other,
24            // Pattern reachable when "dma" feature is enabled
25            _ => crate::ehal::spi::ErrorKind::Other,
26        }
27    }
28}
29
30impl<C, D, R, T> ehal::spi::ErrorType for Spi<C, D, R, T>
31where
32    C: ValidConfig,
33    D: Capability,
34{
35    type Error = Error;
36}
37
38impl embedded_io::Error for Error {
39    fn kind(&self) -> embedded_io::ErrorKind {
40        embedded_io::ErrorKind::Other
41    }
42}
43
44impl<C, D, R, T> embedded_io::ErrorType for Spi<C, D, R, T>
45where
46    C: ValidConfig,
47    D: Capability,
48{
49    type Error = Error;
50}
51
52impl ehal_nb::serial::Error for Error {
53    #[allow(unreachable_patterns)]
54    fn kind(&self) -> ehal_nb::serial::ErrorKind {
55        match self {
56            Error::Overflow => ehal_nb::serial::ErrorKind::Overrun,
57            Error::LengthError => ehal_nb::serial::ErrorKind::Other,
58            // Pattern reachable when "dma" feature is enabled
59            _ => ehal_nb::serial::ErrorKind::Other,
60        }
61    }
62}
63
64impl<C, D, R, T> ehal_nb::serial::ErrorType for Spi<C, D, R, T>
65where
66    C: ValidConfig,
67    D: Capability,
68{
69    type Error = Error;
70}
71
72// Implementations for SPIs in either Master or Slave mode.
73impl<P, M, C, D, R, T> Spi<Config<P, M, C>, D, R, T>
74where
75    Config<P, M, C>: ValidConfig,
76    P: ValidPads,
77    M: OpMode,
78    C: Size + 'static,
79    C::Word: PrimInt + AsPrimitive<DataWidth>,
80    DataWidth: AsPrimitive<C::Word>,
81    D: Capability,
82{
83    /// Read and write a single word to the bus simultaneously.
84    #[inline]
85    fn transfer_word_in_place(&mut self, word: C::Word) -> Result<C::Word, Error> {
86        self.block_on_flags(Flags::DRE)?;
87
88        unsafe {
89            self.write_data(word.as_());
90        }
91
92        self.flush_rx()?;
93        let word = unsafe { self.read_data().as_() };
94        Ok(word)
95    }
96
97    /// Perform a transfer, word by word.
98    ///
99    /// No-op words will be written if `read` is longer than `write`. Extra
100    /// words are ignored if `write` is longer than `read`.
101    #[inline]
102    fn transfer_word_by_word(
103        &mut self,
104        read: &mut [C::Word],
105        write: &[C::Word],
106    ) -> Result<(), Error> {
107        let nop_word = self.config.nop_word;
108
109        for (r, w) in read
110            .iter_mut()
111            .zip(write.iter().chain(core::iter::repeat(&nop_word.as_())))
112        {
113            *r = self.transfer_word_in_place(*w)?;
114        }
115
116        Ok(())
117    }
118
119    /// Wait on a TXC while ignoring buffer overflow errors.
120    #[inline]
121    fn flush_tx(&mut self) {
122        // Ignore buffer overflow errors
123        let _ = self.block_on_flags(Flags::TXC);
124    }
125
126    /// Wait on RXC flag
127    #[inline]
128    fn flush_rx(&mut self) -> Result<(), Error> {
129        self.block_on_flags(Flags::RXC)
130    }
131}
132
133// Implementations specific to Master mode SPIs.
134impl<P, M, C, D> Spi<Config<P, M, C>, D>
135where
136    Config<P, M, C>: ValidConfig,
137    P: ValidPads,
138    M: MasterMode,
139    C: Size + 'static,
140    C::Word: PrimInt + AsPrimitive<DataWidth> + Copy,
141    D: Capability,
142    DataWidth: AsPrimitive<C::Word>,
143{
144    #[inline]
145    fn read_word_by_word(&mut self, words: &mut [Word<C>]) -> Result<(), Error> {
146        // Due to the nature of how SPI works, we must send a word in order to clock a
147        // receive
148        for word in words.iter_mut() {
149            *word = self.transfer_word_in_place(self.config.nop_word.as_())?;
150        }
151        Ok(())
152    }
153
154    #[inline]
155    fn write_word_by_word(&mut self, words: &[Word<C>]) -> Result<(), Error> {
156        // Ignore RX buffer overflows by disabling the receiver
157        self.config.as_mut().regs.rx_disable();
158
159        for word in words {
160            self.block_on_flags(Flags::DRE)?;
161            unsafe {
162                self.write_data(word.as_());
163            }
164        }
165
166        // Reenable receiver only if necessary
167        if D::RX_ENABLE {
168            self.config.as_mut().regs.rx_enable();
169        }
170        Ok(())
171    }
172}
173
174/// [`SpiBus`] implementation for [`Spi`], using word-by-word transfers.
175impl<P, M, C> SpiBus<Word<C>> for Spi<Config<P, M, C>, Duplex>
176where
177    Config<P, M, C>: ValidConfig,
178    P: ValidPads,
179    M: MasterMode,
180    C: Size + 'static,
181    C::Word: PrimInt + AsPrimitive<DataWidth> + Copy,
182    DataWidth: AsPrimitive<C::Word>,
183{
184    #[inline]
185    fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> {
186        self.read_word_by_word(words)
187    }
188
189    #[inline]
190    fn write(&mut self, words: &[Word<C>]) -> Result<(), Self::Error> {
191        self.write_word_by_word(words)
192    }
193
194    #[inline]
195    fn transfer(&mut self, read: &mut [Word<C>], write: &[Word<C>]) -> Result<(), Self::Error> {
196        self.transfer_word_by_word(read, write)
197    }
198
199    #[inline]
200    fn transfer_in_place(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> {
201        for word in words {
202            let read = self.transfer_word_in_place(*word)?;
203            *word = read;
204        }
205
206        Ok(())
207    }
208
209    #[inline]
210    fn flush(&mut self) -> Result<(), Error> {
211        self.flush_tx();
212        Ok(())
213    }
214}