atsamd_hal/sercom/spi/impl_ehal/
thumbv6m.rs

1//! Implement Embedded HAL ([v0.2](crate::ehal_02) and [nb](ehal_nb)) traits for
2//! [`Spi`] structs
3//!
4//! As noted in the [spi module](super) documentation, the embedded-hal trait
5//! implementations vary by both [`Size`] and [`Capability`]. Each
6//! implementation is optimized to take advantage of all information known at
7//! compile-time, so it is importatnt to carefully read the documentation in
8//! this module.
9//!
10//! # Variations by [`Size`]
11//!
12//! SAMD11 and SAMD21 chips do not have 32-bit extension mode, so their
13//! transaction `Size` can only vary by the [`CharSize`]. Both options,
14//! [`EightBit`] and [`NineBit`], are [`AtomicSize`]s, because each can be
15//! completed with a single read/write of the `DATA` register. Consequently,
16//! each can implement both the blocking and non-blocking embedded HAL traits.
17//! These traits are implemented for the [`Word`] type of the corresponding
18//! `CharSize`. For example, an [`Spi`] struct with a `NineBit` `CharSize` would
19//! implement `spi::FullDuplex<u16>`.
20//!
21//! Note that embedded HAL does not offer a way to transmit slices in a
22//! non-blocking fashion, but this can be done using
23#![cfg_attr(feature = "dma", doc = "[`DMA`](crate::dmac)")]
24#![cfg_attr(not(feature = "dma"), doc = "`DMA`")]
25//! or using interrupts and the [`spi_future`](crate::sercom::spi_future) module.
26//!
27//! # Variations by [`Capability`]
28//!
29//! The implementations in this module also seek to optimize as much as possible
30//! based on the `Capability` of the `Spi` struct. They follow a few general
31//! rules:
32//! - [`Tx`] structs can never receive data, so their corresponding trait
33//!   implementations never read the `DATA` register and can never return an
34//!   [`Error::Overflow`].
35//! - [`Rx`] structs in a [`MasterMode`](super::MasterMode) must initiate all
36//!   transactions, so their implementations of non-blocking traits must track
37//!   the state of on-going transactions.
38//! - [`Duplex`] structs must always read as many bytes as they send, even when
39//!   implementing `Write`-only traits, to ensure they never introduce an
40//!   [`Error::Overflow`].
41//!
42//! # Notes on individual embedded HAL traits
43//!
44//! ## `spi::FullDuplex`
45//!
46//! `spi::FullDuplex` is only implemented for structs with `Duplex`
47//! `Capability`. Although the embedded HAL documentation assumes a
48//! `MasterMode`, this module also implements it for the [`Slave`] [`OpMode`].
49//!
50//! ## `serial::Read`
51//!
52//! `serial::Read` is only implemented for structs with `Rx` `Capability`. When
53//! in a `MasterMode`, it initiates and tracks the state of the on-going
54//! transactions. But this is not required when acting as a `Slave`.
55//!
56//! ## `serial::Write`
57//!
58//! `serial::Write` is only implemented for structs with `Tx` `Capability`.
59//! These implementations never read the `DATA` register and ignore all
60//! instances of [`Error::Overflow`].
61//!
62//! ## `blocking::serial::Write`
63//!
64//! This trait uses the `blocking::serial::write::Default` implementation for
65//! implementers of `serial::Write`.
66//!
67//! ## `blocking::spi` traits
68//!
69//! These traits are implemented following all of the rules outlined above for
70//! the different [`Size`] and [`Capability`] options.
71
72use super::*;
73use crate::ehal_nb;
74use nb::Error::WouldBlock;
75use num_traits::{AsPrimitive, PrimInt};
76
77//=============================================================================
78// serial::Read
79//=============================================================================
80
81/// Implement [`Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`]
82///
83/// [`Read`] is only implemented for `Spi` structs with `Rx`
84/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so
85/// it keeps track of the transaction state. If a transaction is in progress,
86/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`.
87///
88/// [`Read`]: ehal_nb::serial::Read
89impl<P, M, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
90where
91    Config<P, M, C>: ValidConfig,
92    P: ValidPads,
93    M: MasterMode,
94    C: CharSize,
95    C::Word: PrimInt,
96    DataWidth: AsPrimitive<C::Word>,
97{
98    #[inline]
99    fn read(&mut self) -> nb::Result<C::Word, Error> {
100        let in_progress = self.capability.in_progress;
101        let flags = self.read_flags_errors()?;
102        if !in_progress && flags.contains(Flags::DRE) {
103            unsafe { self.write_data(0) };
104            self.capability.in_progress = true;
105            Err(WouldBlock)
106        } else if in_progress && flags.contains(Flags::RXC) {
107            self.capability.in_progress = false;
108            unsafe { Ok(self.read_data().as_()) }
109        } else {
110            Err(WouldBlock)
111        }
112    }
113}
114
115/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`]
116///
117/// [`Read`] is only implemented for `Spi` structs with `Rx`
118/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so
119/// it keeps track of the transaction state. If a transaction is in progress,
120/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`.
121///
122/// [`Read`]: crate::ehal_02::serial::Read
123impl<P, M, C> serial::Read<C::Word> for Spi<Config<P, M, C>, Rx>
124where
125    Config<P, M, C>: ValidConfig,
126    P: ValidPads,
127    M: MasterMode,
128    C: CharSize,
129    C::Word: PrimInt,
130    DataWidth: AsPrimitive<C::Word>,
131{
132    type Error = Error;
133
134    #[inline]
135    fn read(&mut self) -> nb::Result<C::Word, Error> {
136        <Self as ehal_nb::serial::Read<C::Word>>::read(self)
137    }
138}
139
140/// Implement [`Read`] for [`Rx`] [`Spi`] structs in [`Slave`]
141/// [`OpMode`]
142///
143/// [`Read`] is only implemented for `Spi` structs with `Rx`
144/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate
145/// transactions, so it does not have to store any internal state. It only has
146/// to wait on `RXC`.
147///
148/// [`Read`]: ehal_nb::serial::Read
149impl<P, C> ehal_nb::serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
150where
151    Config<P, Slave, C>: ValidConfig,
152    P: ValidPads,
153    C: CharSize,
154    C::Word: PrimInt,
155    DataWidth: AsPrimitive<C::Word>,
156{
157    /// Wait for an `RXC` flag, then read the word
158    #[inline]
159    fn read(&mut self) -> nb::Result<C::Word, Error> {
160        let flags = self.read_flags_errors()?;
161        if flags.contains(Flags::RXC) {
162            unsafe { Ok(self.read_data().as_()) }
163        } else {
164            Err(WouldBlock)
165        }
166    }
167}
168
169/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`]
170/// [`OpMode`]
171///
172/// [`serial::Read`] is only implemented for `Spi` structs with `Rx`
173/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate
174/// transactions, so it does not have to store any internal state. It only has
175/// to wait on `RXC`.
176impl<P, C> serial::Read<C::Word> for Spi<Config<P, Slave, C>, Rx>
177where
178    Config<P, Slave, C>: ValidConfig,
179    P: ValidPads,
180    C: CharSize,
181    C::Word: PrimInt,
182    DataWidth: AsPrimitive<C::Word>,
183{
184    type Error = Error;
185
186    /// Wait for an `RXC` flag, then read the word
187    #[inline]
188    fn read(&mut self) -> nb::Result<C::Word, Error> {
189        <Self as ehal_nb::serial::Read<C::Word>>::read(self)
190    }
191}
192
193//=============================================================================
194// embedded_io::Read
195//=============================================================================
196impl<P, M> embedded_io::Read for Spi<Config<P, M, EightBit>, Rx>
197where
198    Config<P, M, EightBit>: ValidConfig,
199    P: ValidPads,
200    M: MasterMode,
201{
202    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
203        for byte in buf.iter_mut() {
204            let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
205            *byte = w;
206        }
207
208        Ok(buf.len())
209    }
210}
211
212impl<P> embedded_io::Read for Spi<Config<P, Slave, EightBit>, Rx>
213where
214    Config<P, Slave, EightBit>: ValidConfig,
215    P: ValidPads,
216{
217    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
218        if buf.is_empty() {
219            return Ok(0);
220        };
221
222        for byte in buf.iter_mut() {
223            let w = nb::block!(<Self as ehal_nb::serial::Read>::read(self))?;
224            *byte = w;
225        }
226
227        Ok(buf.len())
228    }
229}
230
231//=============================================================================
232// serial::Write
233//=============================================================================
234
235/// Implement [`Write`] for [`Tx`] [`Spi`] structs
236///
237/// [`Write`] is only implemented for `Spi` structs with `Tx`
238/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never
239/// reads the DATA register and ignores all buffer overflow errors.
240///
241/// [`Write`]: ehal_nb::serial::Write
242impl<P, M, C> ehal_nb::serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
243where
244    Config<P, M, C>: ValidConfig,
245    P: ValidPads,
246    M: OpMode,
247    C: CharSize,
248    C::Word: PrimInt + AsPrimitive<DataWidth>,
249{
250    #[inline]
251    fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
252        // Ignore buffer overflow errors
253        if self.read_flags().contains(Flags::DRE) {
254            unsafe { self.write_data(word.as_()) };
255            Ok(())
256        } else {
257            Err(WouldBlock)
258        }
259    }
260
261    #[inline]
262    fn flush(&mut self) -> nb::Result<(), Error> {
263        // Ignore buffer overflow errors
264        if self.read_flags().contains(Flags::TXC) {
265            Ok(())
266        } else {
267            Err(WouldBlock)
268        }
269    }
270}
271
272/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs
273///
274/// `serial::Write` is only implemented for `Spi` structs with `Tx`
275/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never
276/// reads the DATA register and ignores all buffer overflow errors.
277impl<P, M, C> serial::Write<C::Word> for Spi<Config<P, M, C>, Tx>
278where
279    Config<P, M, C>: ValidConfig,
280    P: ValidPads,
281    M: OpMode,
282    C: CharSize,
283    C::Word: PrimInt + AsPrimitive<DataWidth>,
284{
285    type Error = Error;
286
287    #[inline]
288    fn write(&mut self, word: C::Word) -> nb::Result<(), Error> {
289        <Self as ehal_nb::serial::Write<C::Word>>::write(self, word)
290    }
291
292    #[inline]
293    fn flush(&mut self) -> nb::Result<(), Error> {
294        <Self as ehal_nb::serial::Write<C::Word>>::flush(self)
295    }
296}
297
298//=============================================================================
299// blocking::serial::Write
300//=============================================================================
301
302impl<C> blocking::serial::write::Default<C::Word> for Spi<C, Tx>
303where
304    C: ValidConfig,
305    Spi<C, Tx>: serial::Write<C::Word>,
306{
307}
308
309//=============================================================================
310// embedded_io::Write
311//=============================================================================
312impl<P, M> embedded_io::Write for Spi<Config<P, M, EightBit>, Tx>
313where
314    Config<P, M, EightBit>: ValidConfig,
315    P: ValidPads,
316    M: OpMode,
317{
318    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
319        for byte in buf {
320            nb::block!(<Self as ehal_nb::serial::Write>::write(self, *byte))?;
321        }
322
323        Ok(buf.len())
324    }
325
326    fn flush(&mut self) -> Result<(), Self::Error> {
327        nb::block!(<Self as ehal_nb::serial::Write>::flush(self))
328    }
329}
330
331//=============================================================================
332// spi::FullDuplex
333//=============================================================================
334
335/// Implement embedded-hal-nb [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`]
336///
337/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`]
338/// [`Capability`]. The [`Word`] size used in the implementation depends on the
339/// corresponding [`CharSize`].
340///
341/// [`spi::FullDuplex`]: ehal_nb::spi::FullDuplex
342impl<C> ehal_nb::spi::FullDuplex<C::Word> for Spi<C, Duplex>
343where
344    C: ValidConfig,
345    C::Word: PrimInt + AsPrimitive<u16>,
346    u16: AsPrimitive<C::Word>,
347{
348    #[inline]
349    fn read(&mut self) -> nb::Result<C::Word, Error> {
350        let flags = self.read_flags_errors()?;
351        if flags.contains(Flags::RXC) {
352            unsafe { Ok(self.read_data().as_()) }
353        } else {
354            Err(WouldBlock)
355        }
356    }
357
358    #[inline]
359    fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> {
360        let flags = self.read_flags_errors()?;
361        if flags.contains(Flags::DRE) {
362            unsafe { self.write_data(word.as_()) };
363            Ok(())
364        } else {
365            Err(WouldBlock)
366        }
367    }
368}
369
370/// Implement embedded-hal 0.2 [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`]
371///
372/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`]
373/// [`Capability`]. The [`Word`] size used in the implementation depends on the
374/// corresponding [`CharSize`].
375///
376/// [`spi::FullDuplex`]: crate::ehal_02::spi::FullDuplex
377impl<C> crate::ehal_02::spi::FullDuplex<C::Word> for Spi<C, Duplex>
378where
379    C: ValidConfig,
380    C::Word: PrimInt + AsPrimitive<u16>,
381    u16: AsPrimitive<C::Word>,
382{
383    type Error = Error;
384
385    #[inline]
386    fn read(&mut self) -> nb::Result<C::Word, Error> {
387        let flags = self.read_flags_errors()?;
388        if flags.contains(Flags::RXC) {
389            unsafe { Ok(self.read_data().as_()) }
390        } else {
391            Err(WouldBlock)
392        }
393    }
394
395    #[inline]
396    fn send(&mut self, word: C::Word) -> nb::Result<(), Error> {
397        let flags = self.read_flags_errors()?;
398        if flags.contains(Flags::DRE) {
399            unsafe { self.write_data(word.as_()) };
400            Ok(())
401        } else {
402            Err(WouldBlock)
403        }
404    }
405}
406
407//=============================================================================
408// Note on macros
409//=============================================================================
410
411// Macros are necessary for the following implementations of the embedded HAL
412// `blocking` traits because of a limitation in the Rust trait system. The
413// compiler can't seem to recongnize that the `blocking::spi::*::Default` traits
414// can never be implemented for [`Spi`] in downstream crates, because that would
415// violate the orphan rules.
416
417//=============================================================================
418// blocking::spi::Transfer
419//=============================================================================
420
421macro_rules! impl_blocking_spi_transfer {
422    ( $($CharSize:ident),+ ) => {
423        $(
424            /// Implement [`Transfer`] for [`Spi`] structs that can [`Receive`]
425            ///
426            /// The transfer accepts a slice of primitive integers, depending on
427            /// the [`CharSize`] (`u8` or `u16`).
428            ///
429            /// [`Transfer`]: blocking::spi::Transfer
430            impl<P, M, A> blocking::spi::Transfer<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, A>
431            where
432                Config<P, M, $CharSize>: ValidConfig,
433                P: ValidPads,
434                M: OpMode,
435                A: Receive,
436            {
437                type Error = Error;
438
439                #[inline]
440                fn transfer<'w>(&mut self, words: &'w mut [Word<$CharSize>]) -> Result<&'w [Word<$CharSize>], Error> {
441                    let cells = core::cell::Cell::from_mut(words).as_slice_of_cells();
442                    let mut to_send = cells.iter();
443                    let mut to_recv = cells.iter();
444                    while to_recv.len() > 0 {
445                        let flags = self.read_flags_errors()?;
446                        if to_send.len() > 0 && flags.contains(Flags::DRE) {
447                            let word = match to_send.next() {
448                                Some(cell) => cell.get(),
449                                None => unreachable!(),
450                            };
451                            self.config.as_mut().regs.write_data(word as u16);
452                        }
453                        if to_recv.len() > to_send.len() && flags.contains(Flags::RXC) {
454                            let word = self.config.as_mut().regs.read_data() as Word<$CharSize>;
455                            match to_recv.next() {
456                                Some(cell) => cell.set(word),
457                                None => unreachable!(),
458                            }
459                        }
460                    }
461                    Ok(words)
462                }
463            }
464        )+
465    }
466}
467
468impl_blocking_spi_transfer!(EightBit, NineBit);
469
470//=============================================================================
471// blocking::spi::Write
472//=============================================================================
473
474macro_rules! impl_blocking_spi_write {
475    ( $($CharSize:ident),+ ) => {
476        $(
477            /// Implement [`Write`] for [`Spi`] structs with [`Duplex`]
478            /// [`Capability`]
479            ///
480            /// The transfer accepts a slice of primitive integers, depending on
481            /// the [`CharSize`] (`u8` or `u16`).
482            ///
483            /// [`Write`]: blocking::spi::Write
484            impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
485            where
486                Config<P, M, $CharSize>: ValidConfig,
487                P: ValidPads,
488                M: OpMode,
489            {
490                type Error = Error;
491
492                #[inline]
493                fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
494                    // We are `Duplex`, so we must receive as many words as we send,
495                    // otherwise we could trigger an overflow
496                    let mut to_send = words.iter();
497                    let mut to_recv = to_send.len();
498                    while to_recv > 0 {
499                        let flags = self.read_flags_errors()?;
500                        if to_send.len() > 0 && flags.contains(Flags::DRE) {
501                            let word = match to_send.next() {
502                                Some(word) => *word,
503                                None => unreachable!(),
504                            };
505                            self.config.as_mut().regs.write_data(word as u16);
506                        }
507                        if to_recv > to_send.len() && flags.contains(Flags::RXC) {
508                            self.config.as_mut().regs.read_data();
509                            to_recv -= 1;
510                        }
511                    }
512                    Ok(())
513                }
514            }
515
516            /// Implement [`Write`] for [`Spi`] structs with [`Tx`]
517            /// [`Capability`]
518            ///
519            /// The transfer accepts a slice of primitive integers, depending on
520            /// the [`CharSize`] (`u8` or `u16`).
521            ///
522            /// Because the `Capability` is `Tx`, this implementation never
523            /// reads the DATA register and ignores all buffer overflow errors.
524            ///
525            /// [`Write`]: blocking::spi::Write
526            impl<P, M> blocking::spi::Write<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
527            where
528                Config<P, M, $CharSize>: ValidConfig,
529                P: ValidPads,
530                M: OpMode,
531            {
532                type Error = Error;
533
534                #[inline]
535                fn write(&mut self, words: &[Word<$CharSize>]) -> Result<(), Error> {
536                    // We are `Tx`, so we don't have to consider reading at all, ever.
537                    for word in words {
538                        loop {
539                            // Ignore buffer overflow errors
540                            if self.read_status().contains(Status::LENERR) {
541                                return Err(Error::LengthError)
542                            } else if self.read_flags().contains(Flags::DRE) {
543                                self.config.as_mut().regs.write_data(*word as u16);
544                                break
545                            }
546                        }
547                    }
548                    // Wait until all data is shifted out
549                    while !self.read_flags().contains(Flags::TXC) {}
550                    Ok(())
551                }
552            }
553        )+
554    }
555}
556
557impl_blocking_spi_write!(EightBit, NineBit);
558
559//=============================================================================
560// blocking::spi::WriteIter
561//=============================================================================
562
563macro_rules! impl_blocking_spi_write_iter {
564    ( $($CharSize:ident),+ ) => {
565        $(
566            /// Implement [`WriteIter`] for [`Spi`] structs with [`Duplex`]
567            /// [`Capability`]
568            ///
569            /// The transfer accepts a slice of primitive integers, depending on
570            /// the [`CharSize`] (`u8` or `u16`).
571            ///
572            /// [`WriteIter`]: blocking::spi::WriteIter
573            impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Duplex>
574            where
575                Config<P, M, $CharSize>: ValidConfig,
576                P: ValidPads,
577                M: OpMode,
578            {
579                type Error = Error;
580
581                #[inline]
582                fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
583                where
584                    WI: IntoIterator<Item = Word<$CharSize>>,
585                {
586                    // We are `Duplex`, so we must receive as many words as we send,
587                    // otherwise we could trigger an overflow. However, we don't know
588                    // how many words there are to start with, so we have to send and
589                    // receive them one at a time.
590                    for word in words.into_iter() {
591                        loop {
592                            let flags = self.read_flags_errors()?;
593                            if flags.contains(Flags::DRE) {
594                                unsafe { self.write_data(word as u16) };
595                                break
596                            }
597                        }
598                        loop {
599                            let flags = self.read_flags_errors()?;
600                            if flags.contains(Flags::RXC) {
601                                self.config.as_mut().regs.read_data() as Word<$CharSize>;
602                                break
603                            }
604                        }
605                    }
606                    Ok(())
607                }
608            }
609
610            /// Implement [`WriteIter`] for [`Spi`] structs with [`Tx`]
611            /// [`Capability`]
612            ///
613            /// The transfer accepts a slice of primitive integers, depending on
614            /// the [`CharSize`] (`u8` or `u16`).
615            ///
616            /// Because the `Capability` is `Tx`, this implementation never
617            /// reads the DATA register and ignores all buffer overflow errors.
618            ///
619            /// [`WriteIter`]: blocking::spi::WriteIter
620            impl<P, M> blocking::spi::WriteIter<Word<$CharSize>> for Spi<Config<P, M, $CharSize>, Tx>
621            where
622                Config<P, M, $CharSize>: ValidConfig,
623                P: ValidPads,
624                M: OpMode,
625            {
626                type Error = Error;
627
628                #[inline]
629                fn write_iter<WI>(&mut self, words: WI) -> Result<(), Error>
630                where
631                    WI: IntoIterator<Item = Word<$CharSize>>,
632                {
633                    // We are `Tx`, so we don't have to consider reading at all, ever.
634                    for word in words.into_iter() {
635                        loop {
636                            // Ignore buffer overflow errors
637                            if self.read_status().contains(Status::LENERR) {
638                                return Err(Error::LengthError)
639                            } else if self.read_flags().contains(Flags::DRE) {
640                                unsafe { self.write_data(word as u16) };
641                                break
642                            }
643                        }
644                    }
645                    // Wait until all data is shifted out
646                    while !self.read_flags().contains(Flags::TXC) {}
647                    Ok(())
648                }
649            }
650        )+
651    };
652}
653
654impl_blocking_spi_write_iter!(EightBit, NineBit);