1#![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_nrf::{
9 bind_interrupts,
10 buffered_uarte::{BufferedUarte, InterruptHandler},
11 gpio::Pin as GpioPin,
12 peripherals,
13};
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18#[non_exhaustive]
19pub struct Config {
20 pub baudrate: ariel_os_embassy_common::uart::Baudrate<Baudrate>,
22 pub data_bits: DataBits,
24 pub stop_bits: StopBits,
26 pub parity: Parity,
28}
29
30impl Default for Config {
31 fn default() -> Self {
32 Self {
33 baudrate: ariel_os_embassy_common::uart::Baudrate::_115200,
34 data_bits: DataBits::Data8,
35 stop_bits: StopBits::Stop1,
36 parity: Parity::None,
37 }
38 }
39}
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44#[non_exhaustive]
45pub enum Baudrate {
46 _1200,
48 _2400,
50 _4800,
52 _9600,
54 _14400,
56 _19200,
58 _28800,
60 _31250,
62 _38400,
64 _56000,
66 _57600,
68 _76800,
70 _115200,
72 _230400,
74 _250000,
76 _460800,
78 _921600,
80 _1000000,
82}
83
84impl From<Baudrate> for u32 {
85 fn from(baud: Baudrate) -> u32 {
86 match baud {
87 Baudrate::_1200 => 1200,
88 Baudrate::_2400 => 2400,
89 Baudrate::_4800 => 4800,
90 Baudrate::_9600 => 9600,
91 Baudrate::_14400 => 14_400,
92 Baudrate::_19200 => 19_200,
93 Baudrate::_28800 => 28_800,
94 Baudrate::_31250 => 31_250,
95 Baudrate::_38400 => 38_400,
96 Baudrate::_56000 => 56_000,
97 Baudrate::_57600 => 57_600,
98 Baudrate::_76800 => 76_800,
99 Baudrate::_115200 => 11_5200,
100 Baudrate::_230400 => 23_0400,
101 Baudrate::_250000 => 25_0000,
102 Baudrate::_460800 => 46_0800,
103 Baudrate::_921600 => 92_1600,
104 Baudrate::_1000000 => 1_000_000,
105 }
106 }
107}
108
109fn from_baudrate(baud: Baudrate) -> embassy_nrf::buffered_uarte::Baudrate {
110 match baud {
111 Baudrate::_1200 => embassy_nrf::uarte::Baudrate::BAUD1200,
112 Baudrate::_2400 => embassy_nrf::uarte::Baudrate::BAUD2400,
113 Baudrate::_4800 => embassy_nrf::uarte::Baudrate::BAUD4800,
114 Baudrate::_9600 => embassy_nrf::uarte::Baudrate::BAUD9600,
115 Baudrate::_14400 => embassy_nrf::uarte::Baudrate::BAUD14400,
116 Baudrate::_19200 => embassy_nrf::uarte::Baudrate::BAUD19200,
117 Baudrate::_28800 => embassy_nrf::uarte::Baudrate::BAUD28800,
118 Baudrate::_31250 => embassy_nrf::uarte::Baudrate::BAUD31250,
119 Baudrate::_38400 => embassy_nrf::uarte::Baudrate::BAUD38400,
120 Baudrate::_56000 => embassy_nrf::uarte::Baudrate::BAUD56000,
121 Baudrate::_57600 => embassy_nrf::uarte::Baudrate::BAUD57600,
122 Baudrate::_76800 => embassy_nrf::uarte::Baudrate::BAUD76800,
123 Baudrate::_115200 => embassy_nrf::uarte::Baudrate::BAUD115200,
124 Baudrate::_230400 => embassy_nrf::uarte::Baudrate::BAUD230400,
125 Baudrate::_250000 => embassy_nrf::uarte::Baudrate::BAUD250000,
126 Baudrate::_460800 => embassy_nrf::uarte::Baudrate::BAUD460800,
127 Baudrate::_921600 => embassy_nrf::uarte::Baudrate::BAUD921600,
128 Baudrate::_1000000 => embassy_nrf::uarte::Baudrate::BAUD1M,
129 }
130}
131
132impl From<ariel_os_embassy_common::uart::Baudrate<Self>> for Baudrate {
133 fn from(baud: ariel_os_embassy_common::uart::Baudrate<Self>) -> Baudrate {
134 match baud {
135 ariel_os_embassy_common::uart::Baudrate::Hal(baud) => baud,
136 ariel_os_embassy_common::uart::Baudrate::_2400 => Baudrate::_2400,
137 ariel_os_embassy_common::uart::Baudrate::_4800 => Baudrate::_4800,
138 ariel_os_embassy_common::uart::Baudrate::_9600 => Baudrate::_9600,
139 ariel_os_embassy_common::uart::Baudrate::_19200 => Baudrate::_19200,
140 ariel_os_embassy_common::uart::Baudrate::_38400 => Baudrate::_38400,
141 ariel_os_embassy_common::uart::Baudrate::_57600 => Baudrate::_57600,
142 ariel_os_embassy_common::uart::Baudrate::_115200 => Baudrate::_115200,
143 }
144 }
145}
146
147#[derive(Debug, Copy, Clone, PartialEq, Eq)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150#[non_exhaustive]
151pub enum DataBits {
152 Data8,
154}
155
156impl From<ariel_os_embassy_common::uart::DataBits<Self>> for DataBits {
157 fn from(databits: ariel_os_embassy_common::uart::DataBits<Self>) -> DataBits {
158 match databits {
159 ariel_os_embassy_common::uart::DataBits::Hal(bits) => bits,
160 ariel_os_embassy_common::uart::DataBits::Data8 => DataBits::Data8,
161 }
162 }
163}
164#[derive(Debug, Copy, Clone, PartialEq, Eq)]
166#[cfg_attr(feature = "defmt", derive(defmt::Format))]
167#[non_exhaustive]
168pub enum StopBits {
169 Stop1,
171}
172
173impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
174 fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
175 match stopbits {
176 ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
177 ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
178 }
179 }
180}
181
182#[derive(Debug, Copy, Clone, PartialEq, Eq)]
184#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185#[non_exhaustive]
186pub enum Parity {
187 None,
189 Even,
191}
192
193fn from_parity(parity: Parity) -> embassy_nrf::uarte::Parity {
194 match parity {
195 Parity::None => embassy_nrf::uarte::Parity::EXCLUDED,
196 Parity::Even => embassy_nrf::uarte::Parity::INCLUDED,
197 }
198}
199
200impl From<ariel_os_embassy_common::uart::Parity<Self>> for Parity {
201 fn from(parity: ariel_os_embassy_common::uart::Parity<Self>) -> Self {
202 match parity {
203 ariel_os_embassy_common::uart::Parity::Hal(parity) => parity,
204 ariel_os_embassy_common::uart::Parity::None => Self::None,
205 ariel_os_embassy_common::uart::Parity::Even => Self::Even,
206 }
207 }
208}
209
210macro_rules! define_uart_drivers {
211 ($( $interrupt:ident => $peripheral:ident + $timer:ident + $ppi_ch1:ident + $ppi_ch2:ident + $ppi_group:ident),* $(,)?) => {
212 $(
213 pub struct $peripheral<'d> {
215 uart: BufferedUarte<'d>,
216 }
217
218 paste::paste! {
221 #[allow(dead_code)]
222 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
223 #[allow(dead_code)]
224 static [<PREVENT_MULTIPLE_ $timer>]: () = ();
225 #[allow(dead_code)]
226 static [<PREVENT_MULTIPLE_ $ppi_ch1>]: () = ();
227 #[allow(dead_code)]
228 static [<PREVENT_MULTIPLE_ $ppi_ch2>]: () = ();
229 #[allow(dead_code)]
230 static [<PREVENT_MULTIPLE_ $ppi_group>]: () = ();
231 }
232
233 paste::paste! {
235 static [< ACTIVE_ $peripheral >]: AtomicBool = AtomicBool::new(false);
236 }
237
238 impl<'d> $peripheral<'d> {
239 #[expect(clippy::new_ret_no_self)]
246 pub fn new<RX: GpioPin, TX: GpioPin>(
247 rx_pin: impl $crate::IntoPeripheral<'d, RX>,
248 tx_pin: impl $crate::IntoPeripheral<'d, TX>,
249 rx_buffer: &'d mut [u8],
250 tx_buffer: &'d mut [u8],
251 config: Config,
252 ) -> Result<Uart<'d>, ConfigError> {
253 let mut uart_config = embassy_nrf::uarte::Config::default();
254 uart_config.baudrate = from_baudrate(Baudrate::from(config.baudrate));
255 uart_config.parity = from_parity(config.parity);
256 bind_interrupts!(struct Irqs {
257 $interrupt => InterruptHandler<peripherals::$peripheral>;
258 });
259
260 paste::paste! {
262 if [< ACTIVE_ $peripheral >].swap(true, Ordering::AcqRel) {
263 panic!("UART peripheral already initialized")
264 }
265 }
266
267 let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
271 let timer_peripheral = unsafe { peripherals::$timer::steal() };
274 let ppi_ch1_peripheral = unsafe { peripherals::$ppi_ch1::steal() };
277 let ppi_ch2_peripheral = unsafe { peripherals::$ppi_ch2::steal() };
280 let ppi_group_peripheral = unsafe { peripherals::$ppi_group::steal() };
283
284 let uart = BufferedUarte::new(
285 uart_peripheral,
286 timer_peripheral,
287 ppi_ch1_peripheral,
288 ppi_ch2_peripheral,
289 ppi_group_peripheral,
290 rx_pin.into_hal_peripheral(),
291 tx_pin.into_hal_peripheral(),
292 Irqs,
293 uart_config,
294 rx_buffer,
295 tx_buffer
296 );
297
298 Ok(Uart::$peripheral(Self { uart }))
299 }
300 }
301
302 impl<'d> Drop for $peripheral<'d> {
303 fn drop(&mut self) {
304 paste::paste! {
305 [< ACTIVE_ $peripheral >].store(false, Ordering::Release);
306 }
307 }
308 }
309 )*
310
311 pub enum Uart<'d> {
313 $(
314 #[doc = concat!(stringify!($peripheral), " peripheral.")]
315 $peripheral($peripheral<'d>)
316 ),*
317 }
318
319 impl embedded_io_async::ErrorType for Uart<'_> {
320 type Error = embassy_nrf::buffered_uarte::Error;
321 }
322
323 impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
324 }
325}
326
327#[cfg(context = "nrf52832")]
329define_uart_drivers!(
330 UARTE0 => UARTE0 + TIMER4 + PPI_CH14 + PPI_CH15 + PPI_GROUP5,
331);
332#[cfg(context = "nrf52833")]
333define_uart_drivers!(
334 UARTE0 => UARTE0 + TIMER3 + PPI_CH13 + PPI_CH14 + PPI_GROUP4,
335 UARTE1 => UARTE1 + TIMER4 + PPI_CH15 + PPI_CH16 + PPI_GROUP5,
336);
337#[cfg(context = "nrf52840")]
338define_uart_drivers!(
339 UARTE0 => UARTE0 + TIMER3 + PPI_CH13 + PPI_CH14 + PPI_GROUP4,
340 UARTE1 => UARTE1 + TIMER4 + PPI_CH15 + PPI_CH16 + PPI_GROUP5,
341);
342#[cfg(context = "nrf5340-app")]
343define_uart_drivers!(
344 SERIAL3 => SERIAL3 + TIMER2 + PPI_CH18 + PPI_CH19 + PPI_GROUP5,
345);
346#[cfg(any(context = "nrf9151", context = "nrf9160"))]
347define_uart_drivers!(
348 SERIAL3 => SERIAL3 + TIMER2 + PPI_CH14 + PPI_CH15 + PPI_GROUP5,
349);
350
351#[doc(hidden)]
352pub fn init(peripherals: &mut crate::OptionalPeripherals) {
353 cfg_select! {
355 context = "nrf52832" => {
356 let _ = peripherals.UARTE0.take().unwrap();
357 let _ = peripherals.TIMER4.take().unwrap();
358 let _ = peripherals.PPI_CH14.take().unwrap();
359 let _ = peripherals.PPI_CH15.take().unwrap();
360 let _ = peripherals.PPI_GROUP5.take().unwrap();
361 }
362 context = "nrf52833" => {
363 let _ = peripherals.UARTE0.take().unwrap();
364 let _ = peripherals.TIMER3.take().unwrap();
365 let _ = peripherals.PPI_CH13.take().unwrap();
366 let _ = peripherals.PPI_CH14.take().unwrap();
367 let _ = peripherals.PPI_GROUP4.take().unwrap();
368
369 let _ = peripherals.UARTE1.take().unwrap();
370 let _ = peripherals.TIMER4.take().unwrap();
371 let _ = peripherals.PPI_CH15.take().unwrap();
372 let _ = peripherals.PPI_CH16.take().unwrap();
373 let _ = peripherals.PPI_GROUP5.take().unwrap();
374 }
375 context = "nrf52840" => {
376 let _ = peripherals.UARTE0.take().unwrap();
377 let _ = peripherals.TIMER3.take().unwrap();
378 let _ = peripherals.PPI_CH13.take().unwrap();
379 let _ = peripherals.PPI_CH14.take().unwrap();
380 let _ = peripherals.PPI_GROUP4.take().unwrap();
381
382 let _ = peripherals.UARTE1.take().unwrap();
383 let _ = peripherals.TIMER4.take().unwrap();
384 let _ = peripherals.PPI_CH15.take().unwrap();
385 let _ = peripherals.PPI_CH16.take().unwrap();
386 let _ = peripherals.PPI_GROUP5.take().unwrap();
387 }
388 context = "nrf5340-app" => {
389 let _ = peripherals.SERIAL3.take().unwrap();
390 let _ = peripherals.TIMER2.take().unwrap();
391 let _ = peripherals.PPI_CH18.take().unwrap();
392 let _ = peripherals.PPI_CH19.take().unwrap();
393 let _ = peripherals.PPI_GROUP5.take().unwrap();
394 }
395 any(context = "nrf9151", context = "nrf9160") => {
396 let _ = peripherals.SERIAL3.take().unwrap();
397 let _ = peripherals.TIMER2.take().unwrap();
398 let _ = peripherals.PPI_CH14.take().unwrap();
399 let _ = peripherals.PPI_CH15.take().unwrap();
400 let _ = peripherals.PPI_GROUP5.take().unwrap();
401 }
402 _ => {
403 compile_error!("this nRF chip is not supported");
404 }
405 }
406}