1use 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
22unsafe impl<S: Sercom> Sync for Registers<S> {}
25
26impl<S: Sercom> Registers<S> {
27    #[inline]
29    pub(super) fn new(sercom: S) -> Self {
30        Self { sercom }
31    }
32
33    #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
35    #[inline]
36    fn usart(&self) -> &pac::sercom0::Usart {
37        self.sercom.usart()
38    }
39
40    #[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    pub(super) fn data_ptr<T>(&self) -> *mut T {
51        self.usart().data().as_ptr() as *mut _
52    }
53
54    #[inline]
56    pub(super) fn free(self) -> S {
57        self.sercom
58    }
59
60    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[inline]
130    pub(super) fn set_parity(&mut self, parity: Parity) {
131        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    #[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    #[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    #[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    #[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    #[inline]
200    pub(super) fn get_start_of_frame_detection(&self) -> bool {
201        self.usart().ctrlb().read().sfde().bit()
202    }
203
204    #[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    #[inline]
215    pub(super) fn get_collision_detection(&self) -> bool {
216        self.usart().ctrlb().read().colden().bit()
217    }
218
219    #[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    #[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    #[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    #[inline]
303    pub(super) fn get_immediate_overflow_notification(&self) -> bool {
304        self.usart().ctrla().read().ibon().bit()
305    }
306
307    #[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    #[inline]
318    pub(super) fn get_run_in_standby(&self) -> bool {
319        self.usart().ctrla().read().runstdby().bit()
320    }
321
322    #[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    #[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    #[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    #[inline]
360    pub(super) fn read_flags(&self) -> Flags {
361        Flags::from_bits_truncate(self.usart().intflag().read().bits())
362    }
363
364    #[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    #[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    #[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    #[inline]
390    pub(super) fn read_status(&self) -> Status {
391        Status::from_bits_truncate(self.usart().status().read().bits())
392    }
393
394    #[inline]
396    pub(super) unsafe fn read_data(&mut self) -> super::DataReg {
397        self.usart().data().read().data().bits()
398    }
399
400    #[inline]
402    pub(super) unsafe fn write_data(&mut self, data: super::DataReg) {
403        self.usart()
404            .data()
405            .write(|w| unsafe { w.data().bits(data) })
406    }
407
408    #[inline]
412    pub(super) fn enable(&mut self, rxen: bool, txen: bool) {
413        let usart = self.usart();
414
415        if rxen {
417            usart.ctrlb().modify(|_, w| w.rxen().set_bit());
418            while usart.syncbusy().read().ctrlb().bit_is_set() {}
419        }
420
421        if txen {
423            usart.ctrlb().modify(|_, w| w.txen().set_bit());
424            while usart.syncbusy().read().ctrlb().bit_is_set() {}
425        }
426
427        self.enable_peripheral(true);
429    }
430
431    #[inline]
432    pub(super) fn disable(&mut self) {
433        let usart = self.usart();
434
435        usart.ctrlb().modify(|_, w| w.rxen().clear_bit());
437        while usart.syncbusy().read().ctrlb().bit_is_set() {}
438
439        usart.ctrlb().modify(|_, w| w.txen().clear_bit());
441        while usart.syncbusy().read().ctrlb().bit_is_set() {}
442
443        self.enable_peripheral(false);
444    }
445
446    pub(super) fn enable_peripheral(&mut self, enable: bool) {
449        self.usart().ctrla().modify(|_, w| w.enable().bit(enable));
450        while self.usart().syncbusy().read().enable().bit_is_set() {}
451    }
452}
453
454#[inline]
457fn calculate_baud_asynchronous_arithm(baudrate: u32, clk_freq: u32, n_samples: u8) -> u16 {
458    const SHIFT: u8 = 32;
459    let sample_rate = (n_samples as u64 * baudrate as u64) << SHIFT;
460    let ratio = sample_rate / clk_freq as u64;
461    let scale = (1u64 << SHIFT) - ratio;
462    let baud_calculated = (65536u64 * scale) >> SHIFT;
463    baud_calculated as u16
464}
465
466#[inline]
469fn calculate_baud_asynchronous_fractional(
470    baudrate: u32,
471    clk_freq: u32,
472    n_samples: u8,
473) -> (u16, u8) {
474    let baud_mult = (clk_freq * 8) / (n_samples as u32 * baudrate);
475    ((baud_mult / 8) as u16, (baud_mult % 8) as u8)
476}