Skip to main content

atsam4_hal/
serial.rs

1extern crate nb;
2
3// device crate
4use {
5    crate::clock::{Enabled, Uart0Clock, Uart1Clock},
6    crate::gpio::{Pa10, Pa9, PfA},
7    crate::pac::{UART0, UART1},
8    core::marker::PhantomData,
9    hal::{serial::Read, serial::Write},
10    paste::paste,
11};
12
13#[cfg(feature = "atsam4s")]
14use crate::gpio::{Pb2, Pb3};
15
16#[cfg(any(feature = "atsam4e", feature = "atsam4n"))]
17use crate::gpio::{Pa5, Pa6, PfC};
18
19#[derive(Debug, defmt::Format)]
20pub enum Parity {
21    Even,
22    Odd,
23    Space,
24    Mark,
25}
26
27#[derive(Debug, defmt::Format)]
28pub enum CharacterLength {
29    FiveBits,
30    SixBits,
31    SevenBits,
32    EightBits,
33}
34
35#[derive(Debug, defmt::Format)]
36pub enum StopBits {
37    One,
38    OnePointFive,
39    Two,
40}
41
42#[derive(Debug, defmt::Format)]
43pub enum Error {
44    /// Buffer overrun
45    Overrun,
46    // omitted: other error variants
47}
48
49macro_rules! uarts {
50    (
51        $($PortType:ident: (
52            $UART:ident,
53            $Uart:ident,
54            $uart:ident,
55            $pin_rx:ty,
56            $pin_tx:ty
57        ),)+
58    ) => {
59        paste! {
60            $(
61                pub struct $PortType {
62                    uart: $UART,
63                    clock: PhantomData<[<$Uart Clock>]<Enabled>>,
64                    rx_pin: PhantomData<$pin_rx>,
65                    tx_pin: PhantomData<$pin_tx>,
66                }
67
68                impl $PortType {
69                    pub fn new (
70                        mut uart: $UART,
71                        clock: [<$Uart Clock>]<Enabled>,
72                        _rx_pin: $pin_rx,
73                        _tx_pin: $pin_tx,
74                        baud_rate: u32,
75                        parity: Option<Parity>,
76                    ) -> Self {
77                        Self::reset_and_disable(&mut uart);
78
79                        let clock_divisor:u32 = ((clock.frequency() / baud_rate) / 16).raw();
80                        if !(1..=65535).contains(&clock_divisor) {
81                            panic!("Unsupported baud_rate specified for serial device (cd = {})", clock_divisor);
82                        }
83
84                        // Configure the baud rate generator
85                        uart.brgr.write(|w| unsafe { w.bits(clock_divisor) });
86
87                        // Configure the mode
88                        uart.mr.write(|w| unsafe {
89                            // parity
90                            if let Some(parity) = parity {
91                                let p = match parity {
92                                    Parity::Even => 0,
93                                    Parity::Odd => 1,
94                                    Parity::Space => 2,
95                                    Parity::Mark => 3,
96                                };
97                                w.par().bits(p);
98                            }
99                            else {
100                                w.par().bits(4);  // No parity
101                            }
102
103                            w.chmode().bits(0) // Normal mode (not loopback)
104                        });
105
106                        Self::enable(&mut uart);
107
108                        $PortType {
109                            uart,
110                            clock: PhantomData,
111                            rx_pin: PhantomData,
112                            tx_pin: PhantomData,
113                        }
114                    }
115
116                    fn reset_and_disable(uart: &mut $UART) {
117                        unsafe { uart.cr.write_with_zero(|w| {
118                            w.rstrx().set_bit().rsttx().set_bit().rxdis().set_bit().txdis().set_bit()
119                        })};
120                    }
121
122                    fn enable(uart: &mut $UART) {
123                        unsafe {uart.cr.write_with_zero(|w| {
124                            w.rxen().set_bit().txen().set_bit()
125                        })};
126                    }
127
128                    pub fn write_string_blocking(&mut self, data: &str) {
129                        for c in data.chars() {
130                            loop {
131                                if let Err(_e) = self.write(c as u8) {
132                                    continue;
133                                }
134
135                                break;
136                            }
137                        }
138                    }
139                }
140
141                impl Read<u8> for $PortType {
142                    type Error = Error;
143
144                    fn read(&mut self) -> nb::Result<u8, Error> {
145                        // read the status register
146                        let isr = self.uart.sr.read();
147
148                        if isr.ovre().bit_is_set() {
149                            // Error: Buffer overrun
150                            Err(nb::Error::Other(Error::Overrun))
151                        }
152                        // omitted: checks for other errors
153                        else if isr.rxrdy().bit_is_set() {
154                            // Data available: read the data register
155                            Ok(self.uart.rhr.read().bits() as u8)
156                        } else {
157                            // No data available yet
158                            Err(nb::Error::WouldBlock)
159                        }
160                    }
161                }
162
163                impl Write<u8> for $PortType {
164                    type Error = Error;
165
166                    fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
167                        // read the status register
168                        let isr = self.uart.sr.read();
169
170                        // omitted: checks for other errors
171                        if isr.txrdy().bit_is_set() {
172                            unsafe { Ok(self.uart.thr.write_with_zero(|w| w.txchr().bits(byte) )) }
173                        } else {
174                            // No data available yet
175                            Err(nb::Error::WouldBlock)
176                        }
177                    }
178
179                    fn flush(&mut self) -> nb::Result<(), Error> {
180                        // No data available yet
181                        Err(nb::Error::WouldBlock)
182                    }
183                }
184            )+
185        }
186    }
187}
188
189#[cfg(any(feature = "atsam4e", feature = "atsam4n"))]
190uarts!(
191    Uart0: (UART0, Uart0, uart0, Pa9<PfA>, Pa10<PfA>),
192    Uart1: (UART1, Uart1, uart1, Pa5<PfC>, Pa6<PfC>),
193);
194
195#[cfg(feature = "atsam4s")]
196uarts!(
197    Uart0: (UART0, Uart0, uart0, Pa9<PfA>, Pa10<PfA>),
198    Uart1: (UART1, Uart1, uart1, Pb2<PfA>, Pb3<PfA>),
199);
200
201pub type Serial0 = Uart0;
202pub type Serial1 = Uart1;