Skip to main content

rp235x_hal/uart/
peripheral.rs

1//! Universal Asynchronous Receiver Transmitter - Bi-directional Peripheral Code
2//!
3//! This module brings together `uart::reader` and `uart::writer` to give a
4//! UartPeripheral object that can both read and write.
5
6use core::{convert::Infallible, fmt};
7use embedded_hal_0_2::serial as eh0;
8use fugit::HertzU32;
9use nb::Error::{Other, WouldBlock};
10
11use crate::{
12    pac::{self, uart0::uartlcr_h::W as UART_LCR_H_Writer, Peripherals, UART0, UART1},
13    typelevel::OptionT,
14    uart::*,
15};
16
17use embedded_hal_nb::serial::{ErrorType, Read, Write};
18
19/// An UART Peripheral based on an underlying UART device.
20pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
21    device: D,
22    _state: S,
23    pins: P,
24    read_error: Option<ReadErrorType>,
25}
26
27impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
28    fn transition<To: State>(self, state: To) -> UartPeripheral<To, D, P> {
29        UartPeripheral {
30            device: self.device,
31            pins: self.pins,
32            _state: state,
33            read_error: None,
34        }
35    }
36
37    /// Releases the underlying device and pins.
38    pub fn free(self) -> (D, P) {
39        (self.device, self.pins)
40    }
41}
42
43impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
44    /// Creates an UartPeripheral in Disabled state.
45    pub fn new(device: D, pins: P, resets: &mut pac::RESETS) -> UartPeripheral<Disabled, D, P> {
46        device.reset_bring_down(resets);
47        device.reset_bring_up(resets);
48
49        UartPeripheral {
50            device,
51            _state: Disabled,
52            pins,
53            read_error: None,
54        }
55    }
56
57    /// Enables the provided UART device with the given configuration.
58    pub fn enable(
59        self,
60        config: UartConfig,
61        frequency: HertzU32,
62    ) -> Result<UartPeripheral<Enabled, D, P>, Error> {
63        let (mut device, pins) = self.free();
64        configure_baudrate(&mut device, config.baudrate, frequency)?;
65
66        device.uartlcr_h().write(|w| {
67            // FIFOs are enabled
68            w.fen().set_bit(); // Leaved here for backward compatibility
69            set_format(w, &config.data_bits, &config.stop_bits, &config.parity);
70            w
71        });
72
73        // Enable the UART, and the TX,RC,CTS and RTS based on the pins
74        device.uartcr().write(|w| {
75            w.uarten().set_bit();
76            w.txe().bit(P::Tx::IS_SOME);
77            w.rxe().bit(P::Rx::IS_SOME);
78            w.ctsen().bit(P::Cts::IS_SOME);
79            w.rtsen().bit(P::Rts::IS_SOME);
80
81            w
82        });
83
84        device.uartdmacr().write(|w| {
85            w.txdmae().set_bit();
86            w.rxdmae().set_bit();
87            w
88        });
89
90        Ok(UartPeripheral {
91            device,
92            pins,
93            _state: Enabled,
94            read_error: None,
95        })
96    }
97}
98
99impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Enabled, D, P> {
100    /// Disable this UART Peripheral, falling back to the Disabled state.
101    pub fn disable(self) -> UartPeripheral<Disabled, D, P> {
102        // Disable the UART, both TX and RX
103        self.device.uartcr().write(|w| {
104            w.uarten().clear_bit();
105            w.txe().clear_bit();
106            w.rxe().clear_bit();
107            w.ctsen().clear_bit();
108            w.rtsen().clear_bit();
109            w
110        });
111
112        self.transition(Disabled)
113    }
114
115    /// Enable/disable the rx/tx FIFO
116    ///
117    /// Unfortunately, it's not possible to enable/disable rx/tx
118    /// independently on this chip
119    /// Default is false
120    pub fn set_fifos(&mut self, enable: bool) {
121        super::reader::set_fifos(&self.device, enable)
122    }
123
124    /// Set rx FIFO watermark
125    ///
126    /// See DS: Table 423
127    pub fn set_rx_watermark(&mut self, watermark: FifoWatermark) {
128        super::reader::set_rx_watermark(&self.device, watermark)
129    }
130
131    /// Set tx FIFO watermark
132    ///
133    /// See DS: Table 423
134    pub fn set_tx_watermark(&mut self, watermark: FifoWatermark) {
135        super::writer::set_tx_watermark(&self.device, watermark)
136    }
137
138    /// Enables the Receive Interrupt.
139    ///
140    /// The relevant UARTx IRQ will fire when there is data in the receive register.
141    pub fn enable_rx_interrupt(&mut self) {
142        super::reader::enable_rx_interrupt(&self.device)
143    }
144
145    /// Enables the Transmit Interrupt.
146    ///
147    /// The relevant UARTx IRQ will fire when there is space in the transmit FIFO.
148    pub fn enable_tx_interrupt(&mut self) {
149        super::writer::enable_tx_interrupt(&self.device)
150    }
151
152    /// Disables the Receive Interrupt.
153    pub fn disable_rx_interrupt(&mut self) {
154        super::reader::disable_rx_interrupt(&self.device)
155    }
156
157    /// Disables the Transmit Interrupt.
158    pub fn disable_tx_interrupt(&mut self) {
159        super::writer::disable_tx_interrupt(&self.device)
160    }
161
162    /// Is there space in the UART TX FIFO for new data to be written?
163    pub fn uart_is_writable(&self) -> bool {
164        super::writer::uart_is_writable(&self.device)
165    }
166
167    /// Is the UART still busy transmitting data?
168    pub fn uart_is_busy(&self) -> bool {
169        super::writer::uart_is_busy(&self.device)
170    }
171
172    /// Is there data in the UART RX FIFO ready to be read?
173    pub fn uart_is_readable(&self) -> bool {
174        super::reader::is_readable(&self.device)
175    }
176
177    /// Writes bytes to the UART.
178    /// This function writes as long as it can. As soon that the FIFO is full, if :
179    /// - 0 bytes were written, a WouldBlock Error is returned
180    /// - some bytes were written, it is deemed to be a success
181    ///
182    /// Upon success, the remaining slice is returned.
183    pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
184        super::writer::write_raw(&self.device, data)
185    }
186
187    /// Reads bytes from the UART.
188    /// This function reads as long as it can. As soon that the FIFO is empty, if :
189    /// - 0 bytes were read, a WouldBlock Error is returned
190    /// - some bytes were read, it is deemed to be a success
191    ///
192    /// Upon success, it will return how many bytes were read.
193    pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<usize, ReadError<'b>> {
194        super::reader::read_raw(&self.device, buffer)
195    }
196
197    /// Writes bytes to the UART.
198    ///
199    /// This function blocks until the full buffer has been sent.
200    pub fn write_full_blocking(&self, data: &[u8]) {
201        super::writer::write_full_blocking(&self.device, data);
202    }
203
204    /// Reads bytes from the UART.
205    ///
206    /// This function blocks until the full buffer has been received.
207    pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> {
208        super::reader::read_full_blocking(&self.device, buffer)
209    }
210
211    /// Initiates a break
212    ///
213    /// If transmitting, this takes effect immediately after the current byte has completed.  
214    /// For proper execution of the break command, this must be held for at least 2 complete frames
215    /// worth of time.
216    ///
217    /// <div class="warning">The device won’t be able to send anything while breaking.</div>
218    ///
219    /// # Example
220    ///
221    /// ```no_run
222    /// # use rp235x_hal::uart::{Pins, ValidUartPinout, Enabled, UartPeripheral};
223    /// # use rp235x_hal::pac::UART0;
224    /// # use rp235x_hal::timer::{Timer, CopyableTimer0};
225    /// # use rp235x_hal::typelevel::OptionTNone;
226    /// # use embedded_hal_0_2::blocking::delay::DelayUs;
227    /// # type PINS = Pins<OptionTNone, OptionTNone, OptionTNone, OptionTNone>;
228    /// # fn example(mut serial: UartPeripheral<Enabled, rp235x_hal::pac::UART0, PINS>, mut timer: Timer<CopyableTimer0>) {
229    /// serial.lowlevel_break_start();
230    /// // at 115_200Bps on 8N1 configuration, 20bits takes (20*10⁶)/115200 = 173.611…μs.
231    /// timer.delay_us(175);
232    /// serial.lowlevel_break_stop();
233    /// }
234    /// ```
235    pub fn lowlevel_break_start(&mut self) {
236        self.device.uartlcr_h().modify(|_, w| w.brk().set_bit());
237    }
238
239    /// Terminates a break condition.
240    ///
241    /// See `lowlevel_break_start` for more details.
242    pub fn lowlevel_break_stop(&mut self) {
243        self.device.uartlcr_h().modify(|_, w| w.brk().clear_bit());
244    }
245
246    /// Join the reader and writer halves together back into the original Uart peripheral.
247    ///
248    /// A reader/writer pair can be obtained by calling [`split`].
249    ///
250    /// [`split`]: #method.split
251    pub fn join(reader: Reader<D, P>, writer: Writer<D, P>) -> Self {
252        let _ = writer;
253        Self {
254            device: reader.device,
255            _state: Enabled,
256            pins: reader.pins,
257            read_error: reader.read_error,
258        }
259    }
260}
261
262impl<P: ValidUartPinout<UART0>> UartPeripheral<Enabled, UART0, P> {
263    /// Split this peripheral into a separate reader and writer.
264    pub fn split(self) -> (Reader<UART0, P>, Writer<UART0, P>) {
265        let reader = Reader {
266            device: self.device,
267            pins: self.pins,
268            read_error: self.read_error,
269        };
270        // Safety: reader and writer will never write to the same address
271        let device_copy = unsafe { Peripherals::steal().UART0 };
272        let writer = Writer {
273            device: device_copy,
274            device_marker: core::marker::PhantomData,
275            pins: core::marker::PhantomData,
276        };
277        (reader, writer)
278    }
279}
280
281impl<P: ValidUartPinout<UART1>> UartPeripheral<Enabled, UART1, P> {
282    /// Split this peripheral into a separate reader and writer.
283    pub fn split(self) -> (Reader<UART1, P>, Writer<UART1, P>) {
284        let reader = Reader {
285            device: self.device,
286            pins: self.pins,
287            read_error: self.read_error,
288        };
289        // Safety: reader and writer will never write to the same address
290        let device_copy = unsafe { Peripherals::steal().UART1 };
291        let writer = Writer {
292            device: device_copy,
293            device_marker: core::marker::PhantomData,
294            pins: core::marker::PhantomData,
295        };
296        (reader, writer)
297    }
298}
299
300/// The PL011 (PrimeCell UART) supports a fractional baud rate divider
301/// From the wanted baudrate, we calculate the divider's two parts: integer and fractional parts.
302/// Code inspired from the C SDK.
303fn calculate_baudrate_dividers(
304    wanted_baudrate: HertzU32,
305    frequency: HertzU32,
306) -> Result<(u16, u16), Error> {
307    // See [Section 12.1.7.1](https://rptl.io/rp2350-datasheet#section_uart)
308    // of the RP2350 datasheet for an explanation of how baudrate is calculated
309    let baudrate_div = frequency
310        .to_Hz()
311        .checked_mul(8)
312        .and_then(|r| r.checked_div(wanted_baudrate.to_Hz()))
313        .ok_or(Error::BadArgument)?;
314
315    Ok(
316        match (baudrate_div >> 7, (baudrate_div & 0x7F).div_ceil(2)) {
317            (0, _) => (1, 0),
318
319            (int_part, _) if int_part >= 65535 => (65535, 0),
320
321            (int_part, frac_part) => (int_part as u16, frac_part as u16),
322        },
323    )
324}
325
326/// Baudrate configuration. Code loosely inspired from the C SDK.
327#[allow(unknown_lints)]
328#[allow(clippy::needless_pass_by_ref_mut)]
329fn configure_baudrate<U: UartDevice>(
330    device: &mut U,
331    wanted_baudrate: HertzU32,
332    frequency: HertzU32,
333) -> Result<HertzU32, Error> {
334    let (baud_div_int, baud_div_frac) = calculate_baudrate_dividers(wanted_baudrate, frequency)?;
335
336    // First we load the integer part of the divider.
337    device.uartibrd().write(|w| unsafe {
338        w.baud_divint().bits(baud_div_int);
339        w
340    });
341
342    // Then we load the fractional part of the divider.
343    device.uartfbrd().write(|w| unsafe {
344        w.baud_divfrac().bits(baud_div_frac as u8);
345        w
346    });
347
348    // PL011 needs a (dummy) line control register write to latch in the
349    // divisors. We don't want to actually change LCR contents here.
350    device.uartlcr_h().modify(|_, w| w);
351
352    Ok(HertzU32::from_raw(
353        (4 * frequency.to_Hz()) / (64 * baud_div_int as u32 + baud_div_frac as u32),
354    ))
355}
356
357/// Format configuration. Code loosely inspired from the C SDK.
358fn set_format<'w>(
359    w: &'w mut UART_LCR_H_Writer,
360    data_bits: &DataBits,
361    stop_bits: &StopBits,
362    parity: &Option<Parity>,
363) -> &'w mut UART_LCR_H_Writer {
364    match parity {
365        Some(p) => {
366            w.pen().set_bit();
367            match p {
368                Parity::Odd => w.eps().clear_bit(),
369                Parity::Even => w.eps().set_bit(),
370            };
371        }
372        None => {
373            w.pen().bit(false);
374        }
375    };
376
377    unsafe {
378        w.wlen().bits(match data_bits {
379            DataBits::Five => 0b00,
380            DataBits::Six => 0b01,
381            DataBits::Seven => 0b10,
382            DataBits::Eight => 0b11,
383        })
384    };
385
386    match stop_bits {
387        StopBits::One => w.stp2().clear_bit(),
388        StopBits::Two => w.stp2().set_bit(),
389    };
390
391    w
392}
393
394impl<D: UartDevice, P: ValidUartPinout<D>> eh0::Read<u8> for UartPeripheral<Enabled, D, P> {
395    type Error = ReadErrorType;
396
397    fn read(&mut self) -> nb::Result<u8, Self::Error> {
398        let byte: &mut [u8] = &mut [0; 1];
399
400        match self.read_raw(byte) {
401            Ok(_) => Ok(byte[0]),
402            Err(e) => match e {
403                Other(inner) => Err(Other(inner.err_type)),
404                WouldBlock => Err(WouldBlock),
405            },
406        }
407    }
408}
409
410impl<D: UartDevice, P: ValidUartPinout<D>> ErrorType for UartPeripheral<Enabled, D, P> {
411    type Error = ReadErrorType;
412}
413
414impl<D: UartDevice, P: ValidUartPinout<D>> Read<u8> for UartPeripheral<Enabled, D, P> {
415    fn read(&mut self) -> nb::Result<u8, Self::Error> {
416        let byte: &mut [u8] = &mut [0; 1];
417
418        match self.read_raw(byte) {
419            Ok(_) => Ok(byte[0]),
420            Err(e) => match e {
421                Other(inner) => Err(Other(inner.err_type)),
422                WouldBlock => Err(WouldBlock),
423            },
424        }
425    }
426}
427
428impl<D: UartDevice, P: ValidUartPinout<D>> eh0::Write<u8> for UartPeripheral<Enabled, D, P> {
429    type Error = Infallible;
430
431    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
432        if self.write_raw(&[word]).is_err() {
433            Err(WouldBlock)
434        } else {
435            Ok(())
436        }
437    }
438
439    fn flush(&mut self) -> nb::Result<(), Self::Error> {
440        super::writer::transmit_flushed(&self.device)
441    }
442}
443
444impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for UartPeripheral<Enabled, D, P> {
445    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
446        if self.write_raw(&[word]).is_err() {
447            Err(WouldBlock)
448        } else {
449            Ok(())
450        }
451    }
452
453    fn flush(&mut self) -> nb::Result<(), Self::Error> {
454        super::writer::transmit_flushed(&self.device).map_err(|e| match e {
455            WouldBlock => WouldBlock,
456            Other(v) => match v {},
457        })
458    }
459}
460
461impl<D: UartDevice, P: ValidUartPinout<D>> fmt::Write for UartPeripheral<Enabled, D, P> {
462    fn write_str(&mut self, s: &str) -> fmt::Result {
463        s.bytes()
464            .try_for_each(|c| nb::block!(self.write(c)))
465            .map_err(|_| fmt::Error)
466    }
467}
468
469impl core::fmt::Display for ReadErrorType {
470    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
471        write!(f, "{:?}", self)
472    }
473}
474
475impl core::error::Error for ReadErrorType {}
476
477impl embedded_io::Error for ReadErrorType {
478    fn kind(&self) -> embedded_io::ErrorKind {
479        embedded_io::ErrorKind::Other
480    }
481}
482
483impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::ErrorType
484    for UartPeripheral<Enabled, D, P>
485{
486    type Error = ReadErrorType;
487}
488impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::Read for UartPeripheral<Enabled, D, P> {
489    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
490        // If the last read stored an error, report it now
491        if let Some(err) = self.read_error.take() {
492            return Err(err);
493        }
494        match nb::block!(self.read_raw(buf)) {
495            Ok(bytes_read) => Ok(bytes_read),
496            Err(err) if !err.discarded.is_empty() => {
497                // If an error was reported but some bytes were already read,
498                // return the data now and store the error for the next
499                // invocation.
500                self.read_error = Some(err.err_type);
501                Ok(err.discarded.len())
502            }
503            Err(err) => Err(err.err_type),
504        }
505    }
506}
507
508impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::ReadReady
509    for UartPeripheral<Enabled, D, P>
510{
511    fn read_ready(&mut self) -> Result<bool, Self::Error> {
512        Ok(self.uart_is_readable() || self.read_error.is_some())
513    }
514}
515
516impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::Write for UartPeripheral<Enabled, D, P> {
517    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
518        // Blocks if and only if no bytes can be written.
519        let remaining = nb::block!(super::writer::write_raw(&self.device, buf)).unwrap(); // Infallible
520        Ok(buf.len() - remaining.len())
521    }
522    fn flush(&mut self) -> Result<(), Self::Error> {
523        nb::block!(super::writer::transmit_flushed(&self.device)).unwrap(); // Infallible
524        Ok(())
525    }
526}
527
528impl<D: UartDevice, P: ValidUartPinout<D>> embedded_io::WriteReady
529    for UartPeripheral<Enabled, D, P>
530{
531    fn write_ready(&mut self) -> Result<bool, Self::Error> {
532        Ok(self.uart_is_writable())
533    }
534}