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}