ariel_os_nrf/
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_nrf::{
7    Peripheral, bind_interrupts,
8    buffered_uarte::{BufferedUarte, InterruptHandler},
9    gpio::Pin as GpioPin,
10    peripherals,
11};
12
13/// UART interface configuration.
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[non_exhaustive]
17pub struct Config {
18    /// The baud rate at which UART operates.
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))]
42#[non_exhaustive]
43pub enum Baudrate {
44    /// 1200 baud.
45    _1200,
46    /// 2400 baud.
47    _2400,
48    /// 4800 baud.
49    _4800,
50    /// 9600 baud.
51    _9600,
52    /// 14400 baud.
53    _14400,
54    /// 19200 baud.
55    _19200,
56    /// 28800 baud.
57    _28800,
58    /// 31250 baud.
59    _31250,
60    /// 38400 baud.
61    _38400,
62    /// 56000 baud.
63    _56000,
64    /// 57600 baud.
65    _57600,
66    /// 76800 baud.
67    _76800,
68    /// 115200 baud.
69    _115200,
70    /// 230400 baud.
71    _230400,
72    /// 250000 baud.
73    _250000,
74    /// 460800 baud.
75    _460800,
76    /// 921600 baud.
77    _921600,
78    /// 1 Megabaud.
79    _1000000,
80}
81
82impl From<Baudrate> for u32 {
83    fn from(baud: Baudrate) -> u32 {
84        match baud {
85            Baudrate::_1200 => 1200,
86            Baudrate::_2400 => 2400,
87            Baudrate::_4800 => 4800,
88            Baudrate::_9600 => 9600,
89            Baudrate::_14400 => 14_400,
90            Baudrate::_19200 => 19_200,
91            Baudrate::_28800 => 28_800,
92            Baudrate::_31250 => 31_250,
93            Baudrate::_38400 => 38_400,
94            Baudrate::_56000 => 56_000,
95            Baudrate::_57600 => 57_600,
96            Baudrate::_76800 => 76_800,
97            Baudrate::_115200 => 11_5200,
98            Baudrate::_230400 => 23_0400,
99            Baudrate::_250000 => 25_0000,
100            Baudrate::_460800 => 46_0800,
101            Baudrate::_921600 => 92_1600,
102            Baudrate::_1000000 => 1_000_000,
103        }
104    }
105}
106
107fn from_baudrate(baud: Baudrate) -> embassy_nrf::buffered_uarte::Baudrate {
108    match baud {
109        Baudrate::_1200 => embassy_nrf::uarte::Baudrate::BAUD1200,
110        Baudrate::_2400 => embassy_nrf::uarte::Baudrate::BAUD2400,
111        Baudrate::_4800 => embassy_nrf::uarte::Baudrate::BAUD4800,
112        Baudrate::_9600 => embassy_nrf::uarte::Baudrate::BAUD9600,
113        Baudrate::_14400 => embassy_nrf::uarte::Baudrate::BAUD14400,
114        Baudrate::_19200 => embassy_nrf::uarte::Baudrate::BAUD19200,
115        Baudrate::_28800 => embassy_nrf::uarte::Baudrate::BAUD28800,
116        Baudrate::_31250 => embassy_nrf::uarte::Baudrate::BAUD31250,
117        Baudrate::_38400 => embassy_nrf::uarte::Baudrate::BAUD38400,
118        Baudrate::_56000 => embassy_nrf::uarte::Baudrate::BAUD56000,
119        Baudrate::_57600 => embassy_nrf::uarte::Baudrate::BAUD57600,
120        Baudrate::_76800 => embassy_nrf::uarte::Baudrate::BAUD76800,
121        Baudrate::_115200 => embassy_nrf::uarte::Baudrate::BAUD115200,
122        Baudrate::_230400 => embassy_nrf::uarte::Baudrate::BAUD230400,
123        Baudrate::_250000 => embassy_nrf::uarte::Baudrate::BAUD250000,
124        Baudrate::_460800 => embassy_nrf::uarte::Baudrate::BAUD460800,
125        Baudrate::_921600 => embassy_nrf::uarte::Baudrate::BAUD921600,
126        Baudrate::_1000000 => embassy_nrf::uarte::Baudrate::BAUD1M,
127    }
128}
129
130impl From<ariel_os_embassy_common::uart::Baudrate<Self>> for Baudrate {
131    fn from(baud: ariel_os_embassy_common::uart::Baudrate<Self>) -> Baudrate {
132        match baud {
133            ariel_os_embassy_common::uart::Baudrate::Hal(baud) => baud,
134            ariel_os_embassy_common::uart::Baudrate::_2400 => Baudrate::_2400,
135            ariel_os_embassy_common::uart::Baudrate::_4800 => Baudrate::_4800,
136            ariel_os_embassy_common::uart::Baudrate::_9600 => Baudrate::_9600,
137            ariel_os_embassy_common::uart::Baudrate::_19200 => Baudrate::_19200,
138            ariel_os_embassy_common::uart::Baudrate::_38400 => Baudrate::_38400,
139            ariel_os_embassy_common::uart::Baudrate::_57600 => Baudrate::_57600,
140            ariel_os_embassy_common::uart::Baudrate::_115200 => Baudrate::_115200,
141        }
142    }
143}
144
145/// UART number of data bits.
146#[derive(Debug, Copy, Clone, PartialEq, Eq)]
147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
148#[non_exhaustive]
149pub enum DataBits {
150    /// 8 bits per character.
151    Data8,
152}
153
154impl From<ariel_os_embassy_common::uart::DataBits<Self>> for DataBits {
155    fn from(databits: ariel_os_embassy_common::uart::DataBits<Self>) -> DataBits {
156        match databits {
157            ariel_os_embassy_common::uart::DataBits::Hal(bits) => bits,
158            ariel_os_embassy_common::uart::DataBits::Data8 => DataBits::Data8,
159        }
160    }
161}
162/// UART number of stop bits.
163#[derive(Debug, Copy, Clone, PartialEq, Eq)]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165#[non_exhaustive]
166pub enum StopBits {
167    /// One stop bit.
168    Stop1,
169}
170
171impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
172    fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
173        match stopbits {
174            ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
175            ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
176        }
177    }
178}
179
180/// Parity bit.
181#[derive(Debug, Copy, Clone, PartialEq, Eq)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183#[non_exhaustive]
184pub enum Parity {
185    /// No parity bit.
186    None,
187    /// Even parity bit.
188    Even,
189}
190
191fn from_parity(parity: Parity) -> embassy_nrf::uarte::Parity {
192    match parity {
193        Parity::None => embassy_nrf::uarte::Parity::EXCLUDED,
194        Parity::Even => embassy_nrf::uarte::Parity::INCLUDED,
195    }
196}
197
198impl From<ariel_os_embassy_common::uart::Parity<Self>> for Parity {
199    fn from(parity: ariel_os_embassy_common::uart::Parity<Self>) -> Self {
200        match parity {
201            ariel_os_embassy_common::uart::Parity::Hal(parity) => parity,
202            ariel_os_embassy_common::uart::Parity::None => Self::None,
203            ariel_os_embassy_common::uart::Parity::Even => Self::Even,
204        }
205    }
206}
207
208macro_rules! define_uart_drivers {
209    ($( $interrupt:ident => $peripheral:ident + $timer:ident + $ppi_ch1:ident + $ppi_ch2:ident + $ppi_group:ident),* $(,)?) => {
210        $(
211            /// Peripheral-specific UART driver.
212            pub struct $peripheral<'d> {
213                uart: BufferedUarte<'d, peripherals::$peripheral, peripherals::$timer>,
214            }
215
216            // Make this struct a compile-time-enforced singleton: having multiple statics
217            // defined with the same name would result in a compile-time error.
218            paste::paste! {
219                #[allow(dead_code)]
220                static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
221                #[allow(dead_code)]
222                static [<PREVENT_MULTIPLE_ $timer>]: () = ();
223                #[allow(dead_code)]
224                static [<PREVENT_MULTIPLE_ $ppi_ch1>]: () = ();
225                #[allow(dead_code)]
226                static [<PREVENT_MULTIPLE_ $ppi_ch2>]: () = ();
227                #[allow(dead_code)]
228                static [<PREVENT_MULTIPLE_ $ppi_group>]: () = ();
229            }
230
231            impl<'d> $peripheral<'d> {
232                /// Returns a driver implementing [`embedded_io_async`] for this Uart
233                /// peripheral.
234                ///
235                /// # Errors
236                ///
237                /// This never returns an error.
238                #[expect(clippy::new_ret_no_self)]
239                pub fn new(
240                    rx_pin: impl Peripheral<P: GpioPin> + 'd,
241                    tx_pin: impl Peripheral<P: GpioPin> + 'd,
242                    rx_buffer: &'d mut [u8],
243                    tx_buffer: &'d mut [u8],
244                    config: Config,
245                ) -> Result<Uart<'d>, ConfigError> {
246                    let mut uart_config = embassy_nrf::uarte::Config::default();
247                    uart_config.baudrate = from_baudrate(Baudrate::from(config.baudrate));
248                    uart_config.parity = from_parity(config.parity);
249                    bind_interrupts!(struct Irqs {
250                        $interrupt => InterruptHandler<peripherals::$peripheral>;
251                    });
252
253                    // FIXME(safety): enforce that the init code indeed has run
254                    // SAFETY: this struct being a singleton prevents us from stealing the
255                    // peripheral multiple times.
256                    let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
257                    // SAFETY: this struct being a singleton prevents us from stealing the
258                    // required timer multiple times.
259                    let timer_peripheral = unsafe { peripherals::$timer::steal() };
260                    // SAFETY: this struct being a singleton prevents us from stealing the
261                    // required ppi channel multiple times.
262                    let ppi_ch1_peripheral = unsafe { peripherals::$ppi_ch1::steal() };
263                    // SAFETY: this struct being a singleton prevents us from stealing the
264                    // required ppi channel multiple times.
265                    let ppi_ch2_peripheral = unsafe { peripherals::$ppi_ch2::steal() };
266                    // SAFETY: this struct being a singleton prevents us from stealing the
267                    // required ppi group multiple times.
268                    let ppi_group_peripheral = unsafe { peripherals::$ppi_group::steal() };
269
270                    let uart = BufferedUarte::new(
271                        uart_peripheral,
272                        timer_peripheral,
273                        ppi_ch1_peripheral,
274                        ppi_ch2_peripheral,
275                        ppi_group_peripheral,
276                        Irqs,
277                        rx_pin,
278                        tx_pin,
279                        uart_config,
280                        rx_buffer,
281                        tx_buffer
282                    );
283
284                    Ok(Uart::$peripheral(Self { uart }))
285                }
286            }
287        )*
288
289        /// Peripheral-agnostic UART driver.
290        pub enum Uart<'d> {
291            $(
292                #[doc = concat!(stringify!($peripheral), " peripheral.")]
293                $peripheral($peripheral<'d>)
294            ),*
295        }
296
297        impl embedded_io_async::ErrorType for Uart<'_> {
298            type Error = embassy_nrf::buffered_uarte::Error;
299        }
300
301        impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
302    }
303}
304
305// Define a driver per peripheral
306#[cfg(context = "nrf52832")]
307define_uart_drivers!(
308   UARTE0 => UARTE0 + TIMER4 + PPI_CH14 + PPI_CH15 + PPI_GROUP5,
309);
310#[cfg(context = "nrf52833")]
311define_uart_drivers!(
312   UARTE0 => UARTE0 + TIMER3 + PPI_CH13 + PPI_CH14 + PPI_GROUP4,
313   UARTE1 => UARTE1 + TIMER4 + PPI_CH15 + PPI_CH16 + PPI_GROUP5,
314);
315#[cfg(context = "nrf52840")]
316define_uart_drivers!(
317   UARTE0 => UARTE0 + TIMER3 + PPI_CH13 + PPI_CH14 + PPI_GROUP4,
318   UARTE1 => UARTE1 + TIMER4 + PPI_CH15 + PPI_CH16 + PPI_GROUP5,
319);
320#[cfg(context = "nrf5340")]
321define_uart_drivers!(
322   SERIAL3 => SERIAL3 + TIMER2 + PPI_CH18 + PPI_CH19 + PPI_GROUP5,
323);
324#[cfg(any(context = "nrf9151", context = "nrf9160"))]
325define_uart_drivers!(
326   SERIAL3 => SERIAL3 + TIMER2 + PPI_CH14 + PPI_CH15 + PPI_GROUP5,
327);
328
329#[doc(hidden)]
330pub fn init(peripherals: &mut crate::OptionalPeripherals) {
331    // Take all UART peripherals and do nothing with them.
332    cfg_if::cfg_if! {
333        if #[cfg(context = "nrf52832")] {
334            let _ = peripherals.UARTE0.take().unwrap();
335            let _ = peripherals.TIMER4.take().unwrap();
336            let _ = peripherals.PPI_CH14.take().unwrap();
337            let _ = peripherals.PPI_CH15.take().unwrap();
338            let _ = peripherals.PPI_GROUP5.take().unwrap();
339        } else if #[cfg(context = "nrf52833")] {
340            let _ = peripherals.UARTE0.take().unwrap();
341            let _ = peripherals.TIMER3.take().unwrap();
342            let _ = peripherals.PPI_CH13.take().unwrap();
343            let _ = peripherals.PPI_CH14.take().unwrap();
344            let _ = peripherals.PPI_GROUP4.take().unwrap();
345
346            let _ = peripherals.UARTE1.take().unwrap();
347            let _ = peripherals.TIMER4.take().unwrap();
348            let _ = peripherals.PPI_CH15.take().unwrap();
349            let _ = peripherals.PPI_CH16.take().unwrap();
350            let _ = peripherals.PPI_GROUP5.take().unwrap();
351        } else if #[cfg(context = "nrf52840")] {
352            let _ = peripherals.UARTE0.take().unwrap();
353            let _ = peripherals.TIMER3.take().unwrap();
354            let _ = peripherals.PPI_CH13.take().unwrap();
355            let _ = peripherals.PPI_CH14.take().unwrap();
356            let _ = peripherals.PPI_GROUP4.take().unwrap();
357
358            let _ = peripherals.UARTE1.take().unwrap();
359            let _ = peripherals.TIMER4.take().unwrap();
360            let _ = peripherals.PPI_CH15.take().unwrap();
361            let _ = peripherals.PPI_CH16.take().unwrap();
362            let _ = peripherals.PPI_GROUP5.take().unwrap();
363        } else if #[cfg(context = "nrf5340")] {
364            let _ = peripherals.SERIAL3.take().unwrap();
365            let _ = peripherals.TIMER2.take().unwrap();
366            let _ = peripherals.PPI_CH18.take().unwrap();
367            let _ = peripherals.PPI_CH19.take().unwrap();
368            let _ = peripherals.PPI_GROUP5.take().unwrap();
369        } else if #[cfg(any(context = "nrf9151", context = "nrf9160"))] {
370            let _ = peripherals.SERIAL3.take().unwrap();
371            let _ = peripherals.TIMER2.take().unwrap();
372            let _ = peripherals.PPI_CH14.take().unwrap();
373            let _ = peripherals.PPI_CH15.take().unwrap();
374            let _ = peripherals.PPI_GROUP5.take().unwrap();
375        } else {
376            compile_error!("this nRF chip is not supported");
377        }
378    }
379}