avr_hal_generic/
usart.rs

1//! HAL abstractions for USART/Serial
2//!
3//! Check the documentation of [`Usart`] for details.
4
5use crate::prelude::*;
6use core::cmp::Ordering;
7use core::marker;
8
9use crate::port;
10
11/// Representation of a USART baudrate
12///
13/// Precalculated parameters for configuring a certain USART baudrate.
14#[derive(Debug, Clone, Copy)]
15pub struct Baudrate<CLOCK> {
16    /// Value of the `UBRR#` register
17    pub ubrr: u16,
18    /// Value of the `U2X#` bit
19    pub u2x: bool,
20    /// The baudrate calculation depends on the configured clock rate, thus a `CLOCK` generic
21    /// parameter is needed.
22    pub _clock: marker::PhantomData<CLOCK>,
23}
24
25impl<CLOCK: crate::clock::Clock> PartialEq for Baudrate<CLOCK> {
26    fn eq(&self, other: &Self) -> bool {
27        self.compare_value() == other.compare_value()
28    }
29}
30
31impl<CLOCK: crate::clock::Clock> Eq for Baudrate<CLOCK> {}
32
33impl<CLOCK: crate::clock::Clock> PartialOrd for Baudrate<CLOCK> {
34    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
35        Some(self.compare_value().cmp(&other.compare_value()))
36    }
37}
38
39impl<CLOCK: crate::clock::Clock> Ord for Baudrate<CLOCK> {
40    fn cmp(&self, other: &Self) -> Ordering {
41        other.compare_value().cmp(&self.compare_value())
42    }
43}
44
45impl<CLOCK: crate::clock::Clock> From<u32> for Baudrate<CLOCK> {
46    fn from(baud: u32) -> Self {
47        Baudrate::new(baud)
48    }
49}
50
51impl<CLOCK: crate::clock::Clock> Baudrate<CLOCK> {
52    /// Calculate parameters for a certain baudrate at a certain `CLOCK` speed.
53    pub fn new(baud: u32) -> Baudrate<CLOCK> {
54        let mut ubrr = (CLOCK::FREQ / 4 / baud - 1) / 2;
55        let mut u2x = true;
56        debug_assert!(ubrr <= u16::MAX as u32);
57        if ubrr > 4095 {
58            u2x = false;
59            ubrr = (CLOCK::FREQ / 8 / baud - 1) / 2;
60        }
61
62        Baudrate {
63            ubrr: ubrr as u16,
64            u2x,
65            _clock: marker::PhantomData,
66        }
67    }
68
69    /// Construct a `Baudrate` from given `UBRR#` and `U2X#` values.
70    ///
71    /// This provides exact control over the resulting clock speed.
72    pub fn with_exact(u2x: bool, ubrr: u16) -> Baudrate<CLOCK> {
73        Baudrate {
74            ubrr,
75            u2x,
76            _clock: marker::PhantomData,
77        }
78    }
79
80    fn compare_value(&self) -> u32 {
81        if self.u2x {
82            8 * (self.ubrr as u32 + 1)
83        } else {
84            16 * (self.ubrr as u32 + 1)
85        }
86    }
87}
88
89/// Provide a `into_baudrate()` method for integers.
90///
91/// This extension trait allows conveniently initializing a baudrate by using
92///
93/// ```
94/// let mut serial = arduino_uno::Serial::new(
95///     dp.USART0,
96///     pins.d0,
97///     pins.d1.into_output(&mut pins.ddr),
98///     57600.into_baudrate(),
99/// );
100/// ```
101///
102/// instead of having to call [`Baudrate::new(57600)`](Baudrate::new).
103pub trait BaudrateExt {
104    /// Calculate baudrate parameters from this number.
105    fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK>;
106}
107
108impl BaudrateExt for u32 {
109    fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK> {
110        Baudrate::new(self)
111    }
112}
113
114/// Same as [`BaudrateExt`] but accounts for an errata of certain Arduino boards:
115///
116/// The affected boards where this trait should be used instead are:
117///
118/// - Duemilanove
119/// - Uno
120/// - Mega 2560
121pub trait BaudrateArduinoExt {
122    /// Calculate baudrate parameters from this number (with Arduino errata).
123    fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK>;
124}
125
126impl BaudrateArduinoExt for u32 {
127    fn into_baudrate<CLOCK: crate::clock::Clock>(self) -> Baudrate<CLOCK> {
128        let br = Baudrate::new(self);
129
130        // hardcoded exception for 57600 for compatibility with the bootloader
131        // shipped with the Duemilanove and previous boards and the firmware
132        // on the 8U2 on the Uno and Mega 2560.
133        //
134        // https://github.com/arduino/ArduinoCore-avr/blob/3055c1efa3c6980c864f661e6c8cc5d5ac773af4/cores/arduino/HardwareSerial.cpp#L123-L132
135        if CLOCK::FREQ == 16_000_000 && br.ubrr == 34 && br.u2x {
136            // (CLOCK::FREQ / 8 / 57600 - 1) / 2 == 16
137            Baudrate::with_exact(false, 16)
138        } else {
139            br
140        }
141    }
142}
143
144/// Events/Interrupts for USART peripherals
145#[repr(u8)]
146pub enum Event {
147    /// A complete byte was received.
148    ///
149    /// Corresponds to the `USART_RX` or `USART#_RX` interrupt.  Please refer to the datasheet for
150    /// your MCU for details.
151    RxComplete,
152
153    /// A compete byte was sent.
154    ///
155    /// Corresponds to the `USART_TX` or `USART#_TX` interrupt.  Please refer to the datasheet for
156    /// your MCU for details.
157    TxComplete,
158
159    /// All data from the USART data register was transmitted.
160    ///
161    /// Corresponds to the `USART_UDRE` or `USART#_UDRE` interrupt.  Please refer to the datasheet
162    /// for your MCU for details.
163    DataRegisterEmpty,
164}
165
166/// Internal trait for low-level USART peripherals.
167///
168/// This trait defines the common interface for all USART peripheral variants.  It is used as an
169/// intermediate abstraction ontop of which the [`Usart`] API is built.  **Prefer using the
170/// [`Usart`] API instead of this trait.**
171pub trait UsartOps<H, RX, TX> {
172    /// Enable & initialize this USART peripheral to the given baudrate.
173    ///
174    /// **Warning**: This is a low-level method and should not be called directly from user code.
175    fn raw_init<CLOCK>(&mut self, baudrate: Baudrate<CLOCK>);
176    /// Disable this USART peripheral such that the pins can be used for other purposes again.
177    ///
178    /// **Warning**: This is a low-level method and should not be called directly from user code.
179    fn raw_deinit(&mut self);
180
181    /// Flush all remaining data in the TX buffer.
182    ///
183    /// This operation must be non-blocking and return [`nb::Error::WouldBlock`] if not all data
184    /// was flushed yet.
185    ///
186    /// **Warning**: This is a low-level method and should not be called directly from user code.
187    fn raw_flush(&mut self) -> nb::Result<(), core::convert::Infallible>;
188    /// Write a byte to the TX buffer.
189    ///
190    /// This operation must be non-blocking and return [`nb::Error::WouldBlock`] until the byte is
191    /// enqueued.  The operation should not wait for the byte to have actually been sent.
192    ///
193    /// **Warning**: This is a low-level method and should not be called directly from user code.
194    fn raw_write(&mut self, byte: u8) -> nb::Result<(), core::convert::Infallible>;
195    /// Read a byte from the RX buffer.
196    ///
197    /// This operation must be non-blocking and return [`nb::Error::WouldBlock`] if no incoming
198    /// byte is available.
199    ///
200    /// **Warning**: This is a low-level method and should not be called directly from user code.
201    fn raw_read(&mut self) -> nb::Result<u8, core::convert::Infallible>;
202
203    /// Enable/Disable a certain interrupt.
204    ///
205    /// **Warning**: This is a low-level method and should not be called directly from user code.
206    fn raw_interrupt(&mut self, event: Event, state: bool);
207}
208
209/// USART/Serial driver
210///
211/// # Example
212/// (This example is taken from Arduino Uno)
213/// ```
214/// let dp = arduino_uno::Peripherals::take().unwrap();
215/// let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);
216/// let mut serial = arduino_uno::Serial::new(
217///     dp.USART0,
218///     pins.d0,
219///     pins.d1.into_output(&mut pins.ddr),
220///     57600.into_baudrate(),
221/// );
222///
223/// ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap_infallible();
224///
225/// loop {
226///     let b = nb::block!(serial.read()).unwrap_infallible();
227///     ufmt::uwriteln!(&mut serial, "Got {}!\r", b).unwrap_infallible();
228/// }
229/// ```
230pub struct Usart<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
231    p: USART,
232    rx: RX,
233    tx: TX,
234    _clock: marker::PhantomData<CLOCK>,
235    _h: marker::PhantomData<H>,
236}
237
238impl<H, USART, RXPIN, TXPIN, CLOCK>
239    Usart<
240        H,
241        USART,
242        port::Pin<port::mode::Input, RXPIN>,
243        port::Pin<port::mode::Output, TXPIN>,
244        CLOCK,
245    >
246where
247    USART: UsartOps<H, port::Pin<port::mode::Input, RXPIN>, port::Pin<port::mode::Output, TXPIN>>,
248    RXPIN: port::PinOps,
249    TXPIN: port::PinOps,
250{
251    /// Initialize a USART peripheral on the given pins.
252    ///
253    /// Note that the RX and TX pins are hardwired for each USART peripheral and you *must* pass
254    /// the correct ones.  This is enforced at compile time.
255    pub fn new<IMODE: port::mode::InputMode>(
256        p: USART,
257        rx: port::Pin<port::mode::Input<IMODE>, RXPIN>,
258        tx: port::Pin<port::mode::Output, TXPIN>,
259        baudrate: Baudrate<CLOCK>,
260    ) -> Self {
261        let mut usart = Self {
262            p,
263            rx: rx.forget_imode(),
264            tx,
265            _clock: marker::PhantomData,
266            _h: marker::PhantomData,
267        };
268        usart.p.raw_init(baudrate);
269        usart
270    }
271}
272
273impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> Usart<H, USART, RX, TX, CLOCK> {
274    /// Deinitialize/disable this peripheral and release the pins.
275    pub fn release(mut self) -> (USART, RX, TX) {
276        self.p.raw_deinit();
277        (self.p, self.rx, self.tx)
278    }
279
280    /// Block until all remaining data has been transmitted.
281    pub fn flush(&mut self) {
282        nb::block!(self.p.raw_flush()).unwrap_infallible()
283    }
284
285    /// Transmit a byte.
286    ///
287    /// This method will block until the byte has been enqueued for transmission but **not** until
288    /// it was entirely sent.
289    pub fn write_byte(&mut self, byte: u8) {
290        nb::block!(self.p.raw_write(byte)).unwrap_infallible()
291    }
292
293    /// Receive a byte.
294    ///
295    /// This method will block until a byte could be received.
296    pub fn read_byte(&mut self) -> u8 {
297        nb::block!(self.p.raw_read()).unwrap_infallible()
298    }
299
300    /// Enable the interrupt for [`Event`].
301    pub fn listen(&mut self, event: Event) {
302        self.p.raw_interrupt(event, true);
303    }
304
305    /// Disable the interrupt for [`Event`].
306    pub fn unlisten(&mut self, event: Event) {
307        self.p.raw_interrupt(event, false);
308    }
309
310    /// Split this USART into a [`UsartReader`] and a [`UsartWriter`].
311    ///
312    /// This allows concurrently receiving and transmitting data from different contexts.
313    pub fn split(
314        self,
315    ) -> (
316        UsartReader<H, USART, RX, TX, CLOCK>,
317        UsartWriter<H, USART, RX, TX, CLOCK>,
318    ) {
319        (
320            UsartReader {
321                p: unsafe { core::ptr::read(&self.p) },
322                rx: self.rx,
323                _tx: marker::PhantomData,
324                _clock: marker::PhantomData,
325                _h: marker::PhantomData,
326            },
327            UsartWriter {
328                p: self.p,
329                tx: self.tx,
330                _rx: marker::PhantomData,
331                _clock: marker::PhantomData,
332                _h: marker::PhantomData,
333            },
334        )
335    }
336}
337
338impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite for Usart<H, USART, RX, TX, CLOCK> {
339    type Error = core::convert::Infallible;
340
341    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
342        for b in s.as_bytes().iter() {
343            self.write_byte(*b);
344        }
345        Ok(())
346    }
347}
348
349impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Write<u8>
350    for Usart<H, USART, RX, TX, CLOCK>
351{
352    type Error = core::convert::Infallible;
353
354    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
355        self.p.raw_write(byte)
356    }
357
358    fn flush(&mut self) -> nb::Result<(), Self::Error> {
359        self.p.raw_flush()
360    }
361}
362
363impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Read<u8>
364    for Usart<H, USART, RX, TX, CLOCK>
365{
366    type Error = core::convert::Infallible;
367
368    fn read(&mut self) -> nb::Result<u8, Self::Error> {
369        self.p.raw_read()
370    }
371}
372
373/// Writer half of a [`Usart`] peripheral.
374///
375/// Created by calling [`Usart::split`].  Splitting a peripheral into reader and writer allows
376/// concurrently receiving and transmitting data from different contexts.
377///
378/// The writer half most notably implements [`embedded_hal_v0::serial::Write`] and [`ufmt::uWrite`]
379/// for transmitting data.
380pub struct UsartWriter<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
381    p: USART,
382    tx: TX,
383    _rx: marker::PhantomData<RX>,
384    _clock: marker::PhantomData<CLOCK>,
385    _h: marker::PhantomData<H>,
386}
387
388/// Reader half of a [`Usart`] peripheral.
389///
390/// Created by calling [`Usart::split`].  Splitting a peripheral into reader and writer allows
391/// concurrently receiving and transmitting data from different contexts.
392///
393/// The reader half most notably implements [`embedded_hal_v0::serial::Read`] for receiving data.
394pub struct UsartReader<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> {
395    p: USART,
396    rx: RX,
397    _tx: marker::PhantomData<TX>,
398    _clock: marker::PhantomData<CLOCK>,
399    _h: marker::PhantomData<H>,
400}
401
402impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartWriter<H, USART, RX, TX, CLOCK> {
403    /// Merge this `UsartWriter` with a [`UsartReader`] back into a single [`Usart`] peripheral.
404    pub fn reunite(
405        self,
406        other: UsartReader<H, USART, RX, TX, CLOCK>,
407    ) -> Usart<H, USART, RX, TX, CLOCK> {
408        Usart {
409            p: self.p,
410            rx: other.rx,
411            tx: self.tx,
412            _clock: marker::PhantomData,
413            _h: marker::PhantomData,
414        }
415    }
416}
417
418impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> UsartReader<H, USART, RX, TX, CLOCK> {
419    /// Merge this `UsartReader` with a [`UsartWriter`] back into a single [`Usart`] peripheral.
420    pub fn reunite(
421        self,
422        other: UsartWriter<H, USART, RX, TX, CLOCK>,
423    ) -> Usart<H, USART, RX, TX, CLOCK> {
424        Usart {
425            p: self.p,
426            rx: self.rx,
427            tx: other.tx,
428            _clock: marker::PhantomData,
429            _h: marker::PhantomData,
430        }
431    }
432}
433
434impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> ufmt::uWrite
435    for UsartWriter<H, USART, RX, TX, CLOCK>
436{
437    type Error = core::convert::Infallible;
438
439    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
440        for b in s.as_bytes().iter() {
441            nb::block!(self.p.raw_write(*b)).unwrap_infallible()
442        }
443        Ok(())
444    }
445}
446
447impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Write<u8>
448    for UsartWriter<H, USART, RX, TX, CLOCK>
449{
450    type Error = core::convert::Infallible;
451
452    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
453        self.p.raw_write(byte)
454    }
455
456    fn flush(&mut self) -> nb::Result<(), Self::Error> {
457        self.p.raw_flush()
458    }
459}
460
461impl<H, USART: UsartOps<H, RX, TX>, RX, TX, CLOCK> embedded_hal_v0::serial::Read<u8>
462    for UsartReader<H, USART, RX, TX, CLOCK>
463{
464    type Error = core::convert::Infallible;
465
466    fn read(&mut self) -> nb::Result<u8, Self::Error> {
467        self.p.raw_read()
468    }
469}
470
471#[macro_export]
472macro_rules! impl_usart_traditional {
473    (
474        hal: $HAL:ty,
475        peripheral: $USART:ty,
476        register_suffix: $n:expr,
477        rx: $rxpin:ty,
478        tx: $txpin:ty,
479    ) => {
480        $crate::paste::paste! {
481            impl $crate::usart::UsartOps<
482                $HAL,
483                $crate::port::Pin<$crate::port::mode::Input, $rxpin>,
484                $crate::port::Pin<$crate::port::mode::Output, $txpin>,
485            > for $USART {
486                fn raw_init<CLOCK>(&mut self, baudrate: $crate::usart::Baudrate<CLOCK>) {
487                    self.[<ubrr $n>].write(|w| unsafe { w.bits(baudrate.ubrr) });
488                    self.[<ucsr $n a>].write(|w| w.[<u2x $n>]().bit(baudrate.u2x));
489
490                    // Enable receiver and transmitter but leave interrupts disabled.
491                    self.[<ucsr $n b>].write(|w| w
492                        .[<txen $n>]().set_bit()
493                        .[<rxen $n>]().set_bit()
494                    );
495
496                    // Set frame format to 8n1 for now.  At some point, this should be made
497                    // configurable, similar to what is done in other HALs.
498                    self.[<ucsr $n c>].write(|w| w
499                        .[<umsel $n>]().usart_async()
500                        .[<ucsz $n>]().chr8()
501                        .[<usbs $n>]().stop1()
502                        .[<upm $n>]().disabled()
503                    );
504                }
505
506                fn raw_deinit(&mut self) {
507                    // Wait for any ongoing transfer to finish.
508                    $crate::nb::block!(self.raw_flush()).ok();
509                    self.[<ucsr $n b>].reset();
510                }
511
512                fn raw_flush(&mut self) -> $crate::nb::Result<(), core::convert::Infallible> {
513                    if self.[<ucsr $n a>].read().[<udre $n>]().bit_is_clear() {
514                        Err($crate::nb::Error::WouldBlock)
515                    } else {
516                        Ok(())
517                    }
518                }
519
520                fn raw_write(&mut self, byte: u8) -> $crate::nb::Result<(), core::convert::Infallible> {
521                    // Call flush to make sure the data-register is empty
522                    self.raw_flush()?;
523
524                    self.[<udr $n>].write(|w| unsafe { w.bits(byte) });
525                    Ok(())
526                }
527
528                fn raw_read(&mut self) -> $crate::nb::Result<u8, core::convert::Infallible> {
529                    if self.[<ucsr $n a>].read().[<rxc $n>]().bit_is_clear() {
530                        return Err($crate::nb::Error::WouldBlock);
531                    }
532
533                    Ok(self.[<udr $n>].read().bits())
534                }
535
536                fn raw_interrupt(&mut self, event: $crate::usart::Event, state: bool) {
537                    match event {
538                        $crate::usart::Event::RxComplete =>
539                            self.[<ucsr $n b>].modify(|_, w| w.[<rxcie $n>]().bit(state)),
540                        $crate::usart::Event::TxComplete =>
541                            self.[<ucsr $n b>].modify(|_, w| w.[<txcie $n>]().bit(state)),
542                        $crate::usart::Event::DataRegisterEmpty =>
543                            self.[<ucsr $n b>].modify(|_, w| w.[<udrie $n>]().bit(state)),
544                    }
545                }
546            }
547        }
548    };
549}