diff --git a/esp-hal/src/ecc.rs b/esp-hal/src/ecc.rs index 451620264c..7923e08e06 100644 --- a/esp-hal/src/ecc.rs +++ b/esp-hal/src/ecc.rs @@ -39,7 +39,7 @@ use crate::{ }; /// The ECC Accelerator driver instance -pub struct Ecc<'d, Dm: DriverMode> { +pub struct Ecc<'d, Dm> { ecc: PeripheralRef<'d, ECC>, alignment_helper: AlignmentHelper, phantom: PhantomData, diff --git a/esp-hal/src/hmac.rs b/esp-hal/src/hmac.rs index b1ed0412c4..7327c4cee4 100644 --- a/esp-hal/src/hmac.rs +++ b/esp-hal/src/hmac.rs @@ -298,7 +298,7 @@ impl<'d> Hmac<'d> { // The padding will be spanned over 2 blocks if mod_cursor > 56 { let pad_len = 64 - mod_cursor; - self.alignment_helper.volatile_write_bytes( + self.alignment_helper.volatile_write( #[cfg(esp32s2)] self.regs().wr_message_(0).as_ptr(), #[cfg(not(esp32s2))] @@ -320,7 +320,7 @@ impl<'d> Hmac<'d> { let mod_cursor = self.byte_written % 64; let pad_len = 64 - mod_cursor - core::mem::size_of::(); - self.alignment_helper.volatile_write_bytes( + self.alignment_helper.volatile_write( #[cfg(esp32s2)] self.regs().wr_message_(0).as_ptr(), #[cfg(not(esp32s2))] diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 306526e73a..ca19cf53db 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -430,7 +430,7 @@ impl Default for Config { /// ``` #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct I2c<'d, Dm: DriverMode> { +pub struct I2c<'d, Dm> { i2c: PeripheralRef<'d, AnyI2c>, phantom: PhantomData, config: Config, @@ -467,7 +467,7 @@ impl embedded_hal::i2c::I2c for I2c<'_, Dm> { } } -impl<'d, Dm: DriverMode> I2c<'d, Dm> { +impl<'d, Dm> I2c<'d, Dm> { fn driver(&self) -> Driver<'_> { Driver { info: self.i2c.info(), diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 8d8d21976c..f509c5073d 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -463,7 +463,7 @@ impl I2sTx<'_, Dm> where Dm: DriverMode, { - fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> { + fn write(&mut self, data: &[u8]) -> Result<(), Error> { self.start_tx_transfer(&data, false)?; // wait until I2S_TX_IDLE is 1 @@ -505,8 +505,8 @@ where } /// Writes a slice of data to the I2S peripheral. - pub fn write(&mut self, words: &[impl AcceptedWord]) -> Result<(), Error> { - self.write_bytes(unsafe { + pub fn write_words(&mut self, words: &[impl AcceptedWord]) -> Result<(), Error> { + self.write(unsafe { core::slice::from_raw_parts(words.as_ptr().cast::(), core::mem::size_of_val(words)) }) } @@ -591,7 +591,7 @@ impl I2sRx<'_, Dm> where Dm: DriverMode, { - fn read_bytes(&mut self, mut data: &mut [u8]) -> Result<(), Error> { + fn read(&mut self, mut data: &mut [u8]) -> Result<(), Error> { self.start_rx_transfer(&mut data, false)?; // wait until I2S_RX_IDLE is 1 @@ -634,12 +634,12 @@ where /// Reads a slice of data from the I2S peripheral and stores it in the /// provided buffer. - pub fn read(&mut self, words: &mut [impl AcceptedWord]) -> Result<(), Error> { + pub fn read_words(&mut self, words: &mut [impl AcceptedWord]) -> Result<(), Error> { if core::mem::size_of_val(words) > 4096 || words.is_empty() { return Err(Error::IllegalArgument); } - self.read_bytes(unsafe { + self.read(unsafe { core::slice::from_raw_parts_mut( words.as_mut_ptr().cast::(), core::mem::size_of_val(words), diff --git a/esp-hal/src/lcd_cam/lcd/dpi.rs b/esp-hal/src/lcd_cam/lcd/dpi.rs index 38d6f6b7ea..487abbb94c 100644 --- a/esp-hal/src/lcd_cam/lcd/dpi.rs +++ b/esp-hal/src/lcd_cam/lcd/dpi.rs @@ -130,7 +130,7 @@ pub enum ConfigError { } /// Represents the RGB LCD interface. -pub struct Dpi<'d, Dm: DriverMode> { +pub struct Dpi<'d, Dm> { lcd_cam: PeripheralRef<'d, LCD_CAM>, tx_channel: ChannelTx<'d, Blocking, PeripheralTxChannel>, _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>, diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index af21afd0cf..8b5aa70fd4 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -92,7 +92,7 @@ pub enum ConfigError { } /// Represents the I8080 LCD interface. -pub struct I8080<'d, Dm: DriverMode> { +pub struct I8080<'d, Dm> { lcd_cam: PeripheralRef<'d, LCD_CAM>, tx_channel: ChannelTx<'d, Blocking, PeripheralTxChannel>, _guard: GenericPeripheralGuard<{ system::Peripheral::LcdCam as u8 }>, diff --git a/esp-hal/src/reg_access.rs b/esp-hal/src/reg_access.rs index 54d39c88d7..07c7495fab 100644 --- a/esp-hal/src/reg_access.rs +++ b/esp-hal/src/reg_access.rs @@ -127,13 +127,7 @@ impl AlignmentHelper { // This function is similar to `volatile_set_memory` but will prepend data that // was previously ingested and ensure aligned (u32) writes. - pub fn volatile_write_bytes( - &mut self, - dst_ptr: *mut u32, - val: u8, - count: usize, - offset: usize, - ) { + pub fn volatile_write(&mut self, dst_ptr: *mut u32, val: u8, count: usize, offset: usize) { let dst_ptr = unsafe { dst_ptr.add(offset) }; let mut cursor = if self.buf_fill != 0 { diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 38f9286dd0..a1fd41518a 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -120,8 +120,8 @@ impl crate::interrupt::InterruptConfigurable for Sha<'_> { } // A few notes on this implementation with regards to 'memcpy', -// - It seems that ptr::write_bytes already acts as volatile, while ptr::copy_* -// does not (in this case) +// - It seems that ptr::write already acts as volatile, while ptr::copy_* does +// not (in this case) // - The registers are *not* cleared after processing, so padding needs to be // written out // - This component uses core::intrinsics::volatile_* which is unstable, but is @@ -256,7 +256,7 @@ impl<'d, A: ShaAlgorithm, S: Borrow>> ShaDigest<'d, A, S> { // Zero out remaining data if buffer is almost full (>=448/896), and process // buffer let pad_len = A::CHUNK_LENGTH - mod_cursor; - self.alignment_helper.volatile_write_bytes( + self.alignment_helper.volatile_write( m_mem(&self.sha.borrow().sha, 0), 0_u8, pad_len / self.alignment_helper.align_size(), @@ -274,7 +274,7 @@ impl<'d, A: ShaAlgorithm, S: Borrow>> ShaDigest<'d, A, S> { let mod_cursor = self.cursor % A::CHUNK_LENGTH; // Should be zero if branched above let pad_len = A::CHUNK_LENGTH - mod_cursor - size_of::(); - self.alignment_helper.volatile_write_bytes( + self.alignment_helper.volatile_write( m_mem(&self.sha.borrow().sha, 0), 0, pad_len / self.alignment_helper.align_size(), diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 0aaf40a54e..9192843eaf 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -675,8 +675,8 @@ where /// Write bytes to SPI. After writing, flush is called to ensure all data /// has been transmitted. - pub fn write_bytes(&mut self, words: &[u8]) -> Result<(), Error> { - self.driver().write_bytes(words)?; + pub fn write(&mut self, words: &[u8]) -> Result<(), Error> { + self.driver().write(words)?; self.driver().flush()?; Ok(()) @@ -684,8 +684,8 @@ where /// Read bytes from SPI. The provided slice is filled with data received /// from the slave. - pub fn read_bytes(&mut self, words: &mut [u8]) -> Result<(), Error> { - self.driver().read_bytes(words) + pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> { + self.driver().read(words) } /// Sends `words` to the slave. Returns the `words` received from the slave. @@ -1145,7 +1145,7 @@ where self.driver().configure_datalen(buffer.len(), 0); self.driver().start_operation(); self.driver().flush()?; - self.driver().read_bytes_from_fifo(buffer) + self.driver().read_from_fifo(buffer) } /// Half-duplex write. @@ -1208,7 +1208,7 @@ where if !buffer.is_empty() { // re-using the full-duplex write here - self.driver().write_bytes(buffer)?; + self.driver().write(buffer)?; } else { self.driver().start_operation(); } @@ -2534,11 +2534,11 @@ mod ehal1 { Dm: DriverMode, { fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { - self.driver().read_bytes(words) + self.driver().read(words) } fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.driver().write_bytes(words) + self.driver().write(words) } fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { @@ -2578,7 +2578,7 @@ mod ehal1 { if read_inc > 0 { SpiBus::flush(self)?; self.driver() - .read_bytes_from_fifo(&mut read[read_from..read_to])?; + .read_from_fifo(&mut read[read_from..read_to])?; } write_from = write_to; @@ -2601,14 +2601,14 @@ mod ehal1 { // We need to flush because the blocking transfer functions may return while a // transfer is still in progress. self.flush_async().await?; - self.driver().read_bytes_async(words).await + self.driver().read_async(words).await } async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { // We need to flush because the blocking transfer functions may return while a // transfer is still in progress. self.flush_async().await?; - self.driver().write_bytes_async(words).await + self.driver().write_async(words).await } async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { @@ -2647,7 +2647,7 @@ mod ehal1 { if read_inc > 0 { self.driver() - .read_bytes_from_fifo(&mut read[read_from..read_to])?; + .read_from_fifo(&mut read[read_from..read_to])?; } write_from = write_to; @@ -3233,7 +3233,7 @@ impl Driver { /// have been sent to the wire. If you must ensure that the whole /// messages was written correctly, use [`Self::flush`]. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn write_bytes(&self, words: &[u8]) -> Result<(), Error> { + fn write(&self, words: &[u8]) -> Result<(), Error> { let num_chunks = words.len() / FIFO_SIZE; // Flush in case previous writes have not completed yet, required as per @@ -3260,7 +3260,7 @@ impl Driver { /// Write bytes to SPI. #[cfg_attr(place_spi_driver_in_ram, ram)] - async fn write_bytes_async(&self, words: &[u8]) -> Result<(), Error> { + async fn write_async(&self, words: &[u8]) -> Result<(), Error> { // The fifo has a limited fixed size, so the data must be chunked and then // transmitted for chunk in words.chunks(FIFO_SIZE) { @@ -3277,13 +3277,13 @@ impl Driver { /// perform flushing. If you want to read the response to something you /// have written before, consider using [`Self::transfer`] instead. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn read_bytes(&self, words: &mut [u8]) -> Result<(), Error> { + fn read(&self, words: &mut [u8]) -> Result<(), Error> { let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE]; for chunk in words.chunks_mut(FIFO_SIZE) { - self.write_bytes(&empty_array[0..chunk.len()])?; + self.write(&empty_array[0..chunk.len()])?; self.flush()?; - self.read_bytes_from_fifo(chunk)?; + self.read_from_fifo(chunk)?; } Ok(()) } @@ -3294,12 +3294,12 @@ impl Driver { /// perform flushing. If you want to read the response to something you /// have written before, consider using [`Self::transfer`] instead. #[cfg_attr(place_spi_driver_in_ram, ram)] - async fn read_bytes_async(&self, words: &mut [u8]) -> Result<(), Error> { + async fn read_async(&self, words: &mut [u8]) -> Result<(), Error> { let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE]; for chunk in words.chunks_mut(FIFO_SIZE) { - self.write_bytes_async(&empty_array[0..chunk.len()]).await?; - self.read_bytes_from_fifo(chunk)?; + self.write_async(&empty_array[0..chunk.len()]).await?; + self.read_from_fifo(chunk)?; } Ok(()) } @@ -3311,7 +3311,7 @@ impl Driver { /// something you have written before, consider using [`Self::transfer`] /// instead. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn read_bytes_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> { + fn read_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> { let reg_block = self.regs(); for chunk in words.chunks_mut(FIFO_SIZE) { @@ -3345,9 +3345,9 @@ impl Driver { #[cfg_attr(place_spi_driver_in_ram, ram)] fn transfer<'w>(&self, words: &'w mut [u8]) -> Result<&'w [u8], Error> { for chunk in words.chunks_mut(FIFO_SIZE) { - self.write_bytes(chunk)?; + self.write(chunk)?; self.flush()?; - self.read_bytes_from_fifo(chunk)?; + self.read_from_fifo(chunk)?; } Ok(words) @@ -3356,8 +3356,8 @@ impl Driver { #[cfg_attr(place_spi_driver_in_ram, ram)] async fn transfer_in_place_async(&self, words: &mut [u8]) -> Result<(), Error> { for chunk in words.chunks_mut(FIFO_SIZE) { - self.write_bytes_async(chunk).await?; - self.read_bytes_from_fifo(chunk)?; + self.write_async(chunk).await?; + self.read_from_fifo(chunk)?; } Ok(()) diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 9fcca98593..b650924d7f 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -655,7 +655,7 @@ impl BaudRate { } /// An inactive TWAI peripheral in the "Reset"/configuration state. -pub struct TwaiConfiguration<'d, Dm: DriverMode> { +pub struct TwaiConfiguration<'d, Dm> { twai: PeripheralRef<'d, AnyTwai>, filter: Option<(FilterType, [u8; 8])>, phantom: PhantomData, @@ -1014,7 +1014,7 @@ impl crate::interrupt::InterruptConfigurable for TwaiConfiguration<'_, Blocking> /// /// In this mode, the TWAI controller can transmit and receive messages /// including error signals (such as error and overload frames). -pub struct Twai<'d, Dm: DriverMode> { +pub struct Twai<'d, Dm> { twai: PeripheralRef<'d, AnyTwai>, tx: TwaiTx<'d, Dm>, rx: TwaiRx<'d, Dm>, @@ -1119,7 +1119,7 @@ where } /// Interface to the TWAI transmitter part. -pub struct TwaiTx<'d, Dm: DriverMode> { +pub struct TwaiTx<'d, Dm> { twai: PeripheralRef<'d, AnyTwai>, phantom: PhantomData, _guard: PeripheralGuard, @@ -1164,7 +1164,7 @@ where } /// Interface to the TWAI receiver part. -pub struct TwaiRx<'d, Dm: DriverMode> { +pub struct TwaiRx<'d, Dm> { twai: PeripheralRef<'d, AnyTwai>, phantom: PhantomData, _guard: PeripheralGuard, diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index bb98b09293..20897013d2 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -36,70 +36,6 @@ //! available. See the examples below for more information on how to interact //! with this driver. //! -//! ## Example -//! -//! ### Handling UART Interrupts -//! Notice, that in practice a proper serial terminal should be used -//! to connect to the board (espmonitor and espflash won't work) -//! ```rust, no_run -#![doc = crate::before_snippet!()] -//! # use esp_hal::delay::Delay; -//! # use esp_hal::uart::{AtCmdConfig, Config, RxConfig, Uart, UartInterrupt}; -//! # let delay = Delay::new(); -//! # let config = Config::default().with_rx( -//! # RxConfig::default().with_fifo_full_threshold(30) -//! # ); -//! # let mut uart0 = Uart::new( -//! # peripherals.UART0, -//! # config)?; -//! uart0.set_interrupt_handler(interrupt_handler); -//! -//! critical_section::with(|cs| { -//! uart0.set_at_cmd(AtCmdConfig::default().with_cmd_char(b'#')); -//! uart0.listen(UartInterrupt::AtCmd | UartInterrupt::RxFifoFull); -//! -//! SERIAL.borrow_ref_mut(cs).replace(uart0); -//! }); -//! -//! loop { -//! println!("Send `#` character or >=30 characters"); -//! delay.delay(Duration::from_secs(1)); -//! } -//! # } -//! -//! # use core::cell::RefCell; -//! # use critical_section::Mutex; -//! # use esp_hal::uart::Uart; -//! static SERIAL: Mutex>>> = -//! Mutex::new(RefCell::new(None)); -//! -//! # use esp_hal::uart::UartInterrupt; -//! # use core::fmt::Write; -//! #[handler] -//! fn interrupt_handler() { -//! critical_section::with(|cs| { -//! let mut serial = SERIAL.borrow_ref_mut(cs); -//! if let Some(serial) = serial.as_mut() { -//! let mut buf = [0u8; 64]; -//! if let Ok(cnt) = serial.read_buffered_bytes(&mut buf) { -//! println!("Read {} bytes", cnt); -//! } -//! -//! let pending_interrupts = serial.interrupts(); -//! println!( -//! "Interrupt AT-CMD: {} RX-FIFO-FULL: {}", -//! pending_interrupts.contains(UartInterrupt::AtCmd), -//! pending_interrupts.contains(UartInterrupt::RxFifoFull), -//! ); -//! -//! serial.clear_interrupts( -//! UartInterrupt::AtCmd | UartInterrupt::RxFifoFull -//! ); -//! } -//! }); -//! } -//! ``` -//! //! [embedded-hal]: embedded_hal //! [embedded-io]: embedded_io //! [embedded-hal-async]: embedded_hal_async @@ -280,6 +216,24 @@ pub enum BaudrateTolerance { ErrorPercent(u8), } +/// List of exposed UART events. +#[derive(Debug, EnumSetType)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +#[instability::unstable] +pub enum UartInterrupt { + /// Indicates that the received has detected the configured + /// [`Uart::set_at_cmd`] character. + AtCmd, + + /// The transmitter has finished sending out all data from the FIFO. + TxDone, + + /// The receiver has received more data than what + /// [`RxConfig::fifo_full_threshold`] specifies. + RxFifoFull, +} + /// UART Configuration #[derive(Debug, Clone, Copy, procmacros::BuilderLite)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -460,12 +414,27 @@ where } /// UART (Full-duplex) +/// +/// ```rust, no_run +#[doc = crate::before_snippet!()] +/// # use esp_hal::uart::{Config, Uart}; +/// let mut uart = Uart::new( +/// peripherals.UART0, +/// Config::default())? +/// .with_rx(peripherals.GPIO1) +/// .with_tx(peripherals.GPIO2); +/// +/// uart.write(b"Hello world!")?; +/// # Ok(()) +/// # } +/// ``` pub struct Uart<'d, Dm> { rx: UartRx<'d, Dm>, tx: UartTx<'d, Dm>, } /// UART (Transmit) +#[instability::unstable] pub struct UartTx<'d, Dm> { uart: PeripheralRef<'d, AnyUart>, phantom: PhantomData, @@ -475,6 +444,7 @@ pub struct UartTx<'d, Dm> { } /// UART (Receive) +#[instability::unstable] pub struct UartRx<'d, Dm> { uart: PeripheralRef<'d, AnyUart>, phantom: PhantomData, @@ -562,6 +532,7 @@ where Dm: DriverMode, { /// Configure RTS pin + #[instability::unstable] pub fn with_rts(mut self, rts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rts); rts.set_to_push_pull_output(); @@ -576,6 +547,7 @@ where /// TX signal. /// /// Disconnects the previous pin that was assigned with `with_tx`. + #[instability::unstable] pub fn with_tx(mut self, tx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(tx); // Make sure we don't cause an unexpected low pulse on the pin. @@ -597,7 +569,8 @@ where } /// Writes bytes - pub fn write_bytes(&mut self, data: &[u8]) -> Result { + #[instability::unstable] + pub fn write(&mut self, data: &[u8]) -> Result { let count = data.len(); for &byte in data { @@ -622,8 +595,11 @@ where } /// Flush the transmit buffer of the UART - pub fn flush(&mut self) { + #[instability::unstable] + pub fn flush(&mut self) -> Result<(), Error> { while !self.is_tx_idle() {} + + Ok(()) } /// Checks if the TX line is idle for this UART instance. @@ -677,6 +653,7 @@ impl<'d> UartTx<'d, Blocking> { /// # Ok(()) /// # } /// ``` + #[instability::unstable] pub fn new( uart: impl Peripheral

+ 'd, config: Config, @@ -687,6 +664,7 @@ impl<'d> UartTx<'d, Blocking> { } /// Reconfigures the driver to operate in [`Async`] mode. + #[instability::unstable] pub fn into_async(self) -> UartTx<'d, Async> { if !self.uart.state().is_rx_async.load(Ordering::Acquire) { self.uart @@ -707,6 +685,7 @@ impl<'d> UartTx<'d, Blocking> { impl<'d> UartTx<'d, Async> { /// Reconfigures the driver to operate in [`Blocking`] mode. + #[instability::unstable] pub fn into_blocking(self) -> UartTx<'d, Blocking> { self.uart .state() @@ -755,6 +734,7 @@ where } /// Configure CTS pin + #[instability::unstable] pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cts); cts.init_input(Pull::None); @@ -771,6 +751,7 @@ where /// configure the driver side (i.e. the TX pin), or ensure that the line is /// initially high, to avoid receiving a non-data byte caused by an /// initial low signal level. + #[instability::unstable] pub fn with_rx(self, rx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rx); rx.init_input(Pull::Up); @@ -858,24 +839,22 @@ where } /// Reads bytes from the UART - pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { - let buffered = self.read_buffered_bytes(buf)?; - let buf = &mut buf[buffered..]; - - for byte in buf.iter_mut() { - loop { - if let Some(b) = self.read_byte() { - *byte = b; - break; - } - self.check_for_errors()?; - } + #[instability::unstable] + pub fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); } - Ok(()) + + while self.rx_fifo_count() == 0 { + // Block until we received at least one byte + } + + self.read_buffered_bytes(buf) } /// Read all available bytes from the RX FIFO into the provided buffer and /// returns the number of read bytes without blocking. + #[instability::unstable] pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result { let mut count = 0; while count < buf.len() { @@ -974,6 +953,7 @@ impl<'d> UartRx<'d, Blocking> { /// # Ok(()) /// # } /// ``` + #[instability::unstable] pub fn new( uart: impl Peripheral

+ 'd, config: Config, @@ -984,6 +964,7 @@ impl<'d> UartRx<'d, Blocking> { } /// Reconfigures the driver to operate in [`Async`] mode. + #[instability::unstable] pub fn into_async(self) -> UartRx<'d, Async> { if !self.uart.state().is_tx_async.load(Ordering::Acquire) { self.uart @@ -1002,6 +983,7 @@ impl<'d> UartRx<'d, Blocking> { impl<'d> UartRx<'d, Async> { /// Reconfigures the driver to operate in [`Blocking`] mode. + #[instability::unstable] pub fn into_blocking(self) -> UartRx<'d, Blocking> { self.uart .state() @@ -1082,24 +1064,22 @@ impl<'d> Uart<'d, Async> { tx: self.tx.into_blocking(), } } -} -/// List of exposed UART events. -#[derive(Debug, EnumSetType)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -#[instability::unstable] -pub enum UartInterrupt { - /// Indicates that the received has detected the configured - /// [`Uart::set_at_cmd`] character. - AtCmd, + /// Asynchronously reads data from the UART receive buffer into the + /// provided buffer. + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { + self.rx.read_async(buf).await + } - /// The transmitter has finished sending out all data from the FIFO. - TxDone, + /// Asynchronously writes data to the UART transmit buffer. + pub async fn write_async(&mut self, words: &[u8]) -> Result { + self.tx.write_async(words).await + } - /// The receiver has received more data than what - /// [`RxConfig::fifo_full_threshold`] specifies. - RxFifoFull, + /// Asynchronously flushes the UART transmit buffer. + pub async fn flush_async(&mut self) -> Result<(), Error> { + self.tx.flush_async().await + } } impl<'d, Dm> Uart<'d, Dm> @@ -1123,33 +1103,6 @@ where self.tx.uart.info().regs() } - /// Split the UART into a transmitter and receiver - /// - /// This is particularly useful when having two tasks correlating to - /// transmitting and receiving. - /// ## Example - /// ```rust, no_run - #[doc = crate::before_snippet!()] - /// # use esp_hal::uart::{Config, Uart}; - /// # let mut uart1 = Uart::new( - /// # peripherals.UART1, - /// # Config::default())? - /// # .with_rx(peripherals.GPIO1) - /// # .with_tx(peripherals.GPIO2); - /// // The UART can be split into separate Transmit and Receive components: - /// let (mut rx, mut tx) = uart1.split(); - /// - /// // Each component can be used individually to interact with the UART: - /// tx.write_bytes(&[42u8])?; - /// let mut byte = [0u8; 1]; - /// rx.read_bytes(&mut byte); - /// # Ok(()) - /// # } - /// ``` - pub fn split(self) -> (UartRx<'d, Dm>, UartTx<'d, Dm>) { - (self.rx, self.tx) - } - /// Write bytes out over the UART /// ```rust, no_run #[doc = crate::before_snippet!()] @@ -1158,70 +1111,21 @@ where /// # peripherals.UART1, /// # Config::default())?; /// // Write bytes out over the UART: - /// uart1.write_bytes(b"Hello, world!")?; + /// uart1.write(b"Hello, world!")?; /// # Ok(()) /// # } /// ``` - pub fn write_bytes(&mut self, data: &[u8]) -> Result { - self.tx.write_bytes(data) - } - - /// Reads and clears errors set by received data. - #[instability::unstable] - pub fn check_for_rx_errors(&mut self) -> Result<(), Error> { - self.rx.check_for_errors() + pub fn write(&mut self, data: &[u8]) -> Result { + self.tx.write(data) } /// Reads bytes from the UART - pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { - self.rx.read_bytes(buf) - } - - /// Read all available bytes from the RX FIFO into the provided buffer and - /// returns the number of read bytes without blocking. - pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result { - self.rx.read_buffered_bytes(buf) - } - - /// Configures the AT-CMD detection settings - #[instability::unstable] - pub fn set_at_cmd(&mut self, config: AtCmdConfig) { - #[cfg(not(any(esp32, esp32s2)))] - self.regs() - .clk_conf() - .modify(|_, w| w.sclk_en().clear_bit()); - - self.regs().at_cmd_char().write(|w| unsafe { - w.at_cmd_char().bits(config.cmd_char); - w.char_num().bits(config.char_num) - }); - - if let Some(pre_idle_count) = config.pre_idle_count { - self.regs() - .at_cmd_precnt() - .write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count as _) }); - } - - if let Some(post_idle_count) = config.post_idle_count { - self.regs() - .at_cmd_postcnt() - .write(|w| unsafe { w.post_idle_num().bits(post_idle_count as _) }); - } - - if let Some(gap_timeout) = config.gap_timeout { - self.regs() - .at_cmd_gaptout() - .write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout as _) }); - } - - #[cfg(not(any(esp32, esp32s2)))] - self.regs().clk_conf().modify(|_, w| w.sclk_en().set_bit()); - - sync_regs(self.regs()); + pub fn read(&mut self, buf: &mut [u8]) -> Result { + self.rx.read(buf) } /// Flush the transmit buffer of the UART - pub fn flush(&mut self) { + pub fn flush(&mut self) -> Result<(), Error> { self.tx.flush() } @@ -1319,13 +1223,83 @@ where } } -impl crate::private::Sealed for Uart<'_, Blocking> {} +impl<'d, Dm: DriverMode> Uart<'d, Dm> { + /// Split the UART into a transmitter and receiver + /// + /// This is particularly useful when having two tasks correlating to + /// transmitting and receiving. + /// ## Example + /// ```rust, no_run + #[doc = crate::before_snippet!()] + /// # use esp_hal::uart::{Config, Uart}; + /// # let mut uart1 = Uart::new( + /// # peripherals.UART1, + /// # Config::default())? + /// # .with_rx(peripherals.GPIO1) + /// # .with_tx(peripherals.GPIO2); + /// // The UART can be split into separate Transmit and Receive components: + /// let (mut rx, mut tx) = uart1.split(); + /// + /// // Each component can be used individually to interact with the UART: + /// tx.write(&[42u8])?; + /// let mut byte = [0u8; 1]; + /// rx.read(&mut byte); + /// # Ok(()) + /// # } + /// ``` + #[instability::unstable] + pub fn split(self) -> (UartRx<'d, Dm>, UartTx<'d, Dm>) { + (self.rx, self.tx) + } -#[instability::unstable] -impl crate::interrupt::InterruptConfigurable for Uart<'_, Blocking> { - fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - // `self.tx.uart` and `self.rx.uart` are the same - self.tx.uart.info().set_interrupt_handler(handler); + /// Reads and clears errors set by received data. + #[instability::unstable] + pub fn check_for_rx_errors(&mut self) -> Result<(), Error> { + self.rx.check_for_errors() + } + + /// Read all available bytes from the RX FIFO into the provided buffer and + /// returns the number of read bytes without blocking. + #[instability::unstable] + pub fn read_buffered_bytes(&mut self, buf: &mut [u8]) -> Result { + self.rx.read_buffered_bytes(buf) + } + + /// Configures the AT-CMD detection settings + #[instability::unstable] + pub fn set_at_cmd(&mut self, config: AtCmdConfig) { + #[cfg(not(any(esp32, esp32s2)))] + self.regs() + .clk_conf() + .modify(|_, w| w.sclk_en().clear_bit()); + + self.regs().at_cmd_char().write(|w| unsafe { + w.at_cmd_char().bits(config.cmd_char); + w.char_num().bits(config.char_num) + }); + + if let Some(pre_idle_count) = config.pre_idle_count { + self.regs() + .at_cmd_precnt() + .write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count as _) }); + } + + if let Some(post_idle_count) = config.post_idle_count { + self.regs() + .at_cmd_postcnt() + .write(|w| unsafe { w.post_idle_num().bits(post_idle_count as _) }); + } + + if let Some(gap_timeout) = config.gap_timeout { + self.regs() + .at_cmd_gaptout() + .write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout as _) }); + } + + #[cfg(not(any(esp32, esp32s2)))] + self.regs().clk_conf().modify(|_, w| w.sclk_en().set_bit()); + + sync_regs(self.regs()); } } @@ -1351,6 +1325,68 @@ impl Uart<'_, Blocking> { } /// Listen for the given interrupts + /// + /// ### Example + /// **Note**: In practice a proper serial terminal should be used + /// to connect to the board (espflash won't work) + /// ```rust, no_run + #[doc = crate::before_snippet!()] + /// # use esp_hal::delay::Delay; + /// # use esp_hal::uart::{AtCmdConfig, Config, RxConfig, Uart, UartInterrupt}; + /// # let delay = Delay::new(); + /// # let config = Config::default().with_rx( + /// # RxConfig::default().with_fifo_full_threshold(30) + /// # ); + /// # let mut uart0 = Uart::new( + /// # peripherals.UART0, + /// # config)?; + /// uart0.set_interrupt_handler(interrupt_handler); + /// + /// critical_section::with(|cs| { + /// uart0.set_at_cmd(AtCmdConfig::default().with_cmd_char(b'#')); + /// uart0.listen(UartInterrupt::AtCmd | UartInterrupt::RxFifoFull); + /// + /// SERIAL.borrow_ref_mut(cs).replace(uart0); + /// }); + /// + /// loop { + /// println!("Send `#` character or >=30 characters"); + /// delay.delay(Duration::from_secs(1)); + /// } + /// # } + /// + /// # use core::cell::RefCell; + /// # use critical_section::Mutex; + /// # use esp_hal::uart::Uart; + /// static SERIAL: Mutex>>> = + /// Mutex::new(RefCell::new(None)); + /// + /// # use esp_hal::uart::UartInterrupt; + /// # use core::fmt::Write; + /// #[handler] + /// fn interrupt_handler() { + /// critical_section::with(|cs| { + /// let mut serial = SERIAL.borrow_ref_mut(cs); + /// if let Some(serial) = serial.as_mut() { + /// let mut buf = [0u8; 64]; + /// if let Ok(cnt) = serial.read_buffered_bytes(&mut buf) { + /// println!("Read {} bytes", cnt); + /// } + /// + /// let pending_interrupts = serial.interrupts(); + /// println!( + /// "Interrupt AT-CMD: {} RX-FIFO-FULL: {}", + /// pending_interrupts.contains(UartInterrupt::AtCmd), + /// pending_interrupts.contains(UartInterrupt::RxFifoFull), + /// ); + /// + /// serial.clear_interrupts( + /// UartInterrupt::AtCmd | UartInterrupt::RxFifoFull + /// ); + /// } + /// }); + /// } + /// ``` #[instability::unstable] pub fn listen(&mut self, interrupts: impl Into>) { self.tx.uart.info().enable_listen(interrupts.into(), true) @@ -1375,6 +1411,16 @@ impl Uart<'_, Blocking> { } } +impl crate::private::Sealed for Uart<'_, Blocking> {} + +#[instability::unstable] +impl crate::interrupt::InterruptConfigurable for Uart<'_, Blocking> { + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + // `self.tx.uart` and `self.rx.uart` are the same + self.tx.uart.info().set_interrupt_handler(handler); + } +} + #[instability::unstable] impl ufmt_write::uWrite for Uart<'_, Dm> where @@ -1402,7 +1448,7 @@ where #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { - self.write_bytes(s.as_bytes())?; + self.write(s.as_bytes())?; Ok(()) } } @@ -1423,8 +1469,7 @@ where { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { - self.write_bytes(s.as_bytes()) - .map_err(|_| core::fmt::Error)?; + self.write(s.as_bytes()).map_err(|_| core::fmt::Error)?; Ok(()) } } @@ -1460,15 +1505,7 @@ where Dm: DriverMode, { fn read(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } - - while self.rx_fifo_count() == 0 { - // Block until we received at least one byte - } - - self.read_buffered_bytes(buf) + self.read(buf) } } @@ -1502,7 +1539,7 @@ where } fn flush(&mut self) -> Result<(), Self::Error> { - embedded_io::Write::flush(&mut self.tx) + self.tx.flush() } } @@ -1512,12 +1549,11 @@ where Dm: DriverMode, { fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes(buf) + self.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { - self.flush(); - Ok(()) + self.flush() } } @@ -1681,24 +1717,6 @@ impl Drop for UartTxFuture { } } -impl Uart<'_, Async> { - /// Asynchronously reads data from the UART receive buffer into the - /// provided buffer. - pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { - self.rx.read_async(buf).await - } - - /// Asynchronously writes data to the UART transmit buffer. - pub async fn write_async(&mut self, words: &[u8]) -> Result { - self.tx.write_async(words).await - } - - /// Asynchronously flushes the UART transmit buffer. - pub async fn flush_async(&mut self) -> Result<(), Error> { - self.tx.flush_async().await - } -} - impl UartTx<'_, Async> { /// Asynchronously writes data to the UART transmit buffer in chunks. /// @@ -1706,6 +1724,7 @@ impl UartTx<'_, Async> { /// the UART. Data is written in chunks to avoid overflowing the /// transmit FIFO, and the function waits asynchronously when /// necessary for space in the buffer to become available. + #[instability::unstable] pub async fn write_async(&mut self, words: &[u8]) -> Result { let mut count = 0; let mut offset: usize = 0; @@ -1736,6 +1755,7 @@ impl UartTx<'_, Async> { /// This function ensures that all pending data in the transmit FIFO has /// been sent over the UART. If the FIFO contains data, it waits /// for the transmission to complete before returning. + #[instability::unstable] pub async fn flush_async(&mut self) -> Result<(), Error> { let count = self.tx_fifo_count(); if count > 0 { @@ -1767,6 +1787,7 @@ impl UartRx<'_, Async> { /// # Ok /// When successful, returns the number of bytes written to buf. /// If the passed in buffer is of length 0, Ok(0) is returned. + #[instability::unstable] pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { if buf.is_empty() { return Ok(0); @@ -1796,7 +1817,7 @@ impl UartRx<'_, Async> { let events_happened = UartRxFuture::new(self.uart.reborrow(), events).await; // always drain the fifo, if an error has occurred the data is lost - let read_bytes = self.flush_buffer(buf); + let read = self.flush_buffer(buf); // check error events rx_event_check_for_error(events_happened)?; // Unfortunately, the uart's rx-timeout counter counts up whenever there is @@ -1807,8 +1828,8 @@ impl UartRx<'_, Async> { .int_clr() .write(|w| w.rxfifo_tout().clear_bit_by_one()); - if read_bytes > 0 { - return Ok(read_bytes); + if read > 0 { + return Ok(read); } } } diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index f37ea70cc8..02629a8b04 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -49,7 +49,7 @@ //! let mut usb_serial = UsbSerialJtag::new(peripherals.USB_DEVICE); //! //! // Write bytes out over the USB Serial/JTAG: -//! usb_serial.write_bytes(b"Hello, world!")?; +//! usb_serial.write(b"Hello, world!")?; //! # Ok(()) //! # } //! ``` @@ -66,7 +66,7 @@ //! //! // Each component can be used individually to interact with the USB //! // Serial/JTAG: -//! tx.write_bytes(&[42u8])?; +//! tx.write(&[42u8])?; //! let byte = rx.read_byte()?; //! # Ok(()) //! # } @@ -177,7 +177,7 @@ where } /// Write data to the serial output in chunks of up to 64 bytes - pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> { + pub fn write(&mut self, data: &[u8]) -> Result<(), Error> { for chunk in data.chunks(64) { for byte in chunk { self.regs() @@ -396,8 +396,8 @@ where } /// Write data to the serial output in chunks of up to 64 bytes - pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> { - self.tx.write_bytes(data) + pub fn write(&mut self, data: &[u8]) -> Result<(), Error> { + self.tx.write(data) } /// Write data to the serial output in a non-blocking manner @@ -508,8 +508,7 @@ where Dm: DriverMode, { fn write_str(&mut self, s: &str) -> core::fmt::Result { - self.write_bytes(s.as_bytes()) - .map_err(|_| core::fmt::Error)?; + self.write(s.as_bytes()).map_err(|_| core::fmt::Error)?; Ok(()) } } @@ -541,14 +540,14 @@ where #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { - self.write_bytes(s.as_bytes())?; + self.write(s.as_bytes())?; Ok(()) } #[inline] fn write_char(&mut self, ch: char) -> Result<(), Self::Error> { let mut buffer = [0u8; 4]; - self.write_bytes(ch.encode_utf8(&mut buffer).as_bytes())?; + self.write(ch.encode_utf8(&mut buffer).as_bytes())?; Ok(()) } @@ -623,7 +622,7 @@ where Dm: DriverMode, { fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes(buf)?; + self.write(buf)?; Ok(buf.len()) } @@ -744,7 +743,7 @@ impl<'d> UsbSerialJtag<'d, Async> { } impl UsbSerialJtagTx<'_, Async> { - async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { + async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> { for chunk in words.chunks(64) { for byte in chunk { self.regs() @@ -775,15 +774,15 @@ impl UsbSerialJtagTx<'_, Async> { } impl UsbSerialJtagRx<'_, Async> { - async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result { + async fn read_async(&mut self, buf: &mut [u8]) -> Result { if buf.is_empty() { return Ok(0); } loop { - let read_bytes = self.drain_rx_fifo(buf); - if read_bytes > 0 { - return Ok(read_bytes); + let read = self.drain_rx_fifo(buf); + if read > 0 { + return Ok(read); } UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await; } @@ -804,7 +803,7 @@ impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { #[instability::unstable] impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { async fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes_async(buf).await?; + self.write_async(buf).await?; Ok(buf.len()) } @@ -824,7 +823,7 @@ impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { #[instability::unstable] impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_bytes_async(buf).await + self.read_async(buf).await } }