1use num_traits::{AsPrimitive, PrimInt};
4
5use crate::dmac::{AnyChannel, Beat, Buffer, Ready, channel, sram::DmacDescriptor};
6use crate::ehal::spi::SpiBus;
7use crate::sercom::dma::{
8    SercomPtr, SharedSliceBuffer, SinkSourceBuffer, read_dma, read_dma_linked, write_dma,
9    write_dma_linked,
10};
11
12use super::{
13    Capability, Config, DataWidth, Duplex, Error, MasterMode, OpMode, Receive, Sercom, Size, Slave,
14    Spi, Transmit, ValidConfig, ValidPads, Word,
15};
16
17impl<P, M, Z, D, R, T> Spi<Config<P, M, Z>, D, R, T>
18where
19    P: ValidPads,
20    M: OpMode,
21    Z: Size,
22    Config<P, M, Z>: ValidConfig,
23    D: Capability,
24    Z::Word: Beat,
25{
26    #[inline]
27    pub(in super::super) fn sercom_ptr(&self) -> SercomPtr<Z::Word> {
28        SercomPtr(self.config.regs.spi().data().as_ptr() as *mut _)
29    }
30}
31
32impl<P, M, Z, D, R, T, S> Spi<Config<P, M, Z>, D, R, T>
34where
35    P: ValidPads,
36    M: OpMode,
37    Z: Size + 'static,
38    Config<P, M, Z>: ValidConfig<Sercom = S>,
39    D: Transmit,
40    S: Sercom,
41    Z::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
42    DataWidth: AsPrimitive<Z::Word>,
43    T: AnyChannel<Status = Ready>,
44{
45    pub(super) fn write_dma(&mut self, buf: &[Z::Word]) -> Result<usize, Error> {
46        if buf.is_empty() {
47            return Ok(0);
48        }
49
50        self.config.as_mut().regs.rx_disable();
52
53        let sercom_ptr = self.sercom_ptr();
54        let tx = self._tx_channel.as_mut();
55        let mut words = crate::sercom::dma::SharedSliceBuffer::from_slice(buf);
56
57        unsafe {
61            crate::sercom::dma::write_dma::<_, _, S>(tx, sercom_ptr, &mut words);
62        }
63
64        while !tx.xfer_complete() {
65            core::hint::spin_loop();
66        }
67
68        tx.stop();
70
71        if D::RX_ENABLE {
73            self.config.as_mut().regs.rx_enable();
74        }
75
76        self._tx_channel.as_mut().xfer_success()?;
77        Ok(buf.len())
78    }
79}
80
81impl<P, M, S, C, D, R, T> Spi<Config<P, M, C>, D, R, T>
82where
83    Config<P, M, C>: ValidConfig<Sercom = S>,
84    S: Sercom,
85    P: ValidPads,
86    M: MasterMode,
87    C: Size + 'static,
88    C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
89    DataWidth: AsPrimitive<C::Word>,
90    D: Capability,
91    R: AnyChannel<Status = Ready>,
92    T: AnyChannel<Status = Ready>,
93{
94    #[inline]
95    fn transfer_blocking<Source: Buffer<Beat = C::Word>, Dest: Buffer<Beat = C::Word>>(
96        &mut self,
97        dest: &mut Dest,
98        source: &mut Source,
99    ) -> Result<(), Error> {
100        let sercom_ptr = self.sercom_ptr();
101        let rx = self._rx_channel.as_mut();
102        let tx = self._tx_channel.as_mut();
103
104        unsafe {
108            read_dma::<_, _, S>(rx, sercom_ptr.clone(), dest);
109            write_dma::<_, _, S>(tx, sercom_ptr, source);
110        }
111
112        while !(rx.xfer_complete() && tx.xfer_complete()) {
113            core::hint::spin_loop();
114        }
115
116        tx.stop();
118        rx.stop();
119
120        self.read_status().check_bus_error()?;
122        self._rx_channel
123            .as_mut()
124            .xfer_success()
125            .and(self._tx_channel.as_mut().xfer_success())?;
126        Ok(())
127    }
128
129    #[inline]
130    pub(super) fn read_dma_master(&mut self, mut words: &mut [C::Word]) -> Result<(), Error> {
131        if words.is_empty() {
132            return Ok(());
133        }
134
135        let mut source_word = self.config.nop_word.as_();
136        let mut source = SinkSourceBuffer::new(&mut source_word, words.len());
137
138        self.transfer_blocking(&mut words, &mut source)
139    }
140}
141
142impl<P, M, S, C, R, T> SpiBus<Word<C>> for Spi<Config<P, M, C>, Duplex, R, T>
144where
145    Config<P, M, C>: ValidConfig<Sercom = S>,
146    S: Sercom,
147    P: ValidPads,
148    M: MasterMode,
149    C: Size + 'static,
150    C::Word: PrimInt + AsPrimitive<DataWidth> + Beat,
151    DataWidth: AsPrimitive<C::Word>,
152    R: AnyChannel<Status = Ready>,
153    T: AnyChannel<Status = Ready>,
154{
155    #[inline]
156    fn read(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
157        self.read_dma_master(words)
158    }
159
160    #[inline]
161    fn write(&mut self, words: &[C::Word]) -> Result<(), Self::Error> {
162        self.write_dma(words)?;
163        Ok(())
164    }
165
166    #[inline]
167    fn transfer(&mut self, mut read: &mut [C::Word], write: &[C::Word]) -> Result<(), Self::Error> {
168        use core::cmp::Ordering;
169
170        if write.is_empty() && read.is_empty() {
172            return Ok(());
173        }
174
175        if write.is_empty() {
177            return self.read_dma_master(read);
178        } else if read.is_empty() {
179            self.write_dma(write)?;
180            return Ok(());
181        }
182
183        let mut linked_descriptor = DmacDescriptor::default();
187
188        let mut source_sink_word = self.config.nop_word.as_();
194        let mut sercom_ptr = self.sercom_ptr();
195
196        let (read_link, write_link) = match read.len().cmp(&write.len()) {
197            Ordering::Equal => {
198                let mut write = SharedSliceBuffer::from_slice(write);
199                return self.transfer_blocking(&mut read, &mut write);
200            }
201
202            Ordering::Less => {
205                let mut sink =
206                    SinkSourceBuffer::new(&mut source_sink_word, write.len() - read.len());
207                unsafe {
208                    channel::write_descriptor(
209                        &mut linked_descriptor,
210                        &mut sercom_ptr,
211                        &mut sink,
212                        core::ptr::null_mut(),
214                    );
215                }
216
217                (Some(&mut linked_descriptor), None)
218            }
219
220            Ordering::Greater => {
223                let mut source =
224                    SinkSourceBuffer::new(&mut source_sink_word, read.len() - write.len());
225                unsafe {
226                    channel::write_descriptor(
227                        &mut linked_descriptor,
228                        &mut source,
229                        &mut sercom_ptr,
230                        core::ptr::null_mut(),
232                    );
233                }
234
235                (None, Some(&mut linked_descriptor))
236            }
237        };
238
239        let rx = self._rx_channel.as_mut();
240        let tx = self._tx_channel.as_mut();
241
242        let mut write = SharedSliceBuffer::from_slice(write);
243
244        unsafe {
248            read_dma_linked::<_, _, S>(rx, sercom_ptr.clone(), &mut read, read_link);
249            write_dma_linked::<_, _, S>(tx, sercom_ptr, &mut write, write_link);
250        }
251
252        while !(rx.xfer_complete() && tx.xfer_complete()) {
253            core::hint::spin_loop();
254        }
255
256        tx.stop();
258        rx.stop();
259
260        self.read_status().check_bus_error()?;
262        self._rx_channel
263            .as_mut()
264            .xfer_success()
265            .and(self._tx_channel.as_mut().xfer_success())?;
266        Ok(())
267    }
268
269    #[inline]
270    fn transfer_in_place(&mut self, words: &mut [C::Word]) -> Result<(), Self::Error> {
271        unsafe {
279            let mut read_buf = SharedSliceBuffer::from_slice_unchecked(words);
280            let mut write_buf = SharedSliceBuffer::from_slice(words);
281            self.transfer_blocking(&mut read_buf, &mut write_buf)
282        }
283    }
284
285    #[inline]
286    fn flush(&mut self) -> Result<(), Error> {
287        self.flush_tx();
288        Ok(())
289    }
290}
291
292impl<P, M, Z, D, R, T, S> embedded_io::Write for Spi<Config<P, M, Z>, D, R, T>
295where
296    P: ValidPads,
297    M: OpMode,
298    Z: Size<Word = u8> + 'static,
299    Config<P, M, Z>: ValidConfig<Sercom = S>,
300    D: Transmit,
301    S: Sercom,
302    T: AnyChannel<Status = Ready>,
303{
304    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
305        Spi::write_dma(self, buf)
306    }
307
308    fn flush(&mut self) -> Result<(), Self::Error> {
309        self.flush_tx();
310        Ok(())
311    }
312}
313
314impl<P, M, Z, D, R, T, S> embedded_io::Read for Spi<Config<P, M, Z>, D, R, T>
317where
318    P: ValidPads,
319    M: MasterMode,
320    Z: Size<Word = u8> + 'static,
321    Config<P, M, Z>: ValidConfig<Sercom = S>,
322    D: Receive,
323    S: Sercom,
324    R: AnyChannel<Status = Ready>,
325    T: AnyChannel<Status = Ready>,
326{
327    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
328        self.read_dma_master(buf)?;
329        Ok(buf.len())
330    }
331}
332
333impl<P, Z, D, R, T, S> embedded_io::Read for Spi<Config<P, Slave, Z>, D, R, T>
336where
337    P: ValidPads,
338    Z: Size<Word = u8> + 'static,
339    Config<P, Slave, Z>: ValidConfig<Sercom = S>,
340    D: Receive,
341    S: Sercom,
342    R: AnyChannel<Status = Ready>,
343{
344    fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
345        if buf.is_empty() {
346            return Ok(0);
347        }
348
349        self.flush_rx()?;
353        let sercom_ptr = self.sercom_ptr();
354        let rx = self._rx_channel.as_mut();
355
356        unsafe {
359            read_dma::<_, _, S>(rx, sercom_ptr.clone(), &mut buf);
360        }
361
362        while !(rx.xfer_complete()) {
363            core::hint::spin_loop();
364        }
365
366        rx.stop();
368
369        self.read_status().check_bus_error()?;
371        self._rx_channel.as_mut().xfer_success()?;
372        Ok(buf.len())
373    }
374}