mk20d7_hal/
serial.rs

1use core::marker::PhantomData;
2use core::convert::TryFrom;
3
4use nb;
5use bitrate::{Bps, Hertz};
6use bit_field::BitField;
7use hal::serial;
8use mk20d7::{self, UART0, UART1, UART2};
9use void::Void;
10
11use mcg::MultipurposeClockGenerator;
12use gpio::{
13    Alternate, ALT2, ALT3,
14    gpioa::{PTA1, PTA2},
15    gpiob::{PTB16, PTB17},
16    gpioc::{PTC3, PTC4},
17    gpiod::{PTD2, PTD3, PTD6, PTD7},
18    gpioe::{PTE0, PTE1},
19};
20
21/// Interrupt event
22pub enum Event {
23    /// New data has been received
24    Rxne,
25
26    /// New data can be sent
27    Txe,
28}
29
30/// Serial error
31#[derive(Debug)]
32pub enum Error {
33    /// Framing error
34    Framing,
35
36    /// Noise error
37    Noise,
38
39    /// RX buffer overrun
40    Overrun,
41
42    /// Parity check error
43    Parity,
44
45    #[doc(hidden)]
46    _Extensible,
47}
48
49// FIXME these should be a "sealed" trait
50/// TX pin - DO NOT IMPLEMENT THIS TRAIT
51pub unsafe trait TxPin<UART> {}
52
53// FIXME these should be a "sealed" trait
54/// RX pin - DO NOT IMPLEMENT THIS TRAIT
55pub unsafe trait RxPin<UART> {}
56
57// UART 0 PTA
58unsafe impl RxPin<UART0> for PTA1<Alternate<ALT2>> {}
59unsafe impl TxPin<UART0> for PTA2<Alternate<ALT2>> {}
60
61// UART 0 PTB
62unsafe impl RxPin<UART0> for PTB17<Alternate<ALT3>> {}
63unsafe impl TxPin<UART0> for PTB16<Alternate<ALT3>> {}
64
65// UART 0 PTD
66unsafe impl RxPin<UART0> for PTD6<Alternate<ALT3>> {}
67unsafe impl TxPin<UART0> for PTD7<Alternate<ALT3>> {}
68
69// UART 1 PTC
70unsafe impl RxPin<UART1> for PTC3<Alternate<ALT3>> {}
71unsafe impl TxPin<UART1> for PTC4<Alternate<ALT3>> {}
72
73// UART 1 PTE
74unsafe impl RxPin<UART1> for PTE1<Alternate<ALT3>> {}
75unsafe impl TxPin<UART1> for PTE0<Alternate<ALT3>> {}
76
77// UART 2 PTD
78unsafe impl RxPin<UART1> for PTD2<Alternate<ALT3>> {}
79unsafe impl TxPin<UART1> for PTD3<Alternate<ALT3>> {}
80
81
82/// Serial abstraction
83pub struct Serial<UART, PINS> {
84    uart: UART,
85    pins: PINS,
86}
87
88/// Serial receiver
89pub struct Rx<UART> {
90    _uart: PhantomData<UART>,
91}
92
93/// Serial transmitter
94pub struct Tx<UART> {
95    _uart: PhantomData<UART>,
96}
97
98macro_rules! hal {
99    ($(
100        $UARTX:ident: ($uartX:ident),
101    )+) => {
102        $(
103            impl<TX, RX> Serial<$UARTX, (TX, RX)> {
104                // Reference 47.8.3 Initialization sequence (non ISO-7816)
105                /// Configures a UART peripheral to provide serial communication
106                pub fn $uartX(
107                    uart: $UARTX,
108                    pins: (TX, RX),
109                    baud_rate: Bps<u32>,
110                    mcg: &MultipurposeClockGenerator,
111                ) -> Self
112                where
113                    TX: TxPin<$UARTX>,
114                    RX: RxPin<$UARTX>,
115                {
116                    // Reference: 47.4.4 Baud rate generation
117                    let clock: Hertz<u32> = mcg.get_pll_frequency().into();
118                    let numerator = clock.0;
119                    let denominator = baud_rate.0 * mcg.external_crystal_frequency.0;
120
121                    let module_clock_divisor_main = numerator / denominator;
122
123                    if module_clock_divisor_main >= 8192 {
124                        panic!("Invalid UART clock divider: {}", module_clock_divisor_main);
125                    }
126
127                    let module_clock_divisor_gcd = gcd(numerator, denominator);
128                    let module_clock_divisor_fine_adjustment_denominator = {
129                        denominator / module_clock_divisor_gcd
130                    };
131                    let module_clock_divisor_fine_adjustment_numerator = {
132                        (numerator / module_clock_divisor_gcd) - (module_clock_divisor_main * module_clock_divisor_fine_adjustment_denominator)
133                    };
134                    let module_clock_divisor_fine_adjustment = u8::try_from(
135                        module_clock_divisor_fine_adjustment_numerator * 32 /
136                        module_clock_divisor_fine_adjustment_denominator
137                    ).unwrap();
138
139                    // Reference: 47.3.11 UART Control Register 4 (UART_C4)
140                    uart.c4.write(|w| unsafe { w.brfa().bits(module_clock_divisor_fine_adjustment) });
141
142                    // Reference: 47.3.1 UART Baud Rate Registers: High (UART_BDH)
143                    let module_clock_divisor_high = module_clock_divisor_main.get_bits(8..13) as u8;
144                    uart.bdh.write(|w| unsafe { w.sbr().bits(module_clock_divisor_high) });
145
146                    // Reference: 47.3.2 UART Baud Rate Registers: Low (UART_BDL)
147                    let module_clock_divisor_low = module_clock_divisor_main.get_bits(0..8) as u8;
148                    uart.bdl.write(|w| unsafe { w.sbr().bits(module_clock_divisor_low) });
149
150                    // Reference: 47.3.4 UART Control Register 2 (UART_C2)
151                    uart.c2.write(|w| {
152                        w.re().set_bit();
153                        w.te().set_bit()
154                    });
155
156                    Serial { uart, pins }
157                }
158
159                /// Splits the `Serial` abstraction into a transmitter and a receiver half
160                pub fn split(self) -> (Tx<$UARTX>, Rx<$UARTX>) {
161                    (Tx { _uart: PhantomData }, Rx { _uart: PhantomData })
162                }
163
164                /// Releases the UART peripheral and associated pins
165                pub fn free(self) -> ($UARTX, (TX, RX)) {
166                    (self.uart, self.pins)
167                }
168            }
169
170            fn $uartX<'a>() -> &'a mk20d7::$uartX::RegisterBlock {
171                unsafe { &(*$UARTX::ptr()) }
172            }
173
174            impl serial::Read<u8> for Rx<$UARTX> {
175                type Error = Error;
176
177                fn read(&mut self) -> nb::Result<u8, Error> {
178                    let uart = $uartX();
179                    let s1 = uart.s1.read();
180
181                    if s1.pf().bit_is_set() {
182                        return Err(nb::Error::Other(Error::Parity));
183                    }
184
185                    if s1.fe().bit_is_set() {
186                        return Err(nb::Error::Other(Error::Framing));
187                    }
188
189                    if s1.nf().bit_is_set() {
190                        return Err(nb::Error::Other(Error::Noise));
191                    }
192
193                    if s1.or().bit_is_set() {
194                        return Err(nb::Error::Other(Error::Overrun));
195                    }
196
197                    if s1.rdrf().bit_is_clear() {
198                        return Err(nb::Error::WouldBlock);
199                    }
200
201                    Ok(uart.d.read().rt().bits())
202                }
203            }
204
205            impl serial::Write<u8> for Tx<$UARTX> {
206                // The only possible errors during
207                // transmission are: clear to send (which is disabled in this case) errors and
208                // framing errors (which only occur in SmartCard mode); neither of these apply to
209                // our hardware configuration
210                type Error = Void;
211
212                fn flush(&mut self) -> nb::Result<(), Void> {
213                    if $uartX().s1.read().tc().bit_is_clear() {
214                        return Err(nb::Error::WouldBlock);
215                    }
216
217                    Ok(())
218                }
219
220                fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
221                    let uart = $uartX();
222
223                    if uart.s1.read().tdre().bit_is_clear() {
224                        return Err(nb::Error::WouldBlock);
225                    }
226
227                    uart.d.write(|w| unsafe { w.bits(byte) });
228
229                    Ok(())
230                }
231            }
232        )+
233    }
234}
235
236hal! {
237    UART0: (uart0),
238    UART1: (uart1),
239    UART2: (uart2),
240}
241
242// Euclid's GCD
243fn gcd(numerator: u32, denominator: u32) -> u32 {
244    let mut numerator = numerator;
245    let mut denominator = denominator;
246    while denominator != 0 {
247        let temp = denominator;
248        denominator = numerator % denominator;
249        numerator = temp;
250    }
251    numerator
252}