atsamd_hal/sercom/
spi.rs

1//! Use a SERCOM peripheral for SPI transactions
2//!
3//! Using an SPI peripheral occurs in three steps. First, you must supply
4//! [`gpio`] [`Pin`]s to create a set of [`Pads`]. Next, you combine the `Pads`
5//! with other pieces to form a [`Config`] struct. Finally, after configuring
6//! the peripheral, you [`enable`] it to yield a functional [`Spi`] struct.
7//! Transactions are performed using traits from the Embedded HAL crates,
8//! specifically those from the [`spi`](ehal::spi),
9//! [`serial`](embedded_hal_02::serial), and
10//! [`blocking`](embedded_hal_02::blocking) modules.
11//!
12//! # Crating a set of [`Pads`]
13//!
14//! An SPI peripheral can use up to four [`Pin`]s as [`Sercom`] pads. However,
15//! only certain `Pin` combinations are acceptable. All `Pin`s must be mapped to
16//! the same `Sercom`, and for SAMx5x chips they must also belong to the same
17//! [`IoSet`]. This HAL makes it impossible to use invalid `Pin` combinations,
18//! and the [`Pads`] struct is responsible for enforcing these constraints.
19//!
20//! A `Pads` type takes five parameters: the first specifies the `Sercom`, and
21//! the remaining four type parameters, `DI`, `DO`, `CK` and `SS`, represent the
22//! Data In, Data Out, Sclk and SS pads respectively. Each of these type
23//! parameters is an [`OptionalPad`] and defaults to [`NoneT`]. A `Pad` is just
24//! a `Pin` configured in the correct [`PinMode`] that implements [`IsPad`]. The
25//! [`bsp_pins!`](crate::bsp_pins) macro can be used to define convenient type
26//! aliases for `Pad` types.
27//!
28//! ```
29//! use atsamd_hal::gpio::{PA08, PA09, AlternateC};
30//! use atsamd_hal::sercom::{Sercom0, spi};
31//! use atsamd_hal::typelevel::NoneT;
32//!
33//! type Miso = Pin<PA08, AlternateC>;
34//! type Sclk = Pin<PA09, AlternateC>;
35//!
36//! type Pads = spi::Pads<Sercom0, Miso, NoneT, Sclk>;
37//! ```
38//!
39//! [`enable`]: Config::enable
40//! [`gpio`]: crate::gpio
41//! [`IoSet`]: crate::sercom::pad::IoSet
42//! [`Pin`]: crate::gpio::pin::Pin
43//! [`PinId`]: crate::gpio::pin::PinId
44//! [`PinMode`]: crate::gpio::pin::PinMode
45//!
46//!
47//! Alternatively, you can use the `PadsFromIds` alias to define a set of `Pads`
48//! in terms of [`PinId`]s instead of [`Pin`]s. This is useful when you don't
49//! have [`Pin`] aliases pre-defined.
50//!
51//! ```
52//! use atsamd_hal::gpio::{PA08, PA09};
53//! use atsamd_hal::sercom::{Sercom0, spi};
54//! use atsamd_hal::typelevel::NoneT;
55//!
56//! type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
57//! ```
58//!
59//! Instances of `Pads` are created using the builder pattern. Start by creating
60//! an empty set of `Pads` using [`Default`]. Then pass each respective `Pin`
61//! using the corresponding methods. For SAMD21 and SAMx5x chips, the builder
62//! methods automatically convert each pin to the correct [`PinMode`]. However,
63//! due to inherent ambiguities, users must manually configure `PinMode`s for
64//! SAMD11 chips.
65//!
66//! ```
67//! use atsamd_hal::target_device::Peripherals;
68//! use atsamd_hal::gpio::Pins;
69//! use atsamd_hal::sercom::{Sercom0, spi};
70//!
71//! let mut peripherals = Peripherals::take().unwrap();
72//! let pins = Pins::new(peripherals.PORT);
73//!
74//! let pads = spi::Pads::<Sercom0>::default()
75//!     .sclk(pins.pa09)
76//!     .data_in(pins.pa08)
77//!     .data_out(pins.pa11);
78//! ```
79//!
80//! To be accepted by the [`Config`] struct as a set of [`ValidPads`], the
81//! `Pads` must do two things:
82//! - Specify [`SomePad`] for `CK` and at least one of `DI` or `DO`
83//! - Use a valid combination of [`PadNum`]s, so that the `Pads` implement
84//!   [`DipoDopo`]
85//!
86//! # `Config`uring the peripheral
87//!
88//! Next, create a [`Config`] struct, which represents the SPI peripheral in its
89//! disabled state. A `Config` is specified with three type parameters: the
90//! [`Pads`] type; an [`OpMode`], which defaults to [`Master`]; and a [`Size`]
91//! type that varies by chip. [`Size`] essentially acts as a trait alias. On
92//! SAMD11 and SAMD21 chips, it represents the `CharSize`, which can either be
93//! `EightBit` or `NineBit`. While on SAMx5x chips, it represents the
94//! transaction `Length` in bytes, using type-level numbers provided by the
95//! [`typenum`] crate. Valid transaction lengths, from `U1` to `U255`, are
96//! re-exported in the `lengths` sub-module.
97//!
98//! ```
99//! use atsamd_hal::gpio::{PA08, PA09};
100//! use atsamd_hal::sercom::{Sercom0, spi};
101//! use atsamd_hal::sercom::spi::Master;
102//! use atsamd_hal::typelevel::NoneT;
103//!
104//! // SAMD11/SAMD21-specific imports
105//! use atsamd_hal::sercom::spi::NineBit;
106//!
107//! // SAMx5x-specific imports
108//! use atsamd_hal::sercom::spi::lengths::U2;
109//!
110//! type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
111//!
112//! // SAMD11/SAMD21 version
113//! type Config = spi::Config<Pads, Master, NineBit>;
114//!
115//! // SAMx5x version
116//! type Config = spi::Config<Pads, Master, U2>;
117//! ```
118//!
119//! For simplicity, this module ignores character size on SAMx5x chips. Instead,
120//! the SPI peripheral is always configured to use 32-bit extension mode and the
121//! hardware `LENGTH` counter. Note that, due to a hardware bug, `ICSPACE` must
122//! be at least one when using the length counter. See the silicon errata for
123//! more details.
124//!
125//! Upon creation, the [`Config`] takes ownership of both the [`Pads`] and the
126//! PAC [`Sercom`] struct. It takes a reference to the `PM` or `MCLK`, so that
127//! it can enable the APB clock, and it takes a frequency to indicate the GCLK
128//! configuration. Users are responsible for correctly configuring the GCLK.
129//!
130//! ```
131//! use atsamd_hal::time::U32Ext;
132//!
133//! // Not shown: configure GCLK for 10 MHz
134//!
135//! // SAMD11/SAMD21 version
136//! let pm = peripherals.PM;
137//! let sercom = peripherals.SERCOM0;
138//! let freq = 10.mhz();
139//! let config = spi::Config::new(&pm, sercom, pads, freq);
140//!
141//! // SAMx5x version
142//! let mclk = peripherals.MCLK;
143//! let sercom = peripherals.SERCOM0;
144//! let freq = 10.mhz();
145//! let config = spi::Config::new(&mclk, sercom, pads, freq);
146//! ```
147//!
148//! The [`Config`] uses two different APIs for configuration. For most
149//! parameters, it provides `get_` and `set_` methods that take `&self` and
150//! `&mut self` respectively, e.g. [`get_bit_order`](Config::get_bit_order) and
151//! [`set_bit_order`](Config::set_bit_order). However, because `Config` tracks
152//! the [`OpMode`] and [`Size`] at compile-time, which requires changing the
153//! corresponding type parameters, `Config` also provides a builder-pattern API,
154//! where methods take and return `self`, e.g. [`bit_order`](Config::bit_order).
155//!
156//! Once configured, the [`enable`] method consumes the `Config` and returns an
157//! enabled [`Spi`] struct that can be used for transactions. Because the
158//! `enable` function takes the `Config` as `self`, the builder-pattern API is
159//! usually the more ergonomic option.
160//!
161//! ```
162//! use embedded_hal::spi::MODE_1;
163//!
164//! // SAMD11/SAMD21 version
165//! let spi = spi::Config::new(&pm, sercom, pads, freq)
166//!     .baud(1.mhz())
167//!     .char_size::<NineBit>()
168//!     .bit_order(BitOrder::LsbFirst)
169//!     .spi_mode(MODE_1)
170//!     .enable();
171//!
172//! // SAMx5x version
173//! let spi = spi::Config::new(&mclk, sercom, pads, freq)
174//!     .baud(1.mhz())
175//!     .length::<U2>()
176//!     .bit_order(BitOrder::LsbFirst)
177//!     .spi_mode(MODE_1)
178//!     .enable();
179//! ```
180//!
181//! To be accepted as a [`ValidConfig`], the `Config` must have a set of
182//! [`ValidPads`] that matches its [`OpMode`]. In particular, the `SS` pad must
183//! be [`NoneT`] for [`Master`] mode, where the user is expected to handle it
184//! manaully. But it must be [`SomePad`] in [`MasterHWSS`] and [`Slave`] modes,
185//! where it is controlled by the hardware.
186//!
187//! # Using a functional `Spi` peripheral
188//!
189//! An [`Spi`] struct has two type parameters. The first is the corresponding
190//! `Config`, while the second represents its [`Capability`], i.e. [`Rx`],
191//! [`Tx`] or [`Duplex`]. The [`enable`] function determines the `Capability`
192//! automaically from the set of [`ValidPads`].
193//!
194//! ```
195//! use atsamd_hal::gpio::{PA08, PA09};
196//! use atsamd_hal::sercom::{Sercom0, spi};
197//! use atsamd_hal::sercom::spi::{Master, Rx};
198//! use atsamd_hal::typelevel::NoneT;
199//!
200//! // SAMD11/SAMD21-specific imports
201//! use atsamd_hal::sercom::spi::NineBit;
202//!
203//! // SAMx5x-specific imports
204//! use atsamd_hal::sercom::spi::lengths::U2;
205//!
206//! type Pads = spi::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
207//!
208//! // SAMD11/SAMD21 version
209//! type Config = spi::Config<Pads, Master, NineBit>;
210//!
211//! // SAMx5x version
212//! type Config = spi::Config<Pads, Master, U2>;
213//!
214//! type Spi = spi::Spi<Config, Rx>;
215//! ```
216//!
217//! Only [`Spi`] structs can actually perform transactions. To do so, use the
218//! various embedded HAL traits, like [`spi::SpiBus`](crate::ehal::spi::SpiBus),
219//! [`embedded_io::Read`], [`embedded_io::Write`],
220//! [`embedded_hal_nb::serial::Read`](crate::ehal_nb::serial::Read), or
221//! [`embedded_hal_nb::serial::Write`](crate::ehal_nb::serial::Write). See the
222//! [`impl_ehal`] module documentation for more details about the specific trait
223//! implementations, which vary based on [`Size`] and [`Capability`].
224//!
225//! ```
226//! use nb::block;
227//! use crate::ehal_02::spi::FullDuplex;
228//!
229//! block!(spi.send(0xAA55));
230//! let rcvd: u16 = block!(spi.read());
231//! ```
232//!
233//! ## Flushing the bus
234//!
235//! The [`SpiBus`](crate::ehal::spi::SpiBus) methods do not flush the bus when a
236//! transaction is complete. This is in part to increase performance and allow
237//! for pipelining SPI transactions. This is true for both sync and async
238//! operation. As such, you should ensure you manually call
239//! [`flush`](crate::ehal::spi::SpiBus::flush) when:
240//! * You must synchronize SPI activity and GPIO activity, for example before
241//!   deasserting a CS pin.
242//! * Before deinitializing the SPI peripheral.
243//!
244//! Take note that the [`SpiDevice`](crate::ehal::spi::SpiDevice)
245//! implementations automatically take care of flushing, so no further flushing
246//! is needed.
247//!
248//! [See the embedded-hal
249//! spec](https://docs.rs/embedded-hal/latest/embedded_hal/spi/index.html#flushing)
250//! for more information.
251//!
252//! # [`PanicOnRead`] and [`PanicOnWrite`]
253//!
254//! Some driver libraries take a type implementing [`embedded_hal::spi::SpiBus`]
255//! or [`embedded_hal::spi::SpiDevice`], even when they only need to receive or
256//! send data, but not both. A good example is WS2812 addressable LEDs
257//! (neopixels), which only take a data input. Therefore, their protocol can be
258//! implemented with a [`Tx`] [`Spi`] that only has a MOSI pin. In another
259//! example, often LCD screens only have a MOSI and SCK pins. In order to
260//! unnecessarily tying up pins in the [`Spi`] struct, and provide an escape
261//! hatch for situations where constructing the [`Spi`] struct would otherwise
262//! be impossible, we provide the [`PanicOnRead`] and [`PanicOnWrite`] wrapper
263//! types, which implement [`embedded_hal::spi::SpiBus`].
264//!
265//! As the names imply, they panic if an incompatible method is called. See
266//! [`Spi::into_panic_on_write`] and [`Spi::into_panic_on_read`].
267//!
268//! [`PanicOnRead`] and [`PanicOnWrite`] are compatible with DMA.
269//!
270//! # Using SPI with DMA <span class="stab portability" title="Available on crate feature `dma` only"><code>dma</code></span>
271//!
272//! This HAL includes support for DMA-enabled SPI transfers. Use
273//! [`Spi::with_dma_channels`] ([`Duplex`] and [`Rx`]), and
274//! [`Spi::with_tx_channel`] ([`Tx`]-only) to attach DMA channels to the [`Spi`]
275//! struct. A DMA-enabled [`Spi`] implements the blocking
276//! [`embedded_hal::spi::SpiBus`], [`embedded_io::Write`] and/or
277//! [`embedded_io::Read`] traits, which can be used to perform SPI transactions
278//! which are fast, continuous and low jitter, even if they are preemped by a
279//! higher priority interrupt.
280//!
281//! ```
282//! // Assume channel0 and channel1 are configured `dmac::Channel`, and spi a
283//! // fully-configured `Spi`
284//!
285//! // Create data to send
286//! let buffer: [u8; 50] = [0xff; 50];
287//!
288//! // Attach DMA channels
289//! let spi = spi.with_dma_channels(channel0, channel1);
290//!
291//! // Perform the transfer
292//! spi.write(&mut buffer)?;
293//! ```
294//!
295//! # `async` operation <span class="stab portability" title="Available on crate feature `async` only"><code>async</code></span>
296//!
297//! An [`Spi`] can be used for `async` operations. Configuring a [`Spi`] in
298//! async mode is relatively simple:
299//!
300//! * Bind the corresponding `SERCOM` interrupt source to the SPI
301//!   [`InterruptHandler`] (refer to the module-level [`async_hal`]
302//!   documentation for more information).
303//! * Turn a previously configured [`Spi`] into a [`SpiFuture`] by calling
304//!   [`Spi::into_future`]
305//! * Optionally, add DMA channels to RX, TX or both using
306//!   [`SpiFuture::with_rx_dma_channel`] and [`SpiFuture::with_tx_dma_channel`].
307//!   The API is exactly the same whether DMA channels are used or not.
308//! * Use the provided async methods for reading or writing to the SPI
309//!   peripheral. [`SpiFuture`] implements [`embedded_hal_async::spi::SpiBus`].
310//!
311//! `SpiFuture` implements `AsRef<Spi>` and `AsMut<Spi>` so that it can be
312//! reconfigured using the regular [`Spi`] methods.
313//!
314//! ## Considerations when using `async` [`Spi`] with DMA <span class="stab portability" title="Available on crate feature `async` only"><code>async</code></span> <span class="stab portability" title="Available on crate feature `dma` only"><code>dma</code></span>
315//!
316//! * An [`Spi`] struct must be turned into an [`SpiFuture`] by calling
317//!   [`Spi::into_future`] before calling `with_dma_channel`. The DMA channel
318//!   itself must also be configured in async mode by using
319//!   [`DmaController::into_future`](crate::dmac::DmaController::into_future).
320//!   If a DMA channel is added to the [`Spi`] struct before it is turned into
321//!   an [`SpiFuture`], it will not be able to use DMA in async mode.
322//!
323//! ```
324//! // This will work
325//! let spi = spi.into_future().with_dma_channels(rx_channel, tx_channel);
326//!
327//! // This won't
328//! let spi = spi.with_dma_channels(rx_channel, tx_channel).into_future();
329//! ```
330//!
331//! ### Safety considerations
332//!
333//! In `async` mode, an SPI+DMA transfer does not require `'static` source and
334//! destination buffers. This, in theory, makes its use `unsafe`. However it is
335//! marked as safe for better ergonomics, and to enable the implementation of
336//! the [`embedded_hal_async::spi::SpiBus`] trait.
337//!
338//! This means that, as an user, you **must** ensure that the [`Future`]s
339//! returned by the [`embedded_hal_async::spi::SpiBus`] methods may never be
340//! forgotten through [`forget`] or by wrapping them with a [`ManuallyDrop`].
341//!
342//! The returned futures implement [`Drop`] and will automatically stop any
343//! ongoing transfers; this guarantees that the memory occupied by the
344//! now-dropped buffers may not be corrupted by running transfers.
345//!
346//! This means that using functions like [`futures::select_biased`] to implement
347//! timeouts is safe; transfers will be safely cancelled if the timeout expires.
348//!
349//! This also means that should you [`forget`] this [`Future`] after its first
350//! [`poll`] call, the transfer will keep running, ruining the now-reclaimed
351//! memory, as well as the rest of your day.
352//!
353//! * `await`ing is fine: the [`Future`] will run to completion.
354//! * Dropping an incomplete transfer is also fine. Dropping can happen, for
355//!   example, if the transfer doesn't complete before a timeout expires.
356//! * Dropping an incomplete transfer *without running its destructor* is
357//!   **unsound** and will trigger undefined behavior.
358//!
359//! ```ignore
360//! async fn always_ready() {}
361//!
362//! let mut buffer = [0x00; 10];
363//!
364//! // This is completely safe
365//! spi.read(&mut buffer).await?;
366//!
367//! // This is also safe: we launch a transfer, which is then immediately cancelled
368//! futures::select_biased! {
369//!     _ = spi.read(&mut buffer)?,
370//!     _ = always_ready(),
371//! }
372//!
373//! // This, while contrived, is also safe.
374//! {
375//!     use core::future::Future;
376//!
377//!     let future = spi.read(&mut buffer);
378//!     futures::pin_mut!(future);
379//!     // Assume ctx is a `core::task::Context` given out by the executor.
380//!     // The future is polled, therefore starting the transfer
381//!     future.as_mut().poll(ctx);
382//!
383//!     // Future is dropped here - transfer is cancelled.
384//! }
385//!
386//! // DANGER: This is an example of undefined behavior
387//! {
388//!     use core::future::Future;
389//!     use core::ops::DerefMut;
390//!
391//!     let future = core::mem::ManuallyDrop::new(spi.read(&mut buffer));
392//!     futures::pin_mut!(future);
393//!     // To actually make this example compile, we would need to wrap the returned
394//!     // future from `i2c.read()` in a newtype that implements Future, because we
395//!     // can't actually call as_mut() without being able to name the type we want
396//!     // to deref to.
397//!     let future_ref: &mut SomeNewTypeFuture = &mut future.as_mut();
398//!     future.as_mut().poll(ctx);
399//!
400//!     // Future is NOT dropped here - transfer is not cancelled, resulting un UB.
401//! }
402//! ```
403//!
404//! As you can see, unsoundness is relatively hard to come by - however, caution
405//! should still be exercised.
406//!
407//! [`enable`]: Config::enable
408//! [`gpio`]: crate::gpio
409//! [`IsPad`]: super::pad::IsPad
410//! [`OptionalPad`]: super::pad::OptionalPad
411//! [`PadNum`]: super::pad::PadNum
412//! [`Pin`]: crate::gpio::pin::Pin
413//! [`PinId`]: crate::gpio::pin::PinId
414//! [`PinMode`]: crate::gpio::pin::PinMode
415//! [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
416//! [`embedded_hal::spi::SpiDevice`]: crate::ehal::spi::SpiDevice
417//! [`async_hal`]: crate::async_hal
418//! [`forget`]: core::mem::forget
419//! [`ManuallyDrop`]: core::mem::ManuallyDrop
420//! [`Future`]: core::future::Future
421//! [`poll`]: core::future::Future::poll
422
423use core::marker::PhantomData;
424
425use atsamd_hal_macros::{hal_cfg, hal_docs, hal_macro_helper, hal_module};
426use bitflags::bitflags;
427use num_traits::AsPrimitive;
428
429use crate::ehal;
430pub use crate::ehal::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Phase, Polarity};
431use crate::sercom::{ApbClkCtrl, Sercom, pad::SomePad};
432use crate::time::Hertz;
433use crate::typelevel::{Is, NoneT, Sealed};
434
435mod reg;
436use reg::Registers;
437
438//=============================================================================
439// Chip-specific imports
440//=============================================================================
441
442#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
443use crate::pac::sercom0::spi::ctrla::Modeselect;
444#[hal_cfg("sercom0-d5x")]
445use crate::pac::sercom0::spim::ctrla::Modeselect;
446
447#[hal_module(
448    any("sercom0-d11", "sercom0-d21") => "spi/pads_thumbv6m.rs",
449    "sercom0-d5x" => "spi/pads_thumbv7em.rs",
450)]
451pub mod pads {}
452
453pub use pads::*;
454
455#[hal_module(
456    any("sercom0-d11", "sercom0-d21") => "spi/char_size.rs",
457    "sercom0-d5x" => "spi/length.rs",
458)]
459pub mod size {}
460
461#[cfg(doc)]
462#[hal_cfg(not(any("sercom0-d11", "sercom0-d21")))]
463/// This type is not present with the selected feature set, defined for
464/// documentation only
465pub enum NineBit {}
466
467#[cfg(doc)]
468#[hal_cfg(not(any("sercom0-d11", "sercom0-d21")))]
469/// This type is not present with the selected feature set, defined for
470/// documentation only
471pub enum EightBit {}
472
473#[cfg(doc)]
474#[hal_cfg(not(any("sercom0-d11", "sercom0-d21")))]
475/// This trait is not present with the selected feature set, defined for
476/// documentation only
477pub trait CharSize {
478    /// This type is not present with the selected feature set, defined for
479    /// documentation only
480    type Word;
481}
482
483#[cfg(doc)]
484#[hal_cfg(not("sercom0-d5x"))]
485/// This trait is not present with the selected feature set, defined for
486/// documentation only
487pub trait Length {}
488
489pub use size::*;
490
491/// Valid transaction [`Length`]s from the [`typenum`] crate
492#[hal_cfg("sercom0-d5x")]
493pub mod lengths {
494    seq_macro::seq!(N in 1..=255 {
495        pub use typenum::U~N;
496    });
497}
498
499pub mod impl_ehal;
500
501#[cfg(feature = "async")]
502mod async_api;
503#[cfg(feature = "async")]
504pub use async_api::*;
505
506//=============================================================================
507// BitOrder
508//=============================================================================
509
510/// Define the bit order of transactions
511#[repr(u8)]
512#[derive(Copy, Clone, PartialEq, Eq)]
513#[cfg_attr(feature = "defmt", derive(defmt::Format))]
514pub enum BitOrder {
515    LsbFirst,
516    MsbFirst,
517}
518
519//=============================================================================
520// Flags
521//=============================================================================
522
523const DRE: u8 = 0x01;
524const TXC: u8 = 0x02;
525const RXC: u8 = 0x04;
526const SSL: u8 = 0x08;
527const ERROR: u8 = 0x80;
528
529pub const RX_FLAG_MASK: u8 = RXC | ERROR;
530pub const TX_FLAG_MASK: u8 = DRE | TXC;
531
532bitflags! {
533    /// Interrupt bit flags for SPI transactions
534    ///
535    /// The available interrupt flags are `DRE`, `RXC`, `TXC`, `SSL` and
536    /// `ERROR`. The binary format of the underlying bits exactly matches the
537    /// `INTFLAG` register.
538    #[derive(Clone, Copy)]
539    pub struct Flags: u8 {
540        const DRE = DRE;
541        const TXC = TXC;
542        const RXC = RXC;
543        const SSL = SSL;
544        const ERROR = ERROR;
545    }
546}
547
548#[allow(dead_code)]
549impl Flags {
550    pub(super) const RX: Self = Self::from_bits_retain(RX_FLAG_MASK);
551    pub(super) const TX: Self = Self::from_bits_retain(TX_FLAG_MASK);
552}
553
554//=============================================================================
555// Status
556//=============================================================================
557
558bitflags! {
559    /// Status bit flags for SPI transactions
560    ///
561    /// The available status flags are `BUFOVF` and `LENERR`. The binary format
562    /// of the underlying bits exactly matches the `STATUS` register.
563    #[derive(Clone, Copy)]
564    pub struct Status: u16 {
565        const BUFOVF = 0x0004;
566        const LENERR = 0x0800;
567    }
568}
569
570impl Status {
571    /// Check whether [`Self`] originates from an error.
572    ///
573    /// # Errors
574    ///
575    /// Returns an error if `STATUS` contains `BUFOVF` or `LENERR`
576    pub fn check_bus_error(self) -> Result<(), Error> {
577        // Buffer overflow has priority
578        if self.contains(Status::BUFOVF) {
579            Err(Error::Overflow)
580        } else if self.contains(Status::LENERR) {
581            Err(Error::LengthError)
582        } else {
583            Ok(())
584        }
585    }
586}
587
588//=============================================================================
589// Error
590//=============================================================================
591
592/// Error `enum` for SPI transactions
593///
594/// The SPI peripheral only has two error types, buffer overflow and transaction
595/// length error.
596#[derive(Clone, Copy, Debug, Eq, PartialEq)]
597#[cfg_attr(feature = "defmt", derive(defmt::Format))]
598pub enum Error {
599    Overflow,
600    LengthError,
601    #[cfg(feature = "dma")]
602    Dma(crate::dmac::Error),
603}
604
605//=============================================================================
606// Operating mode
607//=============================================================================
608
609/// Type-level enum representing the SPI operating mode
610///
611/// See the documentation on [type-level enums] for a discussion of the pattern.
612///
613/// The available operating modes are [`Master`], [`MasterHWSS`] and [`Slave`].
614/// In [`Master`] mode, the `SS` signal must be handled by the user, so `SS`
615/// must be [`NoneT`]. In [`MasterHWSS`] mode, the hardware drives the `SS`
616/// line, so [`SomePad`] is required. In [`Slave`] mode, the `SS` pad is
617/// required as well, to indicate when data is valid.
618///
619/// [type-level enums]: crate::typelevel#type-level-enums
620pub trait OpMode: Sealed {
621    /// Corresponding variant from the PAC enum
622    const MODE: Modeselect;
623    /// Bit indicating whether hardware `SS` control is enabled
624    const MSSEN: bool;
625}
626
627/// [`OpMode`] variant for Master mode
628pub enum Master {}
629
630/// [`OpMode`] variant for Master mode with hardware-controlled slave select
631pub enum MasterHWSS {}
632
633/// [`OpMode`] variant for Slave mode
634pub enum Slave {}
635
636impl Sealed for Master {}
637impl Sealed for MasterHWSS {}
638impl Sealed for Slave {}
639
640impl OpMode for Master {
641    const MODE: Modeselect = Modeselect::SpiMaster;
642    const MSSEN: bool = false;
643}
644
645impl OpMode for MasterHWSS {
646    const MODE: Modeselect = Modeselect::SpiMaster;
647    const MSSEN: bool = true;
648}
649
650impl OpMode for Slave {
651    const MODE: Modeselect = Modeselect::SpiSlave;
652    const MSSEN: bool = false;
653}
654
655/// Marker trait for Master operating modes
656///
657/// This trait is implemented for [`Master`] and [`MasterHWSS`] but not for
658/// [`Slave`].
659pub trait MasterMode: OpMode {}
660
661impl MasterMode for Master {}
662impl MasterMode for MasterHWSS {}
663
664//=============================================================================
665// Size
666//=============================================================================
667
668/// Type alias for the width of the `DATA` register
669#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
670pub type DataWidth = u16;
671
672/// Type alias for the width of the `DATA` register
673#[hal_cfg("sercom0-d5x")]
674pub type DataWidth = u32;
675
676/// Trait alias whose definition varies by chip
677///
678/// On SAMD11 and SAMD21 chips, this represents the [`CharSize`].
679#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
680pub trait Size: CharSize {}
681
682#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
683impl<C: CharSize> Size for C {}
684
685/// Type alias for the default [`Size`] type, which varies by chip
686#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
687pub type DefaultSize = EightBit;
688
689/// Trait alias whose definition varies by chip
690///
691/// On SAMx5x chips, this represents the transaction [`Length`].
692#[hal_cfg("sercom0-d5x")]
693pub trait Size: Length {}
694
695#[hal_cfg("sercom0-d5x")]
696impl<L: Length> Size for L {}
697
698/// Type alias for the default [`Size`] type, which varies by chip
699#[hal_cfg("sercom0-d5x")]
700pub type DefaultSize = typenum::U1;
701
702//==============================================================================
703// AtomicSize
704//==============================================================================
705
706/// Marker trait for transaction [`Size`]s that can be completed in a single
707/// read or write of the `DATA` register
708pub trait AtomicSize: Size {}
709
710#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
711impl<C: CharSize> AtomicSize for C {}
712
713#[hal_cfg("sercom0-d5x")]
714seq_macro::seq!(N in 1..=4 {
715    impl AtomicSize for lengths::U~N {}
716});
717
718//==============================================================================
719// Capability
720//==============================================================================
721
722/// Type-level enum representing the simplex or duplex transaction capability
723///
724/// The available, type-level variants are [`Rx`], [`Tx`] and [`Duplex`]. See
725/// the [type-level enum] documentation for more details.
726///
727/// [type-level enum]: crate::typelevel#type-level-enums
728pub trait Capability: Sealed + Default {
729    const RX_ENABLE: bool;
730}
731
732/// Sub-set of [`Capability`] variants that can receive data, i.e. [`Rx`] and
733/// [`Duplex`]
734pub trait Receive: Capability {}
735
736/// Sub-set of [`Capability`] variants that can transmit dat, i.e. [`Tx`] and
737/// [`Duplex`]
738pub trait Transmit: Capability {}
739
740/// Type-level variant of the [`Capability`] enum for simplex, [`Receive`]-only
741/// transactions
742///
743/// [`Spi`] structs are `Rx` when the `DO` (Data Out) type is [`NoneT`] in the
744/// corresponding [`Pads`] struct.
745///
746/// While the [`Tx`] and [`Duplex`] structs are zero-sized, this struct is not.
747/// Because an SPI master must initiate all transactions, using it in a simplex,
748/// [`Receive`]-only context is slightly complicated. In that case, the [`Spi`]
749/// struct must track whether a transaction needs to be started or is already in
750/// progress. This struct contains a `bool` to track that progress.
751#[derive(Default)]
752pub struct Rx {
753    pub(super) in_progress: bool,
754}
755
756impl Sealed for Rx {}
757impl Capability for Rx {
758    const RX_ENABLE: bool = true;
759}
760impl Receive for Rx {}
761
762/// Type-level variant of the [`Capability`] enum for simplex, [`Transmit`]-only
763/// transactions
764///
765/// [`Spi`] structs are `Tx` when the `DI` (Data In) type is [`NoneT`] in the
766/// corresponding [`Pads`] struct.
767#[derive(Default)]
768pub struct Tx;
769
770impl Sealed for Tx {}
771impl Capability for Tx {
772    const RX_ENABLE: bool = false;
773}
774impl Transmit for Tx {}
775
776/// Type-level variant of the [`Capability`] enum for duplex transactions
777///
778/// [`Spi`] structs are `Duplex` when both the `DI` and `DO` [`Pads`] are
779/// [`SomePad`].
780/// corresponding [`Pads`] struct.
781#[derive(Default)]
782pub struct Duplex;
783
784impl Sealed for Duplex {}
785impl Capability for Duplex {
786    const RX_ENABLE: bool = true;
787}
788impl Receive for Duplex {}
789impl Transmit for Duplex {}
790
791//=============================================================================
792// Config
793//=============================================================================
794
795/// A configurable SPI peripheral in its disabled state
796///
797/// See the [module-level](super) documentation for more details on declaring
798/// and instantiating `Pads` types.
799pub struct Config<P, M = Master, Z = DefaultSize>
800where
801    P: ValidPads,
802    M: OpMode,
803    Z: Size,
804{
805    regs: Registers<P::Sercom>,
806    pads: P,
807    mode: PhantomData<M>,
808    size: PhantomData<Z>,
809    freq: Hertz,
810    nop_word: DataWidth,
811}
812
813impl<P: ValidPads> Config<P> {
814    /// Create a new [`Config`] in the default configuration.
815    #[inline]
816    #[hal_macro_helper]
817    fn default(sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
818        let mut regs = Registers { sercom };
819        regs.reset();
820        regs.set_op_mode(Master::MODE, Master::MSSEN);
821        regs.set_dipo_dopo(P::DIPO_DOPO);
822        #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
823        regs.set_char_size(EightBit::BITS);
824        #[hal_cfg("sercom0-d5x")]
825        regs.set_length(1);
826        Self {
827            regs,
828            pads,
829            mode: PhantomData,
830            size: PhantomData,
831            freq: freq.into(),
832            nop_word: 0x00.as_(),
833        }
834    }
835
836    #[hal_docs(
837        {
838            /// Create a new [`Config`] in the default configuration
839            ///
840            /// This function will enable the corresponding APB clock, reset the
841            /// [`Sercom`] peripheral, and return a [`Config`] in the default
842            /// configuration. The default [`OpMode`] is [`Master`], while the default
843            /// [`Size`] is an
844        }
845        any("sercom0-d11", "sercom0-d21") => {
846            /// [`EightBit`] [`CharSize`]
847        }
848        "sercom0-d5x" => {
849            /// `EightBit` `CharSize`
850        }
851        {
852            /// for SAMD11 and SAMD21 chips or a
853        }
854        any("sercom0-d11", "sercom0-d21") => {
855            /// `Length` of `U1`
856        }
857        "sercom0-d5x" => {
858            /// [`Length`] of `U1`
859        }
860        {
861            /// for SAMx5x chips. Note that [`Config`] takes ownership of both the
862            /// PAC [`Sercom`] struct as well as the [`Pads`].
863            ///
864            /// Users must configure GCLK manually. The `freq` parameter represents the
865            /// GCLK frequency for this [`Sercom`] instance.
866        }
867    )]
868    #[inline]
869    pub fn new(
870        apb_clk_ctrl: &ApbClkCtrl,
871        mut sercom: P::Sercom,
872        pads: P,
873        freq: impl Into<Hertz>,
874    ) -> Self {
875        sercom.enable_apb_clock(apb_clk_ctrl);
876        Self::default(sercom, pads, freq)
877    }
878}
879
880impl<P, M, Z> Config<P, M, Z>
881where
882    P: ValidPads,
883    M: OpMode,
884    Z: Size,
885{
886    /// Change the [`OpMode`] or [`Size`]
887    #[inline]
888    fn change<M2, Z2>(self) -> Config<P, M2, Z2>
889    where
890        M2: OpMode,
891        Z2: Size,
892    {
893        Config {
894            regs: self.regs,
895            pads: self.pads,
896            mode: PhantomData,
897            size: PhantomData,
898            freq: self.freq,
899            nop_word: self.nop_word,
900        }
901    }
902
903    /// Obtain a reference to the PAC `SERCOM` struct
904    ///
905    /// # Safety
906    ///
907    /// Directly accessing the `SERCOM` could break the invariants of the
908    /// type-level tracking in this module, so it is unsafe.
909    #[inline]
910    pub unsafe fn sercom(&self) -> &P::Sercom {
911        &self.regs.sercom
912    }
913
914    /// Trigger the [`Sercom`]'s SWRST and return a [`Config`] in the
915    /// default configuration.
916    #[inline]
917    pub fn reset(self) -> Config<P> {
918        Config::default(self.regs.sercom, self.pads, self.freq)
919    }
920
921    /// Consume the [`Config`], reset the peripheral, and return the [`Sercom`]
922    /// and [`Pads`]
923    #[inline]
924    pub fn free(mut self) -> (P::Sercom, P) {
925        self.regs.reset();
926        (self.regs.sercom, self.pads)
927    }
928
929    /// Change the [`OpMode`]
930    #[inline]
931    pub fn op_mode<M2: OpMode>(mut self) -> Config<P, M2, Z> {
932        self.regs.set_op_mode(M2::MODE, M2::MSSEN);
933        self.change()
934    }
935
936    /// Change the [`CharSize`] using the builder pattern
937    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
938    #[inline]
939    pub fn char_size<C2: CharSize>(mut self) -> Config<P, M, C2> {
940        self.regs.set_char_size(C2::BITS);
941        self.change()
942    }
943
944    /// Change the transaction [`Length`] using the builder pattern
945    ///
946    /// To use a run-time dynamic length, set the [`Length`] type to
947    /// [`DynLength`] and then use the [`dyn_length`] method.
948    ///
949    /// [`dyn_length`]: Config::dyn_length
950    #[hal_cfg("sercom0-d5x")]
951    #[inline]
952    pub fn length<L2: Length>(mut self) -> Config<P, M, L2> {
953        self.regs.set_length(L2::U8);
954        self.change()
955    }
956
957    /// Get the clock polarity
958    #[inline]
959    pub fn get_cpol(&self) -> Polarity {
960        self.regs.get_cpol()
961    }
962
963    /// Set the clock polarity
964    #[inline]
965    pub fn set_cpol(&mut self, cpol: Polarity) {
966        self.regs.set_cpol(cpol);
967    }
968
969    /// Set the clock polarity using the builder pattern
970    #[inline]
971    pub fn cpol(mut self, cpol: Polarity) -> Self {
972        self.set_cpol(cpol);
973        self
974    }
975
976    /// Get the clock phase
977    #[inline]
978    pub fn get_cpha(&self) -> Phase {
979        self.regs.get_cpha()
980    }
981
982    /// Set the clock phase
983    #[inline]
984    pub fn set_cpha(&mut self, cpha: Phase) {
985        self.regs.set_cpha(cpha)
986    }
987
988    /// Set the clock phase using the builder pattern
989    #[inline]
990    pub fn cpha(mut self, cpha: Phase) -> Self {
991        self.set_cpha(cpha);
992        self
993    }
994
995    /// Get the SPI mode (clock polarity & phase)
996    #[inline]
997    pub fn get_spi_mode(&self) -> ehal::spi::Mode {
998        self.regs.get_spi_mode()
999    }
1000
1001    /// Set the SPI mode (clock polarity & phase)
1002    #[inline]
1003    pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) {
1004        self.regs.set_spi_mode(mode);
1005    }
1006
1007    /// Set the SPI mode (clock polarity & phase) using the builder pattern
1008    #[inline]
1009    pub fn spi_mode(mut self, mode: ehal::spi::Mode) -> Self {
1010        self.set_spi_mode(mode);
1011        self
1012    }
1013
1014    /// Get the bit order of transmission (MSB/LSB first)
1015    ///
1016    /// This only affects the order of bits within each byte. Bytes are always
1017    /// transferred in little endian order from the 32-bit DATA register.
1018    #[inline]
1019    pub fn get_bit_order(&self) -> BitOrder {
1020        self.regs.get_bit_order()
1021    }
1022
1023    /// Set the bit order of transmission (MSB/LSB first) using the builder
1024    /// pattern
1025    ///
1026    /// This only affects the order of bits within each byte. Bytes are always
1027    /// transferred in little endian order from the 32-bit DATA register.
1028    #[inline]
1029    pub fn set_bit_order(&mut self, order: BitOrder) {
1030        self.regs.set_bit_order(order);
1031    }
1032
1033    /// Set the bit order of transmission (MSB/LSB first) using the builder
1034    /// pattern
1035    ///
1036    /// This only affects the order of bits within each byte. Bytes are always
1037    /// transferred in little endian order from the 32-bit DATA register.
1038    #[inline]
1039    pub fn bit_order(mut self, order: BitOrder) -> Self {
1040        self.set_bit_order(order);
1041        self
1042    }
1043
1044    /// Get the NOP word
1045    ///
1046    /// This word is used when reading in Duplex mode, since an equal number of
1047    /// words must be sent in order to avoid overflow errors.
1048    pub fn get_nop_word(&self) -> DataWidth {
1049        self.nop_word
1050    }
1051
1052    /// Set the NOP word
1053    ///
1054    /// This word is used when reading in Duplex mode, since an equal number of
1055    /// words must be sent in order to avoid overflow errors.
1056    pub fn set_nop_word(&mut self, nop_word: DataWidth) {
1057        self.nop_word = nop_word;
1058    }
1059
1060    /// Set the NOP word using the builder pattern
1061    ///
1062    /// This word is used when reading in Duplex mode, since an equal number of
1063    /// words must be sent in order to avoid overflow errors.
1064    pub fn nop_word(mut self, nop_word: DataWidth) -> Self {
1065        self.nop_word = nop_word;
1066        self
1067    }
1068
1069    /// Get the baud rate
1070    ///
1071    /// The returned baud rate may not exactly match what was set.
1072    #[inline]
1073    pub fn get_baud(&mut self) -> Hertz {
1074        self.regs.get_baud(self.freq)
1075    }
1076
1077    /// Set the baud rate
1078    ///
1079    /// This function will calculate the best BAUD register setting based on the
1080    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
1081    /// half the GCLK frequency. The minimum baud rate is the GCLK frequency /
1082    /// 512. Values outside this range will saturate at the extremes.
1083    #[inline]
1084    pub fn set_baud(&mut self, baud: Hertz) {
1085        self.regs.set_baud(self.freq, baud);
1086    }
1087
1088    /// Set the baud rate using the builder API
1089    ///
1090    /// This function will calculate the best BAUD register setting based on the
1091    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
1092    /// half the GCLK frequency. The minimum baud rate is the GCLK frequency /
1093    /// 512. Values outside this range will saturate at the extremes.
1094    #[inline]
1095    pub fn baud(mut self, baud: Hertz) -> Self {
1096        self.set_baud(baud);
1097        self
1098    }
1099
1100    /// Read the enabled state of the immediate buffer overflow notification
1101    ///
1102    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1103    /// overflow occurs. Otherwise, it will not be issued until its place within
1104    /// the data stream.
1105    #[inline]
1106    pub fn get_ibon(&self) -> bool {
1107        self.regs.get_ibon()
1108    }
1109
1110    /// Enable or disable the immediate buffer overflow notification
1111    ///
1112    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1113    /// overflow occurs. Otherwise, it will not be issued until its place within
1114    /// the data stream.
1115    #[inline]
1116    pub fn set_ibon(&mut self, enabled: bool) {
1117        self.regs.set_ibon(enabled);
1118    }
1119
1120    /// Enable or disable the immediate buffer overflow notification using the
1121    /// builder API
1122    ///
1123    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1124    /// overflow occurs. Otherwise, it will not be issued until its place within
1125    /// the data stream.
1126    #[inline]
1127    pub fn ibon(mut self, enabled: bool) -> Self {
1128        self.set_ibon(enabled);
1129        self
1130    }
1131
1132    /// Read the enable state of run in standby mode
1133    #[inline]
1134    pub fn get_run_in_standby(&self) -> bool {
1135        self.regs.get_run_in_standby()
1136    }
1137
1138    /// Enable or disable run in standby mode
1139    #[inline]
1140    pub fn set_run_in_standby(&mut self, enabled: bool) {
1141        self.regs.set_run_in_standby(enabled);
1142    }
1143
1144    /// Enable or disable run in standby mode using the builder API
1145    #[inline]
1146    pub fn run_in_standby(mut self, enabled: bool) -> Self {
1147        self.set_run_in_standby(enabled);
1148        self
1149    }
1150
1151    /// Enable the SPI peripheral
1152    ///
1153    /// SPI transactions are not possible until the peripheral is enabled.
1154    /// This function is limited to [`ValidConfig`]s.
1155    #[inline]
1156    pub fn enable(mut self) -> Spi<Self, P::Capability>
1157    where
1158        Self: ValidConfig,
1159    {
1160        if P::Capability::RX_ENABLE {
1161            self.regs.rx_enable();
1162        }
1163        self.regs.enable();
1164        Spi {
1165            config: self,
1166            capability: P::Capability::default(),
1167            _rx_channel: NoneT,
1168            _tx_channel: NoneT,
1169        }
1170    }
1171}
1172
1173#[hal_cfg("sercom0-d5x")]
1174impl<P, M> Config<P, M, DynLength>
1175where
1176    P: ValidPads,
1177    M: OpMode,
1178{
1179    /// Get the transaction length
1180    #[inline]
1181    pub fn get_dyn_length(&self) -> u8 {
1182        self.regs.get_length()
1183    }
1184
1185    /// Set the transaction length
1186    ///
1187    /// Write the LENGTH register to set the transaction length. If the length
1188    /// is zero, it will be set to 1.
1189    #[inline]
1190    pub fn set_dyn_length(&mut self, length: u8) {
1191        self.regs.set_length(length);
1192    }
1193
1194    /// Set the transaction length using the builder API
1195    ///
1196    /// Write the LENGTH register to set the transaction length. If the length
1197    /// is zero, it will be set to 1.
1198    #[inline]
1199    pub fn dyn_length(mut self, length: u8) -> Self {
1200        self.set_dyn_length(length);
1201        self
1202    }
1203}
1204
1205//=============================================================================
1206// AnyConfig
1207//=============================================================================
1208
1209/// Type class for all possible [`Config`] types
1210///
1211/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
1212/// [`Config`] types. See the `AnyKind` documentation for more details on the
1213/// pattern.
1214///
1215/// In addition to the normal, `AnyKind` associated types. This trait also
1216/// copies the [`Sercom`], [`Capability`] and [`Word`] types, to make it easier
1217/// to apply bounds to these types at the next level of abstraction.
1218///
1219/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
1220/// [type class]: crate::typelevel#type-classes
1221pub trait AnyConfig: Is<Type = SpecificConfig<Self>> {
1222    type Sercom: Sercom;
1223    type Pads: ValidPads<Sercom = Self::Sercom>;
1224    type Capability: Capability;
1225    type OpMode: OpMode;
1226    type Size: Size;
1227    type Word: 'static;
1228}
1229
1230/// Type alias to recover the specific [`Config`] type from an implementation of
1231/// [`AnyConfig`]
1232pub type SpecificConfig<C> =
1233    Config<<C as AnyConfig>::Pads, <C as AnyConfig>::OpMode, <C as AnyConfig>::Size>;
1234
1235impl<P, M, Z> Sealed for Config<P, M, Z>
1236where
1237    P: ValidPads,
1238    M: OpMode,
1239    Z: Size,
1240{
1241}
1242
1243impl<P, M, Z> AnyConfig for Config<P, M, Z>
1244where
1245    P: ValidPads,
1246    M: OpMode,
1247    Z: Size,
1248{
1249    type Sercom = P::Sercom;
1250    type Pads = P;
1251    type Capability = P::Capability;
1252    type OpMode = M;
1253    type Size = Z;
1254    type Word = Z::Word;
1255}
1256
1257impl<P, M, Z> AsRef<Self> for Config<P, M, Z>
1258where
1259    P: ValidPads,
1260    M: OpMode,
1261    Z: Size,
1262{
1263    #[inline]
1264    fn as_ref(&self) -> &Self {
1265        self
1266    }
1267}
1268
1269impl<P, M, Z> AsMut<Self> for Config<P, M, Z>
1270where
1271    P: ValidPads,
1272    M: OpMode,
1273    Z: Size,
1274{
1275    #[inline]
1276    fn as_mut(&mut self) -> &mut Self {
1277        self
1278    }
1279}
1280
1281//=============================================================================
1282// ValidConfig
1283//=============================================================================
1284
1285/// Marker trait for valid SPI [`Config`]urations
1286///
1287/// A functional SPI peripheral must have, at a minimum, an SCLK pad and
1288/// either a Data In or a Data Out pad. Dependeing on the [`OpMode`], an SS
1289/// pad may also be required.
1290///
1291/// The `ValidConfig` trait is implemented only for valid combinations of
1292/// [`Pads`] and [`OpMode`]. No [`Config`] is valid if the SCK pad is [`NoneT`]
1293/// or if both the Data In and Data Out pads are `NoneT`. When in [`Master`]
1294/// `OpMode`, the `SS` pad must be `NoneT`, while in [`MasterHWSS`] or
1295/// [`Slave`] [`OpMode`], the SS pad must be [`SomePad`].
1296pub trait ValidConfig: AnyConfig {}
1297
1298impl<P, Z> ValidConfig for Config<P, Master, Z>
1299where
1300    P: ValidPads<SS = NoneT>,
1301    Z: Size,
1302{
1303}
1304
1305impl<P, Z> ValidConfig for Config<P, MasterHWSS, Z>
1306where
1307    P: ValidPads,
1308    Z: Size,
1309    P::SS: SomePad,
1310{
1311}
1312
1313impl<P, Z> ValidConfig for Config<P, Slave, Z>
1314where
1315    P: ValidPads,
1316    Z: Size,
1317    P::SS: SomePad,
1318{
1319}
1320
1321//=============================================================================
1322// Spi
1323//=============================================================================
1324
1325/// An enabled SPI peripheral that can perform transactions
1326///
1327/// See the [`impl_ehal`] documentation for details on the implementations of
1328/// the embedded HAL traits, which vary based on [`Size`] and [`Capability`].
1329pub struct Spi<C, A, RxDma = NoneT, TxDma = NoneT>
1330where
1331    C: ValidConfig,
1332    A: Capability,
1333{
1334    config: C,
1335    capability: A,
1336    _rx_channel: RxDma,
1337    _tx_channel: TxDma,
1338}
1339
1340/// Get a shared reference to the underlying [`Config`] struct
1341///
1342/// This can be used to call the various `get_*` functions on `Config`
1343impl<C, A> AsRef<SpecificConfig<C>> for Spi<C, A>
1344where
1345    C: ValidConfig,
1346    A: Capability,
1347{
1348    #[inline]
1349    fn as_ref(&self) -> &SpecificConfig<C> {
1350        self.config.as_ref()
1351    }
1352}
1353
1354impl<C, A, RxDma, TxDma> Spi<C, A, RxDma, TxDma>
1355where
1356    C: ValidConfig,
1357    A: Capability,
1358{
1359    /// Change the transaction [`Length`]
1360    ///
1361    /// Changing the transaction [`Length`] while is enabled is permissible but
1362    /// dangerous. If you have sent or received *any* bytes at the current
1363    /// [`Length`], you **must** wait for a TXC flag before changing to a new
1364    /// [`Length`].
1365    #[inline]
1366    #[allow(clippy::type_complexity)]
1367    #[hal_cfg("sercom0-d5x")]
1368    pub fn length<L: Length>(self) -> Spi<Config<C::Pads, C::OpMode, L>, A, RxDma, TxDma>
1369    where
1370        Config<C::Pads, C::OpMode, L>: ValidConfig,
1371    {
1372        Spi {
1373            config: self.config.into().length(),
1374            capability: self.capability,
1375            _rx_channel: self._rx_channel,
1376            _tx_channel: self._tx_channel,
1377        }
1378    }
1379
1380    /// Update the SPI configuration.
1381    ///
1382    /// Calling this method will temporarily disable the SERCOM peripheral, as
1383    /// some registers are enable-protected. This may interrupt any ongoing
1384    /// transactions.
1385    #[inline]
1386    pub fn reconfigure(&mut self, update: impl FnOnce(&mut SpecificConfig<C>)) {
1387        self.config.as_mut().regs.disable();
1388        update(self.config.as_mut());
1389        self.config.as_mut().regs.enable();
1390    }
1391
1392    /// Enable interrupts for the specified flags
1393    #[inline]
1394    pub fn enable_interrupts(&mut self, flags: Flags) {
1395        self.config.as_mut().regs.enable_interrupts(flags)
1396    }
1397
1398    /// Disable interrupts for the specified flags
1399    #[inline]
1400    pub fn disable_interrupts(&mut self, flags: Flags) {
1401        self.config.as_mut().regs.disable_interrupts(flags);
1402    }
1403
1404    /// Read the interrupt flags
1405    #[inline]
1406    pub fn read_flags(&self) -> Flags {
1407        self.config.as_ref().regs.read_flags()
1408    }
1409
1410    /// Clear the corresponding interrupt flags
1411    ///
1412    /// Only the ERROR, SSL and TXC flags can be cleared.
1413    ///
1414    /// **Note:** Implementations of `flush` methods (eg [`SpiBus::flush`]) wait
1415    /// on and clear the `TXC` flag. Manually clearing this flag could cause
1416    /// them to hang indefinitely.
1417    ///
1418    /// [`SpiBus::flush`]: ehal::spi::SpiBus::flush
1419    #[inline]
1420    pub fn clear_flags(&mut self, flags: Flags) {
1421        self.config.as_mut().regs.clear_flags(flags);
1422    }
1423
1424    /// Read the error status flags
1425    #[inline]
1426    pub fn read_status(&self) -> Status {
1427        self.config.as_ref().regs.read_status()
1428    }
1429
1430    /// Clear the corresponding error status flags
1431    #[inline]
1432    pub fn clear_status(&mut self, status: Status) {
1433        self.config.as_mut().regs.clear_status(status);
1434    }
1435
1436    /// Try to read the interrupt flags, but first check the error status flags.
1437    #[inline]
1438    pub fn read_flags_errors(&self) -> Result<Flags, Error> {
1439        self.config.as_ref().regs.read_flags_errors()
1440    }
1441
1442    /// Read from the DATA register
1443    ///
1444    /// # Safety
1445    ///
1446    /// Reading from the data register directly is `unsafe`, because it will
1447    /// clear the RXC flag, which could break assumptions made elsewhere in
1448    /// this module.
1449    #[inline]
1450    pub unsafe fn read_data(&mut self) -> DataWidth {
1451        self.config.as_mut().regs.read_data()
1452    }
1453
1454    /// Write to the DATA register
1455    ///
1456    /// # Safety
1457    ///
1458    /// Writing to the data register directly is `unsafe`, because it will clear
1459    /// the DRE flag, which could break assumptions made elsewhere in this
1460    /// module.
1461    #[inline]
1462    pub unsafe fn write_data(&mut self, data: DataWidth) {
1463        self.config.as_mut().regs.write_data(data);
1464    }
1465
1466    /// Disable the SPI peripheral and return the [`Config`] struct
1467    #[inline]
1468    pub fn disable(mut self) -> C {
1469        self.config.as_mut().regs.rx_disable();
1470        self.config.as_mut().regs.disable();
1471        self.config
1472    }
1473
1474    /// Block until at least one of the flags specified in `flags`, or `ERROR`,
1475    /// is set.
1476    ///
1477    /// Returns `Err(Error)` if an error is detected; also clears the ERROR
1478    /// interrupt flag and the affected STATUS flags.
1479    fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> {
1480        while !self.read_flags().intersects(flags | Flags::ERROR) {
1481            core::hint::spin_loop();
1482        }
1483        let flags = self.read_flags();
1484        self.check_and_clear_error(flags)
1485    }
1486
1487    #[inline]
1488    fn check_and_clear_error(&mut self, flags: Flags) -> Result<(), Error> {
1489        if flags.contains(Flags::ERROR) {
1490            let errors = self.read_status();
1491            // Clear all status flags at once; BUFOVF has priority, and will mask LENERR if
1492            // both show up at the same time.
1493            self.clear_status(errors);
1494            self.clear_flags(Flags::ERROR);
1495            return errors.check_bus_error();
1496        }
1497
1498        Ok(())
1499    }
1500}
1501
1502impl<C, D> Spi<C, D>
1503where
1504    C: ValidConfig,
1505    D: Receive,
1506    C::OpMode: MasterMode,
1507{
1508    /// Attach RX and TX DMA channels to this [`Spi`]. Its
1509    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1510    /// carry out its transactions. In Master mode, since even read SPI
1511    /// transaction necessarily involve a write to shift data in, [`Rx`]-only
1512    /// must take two DMA channels, just the same as if it were [`Duplex`].
1513    #[cfg(feature = "dma")]
1514    pub fn with_dma_channels<R, T>(self, rx: R, tx: T) -> Spi<C, D, R, T>
1515    where
1516        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1517        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1518    {
1519        Spi {
1520            capability: self.capability,
1521            config: self.config,
1522            _rx_channel: rx,
1523            _tx_channel: tx,
1524        }
1525    }
1526}
1527
1528impl<C> Spi<C, Duplex>
1529where
1530    C: ValidConfig<OpMode = Slave>,
1531{
1532    /// Attach a DMA channel to this [`Spi`]. Its
1533    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1534    /// carry out its transactions. In Slave mode, a [`Duplex`] [`Spi`] needs
1535    /// two DMA channels.
1536    #[cfg(feature = "dma")]
1537    pub fn with_dma_channels_slave<R, T>(self, rx: R, tx: T) -> Spi<C, Duplex, R, T>
1538    where
1539        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1540        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1541    {
1542        Spi {
1543            capability: self.capability,
1544            config: self.config,
1545            _rx_channel: rx,
1546            _tx_channel: tx,
1547        }
1548    }
1549}
1550
1551#[cfg(feature = "dma")]
1552impl<C, T> Spi<C, Rx, NoneT, T>
1553where
1554    C: ValidConfig<OpMode = Slave>,
1555{
1556    /// Attach a DMA channel to this [`Spi`]. Its
1557    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1558    /// carry out its transactions. In Slave mode, a [`Rx`] [`Spi`] only needs a
1559    /// single DMA channel.
1560    #[cfg(feature = "dma")]
1561    pub fn with_rx_channel<R>(self, rx: R) -> Spi<C, Rx, R, T>
1562    where
1563        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1564    {
1565        Spi {
1566            capability: self.capability,
1567            config: self.config,
1568            _rx_channel: rx,
1569            _tx_channel: self._tx_channel,
1570        }
1571    }
1572}
1573
1574#[cfg(feature = "dma")]
1575impl<C, R> Spi<C, Tx, R, NoneT>
1576where
1577    C: ValidConfig,
1578{
1579    /// Attach a DMA channel to this [`Spi`]. Its
1580    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1581    /// carry out its transactions. For [`Tx`] [`Spi`]s, only a single DMA
1582    /// channel is necessary.
1583    #[cfg(feature = "dma")]
1584    pub fn with_tx_channel<T>(self, tx: T) -> Spi<C, Tx, R, T>
1585    where
1586        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1587    {
1588        Spi {
1589            capability: self.capability,
1590            config: self.config,
1591            _rx_channel: self._rx_channel,
1592            _tx_channel: tx,
1593        }
1594    }
1595}
1596
1597#[cfg(feature = "dma")]
1598impl<C, D, R, T> Spi<C, D, R, T>
1599where
1600    C: ValidConfig,
1601    D: Capability,
1602{
1603    /// Reclaim both RX and TX DMA channels. Any subsequent SPI transaction will
1604    /// not use DMA.
1605    pub fn take_dma_channels(self) -> (Spi<C, D, NoneT, NoneT>, R, T)
1606    where
1607        R: crate::dmac::AnyChannel<Status: crate::dmac::ReadyChannel>,
1608        T: crate::dmac::AnyChannel<Status: crate::dmac::ReadyChannel>,
1609    {
1610        (
1611            Spi {
1612                capability: self.capability,
1613                config: self.config,
1614                _rx_channel: NoneT,
1615                _tx_channel: NoneT,
1616            },
1617            self._rx_channel,
1618            self._tx_channel,
1619        )
1620    }
1621
1622    /// Reclaim the RX DMA channel. Any subsequent SPI RX transaction will not
1623    /// use DMA.
1624    pub fn take_rx_channel(self) -> (Spi<C, D, NoneT, T>, R)
1625    where
1626        R: crate::dmac::AnyChannel<Status: crate::dmac::ReadyChannel>,
1627    {
1628        (
1629            Spi {
1630                capability: self.capability,
1631                config: self.config,
1632                _tx_channel: self._tx_channel,
1633                _rx_channel: NoneT,
1634            },
1635            self._rx_channel,
1636        )
1637    }
1638
1639    /// Reclaim the TX DMA channel. Any subsequent SPI TX transaction will not
1640    /// use DMA.
1641    pub fn take_tx_channel(self) -> (Spi<C, D, R, NoneT>, T)
1642    where
1643        T: crate::dmac::AnyChannel<Status: crate::dmac::ReadyChannel>,
1644    {
1645        (
1646            Spi {
1647                capability: self.capability,
1648                config: self.config,
1649                _rx_channel: self._rx_channel,
1650                _tx_channel: NoneT,
1651            },
1652            self._tx_channel,
1653        )
1654    }
1655}
1656
1657/// Wrapper type around a [`Spi`] that allows using
1658/// [`embedded_hal::spi::SpiBus`] even though it only has RX capability. Will
1659/// panic if any write-adjacent method is used (ie, `write`, `transfer`,
1660/// `transfer_in_place`, and `flush`).
1661///
1662/// Also implements `Into<Spi>`, `AsRef<Spi>` and `AsMut<Spi>` if you need to
1663/// use `Spi` methods.
1664///
1665/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
1666pub struct PanicOnWrite<T: crate::ehal::spi::ErrorType>(T);
1667
1668impl<C: ValidConfig, R, T> From<PanicOnWrite<Spi<C, Rx, R, T>>> for Spi<C, Rx, R, T> {
1669    fn from(value: PanicOnWrite<Spi<C, Rx, R, T>>) -> Self {
1670        value.0
1671    }
1672}
1673
1674impl<C: ValidConfig, R, T> AsRef<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
1675    fn as_ref(&self) -> &Spi<C, Rx, R, T> {
1676        &self.0
1677    }
1678}
1679impl<C: ValidConfig, R, T> AsMut<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
1680    fn as_mut(&mut self) -> &mut Spi<C, Rx, R, T> {
1681        &mut self.0
1682    }
1683}
1684
1685impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1686    /// Turn a [`Tx`] [`Spi`] into a [`PanicOnWrite`]
1687    pub fn into_panic_on_write(self) -> PanicOnWrite<Self> {
1688        PanicOnWrite(self)
1689    }
1690}
1691
1692/// Wrapper type around a [`Spi`] that allows using
1693/// [`embedded_hal::spi::SpiBus`] even though it only has TX capability. Will
1694/// panic if any write-adjacent method is used (ie, `read`, `transfer`, and
1695/// `transfer_in_place`).
1696///
1697/// Also implements `Into<Spi>`, `AsRef<Spi>` and `AsMut<Spi>` if you need to
1698/// use `Spi` methods.
1699///
1700/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
1701pub struct PanicOnRead<T: crate::ehal::spi::ErrorType>(T);
1702
1703impl<C: ValidConfig, R, T> From<PanicOnRead<Spi<C, Tx, R, T>>> for Spi<C, Tx, R, T> {
1704    fn from(value: PanicOnRead<Spi<C, Tx, R, T>>) -> Self {
1705        value.0
1706    }
1707}
1708
1709impl<C: ValidConfig, R, T> AsRef<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
1710    fn as_ref(&self) -> &Spi<C, Tx, R, T> {
1711        &self.0
1712    }
1713}
1714
1715impl<C: ValidConfig, R, T> AsMut<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
1716    fn as_mut(&mut self) -> &mut Spi<C, Tx, R, T> {
1717        &mut self.0
1718    }
1719}
1720
1721impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1722    /// Turn a [`Rx`] [`Spi`] into a [`PanicOnRead`]
1723    pub fn into_panic_on_read(self) -> PanicOnRead<Self> {
1724        PanicOnRead(self)
1725    }
1726}
1727
1728#[hal_cfg("sercom0-d5x")]
1729impl<P, M, A> Spi<Config<P, M, DynLength>, A>
1730where
1731    P: ValidPads,
1732    M: OpMode,
1733    Config<P, M, DynLength>: ValidConfig,
1734    A: Capability,
1735{
1736    /// Return the current transaction length
1737    ///
1738    /// Read the LENGTH register to determine the current transaction length
1739    #[inline]
1740    pub fn get_dyn_length(&self) -> u8 {
1741        self.config.get_dyn_length()
1742    }
1743
1744    /// Set the transaction length
1745    ///
1746    /// Write the LENGTH register to set the transaction length. Panics if the
1747    /// length is zero.
1748    ///
1749    /// Changing the transaction `LENGTH` while is enabled is permissible but
1750    /// dangerous. If you have sent or received *any* bytes at the current
1751    /// `LENGTH`, you **must** wait for a TXC flag before changing to a new
1752    /// `LENGTH`.
1753    #[inline]
1754    pub fn set_dyn_length(&mut self, length: u8) {
1755        self.config.set_dyn_length(length);
1756    }
1757}
1758
1759#[cfg(doc)]
1760#[hal_cfg(not("sercom0-d5x"))]
1761impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1762    /// This method is not present with the selected feature set, defined for
1763    /// documentation only
1764    pub fn get_dyn_length(&self) -> u8 {
1765        unimplemented!()
1766    }
1767}
1768
1769//=============================================================================
1770// AnySpi
1771//=============================================================================
1772
1773/// Type class for all possible [`Spi`] types
1774///
1775/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
1776/// [`Spi`] types. See the `AnyKind` documentation for more details on the
1777/// pattern.
1778///
1779/// In addition to the normal, `AnyKind` associated types. This trait also
1780/// copies the [`Sercom`], [`Pads`], [`Capability`], [`OpMode`], [`Size`] and
1781/// [`Word`] types, to make it easier to apply bounds to these types at the next
1782/// level of abstraction.
1783///
1784/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
1785/// [type class]: crate::typelevel#type-classes
1786pub trait AnySpi: Is<Type = SpecificSpi<Self>> {
1787    type Sercom: Sercom;
1788    type Pads: ValidPads;
1789    type Capability: Capability;
1790    type OpMode: OpMode;
1791    type Size: Size;
1792    type Word: 'static;
1793    type Config: ValidConfig<Sercom = Self::Sercom>;
1794}
1795
1796/// Type alias to recover the specific [`Spi`] type from an implementation of
1797/// [`AnySpi`]
1798pub type SpecificSpi<S> = Spi<<S as AnySpi>::Config, <S as AnySpi>::Capability>;
1799
1800impl<C, A> AsRef<Self> for Spi<C, A>
1801where
1802    C: ValidConfig,
1803    A: Capability,
1804{
1805    #[inline]
1806    fn as_ref(&self) -> &Self {
1807        self
1808    }
1809}
1810
1811impl<C, A> AsMut<Self> for Spi<C, A>
1812where
1813    C: ValidConfig,
1814    A: Capability,
1815{
1816    #[inline]
1817    fn as_mut(&mut self) -> &mut Self {
1818        self
1819    }
1820}
1821
1822impl<C, A> Sealed for Spi<C, A>
1823where
1824    C: ValidConfig,
1825    A: Capability,
1826{
1827}
1828
1829impl<C, A> AnySpi for Spi<C, A>
1830where
1831    C: ValidConfig,
1832    A: Capability,
1833{
1834    type Sercom = C::Sercom;
1835    type Pads = C::Pads;
1836    type Capability = A;
1837    type OpMode = C::OpMode;
1838    type Size = C::Size;
1839    type Word = C::Word;
1840    type Config = C;
1841}