Skip to main content

ariel_os_stm32/
uart.rs

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