vorago_shared_hal/uart/
mod.rs

1//! # API for the UART peripheral
2//!
3//! The core of this API are the [Uart], [Rx] and [Tx] structures.
4//! The RX structure also has a dedicated [RxWithInterrupt] variant which allows reading the receiver
5//! using interrupts.
6//!
7//! The [rx_asynch] and [tx_asynch] modules provide an asynchronous non-blocking API for the UART
8//! peripheral.
9//!
10//! ## Examples
11//!
12//! - [UART simple example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/uart.rs)
13//! - [UART with IRQ and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/rtic/src/bin/uart-echo-rtic.rs)
14//! - [Flashloader exposing a CCSDS interface via UART](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader)
15use core::convert::Infallible;
16pub mod regs;
17#[cfg(feature = "vor1x")]
18use crate::InterruptConfig;
19use crate::{FunctionSelect, gpio::IoPeriphPin, pins::AnyPin, sealed::Sealed};
20use arbitrary_int::{prelude::*, u6, u18};
21use fugit::RateExtU32;
22use regs::{ClockScale, Control, Data, Enable, FifoClear, InterruptClear, MmioUart};
23
24use crate::{PeripheralSelect, enable_nvic_interrupt, enable_peripheral_clock, time::Hertz};
25use embedded_hal_nb::serial::Read;
26pub use regs::{Bank, Stopbits, WordSize};
27
28#[cfg(feature = "vor1x")]
29mod pins_vor1x;
30#[cfg(feature = "vor4x")]
31mod pins_vor4x;
32
33#[cfg(feature = "vor4x")]
34use crate::clock::Clocks;
35#[cfg(feature = "vor1x")]
36use va108xx as pac;
37#[cfg(feature = "vor4x")]
38use va416xx as pac;
39
40pub mod tx_asynch;
41pub use tx_asynch::*;
42
43pub mod rx_asynch;
44pub use rx_asynch::*;
45
46//==================================================================================================
47// Type-Level support
48//==================================================================================================
49
50pub trait TxPin: AnyPin {
51    const BANK: Bank;
52    const FUN_SEL: FunctionSelect;
53}
54pub trait RxPin: AnyPin {
55    const BANK: Bank;
56    const FUN_SEL: FunctionSelect;
57}
58
59//==================================================================================================
60// Regular Definitions
61//==================================================================================================
62
63#[derive(Debug, PartialEq, Eq, thiserror::Error)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65#[error("no interrupt ID was set")]
66pub struct NoInterruptIdWasSet;
67
68#[derive(Debug, PartialEq, Eq, thiserror::Error)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[error("transer is pending")]
71pub struct TransferPendingError;
72
73#[derive(Debug, PartialEq, Eq, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum Event {
76    // Receiver FIFO interrupt enable. Generates interrupt
77    // when FIFO is at least half full. Half full is defined as FIFO
78    // count >= RXFIFOIRQTRG
79    RxFifoHalfFull,
80    // Framing error, Overrun error, Parity Error and Break error
81    RxError,
82    // Event for timeout condition: Data in the FIFO and no receiver
83    // FIFO activity for 4 character times
84    RxTimeout,
85
86    // Transmitter FIFO interrupt enable. Generates interrupt
87    // when FIFO is at least half full. Half full is defined as FIFO
88    // count >= TXFIFOIRQTRG
89    TxFifoHalfFull,
90    // FIFO overflow error
91    TxError,
92    // Generate interrupt when transmit FIFO is empty and TXBUSY is 0
93    TxEmpty,
94    // Interrupt when CTSn changes value
95    TxCts,
96}
97
98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
100pub enum Parity {
101    None,
102    Odd,
103    Even,
104}
105
106#[derive(Debug, Copy, Clone, PartialEq, Eq)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub struct Config {
109    pub baudrate: Hertz,
110    pub parity: Parity,
111    pub stopbits: Stopbits,
112    // When false, use standard 16x baud clock, other 8x baud clock
113    pub baud8: bool,
114    pub wordsize: WordSize,
115    pub enable_tx: bool,
116    pub enable_rx: bool,
117}
118
119impl Config {
120    pub fn baudrate(mut self, baudrate: Hertz) -> Self {
121        self.baudrate = baudrate;
122        self
123    }
124
125    pub fn parity_none(mut self) -> Self {
126        self.parity = Parity::None;
127        self
128    }
129
130    pub fn parity_even(mut self) -> Self {
131        self.parity = Parity::Even;
132        self
133    }
134
135    pub fn parity_odd(mut self) -> Self {
136        self.parity = Parity::Odd;
137        self
138    }
139
140    pub fn stopbits(mut self, stopbits: Stopbits) -> Self {
141        self.stopbits = stopbits;
142        self
143    }
144
145    pub fn wordsize(mut self, wordsize: WordSize) -> Self {
146        self.wordsize = wordsize;
147        self
148    }
149
150    pub fn baud8(mut self, baud: bool) -> Self {
151        self.baud8 = baud;
152        self
153    }
154}
155
156impl Default for Config {
157    fn default() -> Config {
158        let baudrate = 115_200_u32.Hz();
159        Config {
160            baudrate,
161            parity: Parity::None,
162            stopbits: Stopbits::One,
163            baud8: false,
164            wordsize: WordSize::Eight,
165            enable_tx: true,
166            enable_rx: true,
167        }
168    }
169}
170
171impl From<Hertz> for Config {
172    fn from(baud: Hertz) -> Self {
173        Config::default().baudrate(baud)
174    }
175}
176
177//==================================================================================================
178// IRQ Definitions
179//==================================================================================================
180
181#[derive(Debug, Copy, Clone)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub struct InterruptContextTimeoutOrMaxSize {
184    rx_idx: usize,
185    mode: InterruptReceptionMode,
186    pub max_len: usize,
187}
188
189impl InterruptContextTimeoutOrMaxSize {
190    pub fn new(max_len: usize) -> Self {
191        InterruptContextTimeoutOrMaxSize {
192            rx_idx: 0,
193            max_len,
194            mode: InterruptReceptionMode::Idle,
195        }
196    }
197}
198
199impl InterruptContextTimeoutOrMaxSize {
200    pub fn reset(&mut self) {
201        self.rx_idx = 0;
202        self.mode = InterruptReceptionMode::Idle;
203    }
204}
205
206/// This struct is used to return the default IRQ handler result to the user
207#[derive(Debug, Default)]
208#[cfg_attr(feature = "defmt", derive(defmt::Format))]
209pub struct InterruptResult {
210    pub bytes_read: usize,
211    pub errors: Option<UartErrors>,
212}
213
214/// This struct is used to return the default IRQ handler result to the user
215#[derive(Debug, Default)]
216#[cfg_attr(feature = "defmt", derive(defmt::Format))]
217pub struct InterruptResultMaxSizeOrTimeout {
218    complete: bool,
219    timeout: bool,
220    pub errors: Option<UartErrors>,
221    pub bytes_read: usize,
222}
223
224impl InterruptResultMaxSizeOrTimeout {
225    pub fn new() -> Self {
226        InterruptResultMaxSizeOrTimeout {
227            complete: false,
228            timeout: false,
229            errors: None,
230            bytes_read: 0,
231        }
232    }
233}
234impl InterruptResultMaxSizeOrTimeout {
235    #[inline]
236    pub fn has_errors(&self) -> bool {
237        self.errors.is_some()
238    }
239
240    #[inline]
241    pub fn overflow_error(&self) -> bool {
242        self.errors.is_some_and(|e| e.overflow)
243    }
244
245    #[inline]
246    pub fn framing_error(&self) -> bool {
247        self.errors.is_some_and(|e| e.framing)
248    }
249
250    #[inline]
251    pub fn parity_error(&self) -> bool {
252        self.errors.is_some_and(|e| e.parity)
253    }
254
255    #[inline]
256    pub fn timeout(&self) -> bool {
257        self.timeout
258    }
259
260    #[inline]
261    pub fn complete(&self) -> bool {
262        self.complete
263    }
264}
265
266#[derive(Debug, PartialEq, Copy, Clone)]
267#[cfg_attr(feature = "defmt", derive(defmt::Format))]
268enum InterruptReceptionMode {
269    Idle,
270    Pending,
271}
272
273#[derive(Default, Debug, Copy, Clone)]
274#[cfg_attr(feature = "defmt", derive(defmt::Format))]
275pub struct UartErrors {
276    overflow: bool,
277    framing: bool,
278    parity: bool,
279    other: bool,
280}
281
282impl UartErrors {
283    #[inline(always)]
284    pub fn overflow(&self) -> bool {
285        self.overflow
286    }
287
288    #[inline(always)]
289    pub fn framing(&self) -> bool {
290        self.framing
291    }
292
293    #[inline(always)]
294    pub fn parity(&self) -> bool {
295        self.parity
296    }
297
298    #[inline(always)]
299    pub fn other(&self) -> bool {
300        self.other
301    }
302}
303
304impl UartErrors {
305    #[inline(always)]
306    pub fn error(&self) -> bool {
307        self.overflow || self.framing || self.parity || self.other
308    }
309}
310
311#[derive(Debug, PartialEq, Eq)]
312#[cfg_attr(feature = "defmt", derive(defmt::Format))]
313pub struct BufferTooShortError {
314    found: usize,
315    expected: usize,
316}
317
318//==================================================================================================
319// UART peripheral wrapper
320//==================================================================================================
321
322pub trait UartInstance: Sealed {
323    const ID: Bank;
324    const PERIPH_SEL: PeripheralSelect;
325}
326
327#[cfg(feature = "vor1x")]
328pub type Uart0 = pac::Uarta;
329#[cfg(feature = "vor4x")]
330pub type Uart0 = pac::Uart0;
331
332impl UartInstance for Uart0 {
333    const ID: Bank = Bank::Uart0;
334    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart0;
335}
336impl Sealed for Uart0 {}
337
338#[cfg(feature = "vor1x")]
339pub type Uart1 = pac::Uartb;
340#[cfg(feature = "vor4x")]
341pub type Uart1 = pac::Uart1;
342
343impl UartInstance for Uart1 {
344    const ID: Bank = Bank::Uart1;
345    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
346}
347impl Sealed for Uart1 {}
348
349#[cfg(feature = "vor4x")]
350impl UartInstance for pac::Uart2 {
351    const ID: Bank = Bank::Uart2;
352    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart2;
353}
354#[cfg(feature = "vor4x")]
355impl Sealed for pac::Uart2 {}
356
357#[derive(Debug, thiserror::Error)]
358#[cfg_attr(feature = "defmt", derive(defmt::Format))]
359#[error("UART ID missmatch between peripheral and pins.")]
360pub struct UartIdMissmatchError;
361
362//==================================================================================================
363// UART implementation
364//==================================================================================================
365
366/// UART driver structure.
367pub struct Uart {
368    tx: Tx,
369    rx: Rx,
370}
371
372impl Uart {
373    cfg_if::cfg_if! {
374        if #[cfg(feature = "vor1x")] {
375            /// Calls [Self::new] with the interrupt configuration to some valid value.
376            pub fn new_with_interrupt<UartPeriph: UartInstance, Tx: TxPin, Rx: RxPin>(
377                uart: UartPeriph,
378                tx_pin: Tx,
379                rx_pin: Rx,
380                sys_clk: Hertz,
381                config: Config,
382                irq_cfg: InterruptConfig,
383            ) -> Result<Self, UartIdMissmatchError> {
384                Self::new(uart, tx_pin, rx_pin, sys_clk, config, Some(irq_cfg))
385            }
386
387            /// Calls [Self::new] with the interrupt configuration to [None].
388            pub fn new_without_interrupt<UartPeriph: UartInstance, Tx: TxPin, Rx: RxPin>(
389                uart: UartPeriph,
390                tx_pin: Tx,
391                rx_pin: Rx,
392                sys_clk: Hertz,
393                config: Config,
394            ) -> Result<Self, UartIdMissmatchError> {
395                Self::new(uart, tx_pin, rx_pin, sys_clk, config, None)
396            }
397
398            /// Create a new UART peripheral driver with an interrupt configuration.
399            ///
400            /// # Arguments
401            ///
402            /// - `syscfg`: The system configuration register block
403            /// - `sys_clk`: The system clock frequency
404            /// - `uart`: The concrete UART peripheral instance.
405            /// - `pins`: UART TX and RX pin tuple.
406            /// - `config`: UART specific configuration parameters like baudrate.
407            /// - `irq_cfg`: Optional interrupt configuration. This should be a valid value if the plan
408            ///   is to use TX or RX functionality relying on interrupts. If only the blocking API without
409            ///   any interrupt support is used, this can be [None].
410            pub fn new<UartPeriph: UartInstance, Tx: TxPin, Rx: RxPin>(
411                uart: UartPeriph,
412                tx_pin: Tx,
413                rx_pin: Rx,
414                sys_clk: Hertz,
415                config: Config,
416                opt_irq_cfg: Option<InterruptConfig>,
417            ) -> Result<Self, UartIdMissmatchError> {
418                Self::new_internal(uart, (tx_pin, rx_pin), sys_clk, config, opt_irq_cfg)
419            }
420        } else if #[cfg(feature = "vor4x")] {
421            /// Create a new UART peripheral driver.
422            ///
423            /// # Arguments
424            ///
425            /// - `clks`: Frozen system clock configuration.
426            /// - `uart`: The concrete UART peripheral instance.
427            /// - `pins`: UART TX and RX pin tuple.
428            /// - `config`: UART specific configuration parameters like baudrate.
429            pub fn new<UartI: UartInstance, Tx: TxPin, Rx: RxPin>(
430                uart: UartI,
431                tx_pin: Tx,
432                rx_pin: Rx,
433                clks: &Clocks,
434                config: Config,
435            ) -> Result<Self, UartIdMissmatchError> {
436                if UartI::ID == Bank::Uart2 {
437                    Self::new_internal(uart, (tx_pin, rx_pin), clks.apb1(), config)
438                } else {
439                    Self::new_internal(uart, (tx_pin, rx_pin), clks.apb2(), config)
440                }
441            }
442
443            /// Create a new UART peripheral driver given a reference clock.
444            ///
445            /// # Arguments
446            ///
447            /// - `ref_clk`: APB1 clock for UART2, APB2 clock otherwise.
448            /// - `uart`: The concrete UART peripheral instance.
449            /// - `pins`: UART TX and RX pin tuple.
450            /// - `config`: UART specific configuration parameters like baudrate.
451            pub fn new_with_ref_clk<Uart: UartInstance, Tx: TxPin, Rx: RxPin>(
452                uart: Uart,
453                tx_pin: Tx,
454                rx_pin: Rx,
455                ref_clk: Hertz,
456                config: Config,
457            ) -> Result<Self, UartIdMissmatchError> {
458                Self::new_internal(uart,(tx_pin, rx_pin),ref_clk, config)
459            }
460        }
461    }
462
463    fn new_internal<UartI: UartInstance, TxPinI: TxPin, RxPinI: RxPin>(
464        _uart: UartI,
465        _pins: (TxPinI, RxPinI),
466        ref_clk: Hertz,
467        config: Config,
468        #[cfg(feature = "vor1x")] opt_irq_cfg: Option<InterruptConfig>,
469    ) -> Result<Self, UartIdMissmatchError> {
470        if UartI::ID != TxPinI::BANK || UartI::ID != RxPinI::BANK {
471            return Err(UartIdMissmatchError);
472        }
473        IoPeriphPin::new(TxPinI::ID, TxPinI::FUN_SEL, None);
474        IoPeriphPin::new(RxPinI::ID, TxPinI::FUN_SEL, None);
475        enable_peripheral_clock(UartI::PERIPH_SEL);
476
477        let mut reg_block = regs::Uart::new_mmio(UartI::ID);
478        let baud_multiplier = match config.baud8 {
479            false => 16,
480            true => 8,
481        };
482
483        // This is the calculation: (64.0 * (x - integer_part as f32) + 0.5) as u32 without floating
484        // point calculations.
485        let frac = ((ref_clk.raw() % (config.baudrate.raw() * 16)) * 64
486            + (config.baudrate.raw() * 8))
487            / (config.baudrate.raw() * 16);
488        // Calculations here are derived from chapter 4.8.5 (p.79) of the datasheet.
489        let x = ref_clk.raw() as f32 / (config.baudrate.raw() * baud_multiplier) as f32;
490        let integer_part = x as u32;
491        reg_block.write_clkscale(
492            ClockScale::builder()
493                .with_int(u18::new(integer_part))
494                .with_frac(u6::new(frac as u8))
495                .build(),
496        );
497
498        let (paren, pareven) = match config.parity {
499            Parity::None => (false, false),
500            Parity::Odd => (true, false),
501            Parity::Even => (true, true),
502        };
503        reg_block.write_ctrl(
504            Control::builder()
505                .with_baud8(config.baud8)
506                .with_auto_rts(false)
507                .with_def_rts(false)
508                .with_auto_cts(false)
509                .with_loopback_block(false)
510                .with_loopback(false)
511                .with_wordsize(config.wordsize)
512                .with_stopbits(config.stopbits)
513                .with_parity_manual(false)
514                .with_parity_even(pareven)
515                .with_parity_enable(paren)
516                .build(),
517        );
518        // Clear the FIFO
519        reg_block.write_fifo_clr(FifoClear::builder().with_tx(true).with_rx(true).build());
520        reg_block.write_enable(
521            Enable::builder()
522                .with_tx(config.enable_tx)
523                .with_rx(config.enable_rx)
524                .build(),
525        );
526
527        #[cfg(feature = "vor1x")]
528        if let Some(irq_cfg) = opt_irq_cfg {
529            if irq_cfg.route {
530                enable_peripheral_clock(PeripheralSelect::Irqsel);
531                unsafe { va108xx::Irqsel::steal() }
532                    .uart(UartI::ID as usize)
533                    .write(|w| unsafe { w.bits(irq_cfg.id as u32) });
534            }
535            if irq_cfg.enable_in_nvic {
536                // Safety: User has specifically configured this.
537                unsafe { enable_nvic_interrupt(irq_cfg.id) };
538            }
539        }
540
541        Ok(Uart {
542            tx: Tx::new(UartI::ID),
543            rx: Rx::new(UartI::ID),
544        })
545    }
546
547    #[inline]
548    pub fn peripheral_id(&self) -> u32 {
549        self.tx.perid()
550    }
551
552    #[inline]
553    pub fn enable_rx(&mut self) {
554        self.rx.enable();
555    }
556
557    #[inline]
558    pub fn disable_rx(&mut self) {
559        self.rx.disable();
560    }
561
562    #[inline]
563    pub fn enable_tx(&mut self) {
564        self.tx.enable();
565    }
566
567    #[inline]
568    pub fn disable_tx(&mut self) {
569        self.tx.disable();
570    }
571
572    /// This also clears status conditons for the RX FIFO.
573    #[inline]
574    pub fn clear_rx_fifo(&mut self) {
575        self.rx.clear_fifo();
576    }
577
578    /// This also clears status conditons for the TX FIFO.
579    #[inline]
580    pub fn clear_tx_fifo(&mut self) {
581        self.tx.clear_fifo();
582    }
583
584    pub fn listen(&mut self, event: Event) {
585        self.tx.regs.modify_irq_enabled(|mut value| {
586            match event {
587                Event::RxError => value.set_rx_status(true),
588                Event::RxFifoHalfFull => value.set_rx(true),
589                Event::RxTimeout => value.set_rx_timeout(true),
590                Event::TxEmpty => value.set_tx_empty(true),
591                Event::TxError => value.set_tx_status(true),
592                Event::TxFifoHalfFull => value.set_tx(true),
593                Event::TxCts => value.set_tx_cts(true),
594            }
595            value
596        });
597    }
598
599    pub fn unlisten(&mut self, event: Event) {
600        self.tx.regs.modify_irq_enabled(|mut value| {
601            match event {
602                Event::RxError => value.set_rx_status(false),
603                Event::RxFifoHalfFull => value.set_rx(false),
604                Event::RxTimeout => value.set_rx_timeout(false),
605                Event::TxEmpty => value.set_tx_empty(false),
606                Event::TxError => value.set_tx_status(false),
607                Event::TxFifoHalfFull => value.set_tx(false),
608                Event::TxCts => value.set_tx_cts(false),
609            }
610            value
611        });
612    }
613
614    /// Poll receiver errors.
615    pub fn poll_rx_errors(&self) -> Option<UartErrors> {
616        self.rx.poll_errors()
617    }
618
619    pub fn split(self) -> (Tx, Rx) {
620        (self.tx, self.rx)
621    }
622}
623
624impl embedded_io::ErrorType for Uart {
625    type Error = Infallible;
626}
627
628impl embedded_hal_nb::serial::ErrorType for Uart {
629    type Error = Infallible;
630}
631
632impl embedded_hal_nb::serial::Read<u8> for Uart {
633    fn read(&mut self) -> nb::Result<u8, Self::Error> {
634        self.rx.read()
635    }
636}
637
638impl embedded_hal_nb::serial::Write<u8> for Uart {
639    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
640        self.tx.write(word).map_err(|e| {
641            if let nb::Error::Other(_) = e {
642                unreachable!()
643            }
644            nb::Error::WouldBlock
645        })
646    }
647
648    fn flush(&mut self) -> nb::Result<(), Self::Error> {
649        self.tx.flush().map_err(|e| {
650            if let nb::Error::Other(_) = e {
651                unreachable!()
652            }
653            nb::Error::WouldBlock
654        })
655    }
656}
657
658#[inline(always)]
659pub fn enable_rx(uart: &mut MmioUart<'static>) {
660    uart.modify_enable(|mut value| {
661        value.set_rx(true);
662        value
663    });
664}
665
666#[inline(always)]
667pub fn disable_rx(uart: &mut MmioUart<'static>) {
668    uart.modify_enable(|mut value| {
669        value.set_rx(false);
670        value
671    });
672}
673
674#[inline(always)]
675pub fn enable_rx_interrupts(uart: &mut MmioUart<'static>, timeout: bool) {
676    uart.modify_irq_enabled(|mut value| {
677        value.set_rx_status(true);
678        value.set_rx(true);
679        if timeout {
680            value.set_rx_timeout(true);
681        }
682        value
683    });
684}
685
686#[inline(always)]
687pub fn disable_rx_interrupts(uart: &mut MmioUart<'static>) {
688    uart.modify_irq_enabled(|mut value| {
689        value.set_rx_status(false);
690        value.set_rx(false);
691        value.set_rx_timeout(false);
692        value
693    });
694}
695
696/// Serial receiver.
697///
698/// Can be created by using the [Uart::split] API.
699pub struct Rx {
700    id: Bank,
701    regs: regs::MmioUart<'static>,
702}
703
704impl Rx {
705    /// Retrieve a TX pin without expecting an explicit UART structure
706    ///
707    /// # Safety
708    ///
709    /// Circumvents the HAL safety guarantees.
710    #[inline(always)]
711    pub unsafe fn steal(id: Bank) -> Self {
712        Self::new(id)
713    }
714
715    #[inline(always)]
716    fn new(id: Bank) -> Self {
717        Self {
718            id,
719            regs: regs::Uart::new_mmio(id),
720        }
721    }
722
723    pub fn poll_errors(&self) -> Option<UartErrors> {
724        let mut errors = UartErrors::default();
725
726        let status = self.regs.read_rx_status();
727        if status.overrun_error() {
728            errors.overflow = true;
729        } else if status.framing_error() {
730            errors.framing = true;
731        } else if status.parity_error() {
732            errors.parity = true;
733        } else {
734            return None;
735        };
736        Some(errors)
737    }
738
739    #[inline]
740    pub fn perid(&self) -> u32 {
741        self.regs.read_perid()
742    }
743
744    #[inline]
745    pub fn clear_fifo(&mut self) {
746        self.regs
747            .write_fifo_clr(FifoClear::builder().with_tx(false).with_rx(true).build());
748    }
749
750    #[inline]
751    pub fn disable_interrupts(&mut self) {
752        disable_rx_interrupts(&mut self.regs);
753    }
754
755    #[inline]
756    pub fn enable_interrupts(
757        &mut self,
758        #[cfg(feature = "vor4x")] enable_in_nvic: bool,
759        timeout: bool,
760    ) {
761        #[cfg(feature = "vor4x")]
762        if enable_in_nvic {
763            unsafe {
764                enable_nvic_interrupt(self.id.interrupt_id_rx());
765            }
766        }
767        enable_rx_interrupts(&mut self.regs, timeout);
768    }
769
770    #[inline]
771    pub fn enable(&mut self) {
772        enable_rx(&mut self.regs);
773    }
774
775    #[inline]
776    pub fn disable(&mut self) {
777        disable_rx(&mut self.regs);
778    }
779
780    /// Low level function to read a word from the UART FIFO.
781    ///
782    /// Uses the [nb] API to allow usage in blocking and non-blocking contexts.
783    ///
784    /// Please note that you might have to mask the returned value with 0xff to retrieve the actual
785    /// value if you use the manual parity mode. See chapter 4.6.2 for more information.
786    #[inline(always)]
787    pub fn read_fifo(&mut self) -> nb::Result<u32, Infallible> {
788        if !self.regs.read_rx_status().data_available() {
789            return Err(nb::Error::WouldBlock);
790        }
791        Ok(self.read_fifo_unchecked())
792    }
793
794    /// Low level function to read a word from from the UART FIFO.
795    ///
796    /// This does not necesarily mean there is a word in the FIFO available.
797    /// Use the [Self::read_fifo] function to read a word from the FIFO reliably using the [nb]
798    /// API.
799    ///
800    /// Please note that you might have to mask the returned value with 0xff to retrieve the actual
801    /// value if you use the manual parity mode. See chapter 4.6.2 for more information.
802    #[inline(always)]
803    pub fn read_fifo_unchecked(&mut self) -> u32 {
804        self.regs.read_data().raw_value()
805    }
806
807    pub fn into_rx_with_irq(self) -> RxWithInterrupt {
808        RxWithInterrupt::new(self)
809    }
810}
811
812impl embedded_io::ErrorType for Rx {
813    type Error = Infallible;
814}
815
816impl embedded_hal_nb::serial::ErrorType for Rx {
817    type Error = Infallible;
818}
819
820impl embedded_hal_nb::serial::Read<u8> for Rx {
821    fn read(&mut self) -> nb::Result<u8, Self::Error> {
822        self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| {
823            if let nb::Error::Other(_) = e {
824                unreachable!()
825            }
826            nb::Error::WouldBlock
827        })
828    }
829}
830
831impl embedded_io::Read for Rx {
832    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
833        if buf.is_empty() {
834            return Ok(0);
835        }
836        let mut read = 0;
837        loop {
838            if self.regs.read_rx_status().data_available() {
839                break;
840            }
841        }
842        for byte in buf.iter_mut() {
843            match <Self as embedded_hal_nb::serial::Read<u8>>::read(self) {
844                Ok(w) => {
845                    *byte = w;
846                    read += 1;
847                }
848                Err(nb::Error::WouldBlock) => break,
849            }
850        }
851
852        Ok(read)
853    }
854}
855
856#[inline(always)]
857pub fn enable_tx(uart: &mut MmioUart<'static>) {
858    uart.modify_enable(|mut value| {
859        value.set_tx(true);
860        value
861    });
862}
863
864#[inline(always)]
865pub fn disable_tx(uart: &mut MmioUart<'static>) {
866    uart.modify_enable(|mut value| {
867        value.set_tx(false);
868        value
869    });
870}
871
872#[inline(always)]
873pub fn enable_tx_interrupts(uart: &mut MmioUart<'static>) {
874    uart.modify_irq_enabled(|mut value| {
875        value.set_tx(true);
876        value.set_tx_empty(true);
877        value.set_tx_status(true);
878        value
879    });
880}
881
882#[inline(always)]
883pub fn disable_tx_interrupts(uart: &mut MmioUart<'static>) {
884    uart.modify_irq_enabled(|mut value| {
885        value.set_tx(false);
886        value.set_tx_empty(false);
887        value.set_tx_status(false);
888        value
889    });
890}
891
892/// Serial transmitter
893///
894/// Can be created by using the [Uart::split] API.
895pub struct Tx {
896    id: Bank,
897    regs: regs::MmioUart<'static>,
898}
899
900impl Tx {
901    /// Retrieve a TX pin without expecting an explicit UART structure
902    ///
903    /// # Safety
904    ///
905    /// Circumvents the HAL safety guarantees.
906    #[inline(always)]
907    pub unsafe fn steal(id: Bank) -> Self {
908        Self::new(id)
909    }
910
911    #[inline(always)]
912    fn new(id: Bank) -> Self {
913        Self {
914            id,
915            regs: regs::Uart::new_mmio(id),
916        }
917    }
918
919    #[inline]
920    pub fn perid(&self) -> u32 {
921        self.regs.read_perid()
922    }
923
924    #[inline]
925    pub fn clear_fifo(&mut self) {
926        self.regs
927            .write_fifo_clr(FifoClear::builder().with_tx(true).with_rx(false).build());
928    }
929
930    #[inline]
931    pub fn enable(&mut self) {
932        self.regs.modify_enable(|mut value| {
933            value.set_tx(true);
934            value
935        });
936    }
937
938    #[inline]
939    pub fn disable(&mut self) {
940        self.regs.modify_enable(|mut value| {
941            value.set_tx(false);
942            value
943        });
944    }
945
946    /// Enables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts.
947    ///
948    /// - The IRQ_TX interrupt is generated when the TX FIFO is at least half empty.
949    /// - The IRQ_TX_STATUS interrupt is generated when write data is lost due to a FIFO overflow
950    /// - The IRQ_TX_EMPTY interrupt is generated when the TX FIFO is empty and the TXBUSY signal
951    ///   is 0
952    #[inline]
953    pub fn enable_interrupts(&mut self, #[cfg(feature = "vor4x")] enable_in_nvic: bool) {
954        #[cfg(feature = "vor4x")]
955        if enable_in_nvic {
956            unsafe { enable_nvic_interrupt(self.id.interrupt_id_tx()) };
957        }
958        // Safety: We own the UART structure
959        enable_tx_interrupts(&mut self.regs);
960    }
961
962    /// Disables the IRQ_TX, IRQ_TX_STATUS and IRQ_TX_EMPTY interrupts.
963    ///
964    /// [Self::enable_interrupts] documents the interrupts.
965    #[inline]
966    pub fn disable_interrupts(&mut self) {
967        // Safety: We own the UART structure
968        disable_tx_interrupts(&mut self.regs);
969    }
970
971    /// Low level function to write a word to the UART FIFO.
972    ///
973    /// Uses the [nb] API to allow usage in blocking and non-blocking contexts.
974    ///
975    /// Please note that you might have to mask the returned value with 0xff to retrieve the actual
976    /// value if you use the manual parity mode. See chapter 11.4.1 for more information.
977    #[inline(always)]
978    pub fn write_fifo(&mut self, data: u32) -> nb::Result<(), Infallible> {
979        if !self.regs.read_tx_status().ready() {
980            return Err(nb::Error::WouldBlock);
981        }
982        self.write_fifo_unchecked(data);
983        Ok(())
984    }
985
986    /// Low level function to write a word to the UART FIFO.
987    ///
988    /// This does not necesarily mean that the FIFO can process another word because it might be
989    /// full.
990    /// Use the [Self::write_fifo] function to write a word to the FIFO reliably using the [nb]
991    /// API.
992    #[inline(always)]
993    pub fn write_fifo_unchecked(&mut self, data: u32) {
994        self.regs.write_data(Data::new_with_raw_value(data));
995    }
996
997    pub fn into_async(self) -> TxAsync {
998        TxAsync::new(self)
999    }
1000}
1001
1002impl embedded_io::ErrorType for Tx {
1003    type Error = Infallible;
1004}
1005
1006impl embedded_hal_nb::serial::ErrorType for Tx {
1007    type Error = Infallible;
1008}
1009
1010impl embedded_hal_nb::serial::Write<u8> for Tx {
1011    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
1012        self.write_fifo(word as u32)
1013    }
1014
1015    fn flush(&mut self) -> nb::Result<(), Self::Error> {
1016        // SAFETY: Only TX related registers are used.
1017        if self.regs.read_tx_status().write_busy() {
1018            return Err(nb::Error::WouldBlock);
1019        }
1020        Ok(())
1021    }
1022}
1023
1024impl embedded_io::Write for Tx {
1025    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1026        if buf.is_empty() {
1027            return Ok(0);
1028        }
1029        loop {
1030            if self.regs.read_tx_status().ready() {
1031                break;
1032            }
1033        }
1034        let mut written = 0;
1035        for byte in buf.iter() {
1036            match <Self as embedded_hal_nb::serial::Write<u8>>::write(self, *byte) {
1037                Ok(_) => written += 1,
1038                Err(nb::Error::WouldBlock) => return Ok(written),
1039            }
1040        }
1041
1042        Ok(written)
1043    }
1044
1045    fn flush(&mut self) -> Result<(), Self::Error> {
1046        nb::block!(<Self as embedded_hal_nb::serial::Write<u8>>::flush(self))
1047    }
1048}
1049
1050/// Serial receiver, using interrupts to offload reading to the hardware.
1051///
1052/// You can use [Rx::into_rx_with_irq] to convert a normal [Rx] structure into this structure.
1053/// This structure provides two distinct ways to read the UART RX using interrupts. It should
1054/// be noted that the interrupt service routine (ISR) still has to be provided by the user. However,
1055/// this structure provides API calls which can be used inside the ISRs to simplify the reading
1056/// of the UART.
1057///
1058///  1. The first way simply empties the FIFO on an interrupt into a user provided buffer. You
1059///     can simply use [Self::start] to prepare the peripheral and then call the
1060///     [Self::on_interrupt] in the interrupt service routine.
1061///  2. The second way reads packets bounded by a maximum size or a baudtick based timeout. You
1062///     can use [Self::read_fixed_len_or_timeout_based_using_irq] to prepare the peripheral and
1063///     then call the [Self::on_interrupt_max_size_or_timeout_based] in the interrupt service
1064///     routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
1065///     start reading the next packet.
1066pub struct RxWithInterrupt(Rx);
1067
1068impl RxWithInterrupt {
1069    pub fn new(rx: Rx) -> Self {
1070        Self(rx)
1071    }
1072
1073    /// This function should be called once at initialization time if the regular
1074    /// [Self::on_interrupt] is used to read the UART receiver to enable and start the receiver.
1075    pub fn start(&mut self) {
1076        #[cfg(feature = "vor4x")]
1077        self.enable_interrupts(true, true);
1078        #[cfg(feature = "vor1x")]
1079        self.enable_interrupts(true);
1080        self.0.enable();
1081    }
1082
1083    #[inline(always)]
1084    pub fn rx(&self) -> &Rx {
1085        &self.0
1086    }
1087
1088    /// This function is used together with the [Self::on_interrupt_max_size_or_timeout_based]
1089    /// function to read packets with a maximum size or variable sized packets by using the
1090    /// receive timeout of the hardware.
1091    ///
1092    /// This function should be called once at initialization to initiate the context state
1093    /// and to [Self::start] the receiver. After that, it should be called after each
1094    /// completed [Self::on_interrupt_max_size_or_timeout_based] call to restart the reception
1095    /// of a packet.
1096    pub fn read_fixed_len_or_timeout_based_using_irq(
1097        &mut self,
1098        context: &mut InterruptContextTimeoutOrMaxSize,
1099    ) -> Result<(), TransferPendingError> {
1100        if context.mode != InterruptReceptionMode::Idle {
1101            return Err(TransferPendingError);
1102        }
1103        context.mode = InterruptReceptionMode::Pending;
1104        context.rx_idx = 0;
1105        self.start();
1106        Ok(())
1107    }
1108
1109    #[inline]
1110    fn enable_interrupts(&mut self, #[cfg(feature = "vor4x")] enable_in_nvic: bool, timeout: bool) {
1111        #[cfg(feature = "vor4x")]
1112        self.0.enable_interrupts(enable_in_nvic, timeout);
1113        #[cfg(feature = "vor1x")]
1114        self.0.enable_interrupts(timeout);
1115    }
1116
1117    #[inline]
1118    fn disable_interrupts(&mut self) {
1119        self.0.disable_interrupts();
1120    }
1121
1122    pub fn cancel_transfer(&mut self) {
1123        self.disable_interrupts();
1124        self.0.clear_fifo();
1125    }
1126
1127    /// This function should be called in the user provided UART interrupt handler.
1128    ///
1129    /// It simply empties any bytes in the FIFO into the user provided buffer and returns the
1130    /// result of the operation.
1131    ///
1132    /// This function will not disable the RX interrupts, so you don't need to call any other
1133    /// API after calling this function to continue emptying the FIFO. RX errors are handled
1134    /// as partial errors and are returned as part of the [InterruptResult].
1135    pub fn on_interrupt(&mut self, buf: &mut [u8; 16]) -> InterruptResult {
1136        let mut result = InterruptResult::default();
1137
1138        let irq_status = self.0.regs.read_irq_status();
1139        let irq_enabled = self.0.regs.read_irq_enabled();
1140        let rx_enabled = irq_enabled.rx();
1141
1142        // Half-Full interrupt. We have a guaranteed amount of data we can read.
1143        if irq_status.rx() {
1144            let available_bytes = self.0.regs.read_rx_fifo_trigger().level().as_usize();
1145
1146            // If this interrupt bit is set, the trigger level is available at the very least.
1147            // Read everything as fast as possible
1148            for _ in 0..available_bytes {
1149                buf[result.bytes_read] = (self.0.read_fifo_unchecked() & 0xff) as u8;
1150                result.bytes_read += 1;
1151            }
1152        }
1153
1154        // Timeout, empty the FIFO completely.
1155        if irq_status.rx_timeout() {
1156            // While there is data in the FIFO, write it into the reception buffer
1157            while let Ok(byte) = self.0.read_fifo() {
1158                buf[result.bytes_read] = byte as u8;
1159                result.bytes_read += 1;
1160            }
1161        }
1162
1163        // RX transfer not complete, check for RX errors
1164        if rx_enabled {
1165            self.check_for_errors(&mut result.errors);
1166        }
1167
1168        // Clear the interrupt status bits
1169        self.0.regs.write_irq_clr(
1170            InterruptClear::builder()
1171                .with_rx_overrun(true)
1172                .with_tx_overrun(false)
1173                .build(),
1174        );
1175        result
1176    }
1177
1178    /// This function should be called in the user provided UART interrupt handler.
1179    ///
1180    /// This function is used to read packets which either have a maximum size or variable sized
1181    /// packet which are bounded by sufficient delays between them, triggering a hardware timeout.
1182    ///
1183    /// If either the maximum number of packets have been read or a timeout occured, the transfer
1184    /// will be deemed completed. The state information of the transfer is tracked in the
1185    /// [InterruptContextTimeoutOrMaxSize] structure.
1186    ///
1187    /// If passed buffer is equal to or larger than the specified maximum length, an
1188    /// [BufferTooShortError] will be returned. Other RX errors are treated as partial errors
1189    /// and returned inside the [InterruptResultMaxSizeOrTimeout] structure.
1190    pub fn on_interrupt_max_size_or_timeout_based(
1191        &mut self,
1192        context: &mut InterruptContextTimeoutOrMaxSize,
1193        buf: &mut [u8],
1194    ) -> Result<InterruptResultMaxSizeOrTimeout, BufferTooShortError> {
1195        if buf.len() < context.max_len {
1196            return Err(BufferTooShortError {
1197                found: buf.len(),
1198                expected: context.max_len,
1199            });
1200        }
1201        let mut result = InterruptResultMaxSizeOrTimeout::default();
1202
1203        let irq_status = self.0.regs.read_irq_status();
1204        let rx_enabled = self.0.regs.read_enable().rx();
1205
1206        // Half-Full interrupt. We have a guaranteed amount of data we can read.
1207        if irq_status.rx() {
1208            // Determine the number of bytes to read, ensuring we leave 1 byte in the FIFO.
1209            // We use this trick/hack because the timeout feature of the peripheral relies on data
1210            // being in the RX FIFO. If data continues arriving, another half-full IRQ will fire.
1211            // If not, the last byte(s) is/are emptied by the timeout interrupt.
1212            let available_bytes = self.0.regs.read_rx_fifo_trigger().level().as_usize();
1213
1214            let bytes_to_read = core::cmp::min(
1215                available_bytes.saturating_sub(1),
1216                context.max_len - context.rx_idx,
1217            );
1218
1219            // If this interrupt bit is set, the trigger level is available at the very least.
1220            // Read everything as fast as possible
1221            for _ in 0..bytes_to_read {
1222                buf[context.rx_idx] = (self.0.read_fifo_unchecked() & 0xff) as u8;
1223                context.rx_idx += 1;
1224            }
1225
1226            // On high-baudrates, data might be available immediately, and we possible have to
1227            // read continuosly? Then again, the CPU should always be faster than that. I'd rather
1228            // rely on the hardware firing another IRQ. I have not tried baudrates higher than
1229            // 115200 so far.
1230        }
1231        // Timeout, empty the FIFO completely.
1232        if irq_status.rx_timeout() {
1233            // While there is data in the FIFO, write it into the reception buffer
1234            loop {
1235                if context.rx_idx == context.max_len {
1236                    break;
1237                }
1238                // While there is data in the FIFO, write it into the reception buffer
1239                match self.0.read() {
1240                    Ok(byte) => {
1241                        buf[context.rx_idx] = byte;
1242                        context.rx_idx += 1;
1243                    }
1244                    Err(_) => break,
1245                }
1246            }
1247            self.irq_completion_handler_max_size_timeout(&mut result, context);
1248            return Ok(result);
1249        }
1250
1251        // RX transfer not complete, check for RX errors
1252        if (context.rx_idx < context.max_len) && rx_enabled {
1253            self.check_for_errors(&mut result.errors);
1254        }
1255
1256        // Clear the interrupt status bits
1257        self.0.regs.write_irq_clr(
1258            InterruptClear::builder()
1259                .with_rx_overrun(true)
1260                .with_tx_overrun(false)
1261                .build(),
1262        );
1263        Ok(result)
1264    }
1265
1266    fn check_for_errors(&self, errors: &mut Option<UartErrors>) {
1267        let rx_status = self.0.regs.read_rx_status();
1268
1269        if rx_status.overrun_error() || rx_status.framing_error() || rx_status.parity_error() {
1270            let err = errors.get_or_insert(UartErrors::default());
1271
1272            if rx_status.overrun_error() {
1273                err.overflow = true;
1274            }
1275            if rx_status.framing_error() {
1276                err.framing = true;
1277            }
1278            if rx_status.parity_error() {
1279                err.parity = true;
1280            }
1281        }
1282    }
1283
1284    fn irq_completion_handler_max_size_timeout(
1285        &mut self,
1286        res: &mut InterruptResultMaxSizeOrTimeout,
1287        context: &mut InterruptContextTimeoutOrMaxSize,
1288    ) {
1289        self.disable_interrupts();
1290        self.0.disable();
1291        res.bytes_read = context.rx_idx;
1292        res.complete = true;
1293        context.mode = InterruptReceptionMode::Idle;
1294        context.rx_idx = 0;
1295    }
1296
1297    /// # Safety
1298    ///
1299    /// This API allows creating multiple UART instances when releasing the TX structure as well.
1300    /// The user must ensure that these instances are not used to create multiple overlapping
1301    /// UART drivers.
1302    pub unsafe fn release(mut self) -> Rx {
1303        self.disable_interrupts();
1304        self.0
1305    }
1306}