use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::slice; use core::sync::atomic::{AtomicU8, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::waitqueue::AtomicWaker; use embedded_hal_nb::nb; use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::pac::uart::Uart as Regs; use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin}; use crate::{Peri, interrupt}; /// Interrupt handler. pub struct BufferedInterruptHandler { _uart: PhantomData, } impl interrupt::typelevel::Handler for BufferedInterruptHandler { unsafe fn on_interrupt() { on_interrupt(T::info().regs, T::buffered_state()) } } /// Bidirectional buffered UART which acts as a combination of [`BufferedUartTx`] and [`BufferedUartRx`]. pub struct BufferedUart<'d> { rx: BufferedUartRx<'d>, tx: BufferedUartTx<'d>, } impl SetConfig for BufferedUart<'_> { type Config = Config; type ConfigError = ConfigError; fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { self.set_config(config) } } impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART. pub fn new( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, _irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner( uart, new_pin!(rx, config.rx_pf()), new_pin!(tx, config.tx_pf()), None, None, tx_buffer, rx_buffer, config, ) } /// Create a new bidirectional buffered UART with request-to-send and clear-to-send pins pub fn new_with_rtscts( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, rts: Peri<'d, impl RtsPin>, cts: Peri<'d, impl CtsPin>, _irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner( uart, new_pin!(rx, config.rx_pf()), new_pin!(tx, config.tx_pf()), new_pin!(rts, config.rts_pf()), new_pin!(cts, config.cts_pf()), tx_buffer, rx_buffer, config, ) } /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.tx.set_config(config)?; self.rx.set_config(config) } /// Set baudrate pub fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { self.rx.set_baudrate(baudrate) } /// Write to UART TX buffer, blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result { self.tx.blocking_write(buffer) } /// Flush UART TX buffer, blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } /// Check if UART is busy. pub fn busy(&self) -> bool { self.tx.busy() } /// Read from UART RX buffer, blocking execution until done. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result { self.rx.blocking_read(buffer) } /// Send break character. pub fn send_break(&mut self) { self.tx.send_break() } /// Split into separate RX and TX handles. pub fn split(self) -> (BufferedUartTx<'d>, BufferedUartRx<'d>) { (self.tx, self.rx) } /// Split into separate RX and TX handles. pub fn split_ref(&mut self) -> (BufferedUartTx<'_>, BufferedUartRx<'_>) { ( BufferedUartTx { info: self.tx.info, state: self.tx.state, tx: self.tx.tx.as_mut().map(Peri::reborrow), cts: self.tx.cts.as_mut().map(Peri::reborrow), reborrowed: true, }, BufferedUartRx { info: self.rx.info, state: self.rx.state, rx: self.rx.rx.as_mut().map(Peri::reborrow), rts: self.rx.rts.as_mut().map(Peri::reborrow), reborrowed: true, }, ) } } /// Rx-only buffered UART. /// /// Can be obtained from [`BufferedUart::split`], or can be constructed independently, /// if you do not need the transmitting half of the driver. pub struct BufferedUartRx<'d> { info: &'static Info, state: &'static BufferedState, rx: Option>, rts: Option>, reborrowed: bool, } impl SetConfig for BufferedUartRx<'_> { type Config = Config; type ConfigError = ConfigError; fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { self.set_config(config) } } impl<'d> BufferedUartRx<'d> { /// Create a new rx-only buffered UART with no hardware flow control. /// /// Useful if you only want Uart Rx. It saves 1 pin. pub fn new( uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, _irq: impl Binding>, rx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner(uart, new_pin!(rx, config.rx_pf()), None, rx_buffer, config) } /// Create a new rx-only buffered UART with a request-to-send pin pub fn new_with_rts( uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, rts: Peri<'d, impl RtsPin>, _irq: impl Binding>, rx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner( uart, new_pin!(rx, config.rx_pf()), new_pin!(rts, config.rts_pf()), rx_buffer, config, ) } /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { if let Some(ref rx) = self.rx { rx.update_pf(config.rx_pf()); } if let Some(ref rts) = self.rts { rts.update_pf(config.rts_pf()); } super::reconfigure(&self.info, &self.state.state, config) } /// Set baudrate pub fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { super::set_baudrate(&self.info, self.state.state.clock.load(Ordering::Relaxed), baudrate) } /// Read from UART RX buffer, blocking execution until done. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result { self.blocking_read_inner(buffer) } } impl Drop for BufferedUartRx<'_> { fn drop(&mut self) { if !self.reborrowed { let state = self.state; // SAFETY: RX is being dropped (and is not reborrowed), so the ring buffer must be deinitialized // in order to meet the requirements of init. unsafe { state.rx_buf.deinit(); } // TX is inactive if the buffer is not available. If this is true, then disable the // interrupt handler since we are running in RX only mode. if state.tx_buf.len() == 0 { self.info.interrupt.disable(); } self.rx.as_ref().map(|x| x.set_as_disconnected()); self.rts.as_ref().map(|x| x.set_as_disconnected()); } } } /// Tx-only buffered UART. /// /// Can be obtained from [`BufferedUart::split`], or can be constructed independently, /// if you do not need the receiving half of the driver. pub struct BufferedUartTx<'d> { info: &'static Info, state: &'static BufferedState, tx: Option>, cts: Option>, reborrowed: bool, } impl SetConfig for BufferedUartTx<'_> { type Config = Config; type ConfigError = ConfigError; fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { self.set_config(config) } } impl<'d> BufferedUartTx<'d> { /// Create a new tx-only buffered UART with no hardware flow control. /// /// Useful if you only want Uart Tx. It saves 1 pin. pub fn new( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, _irq: impl Binding>, tx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner(uart, new_pin!(tx, config.tx_pf()), None, tx_buffer, config) } /// Create a new tx-only buffered UART with a clear-to-send pin pub fn new_with_rts( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, cts: Peri<'d, impl CtsPin>, _irq: impl Binding>, tx_buffer: &'d mut [u8], config: Config, ) -> Result { Self::new_inner( uart, new_pin!(tx, config.tx_pf()), new_pin!(cts, config.cts_pf()), tx_buffer, config, ) } /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { if let Some(ref tx) = self.tx { tx.update_pf(config.tx_pf()); } if let Some(ref cts) = self.cts { cts.update_pf(config.cts_pf()); } super::reconfigure(self.info, &self.state.state, config) } /// Set baudrate pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { super::set_baudrate(&self.info, self.state.state.clock.load(Ordering::Relaxed), baudrate) } /// Write to UART TX buffer, blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result { self.blocking_write_inner(buffer) } /// Flush UART TX buffer, blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { let state = self.state; loop { if state.tx_buf.is_empty() { return Ok(()); } } } /// Check if UART is busy. pub fn busy(&self) -> bool { super::busy(self.info.regs) } /// Send break character pub fn send_break(&mut self) { let r = self.info.regs; r.lcrh().modify(|w| { w.set_brk(true); }); } } impl Drop for BufferedUartTx<'_> { fn drop(&mut self) { if !self.reborrowed { let state = self.state; // SAFETY: TX is being dropped (and is not reborrowed), so the ring buffer must be deinitialized // in order to meet the requirements of init. unsafe { state.tx_buf.deinit(); } // RX is inactive if the buffer is not available. If this is true, then disable the // interrupt handler since we are running in TX only mode. if state.rx_buf.len() == 0 { self.info.interrupt.disable(); } self.tx.as_ref().map(|x| x.set_as_disconnected()); self.cts.as_ref().map(|x| x.set_as_disconnected()); } } } impl embedded_io_async::ErrorType for BufferedUart<'_> { type Error = Error; } impl embedded_io_async::ErrorType for BufferedUartRx<'_> { type Error = Error; } impl embedded_io_async::ErrorType for BufferedUartTx<'_> { type Error = Error; } impl embedded_io_async::Read for BufferedUart<'_> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.read(buf).await } } impl embedded_io_async::Read for BufferedUartRx<'_> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read_inner(buf).await } } impl embedded_io_async::ReadReady for BufferedUart<'_> { fn read_ready(&mut self) -> Result { self.rx.read_ready() } } impl embedded_io_async::ReadReady for BufferedUartRx<'_> { fn read_ready(&mut self) -> Result { self.read_ready_inner() } } impl embedded_io_async::BufRead for BufferedUart<'_> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.rx.fill_buf().await } fn consume(&mut self, amt: usize) { self.rx.consume(amt); } } impl embedded_io_async::BufRead for BufferedUartRx<'_> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.fill_buf_inner().await } fn consume(&mut self, amt: usize) { self.consume_inner(amt); } } impl embedded_io_async::Write for BufferedUart<'_> { async fn write(&mut self, buf: &[u8]) -> Result { self.tx.write_inner(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.tx.flush_inner().await } } impl embedded_io_async::Write for BufferedUartTx<'_> { async fn write(&mut self, buf: &[u8]) -> Result { self.write_inner(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.flush_inner().await } } impl embedded_io::Read for BufferedUart<'_> { fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.read(buf) } } impl embedded_io::Read for BufferedUartRx<'_> { fn read(&mut self, buf: &mut [u8]) -> Result { self.blocking_read_inner(buf) } } impl embedded_io::Write for BufferedUart<'_> { fn write(&mut self, buf: &[u8]) -> Result { self.tx.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.tx.flush() } } impl embedded_io::Write for BufferedUartTx<'_> { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write_inner(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.blocking_flush() } } impl embedded_hal_nb::serial::Error for Error { fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { match self { Error::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, Error::Noise => embedded_hal_nb::serial::ErrorKind::Noise, Error::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, Error::Parity => embedded_hal_nb::serial::ErrorKind::Parity, Error::Break => embedded_hal_nb::serial::ErrorKind::Other, } } } impl embedded_hal_nb::serial::ErrorType for BufferedUart<'_> { type Error = Error; } impl embedded_hal_nb::serial::ErrorType for BufferedUartRx<'_> { type Error = Error; } impl embedded_hal_nb::serial::ErrorType for BufferedUartTx<'_> { type Error = Error; } impl embedded_hal_nb::serial::Read for BufferedUart<'_> { fn read(&mut self) -> nb::Result { self.rx.read() } } impl embedded_hal_nb::serial::Read for BufferedUartRx<'_> { fn read(&mut self) -> nb::Result { if self.info.regs.stat().read().rxfe() { return Err(nb::Error::WouldBlock); } super::read_with_error(self.info.regs).map_err(nb::Error::Other) } } impl embedded_hal_nb::serial::Write for BufferedUart<'_> { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.tx.write(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.tx.flush() } } impl embedded_hal_nb::serial::Write for BufferedUartTx<'_> { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.blocking_write(&[word]).map(drop).map_err(nb::Error::Other) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.blocking_flush().map_err(nb::Error::Other) } } // Impl details /// Buffered UART state. pub(crate) struct BufferedState { /// non-buffered UART state. This is inline in order to avoid [`BufferedUartRx`]/Tx /// needing to carry around a 2nd static reference and waste another 4 bytes. state: State, rx_waker: AtomicWaker, rx_buf: RingBuffer, tx_waker: AtomicWaker, tx_buf: RingBuffer, rx_error: AtomicU8, } // these must match bits 8..12 in RXDATA, but shifted by 8 to the right const RXE_NOISE: u8 = 16; const RXE_OVERRUN: u8 = 8; const RXE_BREAK: u8 = 4; const RXE_PARITY: u8 = 2; const RXE_FRAMING: u8 = 1; impl BufferedState { pub const fn new() -> Self { Self { state: State::new(), rx_waker: AtomicWaker::new(), rx_buf: RingBuffer::new(), tx_waker: AtomicWaker::new(), tx_buf: RingBuffer::new(), rx_error: AtomicU8::new(0), } } } impl<'d> BufferedUart<'d> { fn new_inner( _peri: Peri<'d, T>, rx: Option>, tx: Option>, rts: Option>, cts: Option>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Result { let info = T::info(); let state = T::buffered_state(); let mut this = Self { tx: BufferedUartTx { info, state, tx, cts, reborrowed: false, }, rx: BufferedUartRx { info, state, rx, rts, reborrowed: false, }, }; this.enable_and_configure(tx_buffer, rx_buffer, &config)?; Ok(this) } fn enable_and_configure( &mut self, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: &Config, ) -> Result<(), ConfigError> { let info = self.rx.info; let state = self.rx.state; assert!(!tx_buffer.is_empty()); assert!(!rx_buffer.is_empty()); init_buffers(info, state, Some(tx_buffer), Some(rx_buffer)); super::enable(info.regs); super::configure( info, &state.state, config, true, self.rx.rts.is_some(), true, self.tx.cts.is_some(), )?; info.interrupt.unpend(); unsafe { info.interrupt.enable() }; Ok(()) } } impl<'d> BufferedUartRx<'d> { fn new_inner( _peri: Peri<'d, T>, rx: Option>, rts: Option>, rx_buffer: &'d mut [u8], config: Config, ) -> Result { let mut this = Self { info: T::info(), state: T::buffered_state(), rx, rts, reborrowed: false, }; this.enable_and_configure(rx_buffer, &config)?; Ok(this) } fn enable_and_configure(&mut self, rx_buffer: &'d mut [u8], config: &Config) -> Result<(), ConfigError> { let info = self.info; let state = self.state; init_buffers(info, state, None, Some(rx_buffer)); super::enable(info.regs); super::configure(info, &self.state.state, config, true, self.rts.is_some(), false, false)?; info.interrupt.unpend(); unsafe { info.interrupt.enable() }; Ok(()) } async fn read_inner(&self, buf: &mut [u8]) -> Result { poll_fn(move |cx| { let state = self.state; if let Poll::Ready(r) = self.try_read(buf) { return Poll::Ready(r); } state.rx_waker.register(cx.waker()); Poll::Pending }) .await } fn blocking_read_inner(&self, buffer: &mut [u8]) -> Result { loop { match self.try_read(buffer) { Poll::Ready(res) => return res, Poll::Pending => continue, } } } fn fill_buf_inner(&self) -> impl Future> { poll_fn(move |cx| { let mut rx_reader = unsafe { self.state.rx_buf.reader() }; let (p, n) = rx_reader.pop_buf(); let result = if n == 0 { match Self::get_rx_error(self.state) { None => { self.state.rx_waker.register(cx.waker()); return Poll::Pending; } Some(e) => Err(e), } } else { let buf = unsafe { slice::from_raw_parts(p, n) }; Ok(buf) }; Poll::Ready(result) }) } fn consume_inner(&self, amt: usize) { let mut rx_reader = unsafe { self.state.rx_buf.reader() }; rx_reader.pop_done(amt); // (Re-)Enable the interrupt to receive more data in case it was // disabled because the buffer was full or errors were detected. self.info.regs.cpu_int(0).imask().modify(|w| { w.set_rxint(true); w.set_rtout(true); }); } /// we are ready to read if there is data in the buffer fn read_ready_inner(&self) -> Result { Ok(!self.state.rx_buf.is_empty()) } fn try_read(&self, buf: &mut [u8]) -> Poll> { let state = self.state; if buf.is_empty() { return Poll::Ready(Ok(0)); } let mut rx_reader = unsafe { state.rx_buf.reader() }; let n = rx_reader.pop(|data| { let n = data.len().min(buf.len()); buf[..n].copy_from_slice(&data[..n]); n }); let result = if n == 0 { match Self::get_rx_error(state) { None => return Poll::Pending, Some(e) => Err(e), } } else { Ok(n) }; // (Re-)Enable the interrupt to receive more data in case it was // disabled because the buffer was full or errors were detected. self.info.regs.cpu_int(0).imask().modify(|w| { w.set_rxint(true); w.set_rtout(true); }); Poll::Ready(result) } fn get_rx_error(state: &BufferedState) -> Option { // Cortex-M0 has does not support atomic swap, so we must do two operations. let errs = critical_section::with(|_cs| { let errs = state.rx_error.load(Ordering::Relaxed); state.rx_error.store(0, Ordering::Relaxed); errs }); if errs & RXE_NOISE != 0 { Some(Error::Noise) } else if errs & RXE_OVERRUN != 0 { Some(Error::Overrun) } else if errs & RXE_BREAK != 0 { Some(Error::Break) } else if errs & RXE_PARITY != 0 { Some(Error::Parity) } else if errs & RXE_FRAMING != 0 { Some(Error::Framing) } else { None } } } impl<'d> BufferedUartTx<'d> { fn new_inner( _peri: Peri<'d, T>, tx: Option>, cts: Option>, tx_buffer: &'d mut [u8], config: Config, ) -> Result { let mut this = Self { info: T::info(), state: T::buffered_state(), tx, cts, reborrowed: false, }; this.enable_and_configure(tx_buffer, &config)?; Ok(this) } async fn write_inner(&self, buf: &[u8]) -> Result { poll_fn(move |cx| { let state = self.state; if buf.is_empty() { return Poll::Ready(Ok(0)); } let mut tx_writer = unsafe { state.tx_buf.writer() }; let n = tx_writer.push(|data| { let n = data.len().min(buf.len()); data[..n].copy_from_slice(&buf[..n]); n }); if n == 0 { state.tx_waker.register(cx.waker()); return Poll::Pending; } // The TX interrupt only triggers when the there was data in the // FIFO and the number of bytes drops below a threshold. When the // FIFO was empty we have to manually pend the interrupt to shovel // TX data from the buffer into the FIFO. self.info.interrupt.pend(); Poll::Ready(Ok(n)) }) .await } fn blocking_write_inner(&self, buffer: &[u8]) -> Result { let state = self.state; loop { let empty = state.tx_buf.is_empty(); // SAFETY: tx buf must be initialized if BufferedUartTx exists. let mut tx_writer = unsafe { state.tx_buf.writer() }; let data = tx_writer.push_slice(); if !data.is_empty() { let n = data.len().min(buffer.len()); data[..n].copy_from_slice(&buffer[..n]); tx_writer.push_done(n); if empty { self.info.interrupt.pend(); } return Ok(n); } } } async fn flush_inner(&self) -> Result<(), Error> { poll_fn(move |cx| { let state = self.state; if !state.tx_buf.is_empty() { state.tx_waker.register(cx.waker()); return Poll::Pending; } Poll::Ready(Ok(())) }) .await } fn enable_and_configure(&mut self, tx_buffer: &'d mut [u8], config: &Config) -> Result<(), ConfigError> { let info = self.info; let state = self.state; init_buffers(info, state, Some(tx_buffer), None); super::enable(info.regs); super::configure(info, &state.state, config, false, false, true, self.cts.is_some())?; info.interrupt.unpend(); unsafe { info.interrupt.enable() }; Ok(()) } } fn init_buffers<'d>( info: &Info, state: &BufferedState, tx_buffer: Option<&'d mut [u8]>, rx_buffer: Option<&'d mut [u8]>, ) { if let Some(tx_buffer) = tx_buffer { let len = tx_buffer.len(); unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; } if let Some(rx_buffer) = rx_buffer { let len = rx_buffer.len(); unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; } info.regs.cpu_int(0).imask().modify(|w| { w.set_nerr(true); w.set_frmerr(true); w.set_parerr(true); w.set_brkerr(true); w.set_ovrerr(true); }); } fn on_interrupt(r: Regs, state: &'static BufferedState) { let int = r.cpu_int(0).mis().read(); // Per https://github.com/embassy-rs/embassy/pull/1458, both buffered and unbuffered handlers may be bound. if super::dma_enabled(r) { return; } // RX if state.rx_buf.is_available() { // SAFETY: RX must have been initialized if RXE is set. let mut rx_writer = unsafe { state.rx_buf.writer() }; let rx_buf = rx_writer.push_slice(); let mut n_read = 0; let mut error = false; for rx_byte in rx_buf { let stat = r.stat().read(); if stat.rxfe() { break; } let data = r.rxdata().read(); if (data.0 >> 8) != 0 { // Cortex-M0 does not support atomic fetch_or, must do 2 operations. critical_section::with(|_cs| { let mut value = state.rx_error.load(Ordering::Relaxed); value |= (data.0 >> 8) as u8; state.rx_error.store(value, Ordering::Relaxed); }); error = true; // only fill the buffer with valid characters. the current character is fine // if the error is an overrun, but if we add it to the buffer we'll report // the overrun one character too late. drop it instead and pretend we were // a bit slower at draining the rx fifo than we actually were. // this is consistent with blocking uart error reporting. break; } *rx_byte = data.data(); n_read += 1; } if n_read > 0 { rx_writer.push_done(n_read); state.rx_waker.wake(); } else if error { state.rx_waker.wake(); } // Disable any further RX interrupts when the buffer becomes full or // errors have occurred. This lets us buffer additional errors in the // fifo without needing more error storage locations, and most applications // will want to do a full reset of their uart state anyway once an error // has happened. if state.rx_buf.is_full() || error { r.cpu_int(0).imask().modify(|w| { w.set_rxint(false); w.set_rtout(false); }); } } if int.eot() { r.cpu_int(0).imask().modify(|w| { w.set_eot(false); }); r.cpu_int(0).iclr().write(|w| { w.set_eot(true); }); state.tx_waker.wake(); } // TX if state.tx_buf.is_available() { // SAFETY: TX must have been initialized if TXE is set. let mut tx_reader = unsafe { state.tx_buf.reader() }; let buf = tx_reader.pop_slice(); let mut n_written = 0; for tx_byte in buf.iter_mut() { let stat = r.stat().read(); if stat.txff() { break; } r.txdata().write(|w| { w.set_data(*tx_byte); }); n_written += 1; } if n_written > 0 { // EOT will wake. r.cpu_int(0).imask().modify(|w| { w.set_eot(true); }); tx_reader.pop_done(n_written); } } // Clear TX and error interrupt flags // RX interrupt flags are cleared by writing to ICLR. let mis = r.cpu_int(0).mis().read(); r.cpu_int(0).iclr().write(|w| { w.set_nerr(mis.nerr()); w.set_frmerr(mis.frmerr()); w.set_parerr(mis.parerr()); w.set_brkerr(mis.brkerr()); w.set_ovrerr(mis.ovrerr()); }); // Errors if mis.nerr() { warn!("Noise error"); } if mis.frmerr() { warn!("Framing error"); } if mis.parerr() { warn!("Parity error"); } if mis.brkerr() { warn!("Break error"); } if mis.ovrerr() { warn!("Overrun error"); } }