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. In particular, all [`Pin`]s
15//! must be mapped to the same `Sercom` (see the datasheet). This HAL makes it
16//! impossible to use invalid [`Pin`]/[`Pad`] combinations, and the [`Pads`]
17//! struct is responsible for enforcing these constraints.
18//!
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, `DI`, `DO`, `CK` and `SS`,
23//! represent the Data In, Data Out, Sclk and SS pads respectively. Each of the
24//! remaining type parameters is an [`OptionalPad`] and defaults to [`NoneT`]. A
25//! [`Pad`] is just a [`Pin`] configured in the correct [`PinMode`] that
26//! implements [`IsPad`]. The [`bsp_pins!`](crate::bsp_pins) macro can be used
27//! to define convenient type 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_dma_channel`. The DMA channel
409//!   itself must also be configured in async mode by using
410//!   [`DmaController::into_future`](crate::dmac::DmaController::into_future).
411//!   If a DMA channel is added to the [`Uart`] struct before it is turned into
412//!   an [`UartFuture`], it will not be able to use DMA in async mode.
413//!
414//! ```
415//! // This will work
416//! let uart = uart.into_future().with_dma_channels(rx_channel, tx_channel);
417//!
418//! // This won't
419//! let uart = uart.with_dma_channels(rx_channel, tx_channel).into_future();
420//! ```
421//!
422//! ### Safety considerations
423//!
424//! In `async` mode, an SPI+DMA transfer does not require `'static` source and
425//! destination buffers. This, in theory, makes its use `unsafe`. However it is
426//! marked as safe for better ergonomics.
427//!
428//! This means that, as an user, you **must** ensure that the [`Future`]s
429//! returned by the [`read`](UartFuture::read) and [`write`](UartFuture::write)
430//! methods may never be forgotten through [`forget`] or by wrapping them with a
431//! [`ManuallyDrop`].
432//!
433//! The returned futures implement [`Drop`] and will automatically stop any
434//! ongoing transfers; this guarantees that the memory occupied by the
435//! now-dropped buffers may not be corrupted by running transfers.
436//!
437//! This means that using functions like [`futures::select_biased`] to implement
438//! timeouts is safe; transfers will be safely cancelled if the timeout expires.
439//!
440//! This also means that should you [`forget`] this [`Future`] after its first
441//! [`poll`] call, the transfer will keep running, ruining the now-reclaimed
442//! memory, as well as the rest of your day.
443//!
444//! * `await`ing is fine: the [`Future`] will run to completion.
445//! * Dropping an incomplete transfer is also fine. Dropping can happen, for
446//!   example, if the transfer doesn't complete before a timeout expires.
447//! * Dropping an incomplete transfer *without running its destructor* is
448//!   **unsound** and will trigger undefined behavior.
449//!
450//! ```ignore
451//! async fn always_ready() {}
452//!
453//! let mut buffer = [0x00; 10];
454//!
455//! // This is completely safe
456//! uart.read(&mut buffer).await?;
457//!
458//! // This is also safe: we launch a transfer, which is then immediately cancelled
459//! futures::select_biased! {
460//!     _ = uart.read(&mut buffer)?,
461//!     _ = always_ready(),
462//! }
463//!
464//! // This, while contrived, is also safe.
465//! {
466//!     use core::future::Future;
467//!
468//!     let future = uart.read(&mut buffer);
469//!     futures::pin_mut!(future);
470//!     // Assume ctx is a `core::task::Context` given out by the executor.
471//!     // The future is polled, therefore starting the transfer
472//!     future.as_mut().poll(ctx);
473//!
474//!     // Future is dropped here - transfer is cancelled.
475//! }
476//!
477//! // DANGER: This is an example of undefined behavior
478//! {
479//!     use core::future::Future;
480//!     use core::ops::DerefMut;
481//!
482//!     let future = core::mem::ManuallyDrop::new(uart.read(&mut buffer));
483//!     futures::pin_mut!(future);
484//!     // To actually make this example compile, we would need to wrap the returned
485//!     // future from `i2c.read()` in a newtype that implements Future, because we
486//!     // can't actually call as_mut() without being able to name the type we want
487//!     // to deref to.
488//!     let future_ref: &mut SomeNewTypeFuture = &mut future.as_mut();
489//!     future.as_mut().poll(ctx);
490//!
491//!     // Future is NOT dropped here - transfer is not cancelled, resulting un UB.
492//! }
493//! ```
494//!
495//! As you can see, unsoundness is relatively hard to come by - however, caution
496//! should still be exercised.
497//!
498//! [`enable`]: Config::enable
499//! [`disable`]: Uart::disable
500//! [`reconfigure`]: Uart::reconfigure
501//! [`bsp_pins`]: crate::bsp_pins
502//! [`Pin`]: crate::gpio::pin::Pin
503//! [`Pin`]: crate::gpio::pin::Pin
504//! [`PinId`]: crate::gpio::pin::PinId
505//! [`PinMode`]: crate::gpio::pin::PinMode
506//! [`split`]: Uart::split
507//! [`join`]: Uart::join
508//! [`NoneT`]: crate::typelevel::NoneT
509//! [`receive_with_dma`]: Uart::receive_with_dma
510//! [`send_with_dma`]: Uart::send_with_dma
511//! [`Transfer`]: crate::dmac::Transfer
512//! [`Channel`]: crate::dmac::Channel
513//! [`async_hal`]: crate::async_hal
514//! [`forget`]: core::mem::forget
515//! [`ManuallyDrop`]: core::mem::ManuallyDrop
516//! [`Future`]: core::future::Future
517//! [`poll`]: core::future::Future::poll
518//! [`Sercom`]: crate::sercom::Sercom
519//! [`Sercom0`]: crate::pac::Sercom0
520//! [`PadNum`]: crate::sercom::pad::PadNum
521//! [`Pad`]: crate::sercom::pad::Pad
522//! [`IsPad`]: crate::sercom::pad::IsPad
523//! [`OptionalPad`]: crate::sercom::pad::OptionalPad
524
525use atsamd_hal_macros::{hal_cfg, hal_module};
526
527#[hal_module(
528    any("sercom0-d11", "sercom0-d21") => "uart/pads_thumbv6m.rs",
529    "sercom0-d5x" => "uart/pads_thumbv7em.rs",
530)]
531mod pads {}
532
533pub use pads::*;
534
535mod reg;
536use reg::Registers;
537
538mod charsize;
539pub use charsize::*;
540
541mod flags;
542pub use flags::*;
543
544mod config;
545pub use config::*;
546
547pub mod impl_ehal;
548
549#[cfg(feature = "async")]
550mod async_api;
551#[cfg(feature = "async")]
552pub use async_api::*;
553
554use crate::{
555    sercom::pad::SomePad,
556    typelevel::{NoneT, Sealed},
557};
558use core::marker::PhantomData;
559use num_traits::AsPrimitive;
560
561/// Size of the SERCOM's `DATA` register
562#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
563pub type DataReg = u16;
564
565/// Size of the SERCOM's `DATA` register
566#[hal_cfg("sercom0-d5x")]
567pub type DataReg = u32;
568
569//=============================================================================
570// Stop bits, parity, baud rate, bit order
571//=============================================================================
572
573/// Number of stop bits in a UART frame
574#[derive(Debug, Clone, Copy)]
575pub enum StopBits {
576    /// 1 stop bit
577    OneBit,
578    /// 2 stop bits
579    TwoBits,
580}
581
582/// Parity setting of a UART frame
583#[repr(u8)]
584#[derive(Debug, Clone, Copy)]
585pub enum Parity {
586    /// No parity
587    None,
588    /// Even parity
589    Even,
590    /// Odd parity
591    Odd,
592}
593
594/// Bit order of a UART frame
595#[repr(u8)]
596#[derive(Debug, Clone, Copy)]
597pub enum BitOrder {
598    /// MSB-first
599    MsbFirst,
600    /// LSB-first
601    LsbFirst,
602}
603
604/// Baudrate oversampling values
605///
606/// *NOTE* 3x oversampling has been intentionally left out
607#[repr(u8)]
608#[derive(Debug, Clone, Copy)]
609pub enum Oversampling {
610    // 3 samples per bit
611    // Bits3 = 3,
612    /// 8 samples per bit
613    Bits8 = 8,
614    /// 16 samples per bit
615    Bits16 = 16,
616}
617
618/// Baudrate calculation in asynchronous mode
619#[derive(Debug, Clone, Copy)]
620pub enum BaudMode {
621    /// Asynchronous arithmetic baud calculation
622    Arithmetic(Oversampling),
623    /// Asynchronous fractional baud calculation
624    Fractional(Oversampling),
625}
626
627//=============================================================================
628// Capability
629//=============================================================================
630
631/// Type-level `enum` representing the capabilities of a UART peripheral
632pub trait Capability: Sealed {
633    /// Available interrupt flags for the specified capability
634    const FLAG_MASK: u8;
635    /// Available status flags for the specified capability
636    const STATUS_MASK: u16;
637    /// Enable `CTRLA.RXEN` field?
638    const RXEN: bool;
639    /// Enable `CTRLA.TXEN` field?
640    const TXEN: bool;
641}
642
643/// Type-level enum representing a UART that can transmit
644pub trait Transmit: Capability {}
645
646/// Type-level enum representing a UART that can receive
647pub trait Receive: Capability {}
648
649/// Type-level enum representing a UART that has transmit or receive
650/// capability, but not both
651pub trait Simplex: Capability {}
652
653/// Type-level enum representing a UART that is *not* half of a split
654/// [`Duplex`]
655pub trait SingleOwner: Capability {}
656
657/// Marker type representing a UART that has both transmit and receive
658/// capability
659pub enum Duplex {}
660impl Sealed for Duplex {}
661impl Capability for Duplex {
662    // All flags are valid for a Duplex UART
663    const FLAG_MASK: u8 = DUPLEX_FLAG_MASK;
664
665    // All status flags are valid for a Duplex UART
666    const STATUS_MASK: u16 = DUPLEX_STATUS_MASK;
667
668    const RXEN: bool = true;
669    const TXEN: bool = true;
670}
671impl Receive for Duplex {}
672impl Transmit for Duplex {}
673impl SingleOwner for Duplex {}
674
675/// Marker type representing a UART that can only receive
676pub enum Rx {}
677impl Sealed for Rx {}
678impl Capability for Rx {
679    // Available interrupt flags for a RX half-UART
680    const FLAG_MASK: u8 = RX_FLAG_MASK;
681
682    // Available status flags for a RX half-UART
683    const STATUS_MASK: u16 = RX_STATUS_MASK;
684
685    const RXEN: bool = true;
686    const TXEN: bool = false;
687}
688impl Receive for Rx {}
689impl Simplex for Rx {}
690impl SingleOwner for Rx {}
691
692/// Marker type representing a UART that can only transmit
693pub enum Tx {}
694impl Sealed for Tx {}
695impl Capability for Tx {
696    // Available interrupt flags for a TX half-UART
697    const FLAG_MASK: u8 = TX_FLAG_MASK;
698
699    // There are no settable/clearable status flags for TX half-UARTs
700    const STATUS_MASK: u16 = 0;
701
702    const RXEN: bool = false;
703    const TXEN: bool = true;
704}
705impl Transmit for Tx {}
706impl Simplex for Tx {}
707impl SingleOwner for Tx {}
708
709/// Marker type representing the Rx half of a  [`Duplex`] UART
710pub enum RxDuplex {}
711impl Sealed for RxDuplex {}
712impl Capability for RxDuplex {
713    // Available interrupt flags for a RX half-UART
714    const FLAG_MASK: u8 = RX_FLAG_MASK;
715
716    // Available status flags for a RX half-UART
717    const STATUS_MASK: u16 = RX_STATUS_MASK;
718
719    const RXEN: bool = true;
720    const TXEN: bool = false;
721}
722impl Receive for RxDuplex {}
723
724/// Marker type representing a the Tx half of a [`Duplex`] UART
725pub enum TxDuplex {}
726impl Sealed for TxDuplex {}
727impl Capability for TxDuplex {
728    // Available interrupt flags for a TX half-UART
729    const FLAG_MASK: u8 = TX_FLAG_MASK;
730
731    // There are no settable/clearable status flags for TX half-UARTs
732    const STATUS_MASK: u16 = 0;
733
734    const RXEN: bool = false;
735    const TXEN: bool = true;
736}
737
738impl Transmit for TxDuplex {}
739
740//=============================================================================
741// Uart
742//=============================================================================
743
744/// Abstraction over a UART peripheral, allowing to perform UART transactions.
745/// The second type parameter, `D`, denotes what the struct's [`Capability`] is.
746///
747/// * [`Rx`] or [`RxDuplex`]: Can perform receive transactions
748/// * [`Tx`] or [`TxDuplex`]: Can perform transmit transactions
749/// * [`Duplex`]: Can perform receive and transmit transactions. Additionally,
750///   you can call [`split`](Uart::split) to return a `(Uart<C, RxDuplex>,
751///   Uart<C, TxDuplex>)` tuple.
752pub struct Uart<C, D, RxDma = NoneT, TxDma = NoneT>
753where
754    C: ValidConfig,
755    D: Capability,
756{
757    config: C,
758    capability: PhantomData<D>,
759    rx_channel: RxDma,
760    tx_channel: TxDma,
761}
762
763impl<C, D, R, T> Uart<C, D, R, T>
764where
765    C: ValidConfig,
766    D: Capability,
767{
768    /// Obtain a pointer to the `DATA` register. Necessary for DMA transfers.
769    #[cfg(feature = "dma")]
770    #[inline]
771    pub(crate) fn data_ptr(&self) -> *mut C::Word {
772        self.config.as_ref().registers.data_ptr()
773    }
774
775    /// Helper method to remove the interrupt flags not pertinent to `Self`'s
776    /// `Capability`
777    #[inline]
778    fn capability_flags(flags: Flags) -> Flags {
779        flags & Flags::from_bits_retain(D::FLAG_MASK)
780    }
781
782    /// Helper method to remove the status flags not pertinent to `Self`'s
783    /// `Capability`
784    #[inline]
785    fn capability_status(status: Status) -> Status {
786        status & Status::from_bits_retain(D::STATUS_MASK)
787    }
788
789    /// Read the interrupt flags
790    #[inline]
791    pub fn read_flags(&self) -> Flags {
792        self.config.as_ref().registers.read_flags()
793    }
794
795    /// Clear interrupt status flags
796    ///
797    /// Setting the `ERROR`, `RXBRK`, `CTSIC`, `RXS`, or `TXC` flag will clear
798    /// the interrupts. This function has no effect on the `DRE` or
799    /// `RXC` flags.
800    ///
801    /// Note that only the flags pertinent to `Self`'s [`Capability`]
802    /// will be cleared. The other flags will be **SILENTLY IGNORED**.
803    ///
804    /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
805    ///   `ERROR`
806    /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
807    ///   **Note**: The `CTSIC` flag can only be cleared if a `CTS` Pad was
808    ///   specified in the [`Config`] via the [`clear_ctsic`](Uart::clear_ctsic)
809    ///   method.
810    /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
811    ///   all flags available.
812    ///
813    /// **Warning:** The implementations of of
814    /// [`Write::flush`](embedded_hal_nb::serial::Write::flush) waits on and
815    /// clears the `TXC` flag. Manually clearing this flag could cause it to
816    /// hang indefinitely.
817    #[inline]
818    pub fn clear_flags(&mut self, flags: Flags) {
819        // Remove flags not pertinent to Self's Capability
820        let flags = Self::capability_flags(flags);
821        self.config.as_mut().registers.clear_flags(flags);
822    }
823
824    /// Enable interrupts for the specified flags.
825    ///
826    /// Note that only the flags pertinent to `Self`'s [`Capability`]
827    /// will be cleared. The other flags will be **SILENTLY IGNORED**.
828    ///
829    /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
830    ///   `ERROR`
831    /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
832    ///   **Note**: The `CTSIC` interrupt can only be enabled if a `CTS` Pad was
833    ///   specified in the [`Config`] via the
834    ///   [`enable_ctsic`](Uart::enable_ctsic) method.
835    /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
836    ///   all flags available.
837    #[inline]
838    pub fn enable_interrupts(&mut self, flags: Flags) {
839        // Remove flags not pertinent to Self's Capability
840        let flags = Self::capability_flags(flags);
841        self.config.as_mut().registers.enable_interrupts(flags);
842    }
843
844    /// Disable interrupts for the specified flags.
845    ///
846    /// Note that only the flags pertinent to `Self`'s [`Capability`]
847    /// will be cleared. The other flags will be **SILENTLY IGNORED**
848    ///
849    /// * Available flags for [`Receive`] capability: `RXC`, `RXS`, `RXBRK` and
850    ///   `ERROR`
851    /// * Available flags for [`Transmit`] capability: `DRE` and `TXC`.
852    ///   **Note**: The `CTSIC` interrupt can only be disabled if a `CTS` Pad
853    ///   was specified in the [`Config`] via the
854    ///   [`disable_ctsic`](Uart::disable_ctsic) method.
855    /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
856    ///   all flags available.
857    #[inline]
858    pub fn disable_interrupts(&mut self, flags: Flags) {
859        // Remove flags not pertinent to Self's Capability
860        let flags = Self::capability_flags(flags);
861        self.config.as_mut().registers.disable_interrupts(flags);
862    }
863
864    /// Read the status flags
865    #[inline]
866    pub fn read_status(&self) -> Status {
867        self.config.as_ref().registers.read_status()
868    }
869
870    /// Clear the status flags
871    ///
872    /// Note that only the status flags pertinent to `Self`'s [`Capability`]
873    /// will be cleared. The other stattus flags will be **SILENTLY IGNORED**.
874    ///
875    /// * Available status flags for [`Receive`] capability: `PERR`, `FERR`,
876    ///   `BUFOVF`, `ISF` and `COLL`
877    /// * [`Transmit`]-only [`Uart`]s have no clearable status flags.
878    /// * Since [`Duplex`] [`Uart`]s are [`Receive`] + [`Transmit`] they have
879    ///   all status flags available.
880    #[inline]
881    pub fn clear_status(&mut self, status: Status) {
882        // Remove status flags not pertinent to Self's Capability
883        let flags = Self::capability_status(status);
884        self.config.as_mut().registers.clear_status(flags);
885    }
886
887    #[inline]
888    pub(super) fn _reconfigure<F>(&mut self, update: F)
889    where
890        F: FnOnce(&mut SpecificConfig<C>),
891    {
892        self.config.as_mut().registers.enable_peripheral(false);
893        update(self.config.as_mut());
894        self.config.as_mut().registers.enable_peripheral(true);
895    }
896}
897
898impl<C, D, R, T> Uart<C, D, R, T>
899where
900    C: ValidConfig,
901    <C::Pads as PadSet>::Cts: SomePad,
902    D: Transmit,
903{
904    /// Clear the `CTSIC` interrupt flag
905    #[inline]
906    pub fn clear_ctsic(&mut self) {
907        let bit = CTSIC;
908        self.config
909            .as_mut()
910            .registers
911            .clear_flags(Flags::from_bits_retain(bit));
912    }
913
914    /// Enable the `CTSIC` interrupt
915    #[inline]
916    pub fn enable_ctsic(&mut self) {
917        let bit = CTSIC;
918        self.config
919            .as_mut()
920            .registers
921            .enable_interrupts(Flags::from_bits_retain(bit));
922    }
923
924    /// Disable the `CTSIC` interrupt
925    #[inline]
926    pub fn disable_ctsic(&mut self) {
927        let bit = CTSIC;
928        self.config
929            .as_mut()
930            .registers
931            .disable_interrupts(Flags::from_bits_retain(bit));
932    }
933}
934
935impl<C, D, R, T> Uart<C, D, R, T>
936where
937    C: ValidConfig,
938    D: Simplex,
939{
940    /// Disable the UART peripheral and return the underlying [`Config`]
941    #[inline]
942    pub fn disable(self) -> C {
943        let mut config = self.config;
944        config.as_mut().registers.disable();
945        config
946    }
947
948    /// Reconfigure the UART.
949    ///
950    /// Calling this method will temporarily disable the SERCOM peripheral, as
951    /// some registers are enable-protected. This may interrupt any ongoing
952    /// transactions.
953    ///
954    /// ```
955    /// use atsamd_hal::sercom::uart::{BaudMode, Oversampling, Uart};
956    /// uart.reconfigure(|c| c.set_run_in_standby(false));
957    /// ```
958    #[inline]
959    pub fn reconfigure<U>(&mut self, update: U)
960    where
961        U: FnOnce(&mut SpecificConfig<C>),
962    {
963        self._reconfigure(update);
964    }
965}
966
967#[cfg(feature = "dma")]
968impl<C, D, T> Uart<C, D, NoneT, T>
969where
970    C: ValidConfig,
971    D: Capability,
972{
973    /// Attach a DMA channel to this [`Uart`] for RX transactions. Its
974    /// [`Read`](embedded_io::Read) implementation will use DMA to
975    /// carry out its transactions.
976    pub fn with_rx_channel<R: crate::dmac::AnyChannel<Status = crate::dmac::Ready>>(
977        self,
978        rx_channel: R,
979    ) -> Uart<C, D, R, T> {
980        Uart {
981            config: self.config,
982            capability: self.capability,
983            tx_channel: self.tx_channel,
984            rx_channel,
985        }
986    }
987}
988
989#[cfg(feature = "dma")]
990impl<C, D, R> Uart<C, D, R, NoneT>
991where
992    C: ValidConfig,
993    D: Capability,
994{
995    /// Attach a DMA channel to this [`Uart`] for TX transactions. Its
996    /// [`Write`](embedded_io::Write) implementation will use DMA to
997    /// carry out its transactions.
998    pub fn with_tx_channel<T: crate::dmac::AnyChannel<Status = crate::dmac::Ready>>(
999        self,
1000        tx_channel: T,
1001    ) -> Uart<C, D, R, T> {
1002        Uart {
1003            config: self.config,
1004            capability: self.capability,
1005            rx_channel: self.rx_channel,
1006            tx_channel,
1007        }
1008    }
1009}
1010
1011#[cfg(feature = "dma")]
1012impl<C, D, R, T, S> Uart<C, D, R, T>
1013where
1014    C: ValidConfig,
1015    D: Capability,
1016    R: crate::dmac::AnyChannel<Status = S>,
1017    S: crate::dmac::ReadyChannel,
1018{
1019    /// Reclaim the RX DMA channel. Subsequent RX operations will no longer use
1020    /// DMA.
1021    pub fn take_rx_channel(self) -> (Uart<C, D, NoneT, T>, R) {
1022        (
1023            Uart {
1024                config: self.config,
1025                capability: self.capability,
1026                tx_channel: self.tx_channel,
1027                rx_channel: NoneT,
1028            },
1029            self.rx_channel,
1030        )
1031    }
1032}
1033
1034#[cfg(feature = "dma")]
1035impl<C, D, R, T, S> Uart<C, D, R, T>
1036where
1037    C: ValidConfig,
1038    D: Capability,
1039    T: crate::dmac::AnyChannel<Status = S>,
1040    S: crate::dmac::ReadyChannel,
1041{
1042    /// Reclaim the TX DMA channel. Subsequent TX operations will no longer use
1043    /// DMA.
1044    pub fn take_tx_channel(self) -> (Uart<C, D, R, NoneT>, T) {
1045        (
1046            Uart {
1047                config: self.config,
1048                capability: self.capability,
1049                rx_channel: self.rx_channel,
1050                tx_channel: NoneT,
1051            },
1052            self.tx_channel,
1053        )
1054    }
1055}
1056
1057impl<C, R, T> Uart<C, Duplex, R, T>
1058where
1059    C: ValidConfig,
1060{
1061    /// Split the [`Uart`] into [`RxDuplex`] and [`TxDuplex`] halves
1062    #[allow(clippy::type_complexity)]
1063    #[inline]
1064    pub fn split(self) -> (Uart<C, RxDuplex, R, NoneT>, Uart<C, TxDuplex, NoneT, T>) {
1065        let config = unsafe { core::ptr::read(&self.config) };
1066        (
1067            Uart {
1068                config: self.config,
1069                capability: PhantomData,
1070                rx_channel: self.rx_channel,
1071                tx_channel: NoneT,
1072            },
1073            Uart {
1074                config,
1075                capability: PhantomData,
1076                rx_channel: NoneT,
1077                tx_channel: self.tx_channel,
1078            },
1079        )
1080    }
1081
1082    /// Disable the UART peripheral and return the underlying [`Config`]
1083    #[inline]
1084    pub fn disable(self) -> C {
1085        let mut config = self.config;
1086        config.as_mut().registers.disable();
1087        config
1088    }
1089
1090    /// Update the UART [`Config`]uration.
1091    ///
1092    /// Calling this method will temporarily disable the SERCOM peripheral, as
1093    /// some registers are enable-protected. This may interrupt any ongoing
1094    /// transactions.
1095    ///
1096    /// ```
1097    /// use atsamd_hal::sercom::uart::{BaudMode, Oversampling, Uart};
1098    /// uart.reconfigure(|c| c.set_run_in_standby(false));
1099    /// ```
1100    #[inline]
1101    pub fn reconfigure<F>(&mut self, update: F)
1102    where
1103        F: FnOnce(&mut SpecificConfig<C>),
1104    {
1105        self._reconfigure(update);
1106    }
1107
1108    /// Join [`RxDuplex`] and [`TxDuplex`] halves back into a full `Uart<C,
1109    /// Duplex>`
1110    pub fn join(rx: Uart<C, RxDuplex, R, NoneT>, tx: Uart<C, TxDuplex, NoneT, T>) -> Self {
1111        Self {
1112            config: rx.config,
1113            capability: PhantomData,
1114            rx_channel: rx.rx_channel,
1115            tx_channel: tx.tx_channel,
1116        }
1117    }
1118}
1119
1120impl<C: ValidConfig, R, T> AsMut<Uart<C, Duplex, R, T>>
1121    for (
1122        &mut Uart<C, RxDuplex, R, NoneT>,
1123        &mut Uart<C, TxDuplex, NoneT, T>,
1124    )
1125{
1126    #[inline]
1127    fn as_mut(&mut self) -> &mut Uart<C, Duplex, R, T> {
1128        // SAFETY: Pointer casting &mut Uart<C, RxDuplex> into &mut
1129        // Uart<C, Duplex> should be safe as long as RxDuplex, TxDuplex, R and T are all
1130        // zero-sized types
1131        unsafe { &mut *(self.0 as *mut _ as *mut Uart<C, Duplex, R, T>) }
1132    }
1133}
1134
1135impl<C, D> AsRef<SpecificConfig<C>> for Uart<C, D>
1136where
1137    C: ValidConfig,
1138    D: Capability,
1139{
1140    #[inline]
1141    fn as_ref(&self) -> &SpecificConfig<C> {
1142        self.config.as_ref()
1143    }
1144}
1145
1146//=============================================================================
1147// Rx/Tx specific functionality
1148//=============================================================================
1149
1150impl<C, D, R, T> Uart<C, D, R, T>
1151where
1152    C: ValidConfig,
1153    D: Receive,
1154    DataReg: AsPrimitive<C::Word>,
1155{
1156    /// Read from the DATA register
1157    ///
1158    /// # Safety
1159    ///
1160    /// Reading from the data register directly is `unsafe`, because it will
1161    /// clear the RXC flag, which could break assumptions made elsewhere in
1162    /// this module.
1163    #[inline]
1164    pub unsafe fn read_data(&mut self) -> DataReg {
1165        self.config.as_mut().registers.read_data()
1166    }
1167
1168    /// Read the status register and convert into a [`Result`]
1169    /// containing the corresponding [`Flags`] or [`Error`]
1170    #[inline]
1171    fn read_flags_errors(&self) -> Result<Flags, Error> {
1172        self.read_status().check_bus_error()?;
1173        Ok(self.read_flags())
1174    }
1175
1176    /// Flush the RX buffer and clear RX errors.
1177    ///
1178    /// **Note**: The datasheet states that disabling the receiver (RXEN) clears
1179    /// the RX buffer, and clears the BUFOVF, PERR and FERR bits.
1180    /// However, in practice, it seems like BUFOVF errors still pop
1181    /// up after a disable/enable cycle of the receiver, then immediately begin
1182    /// reading bytes from the DATA register. Instead, this method uses a
1183    /// workaround, which reads a few bytes to clear the RX buffer (3 bytes
1184    /// seems to be the trick), then manually clear the error bits.
1185    #[inline]
1186    pub fn flush_rx_buffer(&mut self) {
1187        // TODO Is this a hardware bug???
1188
1189        // usart.ctrlb.modify(|_, w| w.rxen().clear_bit());
1190        // while usart.syncbusy.read().ctrlb().bit() ||
1191        // usart.ctrlb.read().rxen().bit_is_set() {}
1192
1193        // usart.ctrlb.modify(|_, w| w.rxen().set_bit());
1194        // while usart.syncbusy.read().ctrlb().bit() ||
1195        // usart.ctrlb.read().rxen().bit_is_clear() {}
1196
1197        for _ in 0..=2 {
1198            let _data = unsafe { self.config.as_mut().registers.read_data() };
1199        }
1200
1201        // Clear all errors
1202        self.clear_status(
1203            Status::BUFOVF | Status::FERR | Status::PERR | Status::ISF | Status::COLL,
1204        );
1205    }
1206}
1207
1208impl<C, D, R, T> Uart<C, D, R, T>
1209where
1210    C: ValidConfig,
1211    D: Transmit,
1212{
1213    /// Write to the DATA register
1214    ///
1215    /// # Safety
1216    ///
1217    /// Writing to the data register directly is `unsafe`, because it will clear
1218    /// the DRE flag, which could break assumptions made elsewhere in this
1219    /// module.
1220    #[inline]
1221    pub unsafe fn write_data(&mut self, data: DataReg) {
1222        self.config.as_mut().registers.write_data(data);
1223    }
1224}