1#![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#[derive(Debug, Clone, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14#[non_exhaustive]
15pub struct Config {
16 pub baudrate: ariel_os_embassy_common::uart::Baudrate<Baudrate>,
18 pub data_bits: DataBits,
20 pub stop_bits: StopBits,
22 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct Baudrate {
41 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum DataBits {
76 Data7,
78 Data8,
80 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104pub enum Parity {
105 None,
107 Even,
109 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
133#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134pub enum StopBits {
135 Stop1,
137 Stop0P5,
139 Stop2,
141 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 pub struct $peripheral<'d> {
179 uart: BufferedUart<'d>,
180 }
181
182 paste::paste! {
185 #[allow(dead_code)]
186 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
187 }
188
189 impl<'d> $peripheral<'d> {
190 #[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 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 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 );
260#[cfg(context = "stm32f042k6")]
261define_uart_drivers!(
262 USART1 => USART1,
263 );
265#[cfg(context = "stm32f401re")]
266define_uart_drivers!(
267 USART1 => USART1,
268 USART6 => USART6,
270);
271#[cfg(context = "stm32f411re")]
272define_uart_drivers!(
273 USART1 => USART1,
274 USART6 => USART6,
276);
277#[cfg(context = "stm32f767zi")]
278define_uart_drivers!(
279 USART1 => USART1,
280 USART2 => USART2,
281 USART3 => USART3,
282 UART4 => UART4,
283 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 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 );
309#[cfg(any(context = "stm32u073kc", context = "stm32u083mc"))]
310define_uart_drivers!(
311 USART1 => USART1,
312 USART2_LPUART2 => USART2,
313 USART3_LPUART1 => USART3,
314 );
316#[cfg(context = "stm32u585ai")]
317define_uart_drivers!(
318 LPUART1 => LPUART1,
319 USART1 => USART1,
320 USART3 => USART3,
322 UART4 => UART4,
323 UART5 => UART5,
324);
325#[cfg(context = "stm32wb55rg")]
326define_uart_drivers!(
327 LPUART1 => LPUART1,
328 );
330#[cfg(context = "stm32wba55cg")]
331define_uart_drivers!(
332 LPUART1 => LPUART1,
333 USART1 => USART1,
334 );
336#[cfg(context = "stm32wle5jc")]
337define_uart_drivers!(
338 LPUART1 => LPUART1,
339 USART1 => USART1,
340 );
342
343#[doc(hidden)]
344pub fn init(peripherals: &mut crate::OptionalPeripherals) {
345 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}