stm32f072_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};
11
12use gpio::gpioa::{PA0, PA1, PA10, PA14, PA15, PA2, PA3, PA9};
13use gpio::gpiob::{PB6, PB7, PB10, PB11};
14use gpio::gpioc::{PC4, PC5, PC10, PC11};
15use gpio::{Alternate, AF0, AF1, AF4};
16use rcc::Clocks;
17use time::Bps;
18
19/// Interrupt event
20pub enum Event {
21    /// New data has been received
22    Rxne,
23    /// New data can be sent
24    Txe,
25}
26
27/// Serial error
28#[derive(Debug)]
29pub enum Error {
30    /// Framing error
31    Framing,
32    /// Noise error
33    Noise,
34    /// RX buffer overrun
35    Overrun,
36    /// Parity check error
37    Parity,
38    #[doc(hidden)]
39    _Extensible,
40}
41
42pub trait Pins<USART> {}
43
44impl Pins<USART1> for (PA9<Alternate<AF1>>, PA10<Alternate<AF1>>) {}
45impl Pins<USART1> for (PB6<Alternate<AF0>>, PB7<Alternate<AF0>>) {}
46impl Pins<USART1> for (PA9<Alternate<AF1>>, PB7<Alternate<AF0>>) {}
47impl Pins<USART1> for (PB6<Alternate<AF0>>, PA10<Alternate<AF1>>) {}
48
49impl Pins<USART2> for (PA2<Alternate<AF1>>, PA3<Alternate<AF1>>) {}
50impl Pins<USART2> for (PA2<Alternate<AF1>>, PA15<Alternate<AF1>>) {}
51impl Pins<USART2> for (PA14<Alternate<AF1>>, PA15<Alternate<AF1>>) {}
52impl Pins<USART2> for (PA14<Alternate<AF1>>, PA3<Alternate<AF1>>) {}
53
54impl Pins<USART3> for (PB10<Alternate<AF4>>, PB11<Alternate<AF4>>) {}
55impl Pins<USART3> for (PC4<Alternate<AF1>>, PC5<Alternate<AF1>>) {}
56impl Pins<USART3> for (PC10<Alternate<AF1>>, PC11<Alternate<AF1>>) {}
57
58impl Pins<USART4> for (PA0<Alternate<AF4>>, PA1<Alternate<AF4>>) {}
59impl Pins<USART4> for (PC10<Alternate<AF0>>, PC11<Alternate<AF0>>) {}
60
61/// Serial abstraction
62pub struct Serial<USART, PINS> {
63    usart: USART,
64    pins: PINS,
65}
66
67/// Serial receiver
68pub struct Rx<USART> {
69    _usart: PhantomData<USART>,
70}
71
72/// Serial transmitter
73pub struct Tx<USART> {
74    _usart: PhantomData<USART>,
75}
76
77/// USART1
78impl<PINS> Serial<USART1, PINS> {
79    pub fn usart1(usart: USART1, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
80    where
81        PINS: Pins<USART1>,
82    {
83        // NOTE(unsafe) This executes only during initialisation
84        let rcc = unsafe { &(*RCC::ptr()) };
85
86        /* Enable clock for USART */
87        rcc.apb2enr.modify(|_, w| w.usart1en().set_bit());
88
89        // Calculate correct baudrate divisor on the fly
90        let brr = clocks.pclk().0 / baud_rate.0;
91        usart.brr.write(|w| unsafe { w.bits(brr) });
92
93        /* Reset other registers to disable advanced USART features */
94        usart.cr2.reset();
95        usart.cr3.reset();
96
97        /* Enable transmission and receiving */
98        usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
99
100        Serial { usart, pins }
101    }
102
103    pub fn split(self) -> (Tx<USART1>, Rx<USART1>) {
104        (
105            Tx {
106                _usart: PhantomData,
107            },
108            Rx {
109                _usart: PhantomData,
110            },
111        )
112    }
113    pub fn release(self) -> (USART1, PINS) {
114        (self.usart, self.pins)
115    }
116}
117
118impl hal::serial::Read<u8> for Rx<USART1> {
119    type Error = Error;
120
121    fn read(&mut self) -> nb::Result<u8, Error> {
122        // NOTE(unsafe) atomic read with no side effects
123        let isr = unsafe { (*USART1::ptr()).isr.read() };
124
125        Err(if isr.pe().bit_is_set() {
126            nb::Error::Other(Error::Parity)
127        } else if isr.fe().bit_is_set() {
128            nb::Error::Other(Error::Framing)
129        } else if isr.nf().bit_is_set() {
130            nb::Error::Other(Error::Noise)
131        } else if isr.ore().bit_is_set() {
132            nb::Error::Other(Error::Overrun)
133        } else if isr.rxne().bit_is_set() {
134            // NOTE(read_volatile) see `write_volatile` below
135            return Ok(unsafe { ptr::read_volatile(&(*USART1::ptr()).rdr as *const _ as *const _) });
136        } else {
137            nb::Error::WouldBlock
138        })
139    }
140}
141
142impl hal::serial::Write<u8> for Tx<USART1> {
143    type Error = Void;
144
145    fn flush(&mut self) -> nb::Result<(), Self::Error> {
146        // NOTE(unsafe) atomic read with no side effects
147        let isr = unsafe { (*USART1::ptr()).isr.read() };
148
149        if isr.tc().bit_is_set() {
150            Ok(())
151        } else {
152            Err(nb::Error::WouldBlock)
153        }
154    }
155
156    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
157        // NOTE(unsafe) atomic read with no side effects
158        let isr = unsafe { (*USART1::ptr()).isr.read() };
159
160        if isr.txe().bit_is_set() {
161            // NOTE(unsafe) atomic write to stateless register
162            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
163            unsafe { ptr::write_volatile(&(*USART1::ptr()).tdr as *const _ as *mut _, byte) }
164            Ok(())
165        } else {
166            Err(nb::Error::WouldBlock)
167        }
168    }
169}
170
171/// USART2
172impl<PINS> Serial<USART2, PINS> {
173    pub fn usart2(usart: USART2, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
174    where
175        PINS: Pins<USART2>,
176    {
177        // NOTE(unsafe) This executes only during initialisation
178        let rcc = unsafe { &(*RCC::ptr()) };
179
180        /* Enable clock for USART */
181        rcc.apb1enr.modify(|_, w| w.usart2en().set_bit());
182
183        // Calculate correct baudrate divisor on the fly
184        let brr = clocks.pclk().0 / baud_rate.0;
185        usart.brr.write(|w| unsafe { w.bits(brr) });
186
187        /* Reset other registers to disable advanced USART features */
188        usart.cr2.reset();
189        usart.cr3.reset();
190
191        /* Enable transmission and receiving */
192        usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
193
194        Serial { usart, pins }
195    }
196
197    pub fn split(self) -> (Tx<USART2>, Rx<USART2>) {
198        (
199            Tx {
200                _usart: PhantomData,
201            },
202            Rx {
203                _usart: PhantomData,
204            },
205        )
206    }
207    pub fn release(self) -> (USART2, PINS) {
208        (self.usart, self.pins)
209    }
210}
211
212impl hal::serial::Read<u8> for Rx<USART2> {
213    type Error = Error;
214
215    fn read(&mut self) -> nb::Result<u8, Error> {
216        // NOTE(unsafe) atomic read with no side effects
217        let isr = unsafe { (*USART2::ptr()).isr.read() };
218
219        Err(if isr.pe().bit_is_set() {
220            nb::Error::Other(Error::Parity)
221        } else if isr.fe().bit_is_set() {
222            nb::Error::Other(Error::Framing)
223        } else if isr.nf().bit_is_set() {
224            nb::Error::Other(Error::Noise)
225        } else if isr.ore().bit_is_set() {
226            nb::Error::Other(Error::Overrun)
227        } else if isr.rxne().bit_is_set() {
228            // NOTE(read_volatile) see `write_volatile` below
229            return Ok(unsafe { ptr::read_volatile(&(*USART2::ptr()).rdr as *const _ as *const _) });
230        } else {
231            nb::Error::WouldBlock
232        })
233    }
234}
235
236impl hal::serial::Write<u8> for Tx<USART2> {
237    type Error = Void;
238
239    fn flush(&mut self) -> nb::Result<(), Self::Error> {
240        // NOTE(unsafe) atomic read with no side effects
241        let isr = unsafe { (*USART2::ptr()).isr.read() };
242
243        if isr.tc().bit_is_set() {
244            Ok(())
245        } else {
246            Err(nb::Error::WouldBlock)
247        }
248    }
249
250    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
251        // NOTE(unsafe) atomic read with no side effects
252        let isr = unsafe { (*USART2::ptr()).isr.read() };
253
254        if isr.txe().bit_is_set() {
255            // NOTE(unsafe) atomic write to stateless register
256            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
257            unsafe { ptr::write_volatile(&(*USART2::ptr()).tdr as *const _ as *mut _, byte) }
258            Ok(())
259        } else {
260            Err(nb::Error::WouldBlock)
261        }
262    }
263}
264
265/// USART3
266impl<PINS> Serial<USART3, PINS> {
267    pub fn usart1(usart: USART3, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
268    where
269        PINS: Pins<USART3>,
270    {
271        // NOTE(unsafe) This executes only during initialisation
272        let rcc = unsafe { &(*RCC::ptr()) };
273
274        /* Enable clock for USART */
275        rcc.apb2enr.modify(|_, w| w.usart1en().set_bit());
276
277        // Calculate correct baudrate divisor on the fly
278        let brr = clocks.pclk().0 / baud_rate.0;
279        usart.brr.write(|w| unsafe { w.bits(brr) });
280
281        /* Reset other registers to disable advanced USART features */
282        usart.cr2.reset();
283        usart.cr3.reset();
284
285        /* Enable transmission and receiving */
286        usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
287
288        Serial { usart, pins }
289    }
290
291    pub fn split(self) -> (Tx<USART3>, Rx<USART3>) {
292        (
293            Tx {
294                _usart: PhantomData,
295            },
296            Rx {
297                _usart: PhantomData,
298            },
299        )
300    }
301    pub fn release(self) -> (USART3, PINS) {
302        (self.usart, self.pins)
303    }
304}
305
306impl hal::serial::Read<u8> for Rx<USART3> {
307    type Error = Error;
308
309    fn read(&mut self) -> nb::Result<u8, Error> {
310        // NOTE(unsafe) atomic read with no side effects
311        let isr = unsafe { (*USART3::ptr()).isr.read() };
312
313        Err(if isr.pe().bit_is_set() {
314            nb::Error::Other(Error::Parity)
315        } else if isr.fe().bit_is_set() {
316            nb::Error::Other(Error::Framing)
317        } else if isr.nf().bit_is_set() {
318            nb::Error::Other(Error::Noise)
319        } else if isr.ore().bit_is_set() {
320            nb::Error::Other(Error::Overrun)
321        } else if isr.rxne().bit_is_set() {
322            // NOTE(read_volatile) see `write_volatile` below
323            return Ok(unsafe { ptr::read_volatile(&(*USART3::ptr()).rdr as *const _ as *const _) });
324        } else {
325            nb::Error::WouldBlock
326        })
327    }
328}
329
330impl hal::serial::Write<u8> for Tx<USART3> {
331    type Error = Void;
332
333    fn flush(&mut self) -> nb::Result<(), Self::Error> {
334        // NOTE(unsafe) atomic read with no side effects
335        let isr = unsafe { (*USART3::ptr()).isr.read() };
336
337        if isr.tc().bit_is_set() {
338            Ok(())
339        } else {
340            Err(nb::Error::WouldBlock)
341        }
342    }
343
344    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
345        // NOTE(unsafe) atomic read with no side effects
346        let isr = unsafe { (*USART3::ptr()).isr.read() };
347
348        if isr.txe().bit_is_set() {
349            // NOTE(unsafe) atomic write to stateless register
350            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
351            unsafe { ptr::write_volatile(&(*USART3::ptr()).tdr as *const _ as *mut _, byte) }
352            Ok(())
353        } else {
354            Err(nb::Error::WouldBlock)
355        }
356    }
357}
358
359/// USART4
360impl<PINS> Serial<USART4, PINS> {
361    pub fn usart1(usart: USART4, pins: PINS, baud_rate: Bps, clocks: Clocks) -> Self
362    where
363        PINS: Pins<USART4>,
364    {
365        // NOTE(unsafe) This executes only during initialisation
366        let rcc = unsafe { &(*RCC::ptr()) };
367
368        /* Enable clock for USART */
369        rcc.apb2enr.modify(|_, w| w.usart1en().set_bit());
370
371        // Calculate correct baudrate divisor on the fly
372        let brr = clocks.pclk().0 / baud_rate.0;
373        usart.brr.write(|w| unsafe { w.bits(brr) });
374
375        /* Reset other registers to disable advanced USART features */
376        usart.cr2.reset();
377        usart.cr3.reset();
378
379        /* Enable transmission and receiving */
380        usart.cr1.modify(|_, w| unsafe { w.bits(0xD) });
381
382        Serial { usart, pins }
383    }
384
385    pub fn split(self) -> (Tx<USART4>, Rx<USART4>) {
386        (
387            Tx {
388                _usart: PhantomData,
389            },
390            Rx {
391                _usart: PhantomData,
392            },
393        )
394    }
395    pub fn release(self) -> (USART4, PINS) {
396        (self.usart, self.pins)
397    }
398}
399
400impl hal::serial::Read<u8> for Rx<USART4> {
401    type Error = Error;
402
403    fn read(&mut self) -> nb::Result<u8, Error> {
404        // NOTE(unsafe) atomic read with no side effects
405        let isr = unsafe { (*USART4::ptr()).isr.read() };
406
407        Err(if isr.pe().bit_is_set() {
408            nb::Error::Other(Error::Parity)
409        } else if isr.fe().bit_is_set() {
410            nb::Error::Other(Error::Framing)
411        } else if isr.nf().bit_is_set() {
412            nb::Error::Other(Error::Noise)
413        } else if isr.ore().bit_is_set() {
414            nb::Error::Other(Error::Overrun)
415        } else if isr.rxne().bit_is_set() {
416            // NOTE(read_volatile) see `write_volatile` below
417            return Ok(unsafe { ptr::read_volatile(&(*USART4::ptr()).rdr as *const _ as *const _) });
418        } else {
419            nb::Error::WouldBlock
420        })
421    }
422}
423
424impl hal::serial::Write<u8> for Tx<USART4> {
425    type Error = Void;
426
427    fn flush(&mut self) -> nb::Result<(), Self::Error> {
428        // NOTE(unsafe) atomic read with no side effects
429        let isr = unsafe { (*USART4::ptr()).isr.read() };
430
431        if isr.tc().bit_is_set() {
432            Ok(())
433        } else {
434            Err(nb::Error::WouldBlock)
435        }
436    }
437
438    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
439        // NOTE(unsafe) atomic read with no side effects
440        let isr = unsafe { (*USART4::ptr()).isr.read() };
441
442        if isr.txe().bit_is_set() {
443            // NOTE(unsafe) atomic write to stateless register
444            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
445            unsafe { ptr::write_volatile(&(*USART4::ptr()).tdr as *const _ as *mut _, byte) }
446            Ok(())
447        } else {
448            Err(nb::Error::WouldBlock)
449        }
450    }
451}
452
453impl<USART> Write for Tx<USART>
454where
455    Tx<USART>: hal::serial::Write<u8>,
456{
457    fn write_str(&mut self, s: &str) -> Result {
458        let _ = s
459            .as_bytes()
460            .iter()
461            .map(|c| block!(self.write(*c)))
462            .last();
463        Ok(())
464    }
465}