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::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
431use crate::sercom::{pad::SomePad, ApbClkCtrl, Sercom};
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    /// Obtain a pointer to the `DATA` register. Necessary for DMA transfers.
930    #[inline]
931    #[cfg(feature = "dma")]
932    pub(super) fn data_ptr(&self) -> *mut Z::Word {
933        self.regs.data_ptr::<Z>()
934    }
935
936    /// Change the [`OpMode`]
937    #[inline]
938    pub fn op_mode<M2: OpMode>(mut self) -> Config<P, M2, Z> {
939        self.regs.set_op_mode(M2::MODE, M2::MSSEN);
940        self.change()
941    }
942
943    /// Change the [`CharSize`] using the builder pattern
944    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
945    #[inline]
946    pub fn char_size<C2: CharSize>(mut self) -> Config<P, M, C2> {
947        self.regs.set_char_size(C2::BITS);
948        self.change()
949    }
950
951    /// Change the transaction [`Length`] using the builder pattern
952    ///
953    /// To use a run-time dynamic length, set the [`Length`] type to
954    /// [`DynLength`] and then use the [`dyn_length`] method.
955    ///
956    /// [`dyn_length`]: Config::dyn_length
957    #[hal_cfg("sercom0-d5x")]
958    #[inline]
959    pub fn length<L2: Length>(mut self) -> Config<P, M, L2> {
960        self.regs.set_length(L2::U8);
961        self.change()
962    }
963
964    /// Get the clock polarity
965    #[inline]
966    pub fn get_cpol(&self) -> Polarity {
967        self.regs.get_cpol()
968    }
969
970    /// Set the clock polarity
971    #[inline]
972    pub fn set_cpol(&mut self, cpol: Polarity) {
973        self.regs.set_cpol(cpol);
974    }
975
976    /// Set the clock polarity using the builder pattern
977    #[inline]
978    pub fn cpol(mut self, cpol: Polarity) -> Self {
979        self.set_cpol(cpol);
980        self
981    }
982
983    /// Get the clock phase
984    #[inline]
985    pub fn get_cpha(&self) -> Phase {
986        self.regs.get_cpha()
987    }
988
989    /// Set the clock phase
990    #[inline]
991    pub fn set_cpha(&mut self, cpha: Phase) {
992        self.regs.set_cpha(cpha)
993    }
994
995    /// Set the clock phase using the builder pattern
996    #[inline]
997    pub fn cpha(mut self, cpha: Phase) -> Self {
998        self.set_cpha(cpha);
999        self
1000    }
1001
1002    /// Get the SPI mode (clock polarity & phase)
1003    #[inline]
1004    pub fn get_spi_mode(&self) -> ehal::spi::Mode {
1005        self.regs.get_spi_mode()
1006    }
1007
1008    /// Set the SPI mode (clock polarity & phase)
1009    #[inline]
1010    pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) {
1011        self.regs.set_spi_mode(mode);
1012    }
1013
1014    /// Set the SPI mode (clock polarity & phase) using the builder pattern
1015    #[inline]
1016    pub fn spi_mode(mut self, mode: ehal::spi::Mode) -> Self {
1017        self.set_spi_mode(mode);
1018        self
1019    }
1020
1021    /// Get the bit order of transmission (MSB/LSB first)
1022    ///
1023    /// This only affects the order of bits within each byte. Bytes are always
1024    /// transferred in little endian order from the 32-bit DATA register.
1025    #[inline]
1026    pub fn get_bit_order(&self) -> BitOrder {
1027        self.regs.get_bit_order()
1028    }
1029
1030    /// Set the bit order of transmission (MSB/LSB first) using the builder
1031    /// pattern
1032    ///
1033    /// This only affects the order of bits within each byte. Bytes are always
1034    /// transferred in little endian order from the 32-bit DATA register.
1035    #[inline]
1036    pub fn set_bit_order(&mut self, order: BitOrder) {
1037        self.regs.set_bit_order(order);
1038    }
1039
1040    /// Set the bit order of transmission (MSB/LSB first) using the builder
1041    /// pattern
1042    ///
1043    /// This only affects the order of bits within each byte. Bytes are always
1044    /// transferred in little endian order from the 32-bit DATA register.
1045    #[inline]
1046    pub fn bit_order(mut self, order: BitOrder) -> Self {
1047        self.set_bit_order(order);
1048        self
1049    }
1050
1051    /// Get the NOP word
1052    ///
1053    /// This word is used when reading in Duplex mode, since an equal number of
1054    /// words must be sent in order to avoid overflow errors.
1055    pub fn get_nop_word(&self) -> DataWidth {
1056        self.nop_word
1057    }
1058
1059    /// Set the NOP word
1060    ///
1061    /// This word is used when reading in Duplex mode, since an equal number of
1062    /// words must be sent in order to avoid overflow errors.
1063    pub fn set_nop_word(&mut self, nop_word: DataWidth) {
1064        self.nop_word = nop_word;
1065    }
1066
1067    /// Set the NOP word using the builder pattern
1068    ///
1069    /// This word is used when reading in Duplex mode, since an equal number of
1070    /// words must be sent in order to avoid overflow errors.
1071    pub fn nop_word(mut self, nop_word: DataWidth) -> Self {
1072        self.nop_word = nop_word;
1073        self
1074    }
1075
1076    /// Get the baud rate
1077    ///
1078    /// The returned baud rate may not exactly match what was set.
1079    #[inline]
1080    pub fn get_baud(&mut self) -> Hertz {
1081        self.regs.get_baud(self.freq)
1082    }
1083
1084    /// Set the baud rate
1085    ///
1086    /// This function will calculate the best BAUD register setting based on the
1087    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
1088    /// half the GCLK frequency. The minimum baud rate is the GCLK frequency /
1089    /// 512. Values outside this range will saturate at the extremes.
1090    #[inline]
1091    pub fn set_baud(&mut self, baud: Hertz) {
1092        self.regs.set_baud(self.freq, baud);
1093    }
1094
1095    /// Set the baud rate using the builder API
1096    ///
1097    /// This function will calculate the best BAUD register setting based on the
1098    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
1099    /// half the GCLK frequency. The minimum baud rate is the GCLK frequency /
1100    /// 512. Values outside this range will saturate at the extremes.
1101    #[inline]
1102    pub fn baud(mut self, baud: Hertz) -> Self {
1103        self.set_baud(baud);
1104        self
1105    }
1106
1107    /// Read the enabled state of the immediate buffer overflow notification
1108    ///
1109    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1110    /// overflow occurs. Otherwise, it will not be issued until its place within
1111    /// the data stream.
1112    #[inline]
1113    pub fn get_ibon(&self) -> bool {
1114        self.regs.get_ibon()
1115    }
1116
1117    /// Enable or disable the immediate buffer overflow notification
1118    ///
1119    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1120    /// overflow occurs. Otherwise, it will not be issued until its place within
1121    /// the data stream.
1122    #[inline]
1123    pub fn set_ibon(&mut self, enabled: bool) {
1124        self.regs.set_ibon(enabled);
1125    }
1126
1127    /// Enable or disable the immediate buffer overflow notification using the
1128    /// builder API
1129    ///
1130    /// If set to true, an [`Error::Overflow`] will be issued as soon as an
1131    /// overflow occurs. Otherwise, it will not be issued until its place within
1132    /// the data stream.
1133    #[inline]
1134    pub fn ibon(mut self, enabled: bool) -> Self {
1135        self.set_ibon(enabled);
1136        self
1137    }
1138
1139    /// Read the enable state of run in standby mode
1140    #[inline]
1141    pub fn get_run_in_standby(&self) -> bool {
1142        self.regs.get_run_in_standby()
1143    }
1144
1145    /// Enable or disable run in standby mode
1146    #[inline]
1147    pub fn set_run_in_standby(&mut self, enabled: bool) {
1148        self.regs.set_run_in_standby(enabled);
1149    }
1150
1151    /// Enable or disable run in standby mode using the builder API
1152    #[inline]
1153    pub fn run_in_standby(mut self, enabled: bool) -> Self {
1154        self.set_run_in_standby(enabled);
1155        self
1156    }
1157
1158    /// Enable the SPI peripheral
1159    ///
1160    /// SPI transactions are not possible until the peripheral is enabled.
1161    /// This function is limited to [`ValidConfig`]s.
1162    #[inline]
1163    pub fn enable(mut self) -> Spi<Self, P::Capability>
1164    where
1165        Self: ValidConfig,
1166    {
1167        if P::Capability::RX_ENABLE {
1168            self.regs.rx_enable();
1169        }
1170        self.regs.enable();
1171        Spi {
1172            config: self,
1173            capability: P::Capability::default(),
1174            _rx_channel: NoneT,
1175            _tx_channel: NoneT,
1176        }
1177    }
1178}
1179
1180#[hal_cfg("sercom0-d5x")]
1181impl<P, M> Config<P, M, DynLength>
1182where
1183    P: ValidPads,
1184    M: OpMode,
1185{
1186    /// Get the transaction length
1187    #[inline]
1188    pub fn get_dyn_length(&self) -> u8 {
1189        self.regs.get_length()
1190    }
1191
1192    /// Set the transaction length
1193    ///
1194    /// Write the LENGTH register to set the transaction length. If the length
1195    /// is zero, it will be set to 1.
1196    #[inline]
1197    pub fn set_dyn_length(&mut self, length: u8) {
1198        self.regs.set_length(length);
1199    }
1200
1201    /// Set the transaction length using the builder API
1202    ///
1203    /// Write the LENGTH register to set the transaction length. If the length
1204    /// is zero, it will be set to 1.
1205    #[inline]
1206    pub fn dyn_length(mut self, length: u8) -> Self {
1207        self.set_dyn_length(length);
1208        self
1209    }
1210}
1211
1212//=============================================================================
1213// AnyConfig
1214//=============================================================================
1215
1216/// Type class for all possible [`Config`] types
1217///
1218/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
1219/// [`Config`] types. See the `AnyKind` documentation for more details on the
1220/// pattern.
1221///
1222/// In addition to the normal, `AnyKind` associated types. This trait also
1223/// copies the [`Sercom`], [`Capability`] and [`Word`] types, to make it easier
1224/// to apply bounds to these types at the next level of abstraction.
1225///
1226/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
1227/// [type class]: crate::typelevel#type-classes
1228pub trait AnyConfig: Is<Type = SpecificConfig<Self>> {
1229    type Sercom: Sercom;
1230    type Pads: ValidPads<Sercom = Self::Sercom>;
1231    type Capability: Capability;
1232    type OpMode: OpMode;
1233    type Size: Size;
1234    type Word: 'static;
1235}
1236
1237/// Type alias to recover the specific [`Config`] type from an implementation of
1238/// [`AnyConfig`]
1239pub type SpecificConfig<C> =
1240    Config<<C as AnyConfig>::Pads, <C as AnyConfig>::OpMode, <C as AnyConfig>::Size>;
1241
1242impl<P, M, Z> Sealed for Config<P, M, Z>
1243where
1244    P: ValidPads,
1245    M: OpMode,
1246    Z: Size,
1247{
1248}
1249
1250impl<P, M, Z> AnyConfig for Config<P, M, Z>
1251where
1252    P: ValidPads,
1253    M: OpMode,
1254    Z: Size,
1255{
1256    type Sercom = P::Sercom;
1257    type Pads = P;
1258    type Capability = P::Capability;
1259    type OpMode = M;
1260    type Size = Z;
1261    type Word = Z::Word;
1262}
1263
1264impl<P, M, Z> AsRef<Self> for Config<P, M, Z>
1265where
1266    P: ValidPads,
1267    M: OpMode,
1268    Z: Size,
1269{
1270    #[inline]
1271    fn as_ref(&self) -> &Self {
1272        self
1273    }
1274}
1275
1276impl<P, M, Z> AsMut<Self> for Config<P, M, Z>
1277where
1278    P: ValidPads,
1279    M: OpMode,
1280    Z: Size,
1281{
1282    #[inline]
1283    fn as_mut(&mut self) -> &mut Self {
1284        self
1285    }
1286}
1287
1288//=============================================================================
1289// ValidConfig
1290//=============================================================================
1291
1292/// Marker trait for valid SPI [`Config`]urations
1293///
1294/// A functional SPI peripheral must have, at a minimum, an SCLK pad and
1295/// either a Data In or a Data Out pad. Dependeing on the [`OpMode`], an SS
1296/// pad may also be required.
1297///
1298/// The `ValidConfig` trait is implemented only for valid combinations of
1299/// [`Pads`] and [`OpMode`]. No [`Config`] is valid if the SCK pad is [`NoneT`]
1300/// or if both the Data In and Data Out pads are `NoneT`. When in [`Master`]
1301/// `OpMode`, the `SS` pad must be `NoneT`, while in [`MasterHWSS`] or
1302/// [`Slave`] [`OpMode`], the SS pad must be [`SomePad`].
1303pub trait ValidConfig: AnyConfig {}
1304
1305impl<P, Z> ValidConfig for Config<P, Master, Z>
1306where
1307    P: ValidPads<SS = NoneT>,
1308    Z: Size,
1309{
1310}
1311
1312impl<P, Z> ValidConfig for Config<P, MasterHWSS, Z>
1313where
1314    P: ValidPads,
1315    Z: Size,
1316    P::SS: SomePad,
1317{
1318}
1319
1320impl<P, Z> ValidConfig for Config<P, Slave, Z>
1321where
1322    P: ValidPads,
1323    Z: Size,
1324    P::SS: SomePad,
1325{
1326}
1327
1328//=============================================================================
1329// Spi
1330//=============================================================================
1331
1332/// An enabled SPI peripheral that can perform transactions
1333///
1334/// See the [`impl_ehal`] documentation for details on the implementations of
1335/// the embedded HAL traits, which vary based on [`Size`] and [`Capability`].
1336pub struct Spi<C, A, RxDma = NoneT, TxDma = NoneT>
1337where
1338    C: ValidConfig,
1339    A: Capability,
1340{
1341    config: C,
1342    capability: A,
1343    _rx_channel: RxDma,
1344    _tx_channel: TxDma,
1345}
1346
1347/// Get a shared reference to the underlying [`Config`] struct
1348///
1349/// This can be used to call the various `get_*` functions on `Config`
1350impl<C, A> AsRef<SpecificConfig<C>> for Spi<C, A>
1351where
1352    C: ValidConfig,
1353    A: Capability,
1354{
1355    #[inline]
1356    fn as_ref(&self) -> &SpecificConfig<C> {
1357        self.config.as_ref()
1358    }
1359}
1360
1361impl<C, A, RxDma, TxDma> Spi<C, A, RxDma, TxDma>
1362where
1363    C: ValidConfig,
1364    A: Capability,
1365{
1366    /// Obtain a pointer to the `DATA` register. Necessary for DMA transfers.
1367    #[inline]
1368    #[cfg(feature = "dma")]
1369    pub(super) fn data_ptr(&self) -> *mut C::Word
1370    where
1371        C::Size: Size<Word = C::Word>,
1372    {
1373        self.config.as_ref().data_ptr()
1374    }
1375
1376    /// Change the transaction [`Length`]
1377    ///
1378    /// Changing the transaction [`Length`] while is enabled is permissible but
1379    /// dangerous. If you have sent or received *any* bytes at the current
1380    /// [`Length`], you **must** wait for a TXC flag before changing to a new
1381    /// [`Length`].
1382    #[inline]
1383    #[allow(clippy::type_complexity)]
1384    #[hal_cfg("sercom0-d5x")]
1385    pub fn length<L: Length>(self) -> Spi<Config<C::Pads, C::OpMode, L>, A, RxDma, TxDma>
1386    where
1387        Config<C::Pads, C::OpMode, L>: ValidConfig,
1388    {
1389        Spi {
1390            config: self.config.into().length(),
1391            capability: self.capability,
1392            _rx_channel: self._rx_channel,
1393            _tx_channel: self._tx_channel,
1394        }
1395    }
1396
1397    /// Update the SPI configuration.
1398    ///
1399    /// Calling this method will temporarily disable the SERCOM peripheral, as
1400    /// some registers are enable-protected. This may interrupt any ongoing
1401    /// transactions.
1402    #[inline]
1403    pub fn reconfigure(&mut self, update: impl FnOnce(&mut SpecificConfig<C>)) {
1404        self.config.as_mut().regs.disable();
1405        update(self.config.as_mut());
1406        self.config.as_mut().regs.enable();
1407    }
1408
1409    /// Enable interrupts for the specified flags
1410    #[inline]
1411    pub fn enable_interrupts(&mut self, flags: Flags) {
1412        self.config.as_mut().regs.enable_interrupts(flags)
1413    }
1414
1415    /// Disable interrupts for the specified flags
1416    #[inline]
1417    pub fn disable_interrupts(&mut self, flags: Flags) {
1418        self.config.as_mut().regs.disable_interrupts(flags);
1419    }
1420
1421    /// Read the interrupt flags
1422    #[inline]
1423    pub fn read_flags(&self) -> Flags {
1424        self.config.as_ref().regs.read_flags()
1425    }
1426
1427    /// Clear the corresponding interrupt flags
1428    ///
1429    /// Only the ERROR, SSL and TXC flags can be cleared.
1430    ///
1431    /// **Note:** Implementations of `flush` methods (eg [`SpiBus::flush`]) wait
1432    /// on and clear the `TXC` flag. Manually clearing this flag could cause
1433    /// them to hang indefinitely.
1434    ///
1435    /// [`SpiBus::flush`]: ehal::spi::SpiBus::flush
1436    #[inline]
1437    pub fn clear_flags(&mut self, flags: Flags) {
1438        self.config.as_mut().regs.clear_flags(flags);
1439    }
1440
1441    /// Read the error status flags
1442    #[inline]
1443    pub fn read_status(&self) -> Status {
1444        self.config.as_ref().regs.read_status()
1445    }
1446
1447    /// Clear the corresponding error status flags
1448    #[inline]
1449    pub fn clear_status(&mut self, status: Status) {
1450        self.config.as_mut().regs.clear_status(status);
1451    }
1452
1453    /// Try to read the interrupt flags, but first check the error status flags.
1454    #[inline]
1455    pub fn read_flags_errors(&self) -> Result<Flags, Error> {
1456        self.config.as_ref().regs.read_flags_errors()
1457    }
1458
1459    /// Read from the DATA register
1460    ///
1461    /// # Safety
1462    ///
1463    /// Reading from the data register directly is `unsafe`, because it will
1464    /// clear the RXC flag, which could break assumptions made elsewhere in
1465    /// this module.
1466    #[inline]
1467    pub unsafe fn read_data(&mut self) -> DataWidth {
1468        self.config.as_mut().regs.read_data()
1469    }
1470
1471    /// Write to the DATA register
1472    ///
1473    /// # Safety
1474    ///
1475    /// Writing to the data register directly is `unsafe`, because it will clear
1476    /// the DRE flag, which could break assumptions made elsewhere in this
1477    /// module.
1478    #[inline]
1479    pub unsafe fn write_data(&mut self, data: DataWidth) {
1480        self.config.as_mut().regs.write_data(data);
1481    }
1482
1483    /// Disable the SPI peripheral and return the [`Config`] struct
1484    #[inline]
1485    pub fn disable(mut self) -> C {
1486        self.config.as_mut().regs.rx_disable();
1487        self.config.as_mut().regs.disable();
1488        self.config
1489    }
1490
1491    /// Block until at least one of the flags specified in `flags`, or `ERROR`,
1492    /// is set.
1493    ///
1494    /// Returns `Err(Error)` if an error is detected; also clears the ERROR
1495    /// interrupt flag and the affected STATUS flags.
1496    fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> {
1497        while !self.read_flags().intersects(flags | Flags::ERROR) {
1498            core::hint::spin_loop();
1499        }
1500        let flags = self.read_flags();
1501        self.check_and_clear_error(flags)
1502    }
1503
1504    #[inline]
1505    fn check_and_clear_error(&mut self, flags: Flags) -> Result<(), Error> {
1506        if flags.contains(Flags::ERROR) {
1507            let errors = self.read_status();
1508            // Clear all status flags at once; BUFOVF has priority, and will mask LENERR if
1509            // both show up at the same time.
1510            self.clear_status(errors);
1511            self.clear_flags(Flags::ERROR);
1512            return errors.check_bus_error();
1513        }
1514
1515        Ok(())
1516    }
1517}
1518
1519impl<C, D> Spi<C, D>
1520where
1521    C: ValidConfig,
1522    D: Receive,
1523    C::OpMode: MasterMode,
1524{
1525    /// Attach RX and TX DMA channels to this [`Spi`]. Its
1526    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1527    /// carry out its transactions. In Master mode, since even read SPI
1528    /// transaction necessarily involve a write, [`Rx`]-only must take two
1529    /// DMA channels, just the same as if it were [`Duplex`].
1530    #[cfg(feature = "dma")]
1531    pub fn with_dma_channels<R, T>(self, rx: R, tx: T) -> Spi<C, D, R, T>
1532    where
1533        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1534        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1535    {
1536        Spi {
1537            capability: self.capability,
1538            config: self.config,
1539            _rx_channel: rx,
1540            _tx_channel: tx,
1541        }
1542    }
1543}
1544
1545#[cfg(feature = "dma")]
1546impl<C, D, RxDma, TxDma, S> Spi<C, D, RxDma, TxDma>
1547where
1548    C: ValidConfig,
1549    D: Capability,
1550    RxDma: crate::dmac::AnyChannel<Status = S>,
1551    TxDma: crate::dmac::AnyChannel<Status = S>,
1552    S: crate::dmac::ReadyChannel,
1553{
1554    /// Reclaim the DMA channels. Any subsequent SPI transaction will not use
1555    /// DMA.
1556    pub fn take_dma_channels(self) -> (Spi<C, D, NoneT, NoneT>, RxDma, TxDma) {
1557        (
1558            Spi {
1559                capability: self.capability,
1560                config: self.config,
1561                _rx_channel: NoneT,
1562                _tx_channel: NoneT,
1563            },
1564            self._rx_channel,
1565            self._tx_channel,
1566        )
1567    }
1568}
1569
1570#[cfg(feature = "dma")]
1571impl<C> Spi<C, Duplex>
1572where
1573    C: ValidConfig<OpMode = Slave>,
1574{
1575    /// Attach a DMA channel to this [`Spi`]. Its
1576    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1577    /// carry out its transactions. In Slave mode, a [`Duplex`] [`Spi`] needs
1578    /// two DMA channels.
1579    #[cfg(feature = "dma")]
1580    pub fn with_dma_channels_slave<R, T>(self, rx: R, tx: T) -> Spi<C, Duplex, R, T>
1581    where
1582        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1583        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1584    {
1585        Spi {
1586            capability: self.capability,
1587            config: self.config,
1588            _rx_channel: rx,
1589            _tx_channel: tx,
1590        }
1591    }
1592}
1593
1594#[cfg(feature = "dma")]
1595impl<C> Spi<C, Rx>
1596where
1597    C: ValidConfig<OpMode = Slave>,
1598{
1599    /// Attach a DMA channel to this [`Spi`]. Its
1600    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1601    /// carry out its transactions. In Slave mode, a [`Rx`] [`Spi`] only needs a
1602    /// single DMA channel.
1603    #[cfg(feature = "dma")]
1604    pub fn with_rx_channel<R>(self, rx: R) -> Spi<C, Rx, R, NoneT>
1605    where
1606        R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1607    {
1608        Spi {
1609            capability: self.capability,
1610            config: self.config,
1611            _rx_channel: rx,
1612            _tx_channel: NoneT,
1613        }
1614    }
1615}
1616
1617#[cfg(feature = "dma")]
1618impl<C, D, R, T, S> Spi<C, D, R, T>
1619where
1620    C: ValidConfig,
1621    D: Receive,
1622    R: crate::dmac::AnyChannel<Status = S>,
1623    S: crate::dmac::ReadyChannel,
1624{
1625    /// Reclaim the Rx DMA channel. Any subsequent SPI transaction will not use
1626    /// DMA.
1627    #[cfg(feature = "dma")]
1628    pub fn take_rx_channel(self) -> (Spi<C, D, NoneT, T>, R) {
1629        (
1630            Spi {
1631                capability: self.capability,
1632                config: self.config,
1633                _tx_channel: self._tx_channel,
1634                _rx_channel: NoneT,
1635            },
1636            self._rx_channel,
1637        )
1638    }
1639}
1640
1641#[cfg(feature = "dma")]
1642impl<C> Spi<C, Tx>
1643where
1644    C: ValidConfig,
1645{
1646    /// Attach a DMA channel to this [`Spi`]. Its
1647    /// [`SpiBus`](crate::ehal::spi::SpiBus) implementation will use DMA to
1648    /// carry out its transactions. For [`Tx`] [`Spi`]s, only a single DMA
1649    /// channel is necessary.
1650    #[cfg(feature = "dma")]
1651    pub fn with_tx_channel<T>(self, tx: T) -> Spi<C, Tx, NoneT, T>
1652    where
1653        T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>,
1654    {
1655        Spi {
1656            capability: self.capability,
1657            config: self.config,
1658            _rx_channel: NoneT,
1659            _tx_channel: tx,
1660        }
1661    }
1662}
1663
1664#[cfg(feature = "dma")]
1665impl<C, D, R, T, S> Spi<C, D, R, T>
1666where
1667    C: ValidConfig,
1668    D: Capability,
1669    T: crate::dmac::AnyChannel<Status = S>,
1670    S: crate::dmac::ReadyChannel,
1671{
1672    /// Reclaim the DMA channel. Any subsequent SPI transaction will not use
1673    /// DMA.
1674    pub fn take_tx_channel(self) -> (Spi<C, D, R, NoneT>, T) {
1675        (
1676            Spi {
1677                capability: self.capability,
1678                config: self.config,
1679                _rx_channel: self._rx_channel,
1680                _tx_channel: NoneT,
1681            },
1682            self._tx_channel,
1683        )
1684    }
1685}
1686
1687/// Wrapper type around a [`Spi`] that allows using
1688/// [`embedded_hal::spi::SpiBus`] even though it only has RX capability. Will
1689/// panic if any write-adjacent method is used (ie, `write`, `transfer`,
1690/// `transfer_in_place`, and `flush`).
1691///
1692/// Also implements `Into<Spi>`, `AsRef<Spi>` and `AsMut<Spi>` if you need to
1693/// use `Spi` methods.
1694///
1695/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
1696pub struct PanicOnWrite<T: crate::ehal::spi::ErrorType>(T);
1697
1698impl<C: ValidConfig, R, T> From<PanicOnWrite<Spi<C, Rx, R, T>>> for Spi<C, Rx, R, T> {
1699    fn from(value: PanicOnWrite<Spi<C, Rx, R, T>>) -> Self {
1700        value.0
1701    }
1702}
1703
1704impl<C: ValidConfig, R, T> AsRef<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
1705    fn as_ref(&self) -> &Spi<C, Rx, R, T> {
1706        &self.0
1707    }
1708}
1709impl<C: ValidConfig, R, T> AsMut<Spi<C, Rx, R, T>> for PanicOnWrite<Spi<C, Rx, R, T>> {
1710    fn as_mut(&mut self) -> &mut Spi<C, Rx, R, T> {
1711        &mut self.0
1712    }
1713}
1714
1715impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1716    /// Turn a [`Tx`] [`Spi`] into a [`PanicOnWrite`]
1717    pub fn into_panic_on_write(self) -> PanicOnWrite<Self> {
1718        PanicOnWrite(self)
1719    }
1720}
1721
1722/// Wrapper type around a [`Spi`] that allows using
1723/// [`embedded_hal::spi::SpiBus`] even though it only has TX capability. Will
1724/// panic if any write-adjacent method is used (ie, `read`, `transfer`, and
1725/// `transfer_in_place`).
1726///
1727/// Also implements `Into<Spi>`, `AsRef<Spi>` and `AsMut<Spi>` if you need to
1728/// use `Spi` methods.
1729///
1730/// [`embedded_hal::spi::SpiBus`]: crate::ehal::spi::SpiBus
1731pub struct PanicOnRead<T: crate::ehal::spi::ErrorType>(T);
1732
1733impl<C: ValidConfig, R, T> From<PanicOnRead<Spi<C, Tx, R, T>>> for Spi<C, Tx, R, T> {
1734    fn from(value: PanicOnRead<Spi<C, Tx, R, T>>) -> Self {
1735        value.0
1736    }
1737}
1738
1739impl<C: ValidConfig, R, T> AsRef<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
1740    fn as_ref(&self) -> &Spi<C, Tx, R, T> {
1741        &self.0
1742    }
1743}
1744
1745impl<C: ValidConfig, R, T> AsMut<Spi<C, Tx, R, T>> for PanicOnRead<Spi<C, Tx, R, T>> {
1746    fn as_mut(&mut self) -> &mut Spi<C, Tx, R, T> {
1747        &mut self.0
1748    }
1749}
1750
1751impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1752    /// Turn a [`Rx`] [`Spi`] into a [`PanicOnRead`]
1753    pub fn into_panic_on_read(self) -> PanicOnRead<Self> {
1754        PanicOnRead(self)
1755    }
1756}
1757
1758#[hal_cfg("sercom0-d5x")]
1759impl<P, M, A> Spi<Config<P, M, DynLength>, A>
1760where
1761    P: ValidPads,
1762    M: OpMode,
1763    Config<P, M, DynLength>: ValidConfig,
1764    A: Capability,
1765{
1766    /// Return the current transaction length
1767    ///
1768    /// Read the LENGTH register to determine the current transaction length
1769    #[inline]
1770    pub fn get_dyn_length(&self) -> u8 {
1771        self.config.get_dyn_length()
1772    }
1773
1774    /// Set the transaction length
1775    ///
1776    /// Write the LENGTH register to set the transaction length. Panics if the
1777    /// length is zero.
1778    ///
1779    /// Changing the transaction `LENGTH` while is enabled is permissible but
1780    /// dangerous. If you have sent or received *any* bytes at the current
1781    /// `LENGTH`, you **must** wait for a TXC flag before changing to a new
1782    /// `LENGTH`.
1783    #[inline]
1784    pub fn set_dyn_length(&mut self, length: u8) {
1785        self.config.set_dyn_length(length);
1786    }
1787}
1788
1789#[cfg(doc)]
1790#[hal_cfg(not("sercom0-d5x"))]
1791impl<C: ValidConfig, R, T> Spi<C, Tx, R, T> {
1792    /// This method is not present with the selected feature set, defined for
1793    /// documentation only
1794    pub fn get_dyn_length(&self) -> u8 {
1795        unimplemented!()
1796    }
1797}
1798
1799//=============================================================================
1800// AnySpi
1801//=============================================================================
1802
1803/// Type class for all possible [`Spi`] types
1804///
1805/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
1806/// [`Spi`] types. See the `AnyKind` documentation for more details on the
1807/// pattern.
1808///
1809/// In addition to the normal, `AnyKind` associated types. This trait also
1810/// copies the [`Sercom`], [`Pads`], [`Capability`], [`OpMode`], [`Size`] and
1811/// [`Word`] types, to make it easier to apply bounds to these types at the next
1812/// level of abstraction.
1813///
1814/// [`AnyKind`]: crate::typelevel#anykind-trait-pattern
1815/// [type class]: crate::typelevel#type-classes
1816pub trait AnySpi: Is<Type = SpecificSpi<Self>> {
1817    type Sercom: Sercom;
1818    type Pads: ValidPads;
1819    type Capability: Capability;
1820    type OpMode: OpMode;
1821    type Size: Size;
1822    type Word: 'static;
1823    type Config: ValidConfig<Sercom = Self::Sercom>;
1824}
1825
1826/// Type alias to recover the specific [`Spi`] type from an implementation of
1827/// [`AnySpi`]
1828pub type SpecificSpi<S> = Spi<<S as AnySpi>::Config, <S as AnySpi>::Capability>;
1829
1830impl<C, A> AsRef<Self> for Spi<C, A>
1831where
1832    C: ValidConfig,
1833    A: Capability,
1834{
1835    #[inline]
1836    fn as_ref(&self) -> &Self {
1837        self
1838    }
1839}
1840
1841impl<C, A> AsMut<Self> for Spi<C, A>
1842where
1843    C: ValidConfig,
1844    A: Capability,
1845{
1846    #[inline]
1847    fn as_mut(&mut self) -> &mut Self {
1848        self
1849    }
1850}
1851
1852impl<C, A> Sealed for Spi<C, A>
1853where
1854    C: ValidConfig,
1855    A: Capability,
1856{
1857}
1858
1859impl<C, A> AnySpi for Spi<C, A>
1860where
1861    C: ValidConfig,
1862    A: Capability,
1863{
1864    type Sercom = C::Sercom;
1865    type Pads = C::Pads;
1866    type Capability = A;
1867    type OpMode = C::OpMode;
1868    type Size = C::Size;
1869    type Word = C::Word;
1870    type Config = C;
1871}