atsamd_hal/sercom/uart/
reg.rs

1//! Register-level access to UART configuration
2
3use atsamd_hal_macros::hal_cfg;
4
5use super::{BaudMode, BitOrder, CharSizeEnum, Flags, Oversampling, Parity, Status, StopBits};
6
7use crate::pac;
8use crate::sercom::Sercom;
9
10#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
11use pac::sercom0::usart::ctrla::Modeselect;
12
13#[hal_cfg("sercom0-d5x")]
14use pac::sercom0::usart_int::ctrla::Modeselect;
15
16use crate::time::Hertz;
17
18pub(super) struct Registers<S: Sercom> {
19    sercom: S,
20}
21
22// SAFETY: It is safe to implement Sync for Registers, because it erases the
23// interior mutability of the PAC SERCOM struct.
24unsafe impl<S: Sercom> Sync for Registers<S> {}
25
26impl<S: Sercom> Registers<S> {
27    /// Create a new `Registers` instance
28    #[inline]
29    pub(super) fn new(sercom: S) -> Self {
30        Self { sercom }
31    }
32
33    /// Helper function to access the underlying `USART` from the given `SERCOM`
34    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
35    #[inline]
36    fn usart(&self) -> &pac::sercom0::Usart {
37        self.sercom.usart()
38    }
39
40    /// Helper function to access the underlying `USART_INT` from the given
41    /// `SERCOM`
42    #[hal_cfg("sercom0-d5x")]
43    #[inline]
44    fn usart(&self) -> &pac::sercom0::UsartInt {
45        self.sercom.usart_int()
46    }
47
48    #[cfg(feature = "dma")]
49    /// Get a pointer to the `DATA` register
50    pub(super) fn data_ptr<T>(&self) -> *mut T {
51        self.usart().data().as_ptr() as *mut _
52    }
53
54    /// Free the `Registers` struct and return the underlying `Sercom` instance
55    #[inline]
56    pub(super) fn free(self) -> S {
57        self.sercom
58    }
59
60    /// Reset the SERCOM peripheral
61    #[inline]
62    pub(super) fn swrst(&mut self) {
63        self.usart().ctrla().write(|w| w.swrst().set_bit());
64        while self.usart().syncbusy().read().swrst().bit_is_set() {}
65    }
66
67    /// Configure the SERCOM to use internal clock mode
68    #[inline]
69    pub(super) fn configure_mode(&mut self) {
70        self.usart()
71            .ctrla()
72            .modify(|_, w| w.mode().variant(Modeselect::UsartIntClk));
73    }
74
75    /// Configure the `SERCOM`'s Pads according to RXPO and TXPO
76    #[inline]
77    pub(super) fn configure_pads(&mut self, rxpo: u8, txpo: u8) {
78        self.usart().ctrla().modify(|_, w| unsafe {
79            w.rxpo().bits(rxpo);
80            w.txpo().bits(txpo)
81        });
82    }
83
84    /// Configure the character size
85    #[inline]
86    pub(super) fn set_char_size(&mut self, size: CharSizeEnum) {
87        self.usart()
88            .ctrlb()
89            .modify(|_, w| unsafe { w.chsize().bits(size as u8) });
90    }
91
92    /// Get the current character size setting
93    #[inline]
94    pub(super) fn get_char_size(&self) -> CharSizeEnum {
95        let size = self.usart().ctrlb().read().chsize().bits();
96        match size {
97            0x5 => CharSizeEnum::FiveBit,
98            0x6 => CharSizeEnum::SixBit,
99            0x7 => CharSizeEnum::SevenBit,
100            0x0 => CharSizeEnum::EightBit,
101            0x1 => CharSizeEnum::NineBit,
102            _ => unreachable!(),
103        }
104    }
105
106    /// Change the bit order of transmission (MSB/LSB first)
107    #[inline]
108    pub(super) fn set_bit_order(&mut self, bit_order: BitOrder) {
109        let bits = match bit_order {
110            BitOrder::MsbFirst => false,
111            BitOrder::LsbFirst => true,
112        };
113
114        self.usart().ctrla().modify(|_, w| w.dord().bit(bits));
115    }
116
117    /// Get the current bit order
118    #[inline]
119    pub(super) fn get_bit_order(&self) -> BitOrder {
120        let bits = self.usart().ctrla().read().dord().bit();
121
122        match bits {
123            false => BitOrder::MsbFirst,
124            true => BitOrder::LsbFirst,
125        }
126    }
127
128    /// Change the parity setting
129    #[inline]
130    pub(super) fn set_parity(&mut self, parity: Parity) {
131        // Use only the first two available settings in the FORM field.
132        // Ignore auto-baud options.
133        let enabled = match parity {
134            Parity::None => false,
135            Parity::Odd => {
136                self.usart().ctrlb().modify(|_, w| w.pmode().bit(true));
137                true
138            }
139            Parity::Even => {
140                self.usart().ctrlb().modify(|_, w| w.pmode().bit(false));
141                true
142            }
143        };
144
145        self.usart()
146            .ctrla()
147            .modify(|_, w| unsafe { w.form().bits(enabled as u8) });
148    }
149
150    /// Get the current parity setting
151    #[inline]
152    pub(super) fn get_parity(&self) -> Parity {
153        let form = self.usart().ctrla().read().form().bits();
154        let enabled = form == 0x1 || form == 0x5;
155
156        if !enabled {
157            return Parity::None;
158        }
159
160        let pmode = self.usart().ctrlb().read().pmode().bit();
161
162        match pmode {
163            false => Parity::Even,
164            true => Parity::Odd,
165        }
166    }
167
168    /// Change the stop bit setting
169    #[inline]
170    pub(super) fn set_stop_bits(&mut self, stop_bits: StopBits) {
171        let bits = match stop_bits {
172            StopBits::OneBit => false,
173            StopBits::TwoBits => true,
174        };
175
176        self.usart().ctrlb().modify(|_, w| w.sbmode().bit(bits));
177    }
178
179    /// Get the current stop bit setting
180    #[inline]
181    pub(super) fn get_stop_bits(&self) -> StopBits {
182        let bits = self.usart().ctrlb().read().sbmode().bit();
183        match bits {
184            false => StopBits::OneBit,
185            true => StopBits::TwoBits,
186        }
187    }
188
189    /// Enable or disable the start of frame detector.
190    ///
191    /// When set, the UART will generate interrupts for
192    /// RXC and/or RXS if these interrupt flags have been enabled.
193    #[inline]
194    pub(super) fn set_start_of_frame_detection(&mut self, enabled: bool) {
195        self.usart().ctrlb().modify(|_, w| w.sfde().bit(enabled));
196    }
197
198    /// Get the current SOF detector setting
199    #[inline]
200    pub(super) fn get_start_of_frame_detection(&self) -> bool {
201        self.usart().ctrlb().read().sfde().bit()
202    }
203
204    /// Enable or disable the collision detector.
205    ///
206    /// When set, the UART will detect collisions and update the
207    /// corresponding flag in the STATUS register.
208    #[inline]
209    pub(super) fn set_collision_detection(&mut self, enabled: bool) {
210        self.usart().ctrlb().modify(|_, w| w.colden().bit(enabled));
211    }
212
213    /// Get the current collision detector setting
214    #[inline]
215    pub(super) fn get_collision_detection(&self) -> bool {
216        self.usart().ctrlb().read().colden().bit()
217    }
218
219    /// Set the baud rate
220    ///
221    /// This function will calculate the best BAUD register setting based on the
222    /// stored GCLK frequency and desired baud rate. The maximum baud rate is
223    /// GCLK frequency/oversampling. Values outside this range will saturate at
224    /// the maximum supported baud rate.
225    ///
226    /// Note that 3x oversampling is not supported.
227    #[inline]
228    pub(super) fn set_baud(&mut self, freq: Hertz, baud: Hertz, mode: BaudMode) {
229        use BaudMode::*;
230        use Oversampling::*;
231
232        let usart = self.usart();
233
234        let sampr = match mode {
235            Arithmetic(n) => match n {
236                Bits16 => 0,
237                Bits8 => 2,
238            },
239
240            Fractional(n) => match n {
241                Bits16 => 1,
242                Bits8 => 3,
243            },
244        };
245
246        usart
247            .ctrla()
248            .modify(|_, w| unsafe { w.sampr().bits(sampr) });
249
250        match mode {
251            BaudMode::Arithmetic(n) => {
252                let baud = calculate_baud_asynchronous_arithm(baud.to_Hz(), freq.to_Hz(), n as u8);
253                unsafe { usart.baud_usartfp_mode().write(|w| w.baud().bits(baud)) };
254            }
255
256            BaudMode::Fractional(n) => {
257                let (baud, frac) =
258                    calculate_baud_asynchronous_fractional(baud.to_Hz(), freq.to_Hz(), n as u8);
259                unsafe {
260                    usart.baud_frac_mode().write(|w| {
261                        w.fp().bits(frac);
262                        w.baud().bits(baud)
263                    });
264                }
265            }
266        };
267    }
268
269    /// Get the contents of the `BAUD` register and the current baud mode. Note
270    /// that only the CONTENTS of `BAUD` are returned, and not the actual baud
271    /// rate. Refer to the datasheet to convert the `BAUD` register contents
272    /// into a baud rate.
273    #[inline]
274    pub(super) fn get_baud(&self) -> (u16, BaudMode) {
275        use BaudMode::*;
276        use Oversampling::*;
277
278        let baud = self.usart().baud_usartfp_mode().read().bits();
279        let sampr = self.usart().ctrla().read().sampr().bits();
280        let mode = match sampr {
281            0 => Arithmetic(Bits16),
282            1 => Fractional(Bits16),
283            2 => Arithmetic(Bits8),
284            3 => Fractional(Bits8),
285            _ => unreachable!(),
286        };
287
288        (baud, mode)
289    }
290
291    /// Control the buffer overflow notification
292    ///
293    /// If set to true, an [`RxError::Overflow`] will be issued as soon as an
294    /// overflow occurs. Otherwise, it will not be issued until its place within
295    /// the data stream.
296    #[inline]
297    pub(super) fn set_immediate_overflow_notification(&mut self, set: bool) {
298        self.usart().ctrla().modify(|_, w| w.ibon().bit(set));
299    }
300
301    /// Get the current immediate overflow notification setting
302    #[inline]
303    pub(super) fn get_immediate_overflow_notification(&self) -> bool {
304        self.usart().ctrla().read().ibon().bit()
305    }
306
307    /// Run in standby mode
308    ///
309    /// When set, the UART peripheral will run in standby mode. See the
310    /// datasheet for more details.
311    #[inline]
312    pub(super) fn set_run_in_standby(&mut self, set: bool) {
313        self.usart().ctrla().modify(|_, w| w.runstdby().bit(set));
314    }
315
316    /// Get the current run in standby mode
317    #[inline]
318    pub(super) fn get_run_in_standby(&self) -> bool {
319        self.usart().ctrla().read().runstdby().bit()
320    }
321
322    /// Enable or disable IrDA encoding. The pulse length controls the minimum
323    // pulse length that is required for a pulse to be accepted by the IrDA
324    /// receiver with regards to the serial engine clock period.
325    /// See datasheet for more information.
326    #[inline]
327    pub(super) fn set_irda_encoding(&mut self, pulse_length: Option<u8>) {
328        match pulse_length {
329            Some(l) => {
330                self.usart().rxpl().write(|w| unsafe { w.rxpl().bits(l) });
331                self.usart().ctrlb().modify(|_, w| w.enc().bit(true));
332            }
333            None => {
334                self.usart().ctrlb().modify(|_, w| w.enc().bit(false));
335            }
336        }
337    }
338
339    /// Get the current IrDA encoding setting. The return type is the pulse
340    /// length wrapped in an [`Option`].
341    #[inline]
342    pub(super) fn get_irda_encoding(&self) -> Option<u8> {
343        if self.usart().ctrlb().read().enc().bit() {
344            Some(self.usart().rxpl().read().bits())
345        } else {
346            None
347        }
348    }
349
350    /// Clear specified interrupt flags
351    #[inline]
352    pub(super) fn clear_flags(&mut self, flags: Flags) {
353        self.usart()
354            .intflag()
355            .modify(|_, w| unsafe { w.bits(flags.bits()) });
356    }
357
358    /// Read interrupt flags
359    #[inline]
360    pub(super) fn read_flags(&self) -> Flags {
361        Flags::from_bits_truncate(self.usart().intflag().read().bits())
362    }
363
364    /// Enable specified interrupts
365    #[inline]
366    pub(super) fn enable_interrupts(&mut self, flags: Flags) {
367        self.usart()
368            .intenset()
369            .write(|w| unsafe { w.bits(flags.bits()) });
370    }
371
372    /// Disable specified interrupts
373    #[inline]
374    pub(super) fn disable_interrupts(&mut self, flags: Flags) {
375        self.usart()
376            .intenclr()
377            .write(|w| unsafe { w.bits(flags.bits()) });
378    }
379
380    /// Clear specified status flags
381    #[inline]
382    pub(super) fn clear_status(&mut self, status: Status) {
383        self.usart()
384            .status()
385            .modify(|_, w| unsafe { w.bits(status.bits()) });
386    }
387
388    /// Read status flags
389    #[inline]
390    pub(super) fn read_status(&self) -> Status {
391        Status::from_bits_truncate(self.usart().status().read().bits())
392    }
393
394    /// Read from the `DATA` register
395    #[inline]
396    pub(super) unsafe fn read_data(&mut self) -> super::DataReg {
397        self.usart().data().read().data().bits()
398    }
399
400    /// Write to the `DATA` register
401    #[inline]
402    pub(super) unsafe fn write_data(&mut self, data: super::DataReg) {
403        self.usart().data().write(|w| w.data().bits(data))
404    }
405
406    /// Enable the UART peripheral
407    ///
408    /// UART transactions are not possible until the peripheral is enabled.
409    #[inline]
410    pub(super) fn enable(&mut self, rxen: bool, txen: bool) {
411        let usart = self.usart();
412
413        // Enable RX
414        if rxen {
415            usart.ctrlb().modify(|_, w| w.rxen().set_bit());
416            while usart.syncbusy().read().ctrlb().bit_is_set() {}
417        }
418
419        // Enable TX
420        if txen {
421            usart.ctrlb().modify(|_, w| w.txen().set_bit());
422            while usart.syncbusy().read().ctrlb().bit_is_set() {}
423        }
424
425        // Globally enable peripheral
426        self.enable_peripheral(true);
427    }
428
429    #[inline]
430    pub(super) fn disable(&mut self) {
431        let usart = self.usart();
432
433        // Disable RX
434        usart.ctrlb().modify(|_, w| w.rxen().clear_bit());
435        while usart.syncbusy().read().ctrlb().bit_is_set() {}
436
437        // Disable TX
438        usart.ctrlb().modify(|_, w| w.txen().clear_bit());
439        while usart.syncbusy().read().ctrlb().bit_is_set() {}
440
441        self.enable_peripheral(false);
442    }
443
444    /// Enable or disable the SERCOM peripheral, and wait for the ENABLE bit to
445    /// synchronize.
446    pub(super) fn enable_peripheral(&mut self, enable: bool) {
447        self.usart().ctrla().modify(|_, w| w.enable().bit(enable));
448        while self.usart().syncbusy().read().enable().bit_is_set() {}
449    }
450}
451
452/// Calculate baudrate value using the asynchronous arithmetic method (Table
453/// 24-2)
454#[inline]
455fn calculate_baud_asynchronous_arithm(baudrate: u32, clk_freq: u32, n_samples: u8) -> u16 {
456    const SHIFT: u8 = 32;
457    let sample_rate = (n_samples as u64 * baudrate as u64) << SHIFT;
458    let ratio = sample_rate / clk_freq as u64;
459    let scale = (1u64 << SHIFT) - ratio;
460    let baud_calculated = (65536u64 * scale) >> SHIFT;
461    baud_calculated as u16
462}
463
464/// Calculate baudrate value using the asynchronous frational method (Table
465/// 24-2)
466#[inline]
467fn calculate_baud_asynchronous_fractional(
468    baudrate: u32,
469    clk_freq: u32,
470    n_samples: u8,
471) -> (u16, u8) {
472    let baud_mult = (clk_freq * 8) / (n_samples as u32 * baudrate);
473    ((baud_mult / 8) as u16, (baud_mult % 8) as u8)
474}