atsamd_hal/sercom/uart/
async_api.rs

1use crate::{
2    async_hal::interrupts::{Binding, Handler, InterruptSource},
3    sercom::{
4        uart::{
5            Capability, DataReg, Duplex, Error, Flags, Receive, Rx, RxDuplex, SingleOwner,
6            Transmit, Tx, TxDuplex, Uart, ValidConfig,
7        },
8        Sercom,
9    },
10    typelevel::NoneT,
11};
12use atsamd_hal_macros::hal_macro_helper;
13use core::{marker::PhantomData, task::Poll};
14use num_traits::AsPrimitive;
15
16/// Interrupt handler for async UART operarions
17pub struct InterruptHandler<S: Sercom> {
18    _private: (),
19    _sercom: PhantomData<S>,
20}
21
22impl<S: Sercom> crate::typelevel::Sealed for InterruptHandler<S> {}
23
24impl<S: Sercom> Handler<S::Interrupt> for InterruptHandler<S> {
25    #[inline]
26    #[hal_macro_helper]
27    unsafe fn on_interrupt() {
28        unsafe {
29            let mut peripherals = crate::pac::Peripherals::steal();
30
31            #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
32            let uart = S::reg_block(&mut peripherals).usart();
33            #[hal_cfg("sercom0-d5x")]
34            let uart = S::reg_block(&mut peripherals).usart_int();
35
36            let flags_pending = Flags::from_bits_retain(uart.intflag().read().bits());
37            let enabled_flags = Flags::from_bits_retain(uart.intenset().read().bits());
38            uart.intenclr().write(|w| w.bits(flags_pending.bits()));
39
40            // Disable interrupts, but don't clear the flags. The future will take care of
41            // clearing flags and re-enabling interrupts when woken.
42            if (Flags::RX & enabled_flags).intersects(flags_pending) {
43                S::rx_waker().wake();
44            }
45
46            if (Flags::TX & enabled_flags).intersects(flags_pending) {
47                S::tx_waker().wake();
48            }
49        }
50    }
51}
52
53impl<C, D, S> Uart<C, D, NoneT, NoneT>
54where
55    C: ValidConfig<Sercom = S>,
56    D: SingleOwner,
57    S: Sercom,
58{
59    /// Turn a [`Uart`] into a [`UartFuture`]. This method is only available for
60    /// [`Uart`]s which have a [`Tx`],
61    /// [`Rx`] or [`Duplex`] [`Capability`].
62    #[inline]
63    pub fn into_future<I>(self, _interrupts: I) -> UartFuture<C, D>
64    where
65        I: Binding<S::Interrupt, InterruptHandler<S>>,
66    {
67        S::Interrupt::unpend();
68        unsafe { S::Interrupt::enable() };
69
70        UartFuture { uart: self }
71    }
72}
73
74/// `async` version of a [`Uart`].
75///
76/// Create this struct by calling [`Uart::into_future`](Uart::into_future).
77pub struct UartFuture<C, D, R = NoneT, T = NoneT>
78where
79    C: ValidConfig,
80    D: Capability,
81{
82    uart: Uart<C, D, R, T>,
83}
84
85/// Convenience type for a [`UartFuture`] with RX and TX capabilities
86pub type UartFutureDuplex<C> = UartFuture<C, Duplex>;
87
88/// Convenience type for a RX-only [`UartFuture`].
89pub type UartFutureRx<C> = UartFuture<C, Rx>;
90
91/// Convenience type for the RX half of a [`Duplex`] [`UartFuture`].
92pub type UartFutureRxDuplex<C> = UartFuture<C, RxDuplex>;
93
94/// Convenience type for a TX-only [`UartFuture`].
95pub type UartFutureTx<C> = UartFuture<C, Tx>;
96
97/// Convenience type for the TX half of a [`Duplex`] [`UartFuture`].
98pub type UartFutureTxDuplex<C> = UartFuture<C, TxDuplex>;
99
100impl<C, R, T> UartFuture<C, Duplex, R, T>
101where
102    C: ValidConfig,
103{
104    /// Split the [`UartFuture`] into [`RxDuplex`]and [`TxDuplex`] halves.
105    #[inline]
106    #[allow(clippy::type_complexity)]
107    pub fn split(
108        self,
109    ) -> (
110        UartFuture<C, RxDuplex, R, NoneT>,
111        UartFuture<C, TxDuplex, NoneT, T>,
112    ) {
113        let config = unsafe { core::ptr::read(&self.uart.config) };
114        (
115            UartFuture {
116                uart: Uart {
117                    config: self.uart.config,
118                    capability: PhantomData,
119                    rx_channel: self.uart.rx_channel,
120                    tx_channel: NoneT,
121                },
122            },
123            UartFuture {
124                uart: Uart {
125                    config,
126                    capability: PhantomData,
127                    rx_channel: NoneT,
128                    tx_channel: self.uart.tx_channel,
129                },
130            },
131        )
132    }
133
134    /// Join [`RxDuplex`] and [`TxDuplex`] halves back into a full
135    /// `UartFuture<C, Duplex>`
136    #[inline]
137    pub fn join(
138        rx: UartFuture<C, RxDuplex, R, NoneT>,
139        tx: UartFuture<C, TxDuplex, NoneT, T>,
140    ) -> Self {
141        Self {
142            uart: Uart {
143                config: rx.uart.config,
144                capability: PhantomData,
145                rx_channel: rx.uart.rx_channel,
146                tx_channel: tx.uart.tx_channel,
147            },
148        }
149    }
150}
151
152impl<C, D> UartFuture<C, D, NoneT, NoneT>
153where
154    C: ValidConfig,
155    D: SingleOwner,
156{
157    /// Return the underlying [`Uart`].
158    pub fn free(self) -> Uart<C, D> {
159        self.uart
160    }
161}
162
163impl<C, D, R, T> embedded_io::ErrorType for UartFuture<C, D, R, T>
164where
165    C: ValidConfig,
166    D: Capability,
167{
168    type Error = Error;
169}
170
171impl<C, D, S, R, T> UartFuture<C, D, R, T>
172where
173    C: ValidConfig<Sercom = S>,
174    D: Capability,
175    S: Sercom,
176{
177    #[inline]
178    async fn wait_flags(&mut self, flags_to_wait: Flags) {
179        let flags_to_wait = flags_to_wait & Flags::from_bits_retain(D::FLAG_MASK);
180
181        core::future::poll_fn(|cx| {
182            // Scope maybe_pending so we don't forget to re-poll the register later down.
183            {
184                let maybe_pending = self.uart.config.as_ref().registers.read_flags();
185                if flags_to_wait.intersects(maybe_pending) {
186                    return Poll::Ready(());
187                }
188            }
189
190            if flags_to_wait.intersects(Flags::RX) {
191                self.uart.disable_interrupts(Flags::RX);
192                S::rx_waker().register(cx.waker());
193            }
194            if flags_to_wait.intersects(Flags::TX) {
195                self.uart.disable_interrupts(Flags::RX);
196                S::tx_waker().register(cx.waker());
197            }
198            self.uart.enable_interrupts(flags_to_wait);
199            let maybe_pending = self.uart.config.as_ref().registers.read_flags();
200
201            if !flags_to_wait.intersects(maybe_pending) {
202                Poll::Pending
203            } else {
204                Poll::Ready(())
205            }
206        })
207        .await;
208    }
209}
210
211impl<C, D, S, R, T> UartFuture<C, D, R, T>
212where
213    C: ValidConfig<Sercom = S>,
214    D: Receive,
215    S: Sercom,
216    DataReg: AsPrimitive<C::Word>,
217{
218    /// Use a DMA channel for receiving words on the RX line
219    #[cfg(feature = "dma")]
220    #[inline]
221    pub fn with_rx_dma_channel<Chan: crate::dmac::AnyChannel<Status = crate::dmac::ReadyFuture>>(
222        self,
223        rx_channel: Chan,
224    ) -> UartFuture<C, D, Chan, T> {
225        UartFuture {
226            uart: Uart {
227                config: self.uart.config,
228                capability: PhantomData,
229                rx_channel,
230                tx_channel: self.uart.tx_channel,
231            },
232        }
233    }
234
235    /// Read a single [`Word`](crate::sercom::uart::Word) from the UART.
236    #[inline]
237    pub async fn read_word(&mut self) -> Result<C::Word, Error> {
238        self.wait_flags(Flags::RXC).await;
239        self.uart.read_status().check_bus_error()?;
240        Ok(unsafe { self.uart.read_data().as_() })
241    }
242}
243
244impl<C, D, S, T> UartFuture<C, D, NoneT, T>
245where
246    C: ValidConfig<Sercom = S>,
247    D: Receive,
248    S: Sercom,
249    DataReg: AsPrimitive<C::Word>,
250{
251    /// Read the specified number of [`Word`](crate::sercom::uart::Word)s into a
252    /// buffer, word by word.
253    ///
254    /// In case of an error, returns `Err(Error, usize)` where the `usize`
255    /// represents the number of valid words read before the error occured.
256    #[inline]
257    pub async fn read(&mut self, buffer: &mut [C::Word]) -> Result<(), (Error, usize)> {
258        for (i, word) in buffer.iter_mut().enumerate() {
259            match self.read_word().await {
260                Ok(w) => {
261                    *word = w;
262                }
263                Err(e) => {
264                    return Err((e, i));
265                }
266            }
267        }
268        Ok(())
269    }
270}
271
272impl<C, D, S, R> embedded_io_async::Read for UartFuture<C, D, NoneT, R>
273where
274    C: ValidConfig<Sercom = S, Word = u8>,
275    D: Receive,
276    S: Sercom,
277{
278    #[inline]
279    async fn read(&mut self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
280        self.read(buffer).await.map_err(|(e, _)| e)?;
281        Ok(buffer.len())
282    }
283}
284
285impl<C, D, S, R, T> UartFuture<C, D, R, T>
286where
287    C: ValidConfig<Sercom = S>,
288    D: Transmit,
289    S: Sercom,
290{
291    /// Use a DMA channel for sending words on the TX line
292    #[cfg(feature = "dma")]
293    #[inline]
294    pub fn with_tx_dma_channel<Chan: crate::dmac::AnyChannel<Status = crate::dmac::ReadyFuture>>(
295        self,
296        tx_channel: Chan,
297    ) -> UartFuture<C, D, R, Chan> {
298        UartFuture {
299            uart: Uart {
300                config: self.uart.config,
301                capability: PhantomData,
302                rx_channel: self.uart.rx_channel,
303                tx_channel,
304            },
305        }
306    }
307
308    /// Write a single [`Word`](crate::sercom::uart::Word) to the UART.
309    #[inline]
310    pub async fn write_word(&mut self, word: C::Word) {
311        self.wait_flags(Flags::DRE).await;
312        unsafe { self.uart.write_data(word.as_()) };
313    }
314}
315
316impl<C, D, S, R> UartFuture<C, D, R, NoneT>
317where
318    C: ValidConfig<Sercom = S>,
319    D: Transmit,
320    S: Sercom,
321{
322    /// Write the specified number of [`Word`](crate::sercom::uart::Word)s from
323    /// a buffer to the UART, word by word.
324    #[inline]
325    pub async fn write(&mut self, buffer: &[C::Word]) {
326        for word in buffer {
327            self.write_word(*word).await;
328        }
329    }
330}
331
332impl<C, D, S, R> embedded_io_async::Write for UartFuture<C, D, R, NoneT>
333where
334    C: ValidConfig<Sercom = S, Word = u8>,
335    D: Transmit,
336    S: Sercom,
337{
338    #[inline]
339    async fn write(&mut self, buffer: &[u8]) -> Result<usize, Self::Error> {
340        self.write(buffer).await;
341        Ok(buffer.len())
342    }
343}
344
345impl<C, D, R, T, S> AsRef<Uart<C, D, R, T>> for UartFuture<C, D, R, T>
346where
347    C: ValidConfig<Sercom = S>,
348    D: Capability,
349    S: Sercom,
350{
351    fn as_ref(&self) -> &Uart<C, D, R, T> {
352        &self.uart
353    }
354}
355
356impl<C, D, R, T, S> AsMut<Uart<C, D, R, T>> for UartFuture<C, D, R, T>
357where
358    C: ValidConfig<Sercom = S>,
359    D: Capability,
360    S: Sercom,
361{
362    fn as_mut(&mut self) -> &mut Uart<C, D, R, T> {
363        &mut self.uart
364    }
365}
366
367#[cfg(feature = "dma")]
368mod dma {
369    use super::*;
370    use crate::{
371        dmac::{AnyChannel, Beat, Channel, ReadyFuture},
372        sercom::dma::{
373            async_dma::{read_dma, write_dma},
374            SharedSliceBuffer,
375        },
376    };
377
378    /// Convenience type for a [`UartFuture`] with RX and TX capabilities in DMA
379    /// mode.
380    ///
381    /// The type parameter `R` represents the RX DMA channel ID (`ChX`), and
382    /// `T` represents the TX DMA channel ID.
383    pub type UartFutureDuplexDma<C, R, T> =
384        UartFuture<C, Duplex, Channel<R, ReadyFuture>, Channel<T, ReadyFuture>>;
385
386    /// Convenience type for a RX-only [`UartFuture`] in DMA mode.
387    ///
388    /// The type parameter `R` represents the RX DMA channel ID (`ChX`).
389    pub type UartFutureRxDma<C, R> = UartFuture<C, Rx, Channel<R, ReadyFuture>, NoneT>;
390
391    /// Convenience type for the RX half of a [`Duplex`] [`UartFuture`] in DMA
392    /// mode.
393    ///
394    /// The type parameter `R` represents the RX DMA channel ID (`ChX`).
395    pub type UartFutureRxDuplexDma<C, R> = UartFuture<C, RxDuplex, Channel<R, ReadyFuture>, NoneT>;
396
397    /// Convenience type for a TX-only [`UartFuture`] in DMA mode.
398    ///
399    /// The type parameter `T` represents the TX DMA channel ID (`ChX`).
400    pub type UartFutureTxDma<C, T> = UartFuture<C, Tx, NoneT, Channel<T, ReadyFuture>>;
401
402    /// Convenience type for the TX half of a [`Duplex`] [`UartFuture`] in DMA
403    /// mode.
404    ///
405    /// The type parameter `T` represents the TX DMA channel ID (`ChX`).
406    pub type UartFutureTxDuplexDma<C, T> = UartFuture<C, TxDuplex, NoneT, Channel<T, ReadyFuture>>;
407
408    impl<C, D, R, T> UartFuture<C, D, R, T>
409    where
410        C: ValidConfig,
411        D: Capability,
412        R: AnyChannel<Status = ReadyFuture>,
413    {
414        /// Reclaim the RX DMA channel. Subsequent RX operations will no longer
415        /// use DMA.
416        pub fn take_rx_channel(self) -> (UartFuture<C, D, NoneT, T>, R) {
417            let (uart, channel) = self.uart.take_rx_channel();
418            (UartFuture { uart }, channel)
419        }
420    }
421
422    impl<C, D, R, T> UartFuture<C, D, R, T>
423    where
424        C: ValidConfig,
425        D: Capability,
426        T: AnyChannel<Status = ReadyFuture>,
427    {
428        /// Reclaim the TX DMA channel. Subsequent TX operations will no longer
429        /// use DMA.
430        pub fn take_tx_channel(self) -> (UartFuture<C, D, R, NoneT>, T) {
431            let (uart, channel) = self.uart.take_tx_channel();
432            (UartFuture { uart }, channel)
433        }
434    }
435
436    impl<C, D, S, R, T> UartFuture<C, D, R, T>
437    where
438        C: ValidConfig<Sercom = S>,
439        C::Word: Beat,
440        D: Receive,
441        S: Sercom + 'static,
442        DataReg: AsPrimitive<C::Word>,
443        R: AnyChannel<Status = ReadyFuture>,
444    {
445        /// Read the specified number of [`Word`](crate::sercom::uart::Word)s
446        /// into a buffer using DMA.
447        #[inline]
448        pub async fn read(&mut self, mut words: &mut [C::Word]) -> Result<(), Error> {
449            // SAFETY: Using SercomPtr is safe because we hold on
450            // to &mut self as long as the transfer hasn't completed.
451            let uart_ptr = self.uart.sercom_ptr();
452
453            read_dma::<_, _, S>(&mut self.uart.rx_channel, uart_ptr, &mut words).await?;
454            Ok(())
455        }
456    }
457
458    impl<C, D, S, R, T> embedded_io_async::Read for UartFuture<C, D, R, T>
459    where
460        C: ValidConfig<Sercom = S, Word = u8>,
461        D: Receive,
462        S: Sercom + 'static,
463        DataReg: AsPrimitive<C::Word>,
464        R: AnyChannel<Status = ReadyFuture>,
465    {
466        #[inline]
467        async fn read(&mut self, words: &mut [u8]) -> Result<usize, Error> {
468            self.read(words).await?;
469            Ok(words.len())
470        }
471    }
472
473    impl<C, D, S, R, T> UartFuture<C, D, R, T>
474    where
475        C: ValidConfig<Sercom = S>,
476        C::Word: Beat,
477        D: Transmit,
478        S: Sercom + 'static,
479        T: AnyChannel<Status = ReadyFuture>,
480    {
481        /// Write words from a buffer asynchronously, using DMA.
482        #[inline]
483        pub async fn write(&mut self, words: &[C::Word]) -> Result<(), Error> {
484            // SAFETY: Using SercomPtr is safe because we hold on
485            // to &mut self as long as the transfer hasn't completed.
486            let uart_ptr = self.uart.sercom_ptr();
487
488            let mut words = SharedSliceBuffer::from_slice(words);
489            write_dma::<_, _, S>(&mut self.uart.tx_channel, uart_ptr, &mut words).await?;
490            self.wait_flags(Flags::TXC).await;
491            Ok(())
492        }
493    }
494
495    impl<C, D, S, R, T> embedded_io_async::Write for UartFuture<C, D, R, T>
496    where
497        C: ValidConfig<Sercom = S, Word = u8>,
498        D: Transmit,
499        S: Sercom + 'static,
500        T: AnyChannel<Status = ReadyFuture>,
501    {
502        #[inline]
503        async fn write(&mut self, words: &[u8]) -> Result<usize, Error> {
504            self.write(words).await?;
505            Ok(words.len())
506        }
507    }
508}
509
510#[cfg(feature = "dma")]
511pub use dma::*;