esp_lp_hal/
uart.rs

1//! # Universal Asynchronous Receiver/Transmitter (UART)
2//!
3//! ## Overview
4//!
5//! The UART is a hardware peripheral which handles communication using serial
6//! interfaces. This peripheral provides a cheap and ubiquitous method for full-
7//! and half-duplex communication between devices.
8//!
9//! ## Configuration
10//!
11//! The usual setting such as baud rate, data bits, parity, and stop bits can
12//! easily be configured. See the [config] module documentation for more
13//! information.
14//!
15//! ## Usage
16//!
17//! The UART driver implements a number of third-party traits, with the
18//! intention of making the HAL inter-compatible with various device drivers
19//! from the community. This includes the [embedded-hal], [embedded-hal-nb], and
20//! [embedded-io] traits.
21//!
22//! ## Examples
23//!
24//! ```rust
25//! fn main(mut uart: LpUart) -> ! {
26//!     loop {
27//!         writeln!(uart, "Hello, world!").ok();
28//!         esp_lp_hal::delay::Delay.delay_ms(1000);
29//!     }
30//! }
31//! ```
32//!
33//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
34//! [embedded-hal-nb]: https://docs.rs/embedded-hal-nb/latest/embedded_hal_nb/
35//! [embedded-io]: https://docs.rs/embedded-io/latest/embedded_io/
36
37use crate::pac::LP_UART;
38
39const UART_FIFO_SIZE: u16 = property!("lp_uart.ram_size");
40
41#[doc(hidden)]
42pub unsafe fn conjure() -> LpUart {
43    unsafe {
44        LpUart {
45            uart: LP_UART::steal(),
46        }
47    }
48}
49
50/// UART Error
51#[derive(Debug)]
52pub enum Error {}
53
54#[cfg(feature = "embedded-io")]
55impl core::error::Error for Error {}
56
57#[cfg(feature = "embedded-io")]
58impl core::fmt::Display for Error {
59    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60        write!(f, "UART error")
61    }
62}
63
64#[cfg(feature = "embedded-hal")]
65impl embedded_hal_nb::serial::Error for Error {
66    fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
67        embedded_hal_nb::serial::ErrorKind::Other
68    }
69}
70
71#[cfg(feature = "embedded-io")]
72impl embedded_io_06::Error for Error {
73    fn kind(&self) -> embedded_io_06::ErrorKind {
74        embedded_io_06::ErrorKind::Other
75    }
76}
77
78#[cfg(feature = "embedded-io")]
79impl embedded_io_07::Error for Error {
80    fn kind(&self) -> embedded_io_07::ErrorKind {
81        embedded_io_07::ErrorKind::Other
82    }
83}
84
85/// UART configuration
86pub mod config {
87    /// Number of data bits
88    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
89    pub enum DataBits {
90        /// 5 data bits
91        DataBits5 = 0,
92        /// 6 data bits
93        DataBits6 = 1,
94        /// 7 data bits
95        DataBits7 = 2,
96        /// 8 data bits
97        #[default]
98        DataBits8 = 3,
99    }
100
101    /// Parity check
102    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
103    pub enum Parity {
104        /// No parity
105        #[default]
106        ParityNone = 0,
107        /// Even parity
108        ParityEven = 1,
109        /// Odd parity
110        ParityOdd  = 2,
111    }
112
113    /// Number of stop bits
114    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
115    pub enum StopBits {
116        /// 1 stop bit
117        #[default]
118        Stop1   = 1,
119        /// 1.5 stop bits
120        Stop1p5 = 2,
121        /// 2 stop bits
122        Stop2   = 3,
123    }
124
125    /// UART configuration
126    #[derive(Debug, Clone, Copy)]
127    pub struct Config {
128        baudrate: u32,
129        data_bits: DataBits,
130        parity: Parity,
131        stop_bits: StopBits,
132    }
133
134    impl Config {
135        /// Configure the UART's baud rate
136        pub fn baudrate(mut self, baudrate: u32) -> Self {
137            self.baudrate = baudrate;
138            self
139        }
140
141        /// Configure the UART to use no parity
142        pub fn parity_none(mut self) -> Self {
143            self.parity = Parity::ParityNone;
144            self
145        }
146
147        /// Configure the UART to use even parity
148        pub fn parity_even(mut self) -> Self {
149            self.parity = Parity::ParityEven;
150            self
151        }
152
153        /// Configure the UART to use odd parity
154        pub fn parity_odd(mut self) -> Self {
155            self.parity = Parity::ParityOdd;
156            self
157        }
158
159        /// Configure the UART's data bits
160        pub fn data_bits(mut self, data_bits: DataBits) -> Self {
161            self.data_bits = data_bits;
162            self
163        }
164
165        /// Configure the UART's stop bits
166        pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
167            self.stop_bits = stop_bits;
168            self
169        }
170    }
171
172    impl Default for Config {
173        fn default() -> Config {
174            Config {
175                baudrate: 115_200,
176                data_bits: Default::default(),
177                parity: Default::default(),
178                stop_bits: Default::default(),
179            }
180        }
181    }
182}
183
184/// LP-UART driver
185pub struct LpUart {
186    uart: LP_UART,
187}
188
189impl LpUart {
190    /// Read a single byte from the UART in a non-blocking manner.
191    pub fn read_byte(&mut self) -> nb::Result<u8, Error> {
192        if self.rx_fifo_count() > 0 {
193            let byte = self.uart.fifo().read().rxfifo_rd_byte().bits();
194            Ok(byte)
195        } else {
196            Err(nb::Error::WouldBlock)
197        }
198    }
199
200    /// Write a single byte to the UART in a non-blocking manner.
201    pub fn write_byte(&mut self, byte: u8) -> nb::Result<(), Error> {
202        if self.tx_fifo_count() < UART_FIFO_SIZE {
203            self.uart
204                .fifo()
205                .write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) });
206            Ok(())
207        } else {
208            Err(nb::Error::WouldBlock)
209        }
210    }
211
212    /// Write one or more byte to the UART, blocking until the write has
213    /// completed.
214    pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
215        let count = data.len();
216
217        data.iter()
218            .try_for_each(|c| nb::block!(self.write_byte(*c)))?;
219
220        Ok(count)
221    }
222
223    /// Flush the UART's transmit buffer in a non-blocking manner.
224    pub fn flush_tx(&mut self) -> nb::Result<(), Error> {
225        if self.is_tx_idle() {
226            Ok(())
227        } else {
228            Err(nb::Error::WouldBlock)
229        }
230    }
231
232    fn rx_fifo_count(&mut self) -> u16 {
233        self.uart.status().read().rxfifo_cnt().bits().into()
234    }
235
236    fn tx_fifo_count(&mut self) -> u16 {
237        self.uart.status().read().txfifo_cnt().bits().into()
238    }
239
240    fn is_tx_idle(&self) -> bool {
241        self.uart.fsm_status().read().st_utx_out().bits() == 0
242    }
243}
244
245impl core::fmt::Write for LpUart {
246    fn write_str(&mut self, s: &str) -> core::fmt::Result {
247        self.write_bytes(s.as_bytes())
248            .map_err(|_| core::fmt::Error)?;
249        Ok(())
250    }
251}
252
253#[cfg(feature = "embedded-hal")]
254impl embedded_hal_nb::serial::ErrorType for LpUart {
255    type Error = Error;
256}
257
258#[cfg(feature = "embedded-hal")]
259impl embedded_hal_nb::serial::Read for LpUart {
260    fn read(&mut self) -> nb::Result<u8, Self::Error> {
261        self.read_byte()
262    }
263}
264
265#[cfg(feature = "embedded-hal")]
266impl embedded_hal_nb::serial::Write for LpUart {
267    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
268        self.write_byte(word)
269    }
270
271    fn flush(&mut self) -> nb::Result<(), Self::Error> {
272        self.flush_tx()
273    }
274}
275
276#[cfg(feature = "embedded-io")]
277impl embedded_io_06::ErrorType for LpUart {
278    type Error = Error;
279}
280
281#[cfg(feature = "embedded-io")]
282impl embedded_io_06::Read for LpUart {
283    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
284        if buf.is_empty() {
285            return Ok(0);
286        }
287
288        while self.rx_fifo_count() == 0 {
289            // Block until we have received at least one byte
290        }
291
292        let mut count = 0;
293        while self.rx_fifo_count() > 0 && count < buf.len() {
294            buf[count] = self.uart.fifo().read().rxfifo_rd_byte().bits();
295            count += 1;
296        }
297
298        Ok(count)
299    }
300}
301
302#[cfg(feature = "embedded-io")]
303impl embedded_io_06::ReadReady for LpUart {
304    fn read_ready(&mut self) -> Result<bool, Self::Error> {
305        Ok(self.rx_fifo_count() > 0)
306    }
307}
308
309#[cfg(feature = "embedded-io")]
310impl embedded_io_06::Write for LpUart {
311    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
312        self.write_bytes(buf)
313    }
314
315    fn flush(&mut self) -> Result<(), Self::Error> {
316        loop {
317            match self.flush_tx() {
318                Ok(_) => break,
319                Err(nb::Error::WouldBlock) => { /* Wait */ }
320                #[allow(unreachable_patterns)]
321                Err(nb::Error::Other(e)) => return Err(e),
322            }
323        }
324
325        Ok(())
326    }
327}
328
329#[cfg(feature = "embedded-io")]
330impl embedded_io_07::ErrorType for LpUart {
331    type Error = Error;
332}
333
334#[cfg(feature = "embedded-io")]
335impl embedded_io_07::Read for LpUart {
336    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
337        if buf.is_empty() {
338            return Ok(0);
339        }
340
341        while self.rx_fifo_count() == 0 {
342            // Block until we have received at least one byte
343        }
344
345        let mut count = 0;
346        while self.rx_fifo_count() > 0 && count < buf.len() {
347            buf[count] = self.uart.fifo().read().rxfifo_rd_byte().bits();
348            count += 1;
349        }
350
351        Ok(count)
352    }
353}
354
355#[cfg(feature = "embedded-io")]
356impl embedded_io_07::ReadReady for LpUart {
357    fn read_ready(&mut self) -> Result<bool, Self::Error> {
358        Ok(self.rx_fifo_count() > 0)
359    }
360}
361
362#[cfg(feature = "embedded-io")]
363impl embedded_io_07::Write for LpUart {
364    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
365        self.write_bytes(buf)
366    }
367
368    fn flush(&mut self) -> Result<(), Self::Error> {
369        loop {
370            match self.flush_tx() {
371                Ok(_) => break,
372                Err(nb::Error::WouldBlock) => { /* Wait */ }
373                #[allow(unreachable_patterns)]
374                Err(nb::Error::Other(e)) => return Err(e),
375            }
376        }
377
378        Ok(())
379    }
380}