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