atsamd_hal/sercom/uart/
config.rs

1//! UART [`Config`] definition and implementation\
2
3use atsamd_hal_macros::hal_cfg;
4
5use super::{
6    BaudMode, BitOrder, Capability, CharSize, CharSizeEnum, DataReg, DynCharSize, EightBit,
7    FixedCharSize, Parity, Registers, StopBits, Uart, ValidConfig, ValidPads,
8};
9use crate::{
10    pac,
11    sercom::Sercom,
12    time::Hertz,
13    typelevel::{Is, NoneT, Sealed},
14};
15use core::marker::PhantomData;
16use num_traits::{AsPrimitive, PrimInt};
17
18//=============================================================================
19// Config
20//=============================================================================
21
22/// A configurable, disabled UART peripheral
23///
24/// This `struct` represents a configurable UART peripheral in its disabled
25/// state. It is generic over the set of [`Pads`] and [`CharSize`].
26/// Upon creation, the [`Config`] takes ownership of the
27/// [`Sercom`] and resets it, returning it configured as an UART peripheral
28/// with a default configuration:
29///
30/// * [`EightBit`]
31/// * No parity
32/// * One stop bit
33/// * LSB-first
34///
35/// [`Config`] uses a builder-pattern API to configure the peripheral,
36/// culminating in a call to [`enable`], which consumes the [`Config`] and
37/// returns enabled [`Uart`]. The [`enable`] method is
38/// restricted to [`ValidConfig`]s.
39///
40/// [`enable`]: Config::enable
41/// [`Pads`]: super::Pads
42pub struct Config<P, C = EightBit>
43where
44    P: ValidPads,
45    C: CharSize,
46{
47    pub(super) registers: Registers<P::Sercom>,
48    pads: P,
49    chsize: PhantomData<C>,
50    freq: Hertz,
51}
52
53/// Clock type needed to create a new [`Config`]. [`Pm`](pac::Pm) for thumbv6m
54/// targets.
55#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
56pub type Clock = pac::Pm;
57
58/// Clock type needed to create a new [`Config`]. [`Mclk`](pac::Mclk) for
59/// thumbv7em targets.
60#[hal_cfg("sercom0-d5x")]
61pub type Clock = pac::Mclk;
62
63impl<P: ValidPads> Config<P> {
64    /// Create a new [`Config`] in the default configuration
65    ///
66    /// This function will enable the corresponding APB clock, reset the
67    /// [`Sercom`] peripheral, and return a [`Config`] in the default
68    /// configuration:
69    ///
70    /// * [`EightBit`] [`CharSize`]
71    /// * No parity
72    /// * One stop bit
73    /// * LSB-first
74    ///
75    /// [`Config`] takes ownership of the [`Sercom`] and [`Pads`](super::Pads).
76    ///
77    /// Users must configure GCLK manually. The `freq` parameter represents the
78    /// GCLK frequency for this [`Sercom`] instance.
79    #[inline]
80    pub fn new(clk: &Clock, mut sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
81        sercom.enable_apb_clock(clk);
82        Self::default(sercom, pads, freq).bit_order(BitOrder::LsbFirst)
83    }
84
85    /// Create a new [`Config`] in the default configuration
86    #[inline]
87    fn default(sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
88        let mut registers = Registers::new(sercom);
89        registers.swrst();
90
91        // Enable internal clock mode
92        registers.configure_mode();
93        registers.configure_pads(P::RXPO, P::TXPO);
94        registers.set_char_size(EightBit::SIZE);
95
96        Self {
97            registers,
98            pads,
99            chsize: PhantomData,
100            freq: freq.into(),
101        }
102    }
103}
104
105impl<P, C> Config<P, C>
106where
107    P: ValidPads,
108    C: CharSize,
109{
110    /// Change the [`Config`] [`CharSize`]
111    #[inline]
112    fn change<C2>(self) -> Config<P, C2>
113    where
114        C2: CharSize,
115    {
116        Config {
117            registers: self.registers,
118            pads: self.pads,
119            chsize: PhantomData,
120            freq: self.freq,
121        }
122    }
123
124    /// Trigger the [`Sercom`]'s SWRST and return a [`Config`] in the
125    /// default configuration.
126    #[inline]
127    pub fn reset(self) -> Config<P> {
128        Config::default(self.registers.free(), self.pads, self.freq)
129    }
130
131    /// Consume the [`Config`], reset the peripheral, and return the [`Sercom`]
132    /// and [`Pads`](super::Pads)
133    #[inline]
134    pub fn free(mut self) -> (P::Sercom, P) {
135        self.registers.swrst();
136        (self.registers.free(), self.pads)
137    }
138
139    /// Change the [`CharSize`].
140    #[inline]
141    pub fn char_size<C2: FixedCharSize>(mut self) -> Config<P, C2> {
142        self.registers.set_char_size(C2::SIZE);
143        self.change()
144    }
145
146    /// Change the [`CharSize`] to [`DynCharSize`]. The UART's character
147    /// size will be changed to the default [`CharSizeEnum::EightBit`], and can
148    /// then be changed dynamically on an enabled [`Uart`] without changing
149    /// the underlying [`Config`]'s type through the
150    /// [`reconfigure`](Uart::reconfigure) method.
151    #[inline]
152    pub fn dyn_char_size(mut self) -> Config<P, DynCharSize> {
153        self.registers.set_char_size(CharSizeEnum::EightBit);
154        self.change()
155    }
156
157    /// Change the bit order of transmission (builder pattern version)
158    #[inline]
159    pub fn bit_order(mut self, bit_order: BitOrder) -> Self {
160        self.set_bit_order(bit_order);
161        self
162    }
163
164    /// Change the bit order of transmission (setter version)
165    #[inline]
166    pub fn set_bit_order(&mut self, bit_order: BitOrder) {
167        self.registers.set_bit_order(bit_order);
168    }
169
170    /// Get the current bit order
171    #[inline]
172    pub fn get_bit_order(&self) -> BitOrder {
173        self.registers.get_bit_order()
174    }
175
176    /// Change the parity setting (builder pattern version)
177    #[inline]
178    pub fn parity(mut self, parity: Parity) -> Self {
179        self.set_parity(parity);
180        self
181    }
182
183    /// Change the parity setting (setter version)
184    #[inline]
185    pub fn set_parity(&mut self, parity: Parity) {
186        self.registers.set_parity(parity);
187    }
188
189    /// Get the current parity setting
190    #[inline]
191    pub fn get_parity(&self) -> Parity {
192        self.registers.get_parity()
193    }
194
195    /// Change the stop bit setting (builder pattern version)
196    #[inline]
197    pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
198        self.set_stop_bits(stop_bits);
199        self
200    }
201
202    /// Change the stop bit setting (setter version)
203    #[inline]
204    pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
205        self.registers.set_stop_bits(stop_bits);
206    }
207
208    /// Get the current stop bit setting
209    #[inline]
210    pub fn get_stop_bits(&self) -> StopBits {
211        self.registers.get_stop_bits()
212    }
213
214    /// Enable or disable the start of frame detector (builder pattern version)
215    ///
216    /// When set, the UART will generate interrupts for
217    /// RXC and/or RXS if these interrupt flags have been enabled.
218    #[inline]
219    pub fn start_of_frame_detection(mut self, enabled: bool) -> Self {
220        self.set_start_of_frame_detection(enabled);
221        self
222    }
223
224    /// Enable or disable the start of frame detector (setter version)
225    ///
226    /// When set, the UART will generate interrupts for
227    /// RXC and/or RXS if these interrupt flags have been enabled.
228    #[inline]
229    pub fn set_start_of_frame_detection(&mut self, enabled: bool) {
230        self.registers.set_start_of_frame_detection(enabled);
231    }
232
233    /// Get the current SOF detector setting
234    #[inline]
235    pub fn get_start_of_frame_detection(&self) -> bool {
236        self.registers.get_start_of_frame_detection()
237    }
238
239    /// Enable or disable the collision detector (builder pattern version)
240    ///
241    /// When set, the UART will detect collisions and update the
242    /// corresponding flag in the STATUS register.
243    #[inline]
244    pub fn collision_detection(mut self, enabled: bool) -> Self {
245        self.set_collision_detection(enabled);
246        self
247    }
248
249    /// Enable or disable the collision detector (setter version)
250    ///
251    /// When set, the UART will detect collisions and update the
252    /// corresponding flag in the STATUS register.
253    #[inline]
254    pub fn set_collision_detection(&mut self, enabled: bool) {
255        self.registers.set_collision_detection(enabled);
256    }
257
258    /// Get the current collision detector setting
259    #[inline]
260    pub fn get_collision_detection(&self) -> bool {
261        self.registers.get_collision_detection()
262    }
263
264    /// Set the baud rate (builder pattern version)
265    ///
266    /// This function will calculate the best BAUD register setting based on the
267    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
268    /// GCLK frequency/oversampling. Values outside this range will saturate at
269    /// the maximum supported baud rate.
270    ///
271    /// Note that 3x oversampling is not supported.
272    #[inline]
273    pub fn baud(mut self, baud: Hertz, mode: BaudMode) -> Self {
274        self.set_baud(baud, mode);
275        self
276    }
277
278    /// Set the baud rate (setter version)
279    ///
280    /// This function will calculate the best BAUD register setting based on the
281    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
282    /// GCLK frequency/oversampling. Values outside this range will saturate at
283    /// the maximum supported baud rate.
284    ///
285    /// Note that 3x oversampling is not supported.
286    #[inline]
287    pub fn set_baud(&mut self, baud: Hertz, mode: BaudMode) {
288        self.registers.set_baud(self.freq, baud, mode);
289    }
290
291    /// Get the contents of the `BAUD` register and the current baud mode. Note
292    /// that only the CONTENTS of `BAUD` are returned, and not the actual baud
293    /// rate. Refer to the datasheet to convert the `BAUD` register contents
294    /// into a baud rate.
295    #[inline]
296    pub fn get_baud(&self) -> (u16, BaudMode) {
297        self.registers.get_baud()
298    }
299
300    /// Control the buffer overflow notification (builder pattern version)
301    ///
302    /// If set to true, an [`Error::Overflow`](super::Error::Overflow) will be
303    /// issued as soon as an overflow occurs. Otherwise, it will not be
304    /// issued until its place within the data stream.
305    #[inline]
306    pub fn immediate_overflow_notification(mut self, set: bool) -> Self {
307        self.set_immediate_overflow_notification(set);
308        self
309    }
310
311    /// Control the buffer overflow notification (setter version)
312    ///
313    /// If set to true, an [`Error::Overflow`](super::Error::Overflow) will be
314    /// issued as soon as an overflow occurs. Otherwise, it will not be
315    /// issued until its place within the data stream.
316    #[inline]
317    pub fn set_immediate_overflow_notification(&mut self, set: bool) {
318        self.registers.set_immediate_overflow_notification(set);
319    }
320
321    /// Get the current immediate overflow notification setting
322    #[inline]
323    pub fn get_immediate_overflow_notification(&self) -> bool {
324        self.registers.get_immediate_overflow_notification()
325    }
326
327    /// Run in standby mode (builder pattern version)
328    ///
329    /// When set, the UART peripheral will run in standby mode. See the
330    /// datasheet for more details.
331    #[inline]
332    pub fn run_in_standby(mut self, set: bool) -> Self {
333        self.set_run_in_standby(set);
334        self
335    }
336
337    /// Run in standby mode (setter version)
338    ///
339    /// When set, the UART peripheral will run in standby mode. See the
340    /// datasheet for more details.
341    #[inline]
342    pub fn set_run_in_standby(&mut self, set: bool) {
343        self.registers.set_run_in_standby(set);
344    }
345
346    /// Get the current run in standby mode
347    #[inline]
348    pub fn get_run_in_standby(&self) -> bool {
349        self.registers.get_run_in_standby()
350    }
351
352    /// Enable or disable IrDA encoding (builder pattern version)
353    ///
354    /// The pulse length controls the minimum pulse length that is required for
355    /// a pulse to be accepted by the IrDA receiver with regards to the
356    /// serial engine clock period. See datasheet for more information.
357    #[inline]
358    pub fn irda_encoding(mut self, pulse_length: Option<u8>) -> Self {
359        self.set_irda_encoding(pulse_length);
360        self
361    }
362
363    /// Enable or disable IrDA encoding (setter version)
364    ///
365    /// The pulse length controls the minimum pulse length that is required for
366    /// a pulse to be accepted by the IrDA receiver with regards to the
367    /// serial engine clock period. See datasheet for more information.
368    #[inline]
369    pub fn set_irda_encoding(&mut self, pulse_length: Option<u8>) {
370        self.registers.set_irda_encoding(pulse_length);
371    }
372
373    /// Get the current IrDA encoding setting. The return type is the pulse
374    /// length wrapped in an [`Option`].
375    #[inline]
376    pub fn get_irda_encoding(&self) -> Option<u8> {
377        self.registers.get_irda_encoding()
378    }
379}
380
381impl<P: ValidPads> Config<P, DynCharSize> {
382    /// Dynamically change the character size
383    #[inline]
384    pub fn set_dyn_char_size(&mut self, char_size: CharSizeEnum) {
385        self.registers.set_char_size(char_size);
386    }
387
388    /// Get the current character size setting
389    pub fn get_dyn_char_size(&self) -> CharSizeEnum {
390        self.registers.get_char_size()
391    }
392}
393
394impl<P, C> Config<P, C>
395where
396    P: ValidPads,
397    C: CharSize,
398    Self: ValidConfig,
399{
400    /// Enable the UART peripheral and return a [`Uart`] struct.
401    ///
402    /// UART transactions are not possible until the peripheral is enabled.
403    /// This method is limited to [`ValidConfig`]s
404    #[inline]
405    pub fn enable(mut self) -> Uart<Self, P::Capability> {
406        self.registers
407            .enable(P::Capability::RXEN, P::Capability::TXEN);
408        Uart {
409            config: self,
410            capability: PhantomData,
411            rx_channel: NoneT,
412            tx_channel: NoneT,
413        }
414    }
415}
416
417//=============================================================================
418// AnyConfig
419//=============================================================================
420
421/// Type class for all possible [`Config`] types
422///
423/// This trait uses the [`AnyKind`] trait pattern to create a [type class] for
424/// [`Config`] types. See the `AnyKind` documentation for more details on the
425/// pattern.
426///
427/// In addition to the normal, `AnyKind` associated types. This trait also
428/// copies the [`Sercom`] and `Word` types, to make it easier to apply
429/// bounds to these types at the next level of abstraction.
430///
431/// [`AnyKind`]: crate::typelevel#anykind-trait-patter
432pub trait AnyConfig: Sealed + Is<Type = SpecificConfig<Self>> {
433    type Sercom: Sercom;
434    type Pads: ValidPads<Sercom = Self::Sercom>;
435    type Word: 'static + PrimInt + AsPrimitive<DataReg>;
436    type CharSize: CharSize<Word = Self::Word>;
437}
438
439/// Type alias to recover the specific [`Config`] type from an implementation of
440/// [`AnyConfig`]
441pub type SpecificConfig<C> = Config<<C as AnyConfig>::Pads, <C as AnyConfig>::CharSize>;
442
443/// Type alias to recover the specific [`Sercom`] type from an implementation of
444/// [`AnyConfig`]
445pub type ConfigSercom<C> = <C as AnyConfig>::Sercom;
446
447impl<P, C> AsRef<Self> for Config<P, C>
448where
449    P: ValidPads,
450    C: CharSize,
451{
452    #[inline]
453    fn as_ref(&self) -> &Self {
454        self
455    }
456}
457
458impl<P, C> AsMut<Self> for Config<P, C>
459where
460    P: ValidPads,
461    C: CharSize,
462{
463    #[inline]
464    fn as_mut(&mut self) -> &mut Self {
465        self
466    }
467}
468
469impl<P, C> Sealed for Config<P, C>
470where
471    P: ValidPads,
472    C: CharSize,
473{
474}
475
476impl<P, C> AnyConfig for Config<P, C>
477where
478    P: ValidPads,
479    C: CharSize,
480{
481    type Sercom = P::Sercom;
482    type Word = C::Word;
483    type Pads = P;
484    type CharSize = C;
485}