ariel_os_stm32/
uart.rs

1//! UART configuration.
2
3#![expect(unsafe_code)]
4
5use ariel_os_embassy_common::{impl_async_uart_for_driver_enum, uart::ConfigError};
6use embassy_stm32::{
7    Peripheral, bind_interrupts, peripherals,
8    usart::{BufferedInterruptHandler, BufferedUart, RxPin, TxPin},
9};
10
11/// UART interface configuration.
12#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14#[non_exhaustive]
15pub struct Config {
16    /// The baud rate at which UART should operate.
17    pub baudrate: ariel_os_embassy_common::uart::Baudrate<Baudrate>,
18    /// Number of data bits.
19    pub data_bits: DataBits,
20    /// Number of stop bits.
21    pub stop_bits: StopBits,
22    /// Parity mode used for the interface.
23    pub parity: Parity,
24}
25
26impl Default for Config {
27    fn default() -> Self {
28        Self {
29            baudrate: ariel_os_embassy_common::uart::Baudrate::_115200,
30            data_bits: DataBits::Data8,
31            stop_bits: StopBits::Stop1,
32            parity: Parity::None,
33        }
34    }
35}
36
37/// UART baud rate.
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct Baudrate {
41    /// The baud rate at which UART should operate.
42    baudrate: u32,
43}
44
45impl From<Baudrate> for u32 {
46    fn from(baudrate: Baudrate) -> u32 {
47        baudrate.baudrate
48    }
49}
50
51impl From<u32> for Baudrate {
52    fn from(baudrate: u32) -> Baudrate {
53        Baudrate { baudrate }
54    }
55}
56
57impl From<ariel_os_embassy_common::uart::Baudrate<Self>> for Baudrate {
58    fn from(baud: ariel_os_embassy_common::uart::Baudrate<Self>) -> Baudrate {
59        match baud {
60            ariel_os_embassy_common::uart::Baudrate::Hal(baudrate) => baudrate,
61            ariel_os_embassy_common::uart::Baudrate::_2400 => Baudrate { baudrate: 2400 },
62            ariel_os_embassy_common::uart::Baudrate::_4800 => Baudrate { baudrate: 4800 },
63            ariel_os_embassy_common::uart::Baudrate::_9600 => Baudrate { baudrate: 9600 },
64            ariel_os_embassy_common::uart::Baudrate::_19200 => Baudrate { baudrate: 19_200 },
65            ariel_os_embassy_common::uart::Baudrate::_38400 => Baudrate { baudrate: 38_400 },
66            ariel_os_embassy_common::uart::Baudrate::_57600 => Baudrate { baudrate: 57_600 },
67            ariel_os_embassy_common::uart::Baudrate::_115200 => Baudrate { baudrate: 115_200 },
68        }
69    }
70}
71
72/// UART number of data bits.
73#[derive(Debug, Copy, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum DataBits {
76    /// 7 bits per character.
77    Data7,
78    /// 8 bits per character.
79    Data8,
80    /// 9 bits per character.
81    Data9,
82}
83
84fn from_databits(databits: DataBits) -> embassy_stm32::usart::DataBits {
85    match databits {
86        DataBits::Data7 => embassy_stm32::usart::DataBits::DataBits7,
87        DataBits::Data8 => embassy_stm32::usart::DataBits::DataBits8,
88        DataBits::Data9 => embassy_stm32::usart::DataBits::DataBits9,
89    }
90}
91
92impl From<ariel_os_embassy_common::uart::DataBits<Self>> for DataBits {
93    fn from(databits: ariel_os_embassy_common::uart::DataBits<Self>) -> DataBits {
94        match databits {
95            ariel_os_embassy_common::uart::DataBits::Hal(bits) => bits,
96            ariel_os_embassy_common::uart::DataBits::Data8 => DataBits::Data8,
97        }
98    }
99}
100
101/// Parity bit.
102#[derive(Debug, Copy, Clone, PartialEq, Eq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104pub enum Parity {
105    /// No parity bit.
106    None,
107    /// Even parity bit.
108    Even,
109    /// Odd parity bit.
110    Odd,
111}
112
113fn from_parity(parity: Parity) -> embassy_stm32::usart::Parity {
114    match parity {
115        Parity::None => embassy_stm32::usart::Parity::ParityNone,
116        Parity::Even => embassy_stm32::usart::Parity::ParityEven,
117        Parity::Odd => embassy_stm32::usart::Parity::ParityOdd,
118    }
119}
120
121impl From<ariel_os_embassy_common::uart::Parity<Self>> for Parity {
122    fn from(parity: ariel_os_embassy_common::uart::Parity<Self>) -> Self {
123        match parity {
124            ariel_os_embassy_common::uart::Parity::Hal(parity) => parity,
125            ariel_os_embassy_common::uart::Parity::None => Self::None,
126            ariel_os_embassy_common::uart::Parity::Even => Self::Even,
127        }
128    }
129}
130
131/// UART number of stop bits.
132#[derive(Debug, Copy, Clone, PartialEq, Eq)]
133#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134pub enum StopBits {
135    /// One stop bit.
136    Stop1,
137    /// 0.5 stop bits.
138    Stop0P5,
139    /// Two stop bits.
140    Stop2,
141    /// 1.5 stop bits.
142    Stop1P5,
143}
144
145fn from_stopbits(stop_bits: StopBits) -> embassy_stm32::usart::StopBits {
146    match stop_bits {
147        StopBits::Stop1 => embassy_stm32::usart::StopBits::STOP1,
148        StopBits::Stop0P5 => embassy_stm32::usart::StopBits::STOP0P5,
149        StopBits::Stop2 => embassy_stm32::usart::StopBits::STOP2,
150        StopBits::Stop1P5 => embassy_stm32::usart::StopBits::STOP1P5,
151    }
152}
153
154impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
155    fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
156        match stopbits {
157            ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
158            ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
159        }
160    }
161}
162
163fn convert_error(err: embassy_stm32::usart::ConfigError) -> ConfigError {
164    match err {
165        embassy_stm32::usart::ConfigError::BaudrateTooLow
166        | embassy_stm32::usart::ConfigError::BaudrateTooHigh => ConfigError::BaudrateNotSupported,
167        embassy_stm32::usart::ConfigError::DataParityNotSupported => {
168            ConfigError::DataParityNotSupported
169        }
170        _ => ConfigError::ConfigurationNotSupported,
171    }
172}
173
174macro_rules! define_uart_drivers {
175    ($( $interrupt:ident => $peripheral:ident ),* $(,)?) => {
176        $(
177            /// Peripheral-specific UART driver.
178            pub struct $peripheral<'d> {
179                uart: BufferedUart<'d>,
180            }
181
182            // Make this struct a compile-time-enforced singleton: having multiple statics
183            // defined with the same name would result in a compile-time error.
184            paste::paste! {
185                #[allow(dead_code)]
186                static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
187            }
188
189            impl<'d> $peripheral<'d> {
190                /// Returns a driver implementing embedded-io traits for this Uart
191                /// peripheral.
192                ///
193                /// # Errors
194                ///
195                /// Returns [`ConfigError::BaudrateNotSupported`] when the baud rate cannot be
196                /// applied to the peripheral.
197                /// Returns [`ConfigError::DataParityNotSupported`] when the combination of data
198                /// bits and parity cannot be applied to the peripheral.
199                /// Returns [`ConfigError::ConfigurationNotSupported`] when the requested configuration
200                /// cannot be applied to the peripheral.
201                #[expect(clippy::new_ret_no_self)]
202                pub fn new(
203                    rx_pin: impl Peripheral<P: RxPin<peripherals::$peripheral>> + 'd,
204                    tx_pin: impl Peripheral<P: TxPin<peripherals::$peripheral>> + 'd,
205                    rx_buf: &'d mut [u8],
206                    tx_buf: &'d mut [u8],
207                    config: Config,
208                ) -> Result<Uart<'d>, ConfigError> {
209
210                    let mut uart_config = embassy_stm32::usart::Config::default();
211                    uart_config.baudrate = Baudrate::from(config.baudrate).into();
212                    uart_config.data_bits = from_databits(config.data_bits).into();
213                    uart_config.stop_bits = from_stopbits(config.stop_bits).into();
214                    uart_config.parity = from_parity(config.parity).into();
215                    bind_interrupts!(struct Irqs {
216                        $interrupt => BufferedInterruptHandler<peripherals::$peripheral>;
217                    });
218
219                    // FIXME(safety): enforce that the init code indeed has run
220                    // SAFETY: this struct being a singleton prevents us from stealing the
221                    // peripheral multiple times.
222                    let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
223
224                    let uart = BufferedUart::new(
225                        uart_peripheral,
226                        Irqs,
227                        rx_pin,
228                        tx_pin,
229                        tx_buf,
230                        rx_buf,
231                        uart_config,
232                    ).map_err(convert_error)?;
233
234                    Ok(Uart::$peripheral(Self { uart }))
235                }
236            }
237        )*
238
239        /// Peripheral-agnostic UART driver.
240        pub enum Uart<'d> {
241            $(
242                #[doc = concat!(stringify!($peripheral), " peripheral.")]
243                $peripheral($peripheral<'d>)
244            ),*
245        }
246
247        impl embedded_io_async::ErrorType for Uart<'_> {
248            type Error = embassy_stm32::usart::Error;
249        }
250
251        impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
252    }
253}
254
255#[cfg(context = "stm32c031c6")]
256define_uart_drivers!(
257   USART1 => USART1,
258   // USART2 => USART2, // Often used as SWI
259);
260#[cfg(context = "stm32f042k6")]
261define_uart_drivers!(
262   USART1 => USART1,
263   // USART2 => USART2, // Often used as SWI
264);
265#[cfg(context = "stm32f401re")]
266define_uart_drivers!(
267   USART1 => USART1,
268   // USART2 => USART2, // Often used as SWI
269   USART6 => USART6,
270);
271#[cfg(context = "stm32f411re")]
272define_uart_drivers!(
273   USART1 => USART1,
274   // USART2 => USART2, // Often used as SWI
275   USART6 => USART6,
276);
277#[cfg(context = "stm32f767zi")]
278define_uart_drivers!(
279   USART1 => USART1,
280   USART2 => USART2,
281   USART3 => USART3,
282   UART4 => UART4,
283   // UART5 => UART5, // Often used as SWI
284   USART6 => USART6,
285   UART7 => UART7,
286   UART8 => UART8,
287);
288#[cfg(any(context = "stm32h755zi", context = "stm32h753zi"))]
289define_uart_drivers!(
290   LPUART1 => LPUART1,
291   USART1 => USART1,
292   USART2 => USART2,
293   USART3 => USART3,
294   UART4 => UART4,
295   // UART5 => UART5, // Often used as SWI
296   USART6 => USART6,
297   UART7 => UART7,
298   UART8 => UART8,
299);
300#[cfg(context = "stm32l475vg")]
301define_uart_drivers!(
302   LPUART1 => LPUART1,
303   USART1 => USART1,
304   USART2 => USART2,
305   USART3 => USART3,
306   UART4 => UART4,
307   // UART5 => UART5, // Often used as SWI
308);
309#[cfg(any(context = "stm32u073kc", context = "stm32u083mc"))]
310define_uart_drivers!(
311   USART1 => USART1,
312   USART2_LPUART2 => USART2,
313   USART3_LPUART1 => USART3,
314   // USART4_LPUART3 => USART4, // Often used as SWI
315);
316#[cfg(context = "stm32u585ai")]
317define_uart_drivers!(
318   LPUART1 => LPUART1,
319   USART1 => USART1,
320   // USART2 => USART2, // Often used as SWI
321   USART3 => USART3,
322   UART4 => UART4,
323   UART5 => UART5,
324);
325#[cfg(context = "stm32wb55rg")]
326define_uart_drivers!(
327   LPUART1 => LPUART1,
328   // USART1 => USART1, // Often used as SWI
329);
330#[cfg(context = "stm32wba55cg")]
331define_uart_drivers!(
332   LPUART1 => LPUART1,
333   USART1 => USART1,
334   // USART2 => USART2, // Often used as SWI
335);
336#[cfg(context = "stm32wle5jc")]
337define_uart_drivers!(
338   LPUART1 => LPUART1,
339   USART1 => USART1,
340   // USART2 => USART2, // Often used as SWI
341);
342
343#[doc(hidden)]
344pub fn init(peripherals: &mut crate::OptionalPeripherals) {
345    // Take all UART peripherals and do nothing with them.
346    cfg_if::cfg_if! {
347        if #[cfg(context = "stm32c031c6")] {
348            let _ = peripherals.USART1.take().unwrap();
349        } else if #[cfg(context = "stm32f042k6")] {
350            let _ = peripherals.USART1.take().unwrap();
351            let _ = peripherals.USART2.take().unwrap();
352        } else if #[cfg(context = "stm32f401re")] {
353            let _ = peripherals.USART1.take().unwrap();
354            let _ = peripherals.USART2.take().unwrap();
355            let _ = peripherals.USART6.take().unwrap();
356        } else if #[cfg(context = "stm32f411re")] {
357            let _ = peripherals.USART1.take().unwrap();
358            let _ = peripherals.USART2.take().unwrap();
359            let _ = peripherals.USART6.take().unwrap();
360        } else if #[cfg(context = "stm32f767zi")] {
361            let _ = peripherals.USART1.take().unwrap();
362            let _ = peripherals.USART2.take().unwrap();
363            let _ = peripherals.USART3.take().unwrap();
364            let _ = peripherals.UART4.take().unwrap();
365            let _ = peripherals.UART5.take().unwrap();
366            let _ = peripherals.USART6.take().unwrap();
367            let _ = peripherals.UART7.take().unwrap();
368            let _ = peripherals.UART8.take().unwrap();
369        } else if #[cfg(context = "stm32h755zi")] {
370            let _ = peripherals.LPUART1.take().unwrap();
371            let _ = peripherals.USART1.take().unwrap();
372            let _ = peripherals.USART2.take().unwrap();
373            let _ = peripherals.USART3.take().unwrap();
374            let _ = peripherals.UART4.take().unwrap();
375            let _ = peripherals.UART5.take().unwrap();
376            let _ = peripherals.USART6.take().unwrap();
377            let _ = peripherals.UART7.take().unwrap();
378            let _ = peripherals.UART8.take().unwrap();
379        } else if #[cfg(context = "stm32h753zi")] {
380            let _ = peripherals.LPUART1.take().unwrap();
381            let _ = peripherals.USART1.take().unwrap();
382            let _ = peripherals.USART2.take().unwrap();
383            let _ = peripherals.USART3.take().unwrap();
384            let _ = peripherals.UART4.take().unwrap();
385            let _ = peripherals.UART5.take().unwrap();
386            let _ = peripherals.USART6.take().unwrap();
387            let _ = peripherals.UART7.take().unwrap();
388            let _ = peripherals.UART8.take().unwrap();
389        } else if #[cfg(context = "stm32l475vg")] {
390            let _ = peripherals.LPUART1.take().unwrap();
391            let _ = peripherals.USART1.take().unwrap();
392            let _ = peripherals.USART2.take().unwrap();
393            let _ = peripherals.USART3.take().unwrap();
394            let _ = peripherals.UART4.take().unwrap();
395            let _ = peripherals.UART5.take().unwrap();
396        } else if #[cfg(any(context = "stm32u073kc", context = "stm32u083mc"))] {
397            let _ = peripherals.LPUART1.take().unwrap();
398            let _ = peripherals.LPUART2.take().unwrap();
399            let _ = peripherals.LPUART3.take().unwrap();
400            let _ = peripherals.USART1.take().unwrap();
401            let _ = peripherals.USART2.take().unwrap();
402            let _ = peripherals.USART3.take().unwrap();
403            let _ = peripherals.USART4.take().unwrap();
404        } else if #[cfg(context = "stm32u585ai")] {
405            let _ = peripherals.LPUART1.take().unwrap();
406            let _ = peripherals.USART1.take().unwrap();
407            let _ = peripherals.USART2.take().unwrap();
408            let _ = peripherals.USART3.take().unwrap();
409            let _ = peripherals.UART4.take().unwrap();
410            let _ = peripherals.UART5.take().unwrap();
411        } else if #[cfg(context = "stm32wb55rg")] {
412            let _ = peripherals.LPUART1.take().unwrap();
413            let _ = peripherals.USART1.take().unwrap();
414        } else if #[cfg(context = "stm32wba55cg")] {
415            let _ = peripherals.LPUART1.take().unwrap();
416            let _ = peripherals.USART1.take().unwrap();
417            let _ = peripherals.USART2.take().unwrap();
418        } else if #[cfg(context = "stm32wle5jc")] {
419            let _ = peripherals.LPUART1.take().unwrap();
420            let _ = peripherals.USART1.take().unwrap();
421            let _ = peripherals.USART2.take().unwrap();
422        } else {
423            compile_error!("this STM32 chip is not supported");
424        }
425    }
426}