atsamd_hal/sercom/uart.rs
1//! Use the SERCOM peripheral for UART communications
2//!
3//! Configuring an UART peripheral occurs in three steps. First, you must create
4//! a set of [`Pads`] for use by the peripheral. Next, you assemble pieces into
5//! a [`Config`] struct. After configuring the peripheral, you then [`enable`]
6//! it, yielding a functional [`Uart`] struct. Transactions are performed using
7//! the [`embedded_io::Write`], [`embedded_io::Read`],
8//! [`embedded_hal_nb::serial::Write`], and [`embedded_hal_nb::serial::Read`]
9//! traits.
10//!
11//! # [`Pads`]
12//!
13//! A [`Sercom`] can use up to four [`Pin`]s as peripheral [`Pad`]s, but only
14//! certain [`Pin`] combinations are acceptable. All [`Pin`]s must be mapped to
15//! the same `Sercom` (see the datasheet). SAMx5x chips also require that
16//! [`Pin`]s must be in the same [`IoSet`]. This HAL makes it impossible to use
17//! invalid [`Pin`]/[`Pad`] combinations, and the [`Pads`] struct is responsible
18//! for enforcing these constraints.
19//!
20//!
21//! A `Pads` type takes five type parameters, the first type specifies the
22//! `Sercom`, `DI`, `DO`, `CK` and `SS`, represent the Data In, Data Out, Sclk
23//! and SS pads respectively. Each of the pad type parameters is an
24//! [`OptionalPad`] and defaults to [`NoneT`]. A [`Pad`] is just a [`Pin`]
25//! configured in the correct [`PinMode`] that implements [`IsPad`]. The
26//! [`bsp_pins!`](crate::bsp_pins) macro can be used to define convenient type
27//! aliases for [`Pad`] types.
28//!
29//! ```
30//! use atsamd_hal::gpio::{PA08, PA09, AlternateC};
31//! use atsamd_hal::sercom::{Sercom0, uart};
32//! use atsamd_hal::typelevel::NoneT;
33//!
34//! type Rx = Pin<PA08, AlternateC>;
35//! type Tx = Pin<PA09, AlternateC>;
36//! type Pads = uart::Pads<Sercom0, Rx, Tx>;
37//! ```
38//!
39//! Alternatively, you can use the [`PadsFromIds`] alias to define a set of
40//! `Pads` in terms of [`PinId`]s instead of `Pin`s. This is useful when you
41//! don't have [`Pin`] aliases pre-defined.
42//!
43//! ```
44//! use atsamd_hal::gpio::{PA08, PA09};
45//! use atsamd_hal::sercom::{Sercom0, uart};
46//!
47//! type Pads = uart::PadsFromIds<Sercom0, PA08, PA09>;
48//! ```
49//!
50//! Instances of [`Pads`] are created using the builder pattern. Start by
51//! creating an empty set of [`Pads`] using [`Default`]. Then pass each
52//! respective [`Pin`] using the corresponding methods.
53//!
54//! On SAMD21 and SAMx5x chips, the builder methods automatically convert each
55//! pin to the correct [`PinMode`]. But for SAMD11 chips, users must manually
56//! convert each pin before calling the builder methods. This is a consequence
57//! of inherent ambiguities in the SAMD11 SERCOM pad definitions. Specifically,
58//! the same [`PinId`] can correspond to two different [`PadNum`]s for the
59//! *same* `Sercom`.
60//!
61//! ```
62//! use atsamd_hal::pac::Peripherals;
63//! use atsamd_hal::gpio::Pins;
64//! use atsamd_hal::sercom::{Sercom0, uart};
65//!
66//! let mut peripherals = Peripherals::take().unwrap();
67//! let pins = Pins::new(peripherals.PORT);
68//! let pads = uart::Pads::<Sercom0>::default()
69//! .rx(pins.pa09)
70//! .tx(pins.pa08);
71//! ```
72//!
73//! To be accepted as [`ValidPads`], a set of [`Pads`] must do two things:
74//! - Specify a type for at least one of `RX` or `TX`
75//! - Satisfy the `RxpoTxpo` trait (SAMD11/SAMD21), or the `Rxpo` and `Txpo`
76//! traits (SAMx5x)
77//!
78//! # [`Config`]
79//!
80//! Next, create a [`Config`] struct, which represents the UART peripheral in
81//! its disabled state. A [`Config`] is specified with two type parameters: the
82//! [`Pads`] type; and a [`CharSize`], which defaults to [`EightBit`].
83//!
84//! ```
85//! use atsamd_hal::gpio::{PA08, PA09};
86//! use atsamd_hal::sercom::{Sercom0, uart};
87//! use atsamd_hal::sercom::uart::{NineBit};
88//! use atsamd_hal::typelevel::NoneT;
89//!
90//! type Pads = uart::PadsFromIds<Sercom0, PA08, PA09>;
91//! type Config = uart::Config<Pads, NineBit>;
92//! ```
93//!
94//! Upon creation, the [`Config`] takes ownership of both the [`Pads`] struct
95//! and the PAC `SercomN` struct (eg [`Sercom0`]). It takes a reference to the
96//! PM, so that it can enable the APB clock, and it takes a frequency to
97//! indicate the GCLK configuration. Users are responsible for correctly
98//! configuring the GCLK.
99//!
100//! ```
101//! use atsamd_hal::time::U32Ext;
102//!
103//! let pm = peripherals.PM;
104//! let sercom = peripherals.Sercom0;
105//! // Configure GCLK for 10 MHz
106//! let freq = 10.mhz();
107//! let config = uart::Config::new(&pm, sercom, pads, freq);
108//! ```
109//!
110//! The [`Config`] struct can configure the peripheral in one of two ways:
111//!
112//! * A set of methods is provided to use in a builder pattern: for example
113//! [`baud`](Config::baud), [`stop_bits`](Config::stop_bits), etc. These
114//! methods take `self` and return `Self`.
115//! * A set of methods is provided to use as setters: for example
116//! [`set_baud`](Config::set_baud), [`set_stop_bits`](Config::set_stop_bits),
117//! etc. These methods take `&mut self` and return nothing.
118//!
119//! In any case, the peripheral setup ends with a call to [`enable`], which
120//! consumes the [`Config`] and returns an enabled [`Uart`] peripheral.
121//!
122//! ```
123//! use atsamd_hal::sercom::uart::{StopBits, NineBit, BitOrder, BaudMode, Oversampling};
124//!
125//! let uart = uart::Config::new(&mclk, sercom, pads, freq)
126//! .baud(1.mhz(), BaudMode::Arithmetic(Oversampling::Bits16))
127//! .char_size::<NineBit>()
128//! .bit_order(BitOrder::LsbFirst)
129//! .stop_bits(StopBits::TwoBits)
130//! .enable();
131//! ```
132//!
133//! Alternatively,
134//!
135//! ```
136//! use atsamd_hal::sercom::uart::{StopBits, NineBit, BitOrder, BaudMode, Oversampling};
137//!
138//! let uart = uart::Config::new(&mclk, sercom, pads, freq);
139//! uart.set_baud(1.mhz(), BaudMode::Arithmetic(Oversampling::Bits16));
140//! uart.set_char_size::<NineBit>();
141//! uart.set_bit_order(BitOrder::LsbFirst);
142//! uart.set_stop_bits(StopBits::TwoBits);
143//! let uart = uart.enable();
144//! ```
145//!
146//!
147//! To be accepted as a [`ValidConfig`], the [`Config`] must have at least one
148//! of `Rx` or `Tx` pads.
149//!
150//! ## [`CharSize`]
151//!
152//! The UART peripheral can be configured to use different character sizes. By
153//! default, a [`Config`] is configured with an [`EightBit`] character size.
154//! This can be changed through the [`char_size`](Config::char_size) method.
155//! Changing the character normally also changes the [`Config`]'s type.
156//! Alternatively, you can also use a [`DynCharSize`] through the
157//! [`dyn_char_size`](Config::dyn_char_size) method. This enables you to
158//! dynamically change the character size on the fly through the
159//! [`set_dyn_char_size`](Config::set_dyn_char_size) method when calling
160//! [`reconfigure`](Uart::reconfigure).
161//!
162//! ## Reading the current configuration
163//!
164//! It is possible to read the current configuration by using the getter methods
165//! provided: for example [`get_baud`](Config::get_baud),
166//! [`get_stop_bits`](Config::get_stop_bits), etc.
167//!
168//! # [`Uart`] and capabilities
169//!
170//! [`Uart`] structs can only be created from a [`Config`]. They have two type
171//! parameters: the first one represents the underlying [`Config`], while the
172//! second represents the [`Uart`]'s capabilities. The second type parameter can
173//! be one of:
174//!
175//! * [`Rx`] or [`RxDuplex`]: Can perform receive transactions
176//! * [`Tx`] or [`TxDuplex`]: Can perform transmit transactions
177//! * [`Duplex`]: UART configured as duplex that can perform receive and
178//! transmit transactions. Additionally, the [`split`] method can be called to
179//! return a `Uart<C, RxDuplex>, Uart<C, TxDuplex>)` tuple. See the
180//! [Splitting](self#Splitting) section for more information.
181//!
182//! The nature of the underlying [`Pads`] contained inside [`Config`] determines
183//! the type returned by a call to [`enable`]. If the pads only have a `TX` pin
184//! specified, then [`enable`] will return a `Uart<C, Tx>`. Similarly, If the
185//! pads only have a `RX` pin specified, then [`enable`] will return a `Uart<C,
186//! Rx>`. Finally, if both `RX` and `TX` pins are specified, then [`enable`]
187//! will return a `Uart<C, Duplex>`, which can be further split into a `Uart<C,
188//! RxDuplex>` and a `Uart<C, TxDuplex>`.
189//!
190//! ```
191//! use atsamd_hal::gpio::{PA08, PA09};
192//! use atsamd_hal::sercom::{Sercom0, uart};
193//! use atsamd_hal::sercom::uart::NineBit;
194//! use atsamd_hal::typelevel::NoneT;
195//!
196//! // Assuming SAMD21 or SAMx5x
197//! type Pads = uart::PadsFromIds<Sercom0, PA08, NoneT, PA09>;
198//! type Config = uart::Config<Pads, NineBit>;
199//! type UartRx = uart::Uart<Config, RxDuplex>;
200//! type UartTx = uart::UartTx<Config, RxDuples>;
201//! ```
202//!
203//! Only the [`Uart`] struct can actually perform transactions. To do so, use
204//! the embedded HAL traits, like [`embedded_hal_nb::serial::Read`],
205//! [`embedded_hal_nb::serial::Write`], [`embedded_io::Read`], and
206//! [`embedded_io::Write`].
207//!
208//! ```
209//! use nb::block;
210//! use atsamd_hal::embedded_hal_nb::serial::Write;
211//!
212//! block!(uart_tx.write(0x0fe));
213//! ```
214//!
215//! # UART flow control (CTS/RTS)
216//!
217//! This module supports CTS and RTS pins.
218//!
219//! The `RTS` pin is a fully hardware-controlled output pin that gets deasserted
220//! when:
221//!
222//! * The USART receiver is disabled;
223//! * The USART's RX buffer is full.
224//!
225//! The `CTS` pin is an input pin that provides an interrupt when a change
226//! (rising or falling edge) is detected on the corresponding Pad. This
227//! interrupt, `CTSIC`, can be enabled with the
228//! [`enable_ctsic`](Uart::enable_ctsic) method only when the corresponding
229//! [`Config`] has a `CTS` pad specified. The
230//! [`disable_ctsic`](Uart::disable_ctsic) and
231//! [`clear_ctsic`](Uart::clear_ctsic) methods are also available under the same
232//! conditions. [This application
233//! note](https://www.silabs.com/documents/public/application-notes/an0059.0-uart-flow-control.pdf)
234//! provides more information about UART hardware flow control.
235//!
236//! # Splitting
237//!
238//! A `Uart<C, Duplex>` can be split into its [`RxDuplex`] and [`TxDuplex`]
239//! constituents:
240//!
241//! ```
242//! use atsamd_hal::sercom::uart::Uart;
243//! // Assume uart is a Uart<C, Duplex>
244//! let (rx, tx) = uart.split();
245//! ```
246//!
247//! # Joining
248//!
249//! When a `Uart<C, Duplex>` has been split into its [`RxDuplex`] and
250//! [`TxDuplex`] parts, these parts can be joined back into a `Uart<C, Duplex>`
251//! by calling the [`join`] function for `Uart<C, Duplex>`. It takes a `Uart<C,
252//! RxDuplex>` and a `Uart<C, TxDuplex>` and moves them into a full [`Duplex`]
253//! [`Uart`].
254//!
255//! ```
256//! use atsamd_hal::sercom::uart::Uart;
257//!
258//! // Assume rx is a Uart<C, RxDuplex> and tx is a Uart<C, TxDuplex>
259//! let uart = Uart::join(rx, tx);
260//! // uart is now a Uart<C, Duplex>
261//! ```
262//!
263//! The [`AsMut<Uart<C, Duplex>>`] trait is also implemented for `(&mut Uart<C,
264//! RxDuplex>, &mut Uart<C, TxDuplex>)`. This is useful if you need an `&mut
265//! Uart<C, Duplex>` but you only have a pair of `&mut Uart<C, RxDuplex>` and
266//! `&mut Uart<C, TxDuplex>`. This can be leveraged to use the [`reconfigure`]
267//! method when all you have is a pair of mutable references to the [`RxDuplex`]
268//! and [`TxDuplex`] halves.
269//!
270//! ```
271//! use atsamd_hal::sercom::uart::Uart;
272//!
273//! // Assume rx is a Uart<C, RxDuplex> and tx is a Uart<C, TxDuplex>
274//!
275//! // Reconfigure peripheral from mutable references to RxDuplex
276//! // and TxDuplex halves
277//! (&mut rx, &mut tx).as_mut().reconfigure(|c| c.set_run_in_standby(false));
278//! ```
279//!
280//! # Reading the current configuration
281//!
282//! The `AsRef<Config<P, C>>` trait is implemented for `Uart<Config<P, C>, D>`.
283//! This means you can use the `get_` methods implemented for `Config`, since
284//! they take an `&self` argument.
285//!
286//! ```
287//! // Assume uart is a Uart<C, D>
288//! let (baud, baud_mode) = uart.as_ref().get_baud();
289//! ```
290//!
291//! # Disabling and reconfiguring
292//!
293//! Some methods, such as [`disable`] and [`reconfigure`], need to operate on
294//! all parts of a UART at once. In practice, this means that these methods
295//! operate on the type that was returned by [`enable`]. This can be `Uart<C,
296//! Rx>`, `Uart<C, Tx>`, or `Uart<C, Duplex>`, depending on how the peripheral
297//! was configured.
298//!
299//! The [`reconfigure`] method gives out an `&mut Config` reference, which can
300//! then use the `set_*` methods.
301//!
302//! ```
303//! use atsamd_hal::sercom::uart::Uart;
304//! use atsamd_hal::time::*;
305//!
306//! // Assume config is a valid Duplex UART Config struct
307//! let (rx, tx)= config.enable().split();
308//!
309//! // Send/receive data with tx/rx halves...
310//!
311//! // If the UART peripheral is configured in Duplex mode,
312//! // the two constituting halves need to be joined back into
313//! // a Uart<C, Duplex> before calling disable()
314//! let uart = Uart::join(rx, tx);
315//!
316//! // Reconfigure UART peripheral
317//! uart.reconfigure(|c| c.set_run_in_standby(false));
318//!
319//! // Disable UART peripheral
320//! let config = uart.disable();
321//! ```
322//!
323//! # Non-supported advanced features
324//!
325//! * Synchronous mode (USART) is not supported
326//! * LIN mode is not supported (SAMx5x)
327//! * 32-bit extension mode is not supported (SAMx5x). If you need to transfer
328//! slices, consider using the DMA methods instead. The <span class="stab
329//! portability" title="Available on crate feature `dma`
330//! only"><code>dma</code></span> Cargo feature must be enabled.
331//!
332//! # Using UART with DMA <span class="stab portability" title="Available on crate feature `dma` only"><code>dma</code></span>
333//!
334//! This HAL includes support for DMA-enabled UART transfers. Use
335//! [`Uart::with_rx_channel`] and [`Uart::with_tx_channel`] to attach DMA
336//! channels to the [`Uart`] struct. A DMA-enabled [`Uart`] implements the
337//! blocking [`embedded_io::Write`] and/or [`embedded_io::Read`] traits, which
338//! can be used to perform UART read/writes which are fast, continuous and low
339//! jitter, even if they are preemped by a higher priority interrupt.
340//!
341//!
342//! ```no_run
343//! use atsamd_hal::dmac::channel::{AnyChannel, Ready};
344//! use atsamd_hal::sercom::Uart::{I2c, ValidConfig, Error, TxDuplex};
345//! use atsamd_hal::embedded_io::Write;
346//! fn uart_send_with_dma<A: ValidConfig, C: AnyChannel<Status = Ready>>(uart: Uart<A, TxDuplex>, channel: C, bytes: &[u8]) -> Result<(), Error>{
347//! // Attach a DMA channel
348//! let uart = uart.with_tx_channel(channel);
349//! uart.write(bytes)?;
350//! }
351//! ```
352//!
353//! ## Non-blocking DMA transfers
354//!
355//! Non-blocking DMA transfers are also supported.
356//!
357//! The provided [`send_with_dma`] and [`receive_with_dma`] build and begin a
358//! [`Transfer`], thus starting the UART in a non-blocking way. Note that these
359//! methods require `'static` buffers in order to remain memory-safe.
360//!
361//! Optionally, interrupts can be enabled on the provided [`Channel`]. Please
362//! refer to the [`dmac`](crate::dmac) module-level documentation for more
363//! information.
364//!
365//! ```
366//! // Assume channel0 and channel1 are configured `dmac::Channel`s,
367//! // rx is a Uart<C, RxDuplex>, and tx is a Uart<C, TxDuplex>.
368//!
369//! /// Create data to send
370//! let tx_buffer: [u8; 50] = [0xff; 50];
371//! let rx_buffer: [u8; 100] = [0xab; 100];
372//!
373//! // Launch transmit transfer
374//! let tx_dma = tx.send_with_dma(&mut tx_buffer, channel0, |_| {});
375//!
376//! // Launch receive transfer
377//! let rx_dma = rx.receive_with_dma(&mut rx_buffer, channel1, |_| {});
378//!
379//! // Wait for transfers to complete and reclaim resources
380//! let (chan0, tx_buffer, tx) = tx_dma.wait();
381//! let (chan1, rx, rx_buffer) = rx_dma.wait();
382//! ```
383//!
384//! # `async` operation <span class="stab portability" title="Available on crate feature `async` only"><code>async</code></span>
385//!
386//! A [`Uart`] can be used for `async` operations. Configuring a [`Uart`] in
387//! async mode is relatively simple:
388//!
389//! * Bind the corresponding `SERCOM` interrupt source to the UART
390//! [`InterruptHandler`] (refer to the module-level [`async_hal`]
391//! documentation for more information).
392//! * Turn a previously configured [`Uart`] into a [`UartFuture`] by calling
393//! [`Uart::into_future`]
394//! * Optionally, add DMA channels to RX, TX or both using
395//! [`UartFuture::with_rx_dma_channel`] and
396//! [`UartFuture::with_tx_dma_channel`]. The API is exactly the same whether
397//! DMA channels are used or not.
398//! * Use the provided async methods for reading or writing to the UART
399//! peripheral.
400//!
401//! `UartFuture` implements `AsRef<Uart>` and `AsMut<Uart>` so that it can be
402//! reconfigured using the regular [`Uart`] methods. It also exposes a
403//! [`split`](UartFuture::split) method to split it into its RX and TX parts.
404//!
405//! ## Considerations when using `async` [`Uart`] 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>
406//!
407//! * An [`Uart`] struct must be turned into an [`UartFuture`] by calling
408//! [`Uart::into_future`] before calling `with_rx_dma_channel` or
409//! `with_tx_dma_channel` . The DMA channel itself must also be configured in
410//! async mode by using
411//! [`DmaController::into_future`](crate::dmac::DmaController::into_future).
412//! If a DMA channel is added to the [`Uart`] struct before it is turned into
413//! an [`UartFuture`], it will not be able to use DMA in async mode.
414//!
415//! ```
416//! // This will work
417//! let uart = uart.into_future().with_rx_dma_channel(rx_channel);
418//!
419//! // This won't
420//! let uart = uart.with_rx_dma_channel(rx_channel).into_future();
421//! ```
422//!
423//! ### Safety considerations
424//!
425//! In `async` mode, an SPI+DMA transfer does not require `'static` source and
426//! destination buffers. This, in theory, makes its use `unsafe`. However it is
427//! marked as safe for better ergonomics.
428//!
429//! This means that, as an user, you **must** ensure that the [`Future`]s
430//! returned by the [`read`](UartFuture::read) and [`write`](UartFuture::write)
431//! methods may never be forgotten through [`forget`] or by wrapping them with a
432//! [`ManuallyDrop`].
433//!
434//! The returned futures implement [`Drop`] and will automatically stop any
435//! ongoing transfers; this guarantees that the memory occupied by the
436//! now-dropped buffers may not be corrupted by running transfers.
437//!
438//! This means that using functions like [`futures::select_biased`] to implement
439//! timeouts is safe; transfers will be safely cancelled if the timeout expires.
440//!
441//! This also means that should you [`forget`] this [`Future`] after its first
442//! [`poll`] call, the transfer will keep running, ruining the now-reclaimed
443//! memory, as well as the rest of your day.
444//!
445//! * `await`ing is fine: the [`Future`] will run to completion.
446//! * Dropping an incomplete transfer is also fine. Dropping can happen, for
447//! example, if the transfer doesn't complete before a timeout expires.
448//! * Dropping an incomplete transfer *without running its destructor* is
449//! **unsound** and will trigger undefined behavior.
450//!
451//! ```ignore
452//! async fn always_ready() {}
453//!
454//! let mut buffer = [0x00; 10];
455//!
456//! // This is completely safe
457//! uart.read(&mut buffer).await?;
458//!
459//! // This is also safe: we launch a transfer, which is then immediately cancelled
460//! futures::select_biased! {
461//! _ = uart.read(&mut buffer)?,
462//! _ = always_ready(),
463//! }
464//!
465//! // This, while contrived, is also safe.
466//! {
467//! use core::future::Future;
468//!
469//! let future = uart.read(&mut buffer);
470//! futures::pin_mut!(future);
471//! // Assume ctx is a `core::task::Context` given out by the executor.
472//! // The future is polled, therefore starting the transfer
473//! future.as_mut().poll(ctx);
474//!
475//! // Future is dropped here - transfer is cancelled.
476//! }
477//!
478//! // DANGER: This is an example of undefined behavior
479//! {
480//! use core::future::Future;
481//! use core::ops::DerefMut;
482//!
483//! let future = core::mem::ManuallyDrop::new(uart.read(&mut buffer));
484//! futures::pin_mut!(future);
485//! // To actually make this example compile, we would need to wrap the returned
486//! // future from `i2c.read()` in a newtype that implements Future, because we
487//! // can't actually call as_mut() without being able to name the type we want
488//! // to deref to.
489//! let future_ref: &mut SomeNewTypeFuture = &mut future.as_mut();
490//! future.as_mut().poll(ctx);
491//!
492//! // Future is NOT dropped here - transfer is not cancelled, resulting un UB.
493//! }
494//! ```
495//!
496//! As you can see, unsoundness is relatively hard to come by - however, caution
497//! should still be exercised.
498//!
499//! [`enable`]: Config::enable
500//! [`disable`]: Uart::disable
501//! [`reconfigure`]: Uart::reconfigure
502//! [`bsp_pins`]: crate::bsp_pins
503//! [`IoSet`]: crate::sercom::pad::IoSet
504//! [`Pin`]: crate::gpio::pin::Pin
505//! [`PinId`]: crate::gpio::pin::PinId
506//! [`PinMode`]: crate::gpio::pin::PinMode
507//! [`split`]: Uart::split
508//! [`join`]: Uart::join
509//! [`NoneT`]: crate::typelevel::NoneT
510//! [`receive_with_dma`]: Uart::receive_with_dma
511//! [`send_with_dma`]: Uart::send_with_dma
512//! [`Transfer`]: crate::dmac::Transfer
513//! [`Channel`]: crate::dmac::Channel
514//! [`async_hal`]: crate::async_hal
515//! [`forget`]: core::mem::forget
516//! [`ManuallyDrop`]: core::mem::ManuallyDrop
517//! [`Future`]: core::future::Future
518//! [`poll`]: core::future::Future::poll
519//! [`Sercom`]: crate::sercom::Sercom
520//! [`Sercom0`]: crate::pac::Sercom0
521//! [`PadNum`]: crate::sercom::pad::PadNum
522//! [`Pad`]: crate::sercom::pad::Pad
523//! [`IsPad`]: crate::sercom::pad::IsPad
524//! [`OptionalPad`]: crate::sercom::pad::OptionalPad
525
526use atsamd_hal_macros::{hal_cfg, hal_module};
527
528#[hal_module(
529 any("sercom0-d11", "sercom0-d21") => "uart/pads_thumbv6m.rs",
530 "sercom0-d5x" => "uart/pads_thumbv7em.rs",
531)]
532mod pads {}
533
534pub use pads::*;
535
536mod reg;
537use reg::Registers;
538
539mod charsize;
540pub use charsize::*;
541
542mod flags;
543pub use flags::*;
544
545mod config;
546pub use config::*;
547
548pub mod impl_ehal;
549
550#[cfg(feature = "async")]
551mod async_api;
552#[cfg(feature = "async")]
553pub use async_api::*;
554
555use crate::{
556 sercom::pad::SomePad,
557 typelevel::{NoneT, Sealed},
558};
559use core::marker::PhantomData;
560use num_traits::AsPrimitive;
561
562/// Size of the SERCOM's `DATA` register
563#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
564pub type DataReg = u16;
565
566/// Size of the SERCOM's `DATA` register
567#[hal_cfg("sercom0-d5x")]
568pub type DataReg = u32;
569
570//=============================================================================
571// Stop bits, parity, baud rate, bit order
572//=============================================================================
573
574/// Number of stop bits in a UART frame
575#[derive(Debug, Clone, Copy)]
576pub enum StopBits {
577 /// 1 stop bit
578 OneBit,
579 /// 2 stop bits
580 TwoBits,
581}
582
583/// Parity setting of a UART frame
584#[repr(u8)]
585#[derive(Debug, Clone, Copy)]
586pub enum Parity {
587 /// No parity
588 None,
589 /// Even parity
590 Even,
591 /// Odd parity
592 Odd,
593}
594
595/// Bit order of a UART frame
596#[repr(u8)]
597#[derive(Debug, Clone, Copy)]
598pub enum BitOrder {
599 /// MSB-first
600 MsbFirst,
601 /// LSB-first
602 LsbFirst,
603}
604
605/// Baudrate oversampling values
606///
607/// *NOTE* 3x oversampling has been intentionally left out
608#[repr(u8)]
609#[derive(Debug, Clone, Copy)]
610pub enum Oversampling {
611 // 3 samples per bit
612 // Bits3 = 3,
613 /// 8 samples per bit
614 Bits8 = 8,
615 /// 16 samples per bit
616 Bits16 = 16,
617}
618
619/// Baudrate calculation in asynchronous mode
620#[derive(Debug, Clone, Copy)]
621pub enum BaudMode {
622 /// Asynchronous arithmetic baud calculation
623 Arithmetic(Oversampling),
624 /// Asynchronous fractional baud calculation
625 Fractional(Oversampling),
626}
627
628//=============================================================================
629// Capability
630//=============================================================================
631
632/// Type-level `enum` representing the capabilities of a UART peripheral
633pub trait Capability: Sealed {
634 /// Available interrupt flags for the specified capability
635 const FLAG_MASK: u8;
636 /// Available status flags for the specified capability
637 const STATUS_MASK: u16;
638 /// Enable `CTRLA.RXEN` field?
639 const RXEN: bool;
640 /// Enable `CTRLA.TXEN` field?
641 const TXEN: bool;
642}
643
644/// Type-level enum representing a UART that can transmit
645pub trait Transmit: Capability {}
646
647/// Type-level enum representing a UART that can receive
648pub trait Receive: Capability {}
649
650/// Type-level enum representing a UART that has transmit or receive
651/// capability, but not both
652pub trait Simplex: Capability {}
653
654/// Type-level enum representing a UART that is *not* half of a split
655/// [`Duplex`]
656pub trait SingleOwner: Capability {}
657
658/// Marker type representing a UART that has both transmit and receive
659/// capability
660pub enum Duplex {}
661impl Sealed for Duplex {}
662impl Capability for Duplex {
663 // All flags are valid for a Duplex UART
664 const FLAG_MASK: u8 = DUPLEX_FLAG_MASK;
665
666 // All status flags are valid for a Duplex UART
667 const STATUS_MASK: u16 = DUPLEX_STATUS_MASK;
668
669 const RXEN: bool = true;
670 const TXEN: bool = true;
671}
672impl Receive for Duplex {}
673impl Transmit for Duplex {}
674impl SingleOwner for Duplex {}
675
676/// Marker type representing a UART that can only receive
677pub enum Rx {}
678impl Sealed for Rx {}
679impl Capability for Rx {
680 // Available interrupt flags for a RX half-UART
681 const FLAG_MASK: u8 = RX_FLAG_MASK;
682
683 // Available status flags for a RX half-UART
684 const STATUS_MASK: u16 = RX_STATUS_MASK;
685
686 const RXEN: bool = true;
687 const TXEN: bool = false;
688}
689impl Receive for Rx {}
690impl Simplex for Rx {}
691impl SingleOwner for Rx {}
692
693/// Marker type representing a UART that can only transmit
694pub enum Tx {}
695impl Sealed for Tx {}
696impl Capability for Tx {
697 // Available interrupt flags for a TX half-UART
698 const FLAG_MASK: u8 = TX_FLAG_MASK;
699
700 // There are no settable/clearable status flags for TX half-UARTs
701 const STATUS_MASK: u16 = 0;
702
703 const RXEN: bool = false;
704 const TXEN: bool = true;
705}
706impl Transmit for Tx {}
707impl Simplex for Tx {}
708impl SingleOwner for Tx {}
709
710/// Marker type representing the Rx half of a [`Duplex`] UART
711pub enum RxDuplex {}
712impl Sealed for RxDuplex {}
713impl Capability for RxDuplex {
714 // Available interrupt flags for a RX half-UART
715 const FLAG_MASK: u8 = RX_FLAG_MASK;
716
717 // Available status flags for a RX half-UART
718 const STATUS_MASK: u16 = RX_STATUS_MASK;
719
720 const RXEN: bool = true;
721 const TXEN: bool = false;
722}
723impl Receive for RxDuplex {}
724
725/// Marker type representing a the Tx half of a [`Duplex`] UART
726pub enum TxDuplex {}
727impl Sealed for TxDuplex {}
728impl Capability for TxDuplex {
729 // Available interrupt flags for a TX half-UART
730 const FLAG_MASK: u8 = TX_FLAG_MASK;
731
732 // There are no settable/clearable status flags for TX half-UARTs
733 const STATUS_MASK: u16 = 0;
734
735 const RXEN: bool = false;
736 const TXEN: bool = true;
737}
738
739impl Transmit for TxDuplex {}
740
741//=============================================================================
742// Uart
743//=============================================================================
744
745/// Abstraction over a UART peripheral, allowing to perform UART transactions.
746/// The second type parameter, `D`, denotes what the struct's [`Capability`] is.
747///
748/// * [`Rx`] or [`RxDuplex`]: Can perform receive transactions
749/// * [`Tx`] or [`TxDuplex`]: Can perform transmit transactions
750/// * [`Duplex`]: Can perform receive and transmit transactions. Additionally,
751/// you can call [`split`](Uart::split) to return a `(Uart<C, RxDuplex>,
752/// Uart<C, TxDuplex>)` tuple.
753pub struct Uart<C, D, RxDma = NoneT, TxDma = NoneT>
754where
755 C: ValidConfig,
756 D: Capability,
757{
758 config: C,
759 capability: PhantomData<D>,
760 rx_channel: RxDma,
761 tx_channel: TxDma,
762}
763
764impl<C, D, R, T> Uart<C, D, R, T>
765where
766 C: ValidConfig,
767 D: Capability,
768{
769 /// Obtain a pointer to the `DATA` register. Necessary for DMA transfers.
770 #[cfg(feature = "dma")]
771 #[inline]
772 pub(crate) fn data_ptr(&self) -> *mut C::Word {
773 self.config.as_ref().registers.data_ptr()
774 }
775
776 /// Helper method to remove the interrupt flags not pertinent to `Self`'s
777 /// `Capability`
778 #[inline]
779 fn capability_flags(flags: Flags) -> Flags {
780 flags & Flags::from_bits_retain(D::FLAG_MASK)
781 }
782
783 /// Helper method to remove the status flags not pertinent to `Self`'s
784 /// `Capability`
785 #[inline]
786 fn capability_status(status: Status) -> Status {
787 status & Status::from_bits_retain(D::STATUS_MASK)
788 }
789
790 /// Read the interrupt flags
791 #[inline]
792 pub fn read_flags(&self) -> Flags {
793 self.config.as_ref().registers.read_flags()
794 }
795
796 /// Clear interrupt status flags
797 ///
798 /// Setting the `ERROR`, `RXBRK`, `CTSIC`, `RXS`, or `TXC` flag will clear
799 /// the interrupts. This function has no effect on the `DRE` or
800 /// `RXC` flags.
801 ///
802 /// Note that only the flags pertinent to `Self`'s [`Capability`]
803 /// will be cleared. The other flags will be **SILENTLY IGNORED**.
804 ///
805 /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
806 /// `ERROR`
807 /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
808 /// **Note**: The `CTSIC` flag can only be cleared if a `CTS` Pad was
809 /// specified in the [`Config`] via the [`clear_ctsic`](Uart::clear_ctsic)
810 /// method.
811 /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
812 /// all flags available.
813 ///
814 /// **Warning:** The implementations of of
815 /// [`Write::flush`](embedded_hal_nb::serial::Write::flush) waits on and
816 /// clears the `TXC` flag. Manually clearing this flag could cause it to
817 /// hang indefinitely.
818 #[inline]
819 pub fn clear_flags(&mut self, flags: Flags) {
820 // Remove flags not pertinent to Self's Capability
821 let flags = Self::capability_flags(flags);
822 self.config.as_mut().registers.clear_flags(flags);
823 }
824
825 /// Enable interrupts for the specified flags.
826 ///
827 /// Note that only the flags pertinent to `Self`'s [`Capability`]
828 /// will be cleared. The other flags will be **SILENTLY IGNORED**.
829 ///
830 /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
831 /// `ERROR`
832 /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
833 /// **Note**: The `CTSIC` interrupt can only be enabled if a `CTS` Pad was
834 /// specified in the [`Config`] via the
835 /// [`enable_ctsic`](Uart::enable_ctsic) method.
836 /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
837 /// all flags available.
838 #[inline]
839 pub fn enable_interrupts(&mut self, flags: Flags) {
840 // Remove flags not pertinent to Self's Capability
841 let flags = Self::capability_flags(flags);
842 self.config.as_mut().registers.enable_interrupts(flags);
843 }
844
845 /// Disable interrupts for the specified flags.
846 ///
847 /// Note that only the flags pertinent to `Self`'s [`Capability`]
848 /// will be cleared. The other flags will be **SILENTLY IGNORED**
849 ///
850 /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
851 /// `ERROR`
852 /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
853 /// **Note**: The `CTSIC` interrupt can only be disabled if a `CTS` Pad
854 /// was specified in the [`Config`] via the
855 /// [`disable_ctsic`](Uart::disable_ctsic) method.
856 /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
857 /// all flags available.
858 #[inline]
859 pub fn disable_interrupts(&mut self, flags: Flags) {
860 // Remove flags not pertinent to Self's Capability
861 let flags = Self::capability_flags(flags);
862 self.config.as_mut().registers.disable_interrupts(flags);
863 }
864
865 /// Read the status flags
866 #[inline]
867 pub fn read_status(&self) -> Status {
868 self.config.as_ref().registers.read_status()
869 }
870
871 /// Clear the status flags
872 ///
873 /// Note that only the status flags pertinent to `Self`'s [`Capability`]
874 /// will be cleared. The other stattus flags will be **SILENTLY IGNORED**.
875 ///
876 /// * Available status flags for [`Receive`] capability: `PERR`, `FERR`,
877 /// `BUFOVF`, `ISF` and `COLL`
878 /// * [`Transmit`]-only [`Uart`]s have no clearable status flags.
879 /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
880 /// all status flags available.
881 #[inline]
882 pub fn clear_status(&mut self, status: Status) {
883 // Remove status flags not pertinent to Self's Capability
884 let flags = Self::capability_status(status);
885 self.config.as_mut().registers.clear_status(flags);
886 }
887
888 #[inline]
889 pub(super) fn _reconfigure<F>(&mut self, update: F)
890 where
891 F: FnOnce(&mut SpecificConfig<C>),
892 {
893 self.config.as_mut().registers.enable_peripheral(false);
894 update(self.config.as_mut());
895 self.config.as_mut().registers.enable_peripheral(true);
896 }
897}
898
899impl<C, D, R, T> Uart<C, D, R, T>
900where
901 C: ValidConfig,
902 <C::Pads as PadSet>::Cts: SomePad,
903 D: Transmit,
904{
905 /// Clear the `CTSIC` interrupt flag
906 #[inline]
907 pub fn clear_ctsic(&mut self) {
908 let bit = CTSIC;
909 self.config
910 .as_mut()
911 .registers
912 .clear_flags(Flags::from_bits_retain(bit));
913 }
914
915 /// Enable the `CTSIC` interrupt
916 #[inline]
917 pub fn enable_ctsic(&mut self) {
918 let bit = CTSIC;
919 self.config
920 .as_mut()
921 .registers
922 .enable_interrupts(Flags::from_bits_retain(bit));
923 }
924
925 /// Disable the `CTSIC` interrupt
926 #[inline]
927 pub fn disable_ctsic(&mut self) {
928 let bit = CTSIC;
929 self.config
930 .as_mut()
931 .registers
932 .disable_interrupts(Flags::from_bits_retain(bit));
933 }
934}
935
936impl<C, D, R, T> Uart<C, D, R, T>
937where
938 C: ValidConfig,
939 D: Simplex,
940{
941 /// Disable the UART peripheral and return the underlying [`Config`]
942 #[inline]
943 pub fn disable(self) -> C {
944 let mut config = self.config;
945 config.as_mut().registers.disable();
946 config
947 }
948
949 /// Reconfigure the UART.
950 ///
951 /// Calling this method will temporarily disable the SERCOM peripheral, as
952 /// some registers are enable-protected. This may interrupt any ongoing
953 /// transactions.
954 ///
955 /// ```
956 /// use atsamd_hal::sercom::uart::{BaudMode, Oversampling, Uart};
957 /// uart.reconfigure(|c| c.set_run_in_standby(false));
958 /// ```
959 #[inline]
960 pub fn reconfigure<U>(&mut self, update: U)
961 where
962 U: FnOnce(&mut SpecificConfig<C>),
963 {
964 self._reconfigure(update);
965 }
966}
967
968#[cfg(feature = "dma")]
969impl<C, D, T> Uart<C, D, NoneT, T>
970where
971 C: ValidConfig,
972 D: Capability,
973{
974 /// Attach a DMA channel to this [`Uart`] for RX transactions. Its
975 /// [`Read`](embedded_io::Read) implementation will use DMA to
976 /// carry out its transactions.
977 pub fn with_rx_channel<R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>>(
978 self,
979 rx_channel: R,
980 ) -> Uart<C, D, R, T> {
981 Uart {
982 config: self.config,
983 capability: self.capability,
984 tx_channel: self.tx_channel,
985 rx_channel,
986 }
987 }
988}
989
990#[cfg(feature = "dma")]
991impl<C, D, R> Uart<C, D, R, NoneT>
992where
993 C: ValidConfig,
994 D: Capability,
995{
996 /// Attach a DMA channel to this [`Uart`] for TX transactions. Its
997 /// [`Write`](embedded_io::Write) implementation will use DMA to
998 /// carry out its transactions.
999 pub fn with_tx_channel<T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>>(
1000 self,
1001 tx_channel: T,
1002 ) -> Uart<C, D, R, T> {
1003 Uart {
1004 config: self.config,
1005 capability: self.capability,
1006 rx_channel: self.rx_channel,
1007 tx_channel,
1008 }
1009 }
1010}
1011
1012#[cfg(feature = "dma")]
1013impl<C, D, R, T, S> Uart<C, D, R, T>
1014where
1015 C: ValidConfig,
1016 D: Capability,
1017 R: crate::dmac::AnyChannel<Status = S>,
1018 S: crate::dmac::ReadyChannel,
1019{
1020 /// Reclaim the RX DMA channel. Subsequent RX operations will no longer use
1021 /// DMA.
1022 pub fn take_rx_channel(self) -> (Uart<C, D, NoneT, T>, R) {
1023 (
1024 Uart {
1025 config: self.config,
1026 capability: self.capability,
1027 tx_channel: self.tx_channel,
1028 rx_channel: NoneT,
1029 },
1030 self.rx_channel,
1031 )
1032 }
1033}
1034
1035#[cfg(feature = "dma")]
1036impl<C, D, R, T, S> Uart<C, D, R, T>
1037where
1038 C: ValidConfig,
1039 D: Capability,
1040 T: crate::dmac::AnyChannel<Status = S>,
1041 S: crate::dmac::ReadyChannel,
1042{
1043 /// Reclaim the TX DMA channel. Subsequent TX operations will no longer use
1044 /// DMA.
1045 pub fn take_tx_channel(self) -> (Uart<C, D, R, NoneT>, T) {
1046 (
1047 Uart {
1048 config: self.config,
1049 capability: self.capability,
1050 rx_channel: self.rx_channel,
1051 tx_channel: NoneT,
1052 },
1053 self.tx_channel,
1054 )
1055 }
1056}
1057
1058impl<C, R, T> Uart<C, Duplex, R, T>
1059where
1060 C: ValidConfig,
1061{
1062 /// Split the [`Uart`] into [`RxDuplex`] and [`TxDuplex`] halves
1063 #[allow(clippy::type_complexity)]
1064 #[inline]
1065 pub fn split(self) -> (Uart<C, RxDuplex, R, NoneT>, Uart<C, TxDuplex, NoneT, T>) {
1066 let config = unsafe { core::ptr::read(&self.config) };
1067 (
1068 Uart {
1069 config: self.config,
1070 capability: PhantomData,
1071 rx_channel: self.rx_channel,
1072 tx_channel: NoneT,
1073 },
1074 Uart {
1075 config,
1076 capability: PhantomData,
1077 rx_channel: NoneT,
1078 tx_channel: self.tx_channel,
1079 },
1080 )
1081 }
1082
1083 /// Disable the UART peripheral and return the underlying [`Config`]
1084 #[inline]
1085 pub fn disable(self) -> C {
1086 let mut config = self.config;
1087 config.as_mut().registers.disable();
1088 config
1089 }
1090
1091 /// Update the UART [`Config`]uration.
1092 ///
1093 /// Calling this method will temporarily disable the SERCOM peripheral, as
1094 /// some registers are enable-protected. This may interrupt any ongoing
1095 /// transactions.
1096 ///
1097 /// ```
1098 /// use atsamd_hal::sercom::uart::{BaudMode, Oversampling, Uart};
1099 /// uart.reconfigure(|c| c.set_run_in_standby(false));
1100 /// ```
1101 #[inline]
1102 pub fn reconfigure<F>(&mut self, update: F)
1103 where
1104 F: FnOnce(&mut SpecificConfig<C>),
1105 {
1106 self._reconfigure(update);
1107 }
1108
1109 /// Join [`RxDuplex`] and [`TxDuplex`] halves back into a full `Uart<C,
1110 /// Duplex>`
1111 pub fn join(rx: Uart<C, RxDuplex, R, NoneT>, tx: Uart<C, TxDuplex, NoneT, T>) -> Self {
1112 Self {
1113 config: rx.config,
1114 capability: PhantomData,
1115 rx_channel: rx.rx_channel,
1116 tx_channel: tx.tx_channel,
1117 }
1118 }
1119}
1120
1121impl<C: ValidConfig, R, T> AsMut<Uart<C, Duplex, R, T>>
1122 for (
1123 &mut Uart<C, RxDuplex, R, NoneT>,
1124 &mut Uart<C, TxDuplex, NoneT, T>,
1125 )
1126{
1127 #[inline]
1128 fn as_mut(&mut self) -> &mut Uart<C, Duplex, R, T> {
1129 // SAFETY: Pointer casting &mut Uart<C, RxDuplex> into &mut
1130 // Uart<C, Duplex> should be safe as long as RxDuplex, TxDuplex, R and T are all
1131 // zero-sized types
1132 unsafe { &mut *(self.0 as *mut _ as *mut Uart<C, Duplex, R, T>) }
1133 }
1134}
1135
1136impl<C, D> AsRef<SpecificConfig<C>> for Uart<C, D>
1137where
1138 C: ValidConfig,
1139 D: Capability,
1140{
1141 #[inline]
1142 fn as_ref(&self) -> &SpecificConfig<C> {
1143 self.config.as_ref()
1144 }
1145}
1146
1147//=============================================================================
1148// Rx/Tx specific functionality
1149//=============================================================================
1150
1151impl<C, D, R, T> Uart<C, D, R, T>
1152where
1153 C: ValidConfig,
1154 D: Receive,
1155 DataReg: AsPrimitive<C::Word>,
1156{
1157 /// Read from the DATA register
1158 ///
1159 /// # Safety
1160 ///
1161 /// Reading from the data register directly is `unsafe`, because it will
1162 /// clear the RXC flag, which could break assumptions made elsewhere in
1163 /// this module.
1164 #[inline]
1165 pub unsafe fn read_data(&mut self) -> DataReg {
1166 self.config.as_mut().registers.read_data()
1167 }
1168
1169 /// Read the status register and convert into a [`Result`]
1170 /// containing the corresponding [`Flags`] or [`Error`]
1171 #[inline]
1172 fn read_flags_errors(&self) -> Result<Flags, Error> {
1173 self.read_status().check_bus_error()?;
1174 Ok(self.read_flags())
1175 }
1176
1177 /// Flush the RX buffer and clear RX errors.
1178 ///
1179 /// **Note**: The datasheet states that disabling the receiver (RXEN) clears
1180 /// the RX buffer, and clears the BUFOVF, PERR and FERR bits.
1181 /// However, in practice, it seems like BUFOVF errors still pop
1182 /// up after a disable/enable cycle of the receiver, then immediately begin
1183 /// reading bytes from the DATA register. Instead, this method uses a
1184 /// workaround, which reads a few bytes to clear the RX buffer (3 bytes
1185 /// seems to be the trick), then manually clear the error bits.
1186 #[inline]
1187 pub fn flush_rx_buffer(&mut self) {
1188 // TODO Is this a hardware bug???
1189
1190 // usart.ctrlb.modify(|_, w| w.rxen().clear_bit());
1191 // while usart.syncbusy.read().ctrlb().bit() ||
1192 // usart.ctrlb.read().rxen().bit_is_set() {}
1193
1194 // usart.ctrlb.modify(|_, w| w.rxen().set_bit());
1195 // while usart.syncbusy.read().ctrlb().bit() ||
1196 // usart.ctrlb.read().rxen().bit_is_clear() {}
1197
1198 for _ in 0..=2 {
1199 let _data = unsafe { self.config.as_mut().registers.read_data() };
1200 }
1201
1202 // Clear all errors
1203 self.clear_status(
1204 Status::BUFOVF | Status::FERR | Status::PERR | Status::ISF | Status::COLL,
1205 );
1206 }
1207}
1208
1209impl<C, D, R, T> Uart<C, D, R, T>
1210where
1211 C: ValidConfig,
1212 D: Transmit,
1213{
1214 /// Write to the DATA register
1215 ///
1216 /// # Safety
1217 ///
1218 /// Writing to the data register directly is `unsafe`, because it will clear
1219 /// the DRE flag, which could break assumptions made elsewhere in this
1220 /// module.
1221 #[inline]
1222 pub unsafe fn write_data(&mut self, data: DataReg) {
1223 self.config.as_mut().registers.write_data(data);
1224 }
1225}