stm32f4xx_hal/
serial.rs

1//!
2//! Asynchronous serial communication using USART peripherals
3//!
4//! # Word length
5//!
6//! By default, the UART/USART uses 8 data bits. The `Serial`, `Rx`, and `Tx` structs implement
7//! the embedded-hal read and write traits with `u8` as the word type.
8//!
9//! You can also configure the hardware to use 9 data bits with the `Config` `wordlength_9()`
10//! function. After creating a `Serial` with this option, use the `with_u16_data()` function to
11//! convert the `Serial<_, u8>` object into a `Serial<_, u16>` that can send and receive `u16`s.
12//!
13//! In this mode, the `Serial<_, u16>`, `Rx<_, u16>`, and `Tx<_, u16>` structs instead implement
14//! the embedded-hal read and write traits with `u16` as the word type. You can use these
15//! implementations for 9-bit words.
16
17use core::marker::PhantomData;
18
19mod hal_02;
20mod hal_1;
21
22pub(crate) mod uart_impls;
23pub use uart_impls::Instance;
24use uart_impls::RegisterBlockImpl;
25
26use crate::gpio::{self, PushPull};
27
28use crate::pac;
29
30use crate::gpio::NoPin;
31use crate::rcc::Clocks;
32
33pub mod dma;
34
35/// Serial error kind
36///
37/// This represents a common set of serial operation errors. HAL implementations are
38/// free to define more specific or additional error types. However, by providing
39/// a mapping to these common serial errors, generic code can still react to them.
40#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
41#[non_exhaustive]
42pub enum Error {
43    /// The peripheral receive buffer was overrun.
44    Overrun,
45    /// Received data does not conform to the peripheral configuration.
46    /// Can be caused by a misconfigured device on either end of the serial line.
47    FrameFormat,
48    /// Parity check failed.
49    Parity,
50    /// Serial line is too noisy to read valid data.
51    Noise,
52    /// A different error occurred. The original error may contain more information.
53    Other,
54}
55
56/// UART interrupt events
57#[enumflags2::bitflags]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[derive(Debug, Eq, PartialEq, Copy, Clone)]
60#[repr(u32)]
61pub enum Event {
62    /// IDLE interrupt enable
63    Idle = 1 << 4,
64    /// RXNE interrupt enable
65    RxNotEmpty = 1 << 5,
66    /// Transmission complete interrupt enable
67    TransmissionComplete = 1 << 6,
68    /// TXE interrupt enable
69    TxEmpty = 1 << 7,
70    /// PE interrupt enable
71    ParityError = 1 << 8,
72}
73
74/// UART/USART status flags
75#[enumflags2::bitflags]
76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77#[derive(Debug, Eq, PartialEq, Copy, Clone)]
78#[repr(u32)]
79pub enum Flag {
80    /// Parity error
81    ParityError = 1 << 0,
82    /// Framing error
83    FramingError = 1 << 1,
84    /// Noise detected flag
85    Noise = 1 << 2,
86    /// Overrun error
87    Overrun = 1 << 3,
88    /// IDLE line detected
89    Idle = 1 << 4,
90    /// Read data register not empty
91    RxNotEmpty = 1 << 5,
92    /// Transmission complete
93    TransmissionComplete = 1 << 6,
94    /// Transmit data register empty
95    TxEmpty = 1 << 7,
96    /// LIN break detection flag
97    LinBreak = 1 << 8,
98    /// CTS flag
99    Cts = 1 << 9,
100}
101
102/// UART clearable flags
103#[enumflags2::bitflags]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
105#[derive(Debug, Eq, PartialEq, Copy, Clone)]
106#[repr(u32)]
107pub enum CFlag {
108    /// Read data register not empty
109    RxNotEmpty = 1 << 5,
110    /// Transmission complete
111    TransmissionComplete = 1 << 6,
112    /// LIN break detection flag
113    LinBreak = 1 << 8,
114}
115
116pub mod config;
117
118pub use config::Config;
119
120/// A filler type for when the Tx pin is unnecessary
121pub use gpio::NoPin as NoTx;
122/// A filler type for when the Rx pin is unnecessary
123pub use gpio::NoPin as NoRx;
124
125pub use gpio::alt::SerialAsync as CommonPins;
126
127/// Trait for [`Rx`] interrupt handling.
128pub trait RxISR {
129    /// Return true if the line idle status is set
130    fn is_idle(&self) -> bool;
131
132    /// Return true if the rx register is not empty (and can be read)
133    fn is_rx_not_empty(&self) -> bool;
134
135    /// Clear idle line interrupt flag
136    fn clear_idle_interrupt(&self);
137}
138
139/// Trait for [`Tx`] interrupt handling.
140pub trait TxISR {
141    /// Return true if the tx register is empty (and can accept data)
142    fn is_tx_empty(&self) -> bool;
143}
144
145/// Trait for listening [`Rx`] interrupt events.
146pub trait RxListen {
147    /// Start listening for an rx not empty interrupt event
148    ///
149    /// Note, you will also have to enable the corresponding interrupt
150    /// in the NVIC to start receiving events.
151    fn listen(&mut self);
152
153    /// Stop listening for the rx not empty interrupt event
154    fn unlisten(&mut self);
155
156    /// Start listening for a line idle interrupt event
157    ///
158    /// Note, you will also have to enable the corresponding interrupt
159    /// in the NVIC to start receiving events.
160    fn listen_idle(&mut self);
161
162    /// Stop listening for the line idle interrupt event
163    fn unlisten_idle(&mut self);
164}
165
166/// Trait for listening [`Tx`] interrupt event.
167pub trait TxListen {
168    /// Start listening for a tx empty interrupt event
169    ///
170    /// Note, you will also have to enable the corresponding interrupt
171    /// in the NVIC to start receiving events.
172    fn listen(&mut self);
173
174    /// Stop listening for the tx empty interrupt event
175    fn unlisten(&mut self);
176}
177
178/// Serial abstraction
179pub struct Serial<USART: CommonPins, WORD = u8> {
180    tx: Tx<USART, WORD>,
181    rx: Rx<USART, WORD>,
182}
183
184/// Serial receiver containing RX pin
185pub struct Rx<USART: CommonPins, WORD = u8> {
186    _word: PhantomData<WORD>,
187    usart: USART,
188    pin: USART::Rx<PushPull>,
189}
190
191/// Serial transmitter containing TX pin
192pub struct Tx<USART: CommonPins, WORD = u8> {
193    _word: PhantomData<WORD>,
194    usart: USART,
195    pin: USART::Tx<PushPull>,
196}
197
198pub trait SerialExt: Sized + Instance {
199    fn serial<WORD>(
200        self,
201        pins: (impl Into<Self::Tx<PushPull>>, impl Into<Self::Rx<PushPull>>),
202        config: impl Into<config::Config>,
203        clocks: &Clocks,
204    ) -> Result<Serial<Self, WORD>, config::InvalidConfig>;
205
206    fn tx<WORD>(
207        self,
208        tx_pin: impl Into<Self::Tx<PushPull>>,
209        config: impl Into<config::Config>,
210        clocks: &Clocks,
211    ) -> Result<Tx<Self, WORD>, config::InvalidConfig>
212    where
213        NoPin: Into<Self::Rx<PushPull>>,
214    {
215        self.serial((tx_pin, NoPin::new()), config, clocks)
216            .map(|s| s.split().0)
217    }
218
219    fn rx<WORD>(
220        self,
221        rx_pin: impl Into<Self::Rx<PushPull>>,
222        config: impl Into<config::Config>,
223        clocks: &Clocks,
224    ) -> Result<Rx<Self, WORD>, config::InvalidConfig>
225    where
226        NoPin: Into<Self::Tx<PushPull>>,
227    {
228        self.serial((NoPin::new(), rx_pin), config, clocks)
229            .map(|s| s.split().1)
230    }
231}
232
233impl<USART: Instance, WORD> Serial<USART, WORD> {
234    pub fn new(
235        usart: USART,
236        pins: (
237            impl Into<USART::Tx<PushPull>>,
238            impl Into<USART::Rx<PushPull>>,
239        ),
240        config: impl Into<config::Config>,
241        clocks: &Clocks,
242    ) -> Result<Self, config::InvalidConfig> {
243        <USART as crate::Ptr>::RB::new(usart, pins, config, clocks)
244    }
245}
246
247impl<UART: CommonPins, WORD> Serial<UART, WORD> {
248    pub fn split(self) -> (Tx<UART, WORD>, Rx<UART, WORD>) {
249        (self.tx, self.rx)
250    }
251
252    #[allow(clippy::type_complexity)]
253    pub fn release(self) -> (UART, (UART::Tx<PushPull>, UART::Rx<PushPull>)) {
254        (self.tx.usart, (self.tx.pin, self.rx.pin))
255    }
256}
257
258macro_rules! halUsart {
259    ($USART:ty, $Serial:ident, $Rx:ident, $Tx:ident) => {
260        pub type $Serial<WORD = u8> = Serial<$USART, WORD>;
261        pub type $Tx<WORD = u8> = Tx<$USART, WORD>;
262        pub type $Rx<WORD = u8> = Rx<$USART, WORD>;
263
264        impl Instance for $USART {
265            fn set_stopbits(&self, bits: config::StopBits) {
266                use crate::pac::usart1::cr2::STOP;
267                use config::StopBits;
268
269                self.cr2().write(|w| {
270                    w.stop().variant(match bits {
271                        StopBits::STOP0P5 => STOP::Stop0p5,
272                        StopBits::STOP1 => STOP::Stop1,
273                        StopBits::STOP1P5 => STOP::Stop1p5,
274                        StopBits::STOP2 => STOP::Stop2,
275                    })
276                });
277            }
278        }
279
280        impl crate::Ptr for $USART {
281            type RB = crate::serial::uart_impls::RegisterBlockUsart;
282
283            fn ptr() -> *const Self::RB {
284                Self::ptr()
285            }
286        }
287
288        impl crate::Steal for $USART {
289            unsafe fn steal() -> Self {
290                Self::steal()
291            }
292        }
293    };
294}
295pub(crate) use halUsart;
296
297halUsart! { pac::USART1, Serial1, Rx1, Tx1 }
298halUsart! { pac::USART2, Serial2, Rx2, Tx2 }
299halUsart! { pac::USART6, Serial6, Rx6, Tx6 }
300
301#[cfg(feature = "usart3")]
302halUsart! { pac::USART3, Serial3, Rx3, Tx3 }
303
304impl<UART: CommonPins> Rx<UART, u8> {
305    pub(crate) fn with_u16_data(self) -> Rx<UART, u16> {
306        Rx::new(self.usart, self.pin)
307    }
308}
309
310impl<UART: CommonPins> Rx<UART, u16> {
311    pub(crate) fn with_u8_data(self) -> Rx<UART, u8> {
312        Rx::new(self.usart, self.pin)
313    }
314}
315
316impl<UART: CommonPins> Tx<UART, u8> {
317    pub(crate) fn with_u16_data(self) -> Tx<UART, u16> {
318        Tx::new(self.usart, self.pin)
319    }
320}
321
322impl<UART: CommonPins> Tx<UART, u16> {
323    pub(crate) fn with_u8_data(self) -> Tx<UART, u8> {
324        Tx::new(self.usart, self.pin)
325    }
326}
327
328impl<UART: CommonPins, WORD> Rx<UART, WORD> {
329    pub(crate) fn new(usart: UART, pin: UART::Rx<PushPull>) -> Self {
330        Self {
331            _word: PhantomData,
332            usart,
333            pin,
334        }
335    }
336
337    pub fn join(self, tx: Tx<UART, WORD>) -> Serial<UART, WORD> {
338        Serial { tx, rx: self }
339    }
340}
341
342impl<UART: CommonPins, WORD> Tx<UART, WORD> {
343    pub(crate) fn new(usart: UART, pin: UART::Tx<PushPull>) -> Self {
344        Self {
345            _word: PhantomData,
346            usart,
347            pin,
348        }
349    }
350
351    pub fn join(self, rx: Rx<UART, WORD>) -> Serial<UART, WORD> {
352        Serial { tx: self, rx }
353    }
354}
355
356impl<UART: Instance, WORD> AsRef<Tx<UART, WORD>> for Serial<UART, WORD> {
357    #[inline(always)]
358    fn as_ref(&self) -> &Tx<UART, WORD> {
359        &self.tx
360    }
361}
362
363impl<UART: Instance, WORD> AsRef<Rx<UART, WORD>> for Serial<UART, WORD> {
364    #[inline(always)]
365    fn as_ref(&self) -> &Rx<UART, WORD> {
366        &self.rx
367    }
368}
369
370impl<UART: Instance, WORD> AsMut<Tx<UART, WORD>> for Serial<UART, WORD> {
371    #[inline(always)]
372    fn as_mut(&mut self) -> &mut Tx<UART, WORD> {
373        &mut self.tx
374    }
375}
376
377impl<UART: Instance, WORD> AsMut<Rx<UART, WORD>> for Serial<UART, WORD> {
378    #[inline(always)]
379    fn as_mut(&mut self) -> &mut Rx<UART, WORD> {
380        &mut self.rx
381    }
382}
383
384impl<UART: Instance> Serial<UART, u8> {
385    /// Converts this Serial into a version that can read and write `u16` values instead of `u8`s
386    ///
387    /// This can be used with a word length of 9 bits.
388    pub fn with_u16_data(self) -> Serial<UART, u16> {
389        Serial {
390            tx: self.tx.with_u16_data(),
391            rx: self.rx.with_u16_data(),
392        }
393    }
394}
395
396impl<UART: Instance> Serial<UART, u16> {
397    /// Converts this Serial into a version that can read and write `u8` values instead of `u16`s
398    ///
399    /// This can be used with a word length of 8 bits.
400    pub fn with_u8_data(self) -> Serial<UART, u8> {
401        Serial {
402            tx: self.tx.with_u8_data(),
403            rx: self.rx.with_u8_data(),
404        }
405    }
406}