stm32f30x_hal/
serial.rs

1//! Serial
2
3use core::marker::PhantomData;
4use core::ptr;
5
6use hal::serial;
7use nb;
8use stm32f30x::{USART1, USART2, USART3};
9use void::Void;
10
11use gpio::gpioa::{PA10, PA2, PA3, PA9};
12use gpio::gpiob::{PB10, PB11, PB6, PB7};
13use gpio::gpioc::{PC10, PC11, PC4, PC5};
14use gpio::gpiod::{PD5, PD6, PD8, PD9};
15use gpio::gpioe::{PE0, PE1, PE15};
16use gpio::AF7;
17use rcc::{APB1, APB2, Clocks};
18use time::Bps;
19
20/// Interrupt event
21pub enum Event {
22    /// New data has been received
23    Rxne,
24    /// New data can be sent
25    Txe,
26}
27
28/// Serial error
29#[derive(Debug)]
30pub enum Error {
31    /// Framing error
32    Framing,
33    /// Noise error
34    Noise,
35    /// RX buffer overrun
36    Overrun,
37    /// Parity check error
38    Parity,
39    #[doc(hidden)]
40    _Extensible,
41}
42
43// FIXME these should be "closed" traits
44/// TX pin - DO NOT IMPLEMENT THIS TRAIT
45pub unsafe trait TxPin<USART> {}
46
47/// RX pin - DO NOT IMPLEMENT THIS TRAIT
48pub unsafe trait RxPin<USART> {}
49
50unsafe impl TxPin<USART1> for PA9<AF7> {}
51unsafe impl TxPin<USART1> for PB6<AF7> {}
52unsafe impl TxPin<USART1> for PC4<AF7> {}
53unsafe impl TxPin<USART1> for PE0<AF7> {}
54
55unsafe impl RxPin<USART1> for PA10<AF7> {}
56unsafe impl RxPin<USART1> for PB7<AF7> {}
57unsafe impl RxPin<USART1> for PC5<AF7> {}
58unsafe impl RxPin<USART1> for PE1<AF7> {}
59
60unsafe impl TxPin<USART2> for PA2<AF7> {}
61// unsafe impl TxPin<USART2> for PA14<AF7> {}
62// unsafe impl TxPin<USART2> for PB3<AF7> {}
63unsafe impl TxPin<USART2> for PD5<AF7> {}
64
65unsafe impl RxPin<USART2> for PA3<AF7> {}
66// unsafe impl RxPin<USART2> for PA15<AF7> {}
67// unsafe impl RxPin<USART2> for PB4<AF7> {}
68unsafe impl RxPin<USART2> for PD6<AF7> {}
69
70unsafe impl TxPin<USART3> for PB10<AF7> {}
71unsafe impl TxPin<USART3> for PC10<AF7> {}
72unsafe impl TxPin<USART3> for PD8<AF7> {}
73
74unsafe impl RxPin<USART3> for PB11<AF7> {}
75unsafe impl RxPin<USART3> for PC11<AF7> {}
76unsafe impl RxPin<USART3> for PD9<AF7> {}
77unsafe impl RxPin<USART3> for PE15<AF7> {}
78
79/// Serial abstraction
80pub struct Serial<USART, PINS> {
81    usart: USART,
82    pins: PINS,
83}
84
85/// Serial receiver
86pub struct Rx<USART> {
87    _usart: PhantomData<USART>,
88}
89
90/// Serial transmitter
91pub struct Tx<USART> {
92    _usart: PhantomData<USART>,
93}
94
95macro_rules! hal {
96    ($(
97        $USARTX:ident: ($usartX:ident, $APB:ident, $usartXen:ident, $usartXrst:ident, $pclkX:ident),
98    )+) => {
99        $(
100            impl<TX, RX> Serial<$USARTX, (TX, RX)> {
101                /// Configures a USART peripheral to provide serial communication
102                pub fn $usartX(
103                    usart: $USARTX,
104                    pins: (TX, RX),
105                    baud_rate: Bps,
106                    clocks: Clocks,
107                    apb: &mut $APB,
108                ) -> Self
109                where
110                    TX: TxPin<$USARTX>,
111                    RX: RxPin<$USARTX>,
112                {
113                    // enable or reset $USARTX
114                    apb.enr().modify(|_, w| w.$usartXen().enabled());
115                    apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
116                    apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
117
118                    // disable hardware flow control
119                    // TODO enable DMA
120                    // usart.cr3.write(|w| w.rtse().clear_bit().ctse().clear_bit());
121
122                    let brr = clocks.$pclkX().0 / baud_rate.0;
123                    assert!(brr >= 16, "impossible baud rate");
124                    usart.brr.write(|w| unsafe { w.bits(brr) });
125
126                    // UE: enable USART
127                    // RE: enable receiver
128                    // TE: enable transceiver
129                    usart
130                        .cr1
131                        .write(|w| w.ue().set_bit().re().set_bit().te().set_bit());
132
133                    Serial { usart, pins }
134                }
135
136                /// Starts listening for an interrupt event
137                pub fn listen(&mut self, event: Event) {
138                    match event {
139                        Event::Rxne => {
140                            self.usart.cr1.modify(|_, w| w.rxneie().set_bit())
141                        },
142                        Event::Txe => {
143                            self.usart.cr1.modify(|_, w| w.txeie().set_bit())
144                        },
145                    }
146                }
147
148                /// Starts listening for an interrupt event
149                pub fn unlisten(&mut self, event: Event) {
150                    match event {
151                        Event::Rxne => {
152                            self.usart.cr1.modify(|_, w| w.rxneie().clear_bit())
153                        },
154                        Event::Txe => {
155                            self.usart.cr1.modify(|_, w| w.txeie().clear_bit())
156                        },
157                    }
158                }
159
160                /// Splits the `Serial` abstraction into a transmitter and a receiver half
161                pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
162                    (
163                        Tx {
164                            _usart: PhantomData,
165                        },
166                        Rx {
167                            _usart: PhantomData,
168                        },
169                    )
170                }
171
172                /// Releases the USART peripheral and associated pins
173                pub fn free(self) -> ($USARTX, (TX, RX)) {
174                    (self.usart, self.pins)
175                }
176            }
177
178            impl serial::Read<u8> for Rx<$USARTX> {
179                type Error = Error;
180
181                fn read(&mut self) -> nb::Result<u8, Error> {
182                    // NOTE(unsafe) atomic read with no side effects
183                    let isr = unsafe { (*$USARTX::ptr()).isr.read() };
184
185                    Err(if isr.pe().bit_is_set() {
186                        nb::Error::Other(Error::Parity)
187                    } else if isr.fe().bit_is_set() {
188                        nb::Error::Other(Error::Framing)
189                    } else if isr.nf().bit_is_set() {
190                        nb::Error::Other(Error::Noise)
191                    } else if isr.ore().bit_is_set() {
192                        nb::Error::Other(Error::Overrun)
193                    } else if isr.rxne().bit_is_set() {
194                        // NOTE(read_volatile) see `write_volatile` below
195                        return Ok(unsafe {
196                            ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _ as *const _)
197                        });
198                    } else {
199                        nb::Error::WouldBlock
200                    })
201                }
202            }
203
204            impl serial::Write<u8> for Tx<$USARTX> {
205                // NOTE(Void) See section "29.7 USART interrupts"; the only possible errors during
206                // transmission are: clear to send (which is disabled in this case) errors and
207                // framing errors (which only occur in SmartCard mode); neither of these apply to
208                // our hardware configuration
209                type Error = Void;
210
211                fn flush(&mut self) -> nb::Result<(), Void> {
212                    // NOTE(unsafe) atomic read with no side effects
213                    let isr = unsafe { (*$USARTX::ptr()).isr.read() };
214
215                    if isr.tc().bit_is_set() {
216                        Ok(())
217                    } else {
218                        Err(nb::Error::WouldBlock)
219                    }
220                }
221
222                fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
223                    // NOTE(unsafe) atomic read with no side effects
224                    let isr = unsafe { (*$USARTX::ptr()).isr.read() };
225
226                    if isr.txe().bit_is_set() {
227                        // NOTE(unsafe) atomic write to stateless register
228                        // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
229                        unsafe {
230                            ptr::write_volatile(&(*$USARTX::ptr()).tdr as *const _ as *mut _, byte)
231                        }
232                        Ok(())
233                    } else {
234                        Err(nb::Error::WouldBlock)
235                    }
236                }
237            }
238        )+
239    }
240}
241
242hal! {
243    USART1: (usart1, APB2, usart1en, usart1rst, pclk2),
244    USART2: (usart2, APB1, usart2en, usart2rst, pclk1),
245    USART3: (usart3, APB1, usart3en, usart3rst, pclk1),
246}