stm32f030_hal/
serial.rs

1use core::fmt::{Result, Write};
2use core::marker::PhantomData;
3use core::ptr;
4
5use hal;
6use hal::prelude::*;
7use nb;
8use void::Void;
9
10use stm32::{RCC, USART1, USART2, USART3, USART4, USART5, USART6};
11
12use gpio::*;
13use rcc::Clocks;
14use time::Bps;
15
16/// Interrupt event
17pub enum Event {
18    /// New data has been received
19    Rxne,
20    /// New data can be sent
21    Txe,
22}
23
24/// Serial error
25#[derive(Debug)]
26pub enum Error {
27    /// Framing error
28    Framing,
29    /// Noise error
30    Noise,
31    /// RX buffer overrun
32    Overrun,
33    /// Parity check error
34    Parity,
35    #[doc(hidden)]
36    _Extensible,
37}
38
39pub trait Pins<USART> {}
40
41// The pin combinations are missing. Only grouped pins are defined.
42// TODO find a good way to do that automatically
43#[cfg(any(
44    feature = "stm32f030f4",
45    feature = "stm32f030k6",
46    feature = "stm32f030c6",
47    feature = "stm32f030c8",
48    feature = "stm32f030cc",
49    feature = "stm32f030r8",
50    feature = "stm32f030rc"
51))]
52impl Pins<USART1> for (gpioa::PA9<Alternate<AF1>>, gpioa::PA10<Alternate<AF1>>) {}
53#[cfg(any(
54    feature = "stm32f030f4",
55    feature = "stm32f030k6",
56    feature = "stm32f030c6",
57))]
58impl Pins<USART1> for (gpioa::PA2<Alternate<AF1>>, gpioa::PA3<Alternate<AF1>>) {}
59#[cfg(any(feature = "stm32f030k6", feature = "stm32f030c6",))]
60impl Pins<USART1> for (gpioa::PA14<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>) {}
61#[cfg(any(
62    feature = "stm32f030k6",
63    feature = "stm32f030c6",
64    feature = "stm32f030c8",
65    feature = "stm32f030cc",
66    feature = "stm32f030r8",
67    feature = "stm32f030rc"
68))]
69impl Pins<USART1> for (gpiob::PB6<Alternate<AF0>>, gpiob::PB7<Alternate<AF0>>) {}
70#[cfg(any(
71    feature = "stm32f030c8",
72    feature = "stm32f030cc",
73    feature = "stm32f030r8",
74    feature = "stm32f030rc"
75))]
76impl Pins<USART2> for (gpioa::PA2<Alternate<AF1>>, gpioa::PA3<Alternate<AF1>>) {}
77#[cfg(any(
78    feature = "stm32f030c8",
79    feature = "stm32f030cc",
80    feature = "stm32f030r8",
81    feature = "stm32f030rc"
82))]
83impl Pins<USART2> for (gpioa::PA14<Alternate<AF1>>, gpioa::PA15<Alternate<AF1>>) {}
84// TODO Proper mapping for all pins
85#[cfg(any(feature = "stm32f030cc", feature = "stm32f030rc"))]
86impl Pins<USART3> for (gpiob::PB10<Alternate<AF4>>, gpiob::PB11<Alternate<AF4>>) {}
87#[cfg(any(feature = "stm32f030cc", feature = "stm32f030rc"))]
88impl Pins<USART4> for (gpioa::PA0<Alternate<AF4>>, gpioa::PA1<Alternate<AF4>>) {}
89#[cfg(any(feature = "stm32f030cc", feature = "stm32f030rc"))]
90impl Pins<USART5> for (gpiob::PB3<Alternate<AF4>>, gpiob::PB4<Alternate<AF4>>) {}
91#[cfg(any(feature = "stm32f030cc", feature = "stm32f030rc"))]
92impl Pins<USART6> for (gpioa::PA4<Alternate<AF4>>, gpioa::PA5<Alternate<AF4>>) {}
93
94/// Serial abstraction
95pub struct Serial<USART, PINS> {
96    usart: USART,
97    pins: PINS,
98}
99
100/// Serial receiver
101pub struct Rx<USART> {
102    _usart: PhantomData<USART>,
103}
104
105/// Serial transmitter
106pub struct Tx<USART> {
107    _usart: PhantomData<USART>,
108}
109
110macro_rules! usart {
111    ($($USART:ident: ($usart:ident, $usartXen:ident, $apbenr:ident),)+) => {
112        $(
113            /// USART
114            impl<PINS> Serial<$USART, PINS> {
115                pub fn $usart(usart: $USART, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
116                where
117                    PINS: Pins<$USART>,
118                {
119                    // NOTE(unsafe) This executes only during initialisation
120                    let rcc = unsafe { &(*RCC::ptr()) };
121
122                    /* Enable clock for USART */
123                    rcc.$apbenr.modify(|_, w| w.$usartXen().set_bit());
124
125                    // Calculate correct baudrate divisor on the fly
126                    let brr = clocks.pclk().0 / baud_rate.0;
127                    usart.brr.write(|w| unsafe { w.bits(brr) });
128
129                    /* Reset other registers to disable advanced USART features */
130                    usart.cr2.reset();
131                    usart.cr3.reset();
132
133                    /* Enable transmission and receiving */
134                    usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
135
136                    Serial { usart, pins }
137                }
138
139                pub fn split(self) -> (Tx<$USART>, Rx<$USART>) {
140                    (
141                        Tx {
142                            _usart: PhantomData,
143                        },
144                        Rx {
145                            _usart: PhantomData,
146                        },
147                    )
148                }
149                pub fn release(self) -> ($USART, PINS) {
150                    (self.usart, self.pins)
151                }
152            }
153
154            impl hal::serial::Read<u8> for Rx<$USART> {
155                type Error = Error;
156
157                fn read(&mut self) -> nb::Result<u8, Error> {
158                    // NOTE(unsafe) atomic read with no side effects
159                    let isr = unsafe { (*$USART::ptr()).isr.read() };
160
161                    Err(if isr.pe().bit_is_set() {
162                        nb::Error::Other(Error::Parity)
163                    } else if isr.fe().bit_is_set() {
164                        nb::Error::Other(Error::Framing)
165                    } else if isr.nf().bit_is_set() {
166                        nb::Error::Other(Error::Noise)
167                    } else if isr.ore().bit_is_set() {
168                        nb::Error::Other(Error::Overrun)
169                    } else if isr.rxne().bit_is_set() {
170                        // NOTE(read_volatile) see `write_volatile` below
171                        return Ok(unsafe { ptr::read_volatile(&(*$USART::ptr()).rdr as *const _ as *const _) });
172                    } else {
173                        nb::Error::WouldBlock
174                    })
175                }
176            }
177
178            impl hal::serial::Write<u8> for Tx<$USART> {
179                type Error = Void;
180
181                fn flush(&mut self) -> nb::Result<(), Self::Error> {
182                    // NOTE(unsafe) atomic read with no side effects
183                    let isr = unsafe { (*$USART::ptr()).isr.read() };
184
185                    if isr.tc().bit_is_set() {
186                        Ok(())
187                    } else {
188                        Err(nb::Error::WouldBlock)
189                    }
190                }
191
192                fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
193                    // NOTE(unsafe) atomic read with no side effects
194                    let isr = unsafe { (*$USART::ptr()).isr.read() };
195
196                    if isr.txe().bit_is_set() {
197                        // NOTE(unsafe) atomic write to stateless register
198                        // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
199                        unsafe { ptr::write_volatile(&(*$USART::ptr()).tdr as *const _ as *mut _, byte) }
200                        Ok(())
201                    } else {
202                        Err(nb::Error::WouldBlock)
203                    }
204                }
205            }
206
207        )+
208    }
209}
210
211impl<USART> Write for Tx<USART>
212where
213    Tx<USART>: hal::serial::Write<u8>,
214{
215    fn write_str(&mut self, s: &str) -> Result {
216        let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last();
217        Ok(())
218    }
219}
220
221#[cfg(any(
222    feature = "stm32f030f4",
223    feature = "stm32f030k6",
224    feature = "stm32f030c6",
225    feature = "stm32f030c8",
226    feature = "stm32f030cc",
227    feature = "stm32f030r8",
228    feature = "stm32f030rc"
229))]
230usart! {
231    USART1: (usart1, usart1en, apb2enr),
232}
233
234#[cfg(any(
235    feature = "stm32f030c8",
236    feature = "stm32f030cc",
237    feature = "stm32f030r8",
238    feature = "stm32f030rc"
239))]
240usart! {
241    USART2: (usart2, usart2en, apb1enr),
242}
243
244#[cfg(any(feature = "stm32f030cc", feature = "stm32f030rc"))]
245usart! {
246    USART3: (usart3, usart3en, apb1enr),
247    USART4: (usart4, usart4en, apb1enr),
248    USART5: (usart5, usart5en, apb1enr),
249    // the usart6en bit is missing
250    // USART6: (usart6, usart6en, apb2enr),
251}