From 9acf32635cf9934ed1823ad07951901c32d28fa6 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Thu, 22 Jun 2023 11:21:56 +0000 Subject: [PATCH 1/7] implement embassy async uart read --- esp-hal-common/src/uart.rs | 191 +++++++++++++++++++++---- esp32-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32c2-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32c3-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32c6-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32h2-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32s2-hal/examples/embassy_serial.rs | 91 +++++++++++- esp32s3-hal/examples/embassy_serial.rs | 91 +++++++++++- 8 files changed, 775 insertions(+), 53 deletions(-) diff --git a/esp-hal-common/src/uart.rs b/esp-hal-common/src/uart.rs index 0a5e96491a8..dc3a45ab8ab 100644 --- a/esp-hal-common/src/uart.rs +++ b/esp-hal-common/src/uart.rs @@ -998,7 +998,10 @@ mod asynch { use procmacros::interrupt; use super::{Error, Instance}; - use crate::{uart::UART_FIFO_SIZE, Uart}; + use crate::{ + uart::{FIFO_SPEC, UART_FIFO_SIZE}, + Uart, + }; cfg_if! { if #[cfg(all(uart0, uart1, uart2))] { @@ -1016,6 +1019,7 @@ mod asynch { pub(crate) enum Event { TxDone, TxFiFoEmpty, + RxIntr, } pub(crate) struct UartFuture<'a, T: Instance> { @@ -1034,6 +1038,16 @@ mod asynch { .register_block() .int_ena .modify(|_, w| w.txfifo_empty_int_ena().set_bit()), + Event::RxIntr => { + instance + .register_block() + .int_ena + .modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()); + instance + .register_block() + .int_ena + .modify(|_, w| w.rxfifo_full_int_ena().set_bit()); + } } Self { event, instance } @@ -1055,6 +1069,11 @@ mod asynch { .read() .txfifo_empty_int_ena() .bit_is_clear(), + Event::RxIntr => { + let int_ena_val = self.instance.register_block().int_ena.read(); + int_ena_val.at_cmd_char_det_int_ena().bit_is_clear() + && int_ena_val.rxfifo_full_int_ena().bit_is_clear() + } } } } @@ -1079,16 +1098,51 @@ mod asynch { where T: Instance, { + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + let mut read_bytes = 0; + #[allow(unused_variables)] + let offset = 0; + + // on ESP32-S2 we need to use PeriBus2 to read the FIFO + #[cfg(esp32s2)] + let offset = 0x20c00000; + + UartFuture::new(Event::RxIntr, self.inner()).await; + + while self.uart.get_rx_fifo_count() > 0 && read_bytes < buf.len() { + buf[read_bytes] = unsafe { + let fifo = (self.uart.register_block().fifo.as_ptr() as *mut u8).offset(offset) + as *mut crate::peripherals::generic::Reg; + (*fifo).read().rxfifo_rd_byte().bits() + }; + read_bytes += 1; + } + + Ok(read_bytes) + } + async fn write(&mut self, words: &[u8]) -> Result<(), Error> { for chunk in words.chunks(UART_FIFO_SIZE as usize) { for &byte in chunk { - self.write_byte(byte).unwrap() // should never fail + if self.uart.get_tx_fifo_count() < UART_FIFO_SIZE { + self.write_rxfifo_rd_byte(byte); + } else { + UartFuture::new(Event::TxFiFoEmpty, self.inner()).await; + self.write_rxfifo_rd_byte(byte); + } } UartFuture::new(Event::TxFiFoEmpty, self.inner()).await; } Ok(()) } + fn write_rxfifo_rd_byte(&mut self, byte: u8) { + self.uart + .register_block() + .fifo + .write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) }); + } + async fn flush(&mut self) -> Result<(), Error> { let count = self.inner_mut().get_tx_fifo_count(); if count > 0 { @@ -1115,38 +1169,125 @@ mod asynch { #[interrupt] fn UART0() { let uart = unsafe { &*crate::peripherals::UART0::ptr() }; - uart.int_ena.modify(|_, w| { - w.txfifo_empty_int_ena() - .clear_bit() - .tx_done_int_ena() - .clear_bit() - }); - WAKERS[0].wake(); + let int_ena_val = uart.int_ena.read(); + let int_raw_val = uart.int_raw.read(); + let mut wake = false; + if int_ena_val.txfifo_empty_int_ena().bit_is_set() + && int_raw_val.txfifo_empty_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); + wake = true; + } + if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); + wake = true; + } + if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() + && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) + || (int_ena_val.rxfifo_full_int_ena().bit_is_set() + && int_raw_val.rxfifo_full_int_raw().bit_is_set()) + { + uart.int_clr.write(|w| { + w.at_cmd_char_det_int_clr() + .set_bit() + .rxfifo_full_int_clr() + .set_bit() + }); + uart.int_ena.write(|w| { + w.at_cmd_char_det_int_ena() + .clear_bit() + .rxfifo_full_int_ena() + .clear_bit() + }); + wake = true; + } + if wake { + WAKERS[0].wake(); + } } #[cfg(uart1)] #[interrupt] fn UART1() { - let uart = unsafe { &*crate::peripherals::UART1::ptr() }; - uart.int_ena.modify(|_, w| { - w.txfifo_empty_int_ena() - .clear_bit() - .tx_done_int_ena() - .clear_bit() - }); - WAKERS[1].wake(); + let uart = unsafe { &*crate::peripherals::UART0::ptr() }; + let int_ena_val = uart.int_ena.read(); + let int_raw_val = uart.int_raw.read(); + let mut wake = false; + if int_ena_val.txfifo_empty_int_ena().bit_is_set() + && int_raw_val.txfifo_empty_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); + wake = true; + } + if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); + wake = true; + } + if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() + && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) + || (int_ena_val.rxfifo_full_int_ena().bit_is_set() + && int_raw_val.rxfifo_full_int_raw().bit_is_set()) + { + uart.int_clr.write(|w| { + w.at_cmd_char_det_int_clr() + .set_bit() + .rxfifo_full_int_clr() + .set_bit() + }); + uart.int_ena.write(|w| { + w.at_cmd_char_det_int_ena() + .clear_bit() + .rxfifo_full_int_ena() + .clear_bit() + }); + wake = true; + } + if wake { + WAKERS[0].wake(); + } } #[cfg(uart2)] #[interrupt] fn UART2() { - let uart = unsafe { &*crate::peripherals::UART2::ptr() }; - uart.int_ena.modify(|_, w| { - w.txfifo_empty_int_ena() - .clear_bit() - .tx_done_int_ena() - .clear_bit() - }); - WAKERS[2].wake(); + let uart = unsafe { &*crate::peripherals::UART0::ptr() }; + let int_ena_val = uart.int_ena.read(); + let int_raw_val = uart.int_raw.read(); + let mut wake = false; + if int_ena_val.txfifo_empty_int_ena().bit_is_set() + && int_raw_val.txfifo_empty_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); + wake = true; + } + if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() + { + uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); + wake = true; + } + if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() + && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) + || (int_ena_val.rxfifo_full_int_ena().bit_is_set() + && int_raw_val.rxfifo_full_int_raw().bit_is_set()) + { + uart.int_clr.write(|w| { + w.at_cmd_char_det_int_clr() + .set_bit() + .rxfifo_full_int_clr() + .set_bit() + }); + uart.int_ena.write(|w| { + w.at_cmd_char_det_int_ena() + .clear_bit() + .rxfifo_full_int_ena() + .clear_bit() + }); + wake = true; + } + if wake { + WAKERS[0].wake(); + } } } diff --git a/esp32-hal/examples/embassy_serial.rs b/esp32-hal/examples/embassy_serial.rs index fc941cd5248..737a9e6bfe7 100644 --- a/esp32-hal/examples/embassy_serial.rs +++ b/esp32-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -65,7 +146,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32_hal::interrupt::enable(Interrupt::UART0, esp32_hal::Priority::Priority1).unwrap(); diff --git a/esp32c2-hal/examples/embassy_serial.rs b/esp32c2-hal/examples/embassy_serial.rs index aeb7a76f89f..534cf5fdca8 100644 --- a/esp32c2-hal/examples/embassy_serial.rs +++ b/esp32c2-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32c2_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32c2_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -65,7 +146,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32c2_hal::interrupt::enable(Interrupt::UART0, esp32c2_hal::Priority::Priority1).unwrap(); diff --git a/esp32c3-hal/examples/embassy_serial.rs b/esp32c3-hal/examples/embassy_serial.rs index 428e626d93c..f496e3d047c 100644 --- a/esp32c3-hal/examples/embassy_serial.rs +++ b/esp32c3-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32c3_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32c3_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -72,7 +153,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32c3_hal::interrupt::enable(Interrupt::UART0, esp32c3_hal::Priority::Priority1).unwrap(); diff --git a/esp32c6-hal/examples/embassy_serial.rs b/esp32c6-hal/examples/embassy_serial.rs index 63ef078d163..920ea36f16d 100644 --- a/esp32c6-hal/examples/embassy_serial.rs +++ b/esp32c6-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32c6_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32c6_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -72,7 +153,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32c6_hal::interrupt::enable(Interrupt::UART0, esp32c6_hal::Priority::Priority1).unwrap(); diff --git a/esp32h2-hal/examples/embassy_serial.rs b/esp32h2-hal/examples/embassy_serial.rs index e5f19c876e4..5049b788835 100644 --- a/esp32h2-hal/examples/embassy_serial.rs +++ b/esp32h2-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32h2_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32h2_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -72,7 +153,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32h2_hal::interrupt::enable(Interrupt::UART0, esp32h2_hal::Priority::Priority1).unwrap(); diff --git a/esp32s2-hal/examples/embassy_serial.rs b/esp32s2-hal/examples/embassy_serial.rs index 1fbfc981faf..6f6a1f3ffa5 100644 --- a/esp32s2-hal/examples/embassy_serial.rs +++ b/esp32s2-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32s2_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32s2_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -65,7 +146,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32s2_hal::interrupt::enable(Interrupt::UART0, esp32s2_hal::Priority::Priority1).unwrap(); diff --git a/esp32s3-hal/examples/embassy_serial.rs b/esp32s3-hal/examples/embassy_serial.rs index 66c9a747f54..e8563f3e113 100644 --- a/esp32s3-hal/examples/embassy_serial.rs +++ b/esp32s3-hal/examples/embassy_serial.rs @@ -7,8 +7,10 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::fmt::Write; + use embassy_executor::Executor; -use embassy_time::{Duration, Timer}; +use embassy_time::{with_timeout, Duration}; use esp32s3_hal::{ clock::ClockControl, embassy, @@ -19,18 +21,97 @@ use esp32s3_hal::{ Uart, }; use esp_backtrace as _; +use esp_hal_common::uart::config::AtCmdConfig; use static_cell::StaticCell; +struct Buffer { + len: usize, + buf: [u8; N], +} + +impl Buffer { + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + &self.buf[..self.len] + } + + #[inline(always)] + pub fn is_full(&self) -> bool { + self.len == N + } +} + +impl core::fmt::Write for Buffer { + #[inline] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let sb = s.as_bytes(); + let mut len = sb.len(); + if self.len + len > N { + len = N - self.len; + } + if len > 0 { + self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); + self.len += len; + } + Ok(()) + } +} + +/// rx_fifo_full_threshold +const READ_BUF_SIZE: usize = 128; +/// EOT; CTRL-D +const AT_CMD: u8 = 0x04; + #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { + /// max READ_BUF_SIZE buffers to receive + const MAX_BUFFERS: usize = 10; + /// timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(5); + let mut rbuf = Buffer { + len: 0, + buf: [0; MAX_BUFFERS * READ_BUF_SIZE], + }; + let mut wbuf = Buffer { + len: 0, + buf: [0; 128], + }; + loop { - embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") + if rbuf.len == 0 { + embedded_hal_async::serial::Write::write( + &mut uart, + b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", + ) .await .unwrap(); + } else { + wbuf.len = 0; + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice()) + .await + .unwrap(); + embedded_hal_async::serial::Write::write(&mut uart, b"\r\n") + .await + .unwrap(); + } embedded_hal_async::serial::Write::flush(&mut uart) .await .unwrap(); - Timer::after(Duration::from_millis(1_000)).await; + + rbuf.len = 0; + while let Ok(Ok(len)) = + with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await + { + rbuf.len += len; + // if set_at_cmd is used than stop reading + if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { + break; + } + } } } @@ -72,7 +153,9 @@ fn main() -> ! { #[cfg(feature = "embassy-time-timg0")] embassy::init(&clocks, timer_group0.timer0); - let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); + uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); + uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); esp32s3_hal::interrupt::enable(Interrupt::UART0, esp32s3_hal::Priority::Priority1).unwrap(); From 499eaa205a2659eef01b03e7e8d223c922e861ed Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Thu, 22 Jun 2023 11:32:10 +0000 Subject: [PATCH 2/7] Add embassy async read support for uart --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d0cc339f4..4a49180047e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add initial support for RNG in ESP32-H2 (#591) - Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596) - Add initial support for `I2S` in ESP32-H2 (#597) +- Add embassy async `read` support for `uart` ### Changed From bcfb9fd284b7c8064e528d6455d8784169b2f632 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 23 Jun 2023 12:00:16 +0100 Subject: [PATCH 3/7] changes based on review --- esp-hal-common/src/uart.rs | 204 ++++++++++++++----------------------- 1 file changed, 75 insertions(+), 129 deletions(-) diff --git a/esp-hal-common/src/uart.rs b/esp-hal-common/src/uart.rs index dc3a45ab8ab..846a63fb6a2 100644 --- a/esp-hal-common/src/uart.rs +++ b/esp-hal-common/src/uart.rs @@ -994,7 +994,9 @@ mod asynch { use core::task::Poll; use cfg_if::cfg_if; + use embassy_futures::select::select; use embassy_sync::waitqueue::AtomicWaker; + use esp32c3::uart0::RegisterBlock; use procmacros::interrupt; use super::{Error, Instance}; @@ -1019,7 +1021,8 @@ mod asynch { pub(crate) enum Event { TxDone, TxFiFoEmpty, - RxIntr, + RxFifoFull, + RxCmdCharDetected, } pub(crate) struct UartFuture<'a, T: Instance> { @@ -1038,16 +1041,14 @@ mod asynch { .register_block() .int_ena .modify(|_, w| w.txfifo_empty_int_ena().set_bit()), - Event::RxIntr => { - instance - .register_block() - .int_ena - .modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()); - instance - .register_block() - .int_ena - .modify(|_, w| w.rxfifo_full_int_ena().set_bit()); - } + Event::RxFifoFull => instance + .register_block() + .int_ena + .modify(|_, w| w.rxfifo_full_int_ena().set_bit()), + Event::RxCmdCharDetected => instance + .register_block() + .int_ena + .modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()), } Self { event, instance } @@ -1069,11 +1070,20 @@ mod asynch { .read() .txfifo_empty_int_ena() .bit_is_clear(), - Event::RxIntr => { - let int_ena_val = self.instance.register_block().int_ena.read(); - int_ena_val.at_cmd_char_det_int_ena().bit_is_clear() - && int_ena_val.rxfifo_full_int_ena().bit_is_clear() - } + Event::RxFifoFull => self + .instance + .register_block() + .int_ena + .read() + .rxfifo_full_int_ena() + .bit_is_clear(), + Event::RxCmdCharDetected => self + .instance + .register_block() + .int_ena + .read() + .at_cmd_char_det_int_ena() + .bit_is_clear(), } } } @@ -1107,7 +1117,11 @@ mod asynch { #[cfg(esp32s2)] let offset = 0x20c00000; - UartFuture::new(Event::RxIntr, self.inner()).await; + select( + UartFuture::new(Event::RxCmdCharDetected, self.inner()), + UartFuture::new(Event::RxFifoFull, self.inner()), + ) + .await; while self.uart.get_rx_fifo_count() > 0 && read_bytes < buf.len() { buf[read_bytes] = unsafe { @@ -1122,27 +1136,25 @@ mod asynch { } async fn write(&mut self, words: &[u8]) -> Result<(), Error> { - for chunk in words.chunks(UART_FIFO_SIZE as usize) { - for &byte in chunk { - if self.uart.get_tx_fifo_count() < UART_FIFO_SIZE { - self.write_rxfifo_rd_byte(byte); - } else { - UartFuture::new(Event::TxFiFoEmpty, self.inner()).await; - self.write_rxfifo_rd_byte(byte); - } + let mut offset: usize = 0; + loop { + let mut next_offset = + offset + (UART_FIFO_SIZE - self.uart.get_tx_fifo_count()) as usize; + if next_offset > words.len() { + next_offset = words.len(); + } + for &byte in &words[offset..next_offset] { + self.write_byte(byte).unwrap(); // should never fail + } + if next_offset == words.len() { + break; } + offset = next_offset; UartFuture::new(Event::TxFiFoEmpty, self.inner()).await; } Ok(()) } - fn write_rxfifo_rd_byte(&mut self, byte: u8) { - self.uart - .register_block() - .fifo - .write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) }); - } - async fn flush(&mut self) -> Result<(), Error> { let count = self.inner_mut().get_tx_fifo_count(); if count > 0 { @@ -1165,44 +1177,44 @@ mod asynch { } } - #[cfg(uart0)] - #[interrupt] - fn UART0() { - let uart = unsafe { &*crate::peripherals::UART0::ptr() }; + fn intr_handler(uart: &RegisterBlock) -> bool { let int_ena_val = uart.int_ena.read(); let int_raw_val = uart.int_raw.read(); - let mut wake = false; if int_ena_val.txfifo_empty_int_ena().bit_is_set() && int_raw_val.txfifo_empty_int_raw().bit_is_set() { uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); - wake = true; + return true; } if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() { uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); - wake = true; + return true; } - if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() - && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) - || (int_ena_val.rxfifo_full_int_ena().bit_is_set() - && int_raw_val.rxfifo_full_int_raw().bit_is_set()) + if int_ena_val.at_cmd_char_det_int_ena().bit_is_set() + && int_raw_val.at_cmd_char_det_int_raw().bit_is_set() { - uart.int_clr.write(|w| { - w.at_cmd_char_det_int_clr() - .set_bit() - .rxfifo_full_int_clr() - .set_bit() - }); - uart.int_ena.write(|w| { - w.at_cmd_char_det_int_ena() - .clear_bit() - .rxfifo_full_int_ena() - .clear_bit() - }); - wake = true; + uart.int_clr + .write(|w| w.at_cmd_char_det_int_clr().set_bit()); + uart.int_ena + .write(|w| w.at_cmd_char_det_int_ena().clear_bit()); + return true; } - if wake { + if int_ena_val.rxfifo_full_int_ena().bit_is_set() + && int_raw_val.rxfifo_full_int_raw().bit_is_set() + { + uart.int_clr.write(|w| w.rxfifo_full_int_clr().set_bit()); + uart.int_ena.write(|w| w.rxfifo_full_int_ena().clear_bit()); + return true; + } + false + } + + #[cfg(uart0)] + #[interrupt] + fn UART0() { + let uart = unsafe { &*crate::peripherals::UART0::ptr() }; + if intr_handler(uart) { WAKERS[0].wake(); } } @@ -1210,84 +1222,18 @@ mod asynch { #[cfg(uart1)] #[interrupt] fn UART1() { - let uart = unsafe { &*crate::peripherals::UART0::ptr() }; - let int_ena_val = uart.int_ena.read(); - let int_raw_val = uart.int_raw.read(); - let mut wake = false; - if int_ena_val.txfifo_empty_int_ena().bit_is_set() - && int_raw_val.txfifo_empty_int_raw().bit_is_set() - { - uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); - wake = true; - } - if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() - { - uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); - wake = true; - } - if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() - && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) - || (int_ena_val.rxfifo_full_int_ena().bit_is_set() - && int_raw_val.rxfifo_full_int_raw().bit_is_set()) - { - uart.int_clr.write(|w| { - w.at_cmd_char_det_int_clr() - .set_bit() - .rxfifo_full_int_clr() - .set_bit() - }); - uart.int_ena.write(|w| { - w.at_cmd_char_det_int_ena() - .clear_bit() - .rxfifo_full_int_ena() - .clear_bit() - }); - wake = true; - } - if wake { - WAKERS[0].wake(); + let uart = unsafe { &*crate::peripherals::UART1::ptr() }; + if intr_handler(uart) { + WAKERS[1].wake(); } } #[cfg(uart2)] #[interrupt] fn UART2() { - let uart = unsafe { &*crate::peripherals::UART0::ptr() }; - let int_ena_val = uart.int_ena.read(); - let int_raw_val = uart.int_raw.read(); - let mut wake = false; - if int_ena_val.txfifo_empty_int_ena().bit_is_set() - && int_raw_val.txfifo_empty_int_raw().bit_is_set() - { - uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit()); - wake = true; - } - if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() - { - uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit()); - wake = true; - } - if (int_ena_val.at_cmd_char_det_int_ena().bit_is_set() - && int_raw_val.at_cmd_char_det_int_raw().bit_is_set()) - || (int_ena_val.rxfifo_full_int_ena().bit_is_set() - && int_raw_val.rxfifo_full_int_raw().bit_is_set()) - { - uart.int_clr.write(|w| { - w.at_cmd_char_det_int_clr() - .set_bit() - .rxfifo_full_int_clr() - .set_bit() - }); - uart.int_ena.write(|w| { - w.at_cmd_char_det_int_ena() - .clear_bit() - .rxfifo_full_int_ena() - .clear_bit() - }); - wake = true; - } - if wake { - WAKERS[0].wake(); + let uart = unsafe { &*crate::peripherals::UART2::ptr() }; + if intr_handler(uart) { + WAKERS[2].wake(); } } } From 8f95b4fc8bc7fd4ef9468e8755d5485463ae65be Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Fri, 23 Jun 2023 14:10:08 +0000 Subject: [PATCH 4/7] fix CI failures --- esp-hal-common/src/uart.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/esp-hal-common/src/uart.rs b/esp-hal-common/src/uart.rs index 846a63fb6a2..08c5781525b 100644 --- a/esp-hal-common/src/uart.rs +++ b/esp-hal-common/src/uart.rs @@ -996,12 +996,11 @@ mod asynch { use cfg_if::cfg_if; use embassy_futures::select::select; use embassy_sync::waitqueue::AtomicWaker; - use esp32c3::uart0::RegisterBlock; use procmacros::interrupt; use super::{Error, Instance}; use crate::{ - uart::{FIFO_SPEC, UART_FIFO_SIZE}, + uart::{RegisterBlock, FIFO_SPEC, UART_FIFO_SIZE}, Uart, }; From 6fd1f346bb20b9bc818aa52bb3f5a82cf8944abc Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 25 Jun 2023 13:52:23 +0000 Subject: [PATCH 5/7] change review #2 --- CHANGELOG.md | 45 +++++------ esp32-hal/Cargo.toml | 1 + esp32-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- esp32c2-hal/Cargo.toml | 1 + esp32c2-hal/examples/embassy_serial.rs | 105 +++++++++++------------- esp32c3-hal/Cargo.toml | 1 + esp32c3-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- esp32c6-hal/Cargo.toml | 1 + esp32c6-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- esp32h2-hal/Cargo.toml | 1 + esp32h2-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- esp32s2-hal/Cargo.toml | 1 + esp32s2-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- esp32s3-hal/Cargo.toml | 1 + esp32s3-hal/examples/embassy_serial.rs | 107 +++++++++++-------------- 15 files changed, 346 insertions(+), 453 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a49180047e..d8fa9fb9295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,45 +12,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add bare-bones PSRAM support for ESP32 (#506) -- Add initial support for the ESP32-H2 (#513) +- Add initial support for the ESP32-H2 (#513, #526, #527, #528, #530, #538, #544, #548, #551, #556, #560, #566, #549, #564, #569, #576, #577, #589, #591, #597) - Add bare-bones PSRAM support for ESP32-S3 (#517) - Add async support to the I2C driver (#519) -- Add initial support for RSA in ESP32-H2 (#526) -- Add initial support for SHA in ESP32-H2 (#527) -- Add initial support for AES in ESP32-H2 (#528) -- Add blinky_erased_pins example for ESP32-H2 (#530) -- Add initial support for I2C in ESP32-H2 (#538) - Implement Copy and Eq for EspTwaiError (#540) -- Add LEDC hardware fade support +- Add LEDC hardware fade support (#475) - Added support for multicore async GPIO (#542) -- Add initial support for MCPWM in ESP32-H2 (#544) -- Add some miscellaneous examples for the ESP32-H2 (#548) -- Add initial support for PCNT in ESP32-H2 (#551) -- Add initial support for RMT in ESP32-H2 (#556) -- Add a fn to poll DMA transfers -- Add initial support for LEDC in ESP32-H2 (#560) -- Add initial support for ASSIST_DEBUG in ESP32-H2 (#566) -- Add all `SPI` examples for the ESP32-H2 (#549) -- Add initial support for ADC in ESP32-H2 (#564) +- Add a fn to poll DMA transfers (#559) - Simplify the `Delay` driver, derive `Clone` and `Copy` (#568) -- Add `embassy_serial` and `embassy_wait` examples for ESP32-H2 (#569) - Fix Async GPIO not disabling interupts on chips with multiple banks (#572) -- Add unified field-based efuse access -- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#576) +- Add unified field-based efuse access (#567) - Move `esp-riscv-rt` into esp-hal (#578) -- Add initial implementation of radio clocks for ESP32-H2 (#577) -- Add initial support for `esp-hal-smartled` in ESP32-H2 (#589) -- Add CRC functions from ESP ROM -- Add initial support for RNG in ESP32-H2 (#591) +- Add CRC functions from ESP ROM (#587) - Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596) - Add initial support for `I2S` in ESP32-H2 (#597) -- Add embassy async `read` support for `uart` +- Add embassy async `read` support for `uart` (#615) +- Fix rom::crc docs +- Add octal PSRAM support for ESP32-S3 (#610) ### Changed - Move core interrupt handling from Flash to RAM for RISC-V chips (ESP32-H2, ESP32-C2, ESP32-C3, ESP32-C6) (#541) - Change LED pin to GPIO2 in ESP32 blinky example (#581) -- Udpate ESP32-H2 and C6 ESP32-clocks and remove i2c_clock for all chips but ESP32 (#592) +- Update ESP32-H2 and ESP32-C6 clocks and remove `i2c_clock` for all chips but ESP32 (#592) +- Use both timers in `TIMG0` for embassy time driver when able (#609) ### Fixed @@ -62,9 +47,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ADC driver will now apply attenuation values to the correct ADC's channels. (#554) - Sometimes half-duplex non-DMA SPI reads were reading garbage in non-release mode (#552) - ESP32-C3: Fix GPIO5 ADC channel id (#562) -- ESP32-H2: Fix direct-boot feature -- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions +- ESP32-H2: Fix direct-boot feature (#570) +- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions (#593) - Fixed CI by pinning the log crate to 0.4.18 (#600) +- ESP32-S3: Fix calculation of PSRAM start address +- Fixed wrong variable access (FOSC CLK calibration for ESP32-C6 #593) +- Fixed [trap location in ram](https://github.com/esp-rs/esp-hal/pull/605#issuecomment-1604039683) (#605) +- Add embassy async `read` support for `uart` (#615) +- Fixed a possible overlap of `.data` and `.rwtext` (#616) ### Changed @@ -74,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking - Significantly simplified user-facing GPIO pin types. (#553) +- No longer re-export the `soc` moduleand the contents of the `interrupt` module at the package level (#607) ## [0.9.0] - 2023-05-02 diff --git a/esp32-hal/Cargo.toml b/esp32-hal/Cargo.toml index 24b99dbebbb..155830f52a0 100644 --- a/esp32-hal/Cargo.toml +++ b/esp32-hal/Cargo.toml @@ -47,6 +47,7 @@ sha2 = { version = "0.10.6", default-features = false} smart-leds = "0.3.0" ssd1306 = "0.7.1" static_cell = "1.0.0" +heapless = "0.7.16" [features] default = ["rt", "vectored", "xtal40mhz"] diff --git a/esp32-hal/examples/embassy_serial.rs b/esp32-hal/examples/embassy_serial.rs index 737a9e6bfe7..eb4ff7df512 100644 --- a/esp32-hal/examples/embassy_serial.rs +++ b/esp32-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -150,7 +135,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32_hal::interrupt::enable(Interrupt::UART0, esp32_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32c2-hal/Cargo.toml b/esp32c2-hal/Cargo.toml index ffbca9f7169..05072e497e6 100644 --- a/esp32c2-hal/Cargo.toml +++ b/esp32c2-hal/Cargo.toml @@ -42,6 +42,7 @@ lis3dh-async = "0.7.0" sha2 = { version = "0.10.6", default-features = false} ssd1306 = "0.7.1" static_cell = "1.0.0" +heapless = "0.7.16" [features] default = ["rt", "vectored", "xtal40mhz"] diff --git a/esp32c2-hal/examples/embassy_serial.rs b/esp32c2-hal/examples/embassy_serial.rs index 534cf5fdca8..b0d14b7e42e 100644 --- a/esp32c2-hal/examples/embassy_serial.rs +++ b/esp32c2-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32c2_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32c2_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; /// EOT; CTRL-D const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -150,7 +135,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32c2_hal::interrupt::enable(Interrupt::UART0, esp32c2_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32c3-hal/Cargo.toml b/esp32c3-hal/Cargo.toml index a1e29aace3b..f96863e5558 100644 --- a/esp32c3-hal/Cargo.toml +++ b/esp32c3-hal/Cargo.toml @@ -48,6 +48,7 @@ sha2 = { version = "0.10.6", default-features = false} smart-leds = "0.3.0" ssd1306 = "0.7.1" static_cell = "1.0.0" +heapless = "0.7.16" [features] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] diff --git a/esp32c3-hal/examples/embassy_serial.rs b/esp32c3-hal/examples/embassy_serial.rs index f496e3d047c..337d71fd18c 100644 --- a/esp32c3-hal/examples/embassy_serial.rs +++ b/esp32c3-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32c3_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32c3_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -157,7 +142,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32c3_hal::interrupt::enable(Interrupt::UART0, esp32c3_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32c6-hal/Cargo.toml b/esp32c6-hal/Cargo.toml index 582debc6364..3c0e49f6d72 100644 --- a/esp32c6-hal/Cargo.toml +++ b/esp32c6-hal/Cargo.toml @@ -49,6 +49,7 @@ sha2 = { version = "0.10.6", default-features = false} smart-leds = "0.3.0" ssd1306 = "0.7.1" static_cell = "1.0.0" +heapless = "0.7.16" [features] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] diff --git a/esp32c6-hal/examples/embassy_serial.rs b/esp32c6-hal/examples/embassy_serial.rs index 920ea36f16d..8543dfd78e0 100644 --- a/esp32c6-hal/examples/embassy_serial.rs +++ b/esp32c6-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32c6_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32c6_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -157,7 +142,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32c6_hal::interrupt::enable(Interrupt::UART0, esp32c6_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32h2-hal/Cargo.toml b/esp32h2-hal/Cargo.toml index 07b6cfa3f8c..a1200f966aa 100644 --- a/esp32h2-hal/Cargo.toml +++ b/esp32h2-hal/Cargo.toml @@ -48,6 +48,7 @@ sha2 = { version = "0.10.6", default-features = false} smart-leds = "0.3.0" ssd1306 = "0.7.1" static_cell = "1.0.0" +heapless = "0.7.16" [features] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] diff --git a/esp32h2-hal/examples/embassy_serial.rs b/esp32h2-hal/examples/embassy_serial.rs index 5049b788835..d863c257b31 100644 --- a/esp32h2-hal/examples/embassy_serial.rs +++ b/esp32h2-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32h2_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32h2_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -157,7 +142,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32h2_hal::interrupt::enable(Interrupt::UART0, esp32h2_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32s2-hal/Cargo.toml b/esp32s2-hal/Cargo.toml index 5302423d953..468590238cb 100644 --- a/esp32s2-hal/Cargo.toml +++ b/esp32s2-hal/Cargo.toml @@ -50,6 +50,7 @@ ssd1306 = "0.7.1" static_cell = "1.0.0" usb-device = { version = "0.2.9" } usbd-serial = "0.1.1" +heapless = "0.7.16" [features] default = ["rt", "vectored"] diff --git a/esp32s2-hal/examples/embassy_serial.rs b/esp32s2-hal/examples/embassy_serial.rs index 6f6a1f3ffa5..df975476475 100644 --- a/esp32s2-hal/examples/embassy_serial.rs +++ b/esp32s2-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32s2_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32s2_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -150,7 +135,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32s2_hal::interrupt::enable(Interrupt::UART0, esp32s2_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { diff --git a/esp32s3-hal/Cargo.toml b/esp32s3-hal/Cargo.toml index a3760aa8b99..1ba1032d963 100644 --- a/esp32s3-hal/Cargo.toml +++ b/esp32s3-hal/Cargo.toml @@ -52,6 +52,7 @@ ssd1306 = "0.7.1" static_cell = "1.0.0" usb-device = "0.2.9" usbd-serial = "0.1.1" +heapless = "0.7.16" [features] default = ["rt", "vectored"] diff --git a/esp32s3-hal/examples/embassy_serial.rs b/esp32s3-hal/examples/embassy_serial.rs index e8563f3e113..112f292eb91 100644 --- a/esp32s3-hal/examples/embassy_serial.rs +++ b/esp32s3-hal/examples/embassy_serial.rs @@ -1,7 +1,7 @@ //! embassy serial //! //! This is an example of running the embassy executor and asynchronously -//! writing to a uart. +//! writing to and reading from uart #![no_std] #![no_main] @@ -14,6 +14,7 @@ use embassy_time::{with_timeout, Duration}; use esp32s3_hal::{ clock::ClockControl, embassy, + interrupt, peripherals::{Interrupt, Peripherals, UART0}, prelude::*, timer::TimerGroup, @@ -22,63 +23,26 @@ use esp32s3_hal::{ }; use esp_backtrace as _; use esp_hal_common::uart::config::AtCmdConfig; +use heapless::Vec; use static_cell::StaticCell; -struct Buffer { - len: usize, - buf: [u8; N], -} - -impl Buffer { - #[inline(always)] - pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.len] - } - - #[inline(always)] - pub fn is_full(&self) -> bool { - self.len == N - } -} - -impl core::fmt::Write for Buffer { - #[inline] - fn write_str(&mut self, s: &str) -> core::fmt::Result { - let sb = s.as_bytes(); - let mut len = sb.len(); - if self.len + len > N { - len = N - self.len; - } - if len > 0 { - self.buf[self.len..self.len + len].copy_from_slice(&sb[..len]); - self.len += len; - } - Ok(()) - } -} - -/// rx_fifo_full_threshold +// rx_fifo_full_threshold const READ_BUF_SIZE: usize = 128; -/// EOT; CTRL-D +// EOT (CTRL-D) const AT_CMD: u8 = 0x04; #[embassy_executor::task] async fn run(mut uart: Uart<'static, UART0>) { - /// max READ_BUF_SIZE buffers to receive - const MAX_BUFFERS: usize = 10; - /// timeout read - const READ_TIMEOUT: Duration = Duration::from_secs(5); - let mut rbuf = Buffer { - len: 0, - buf: [0; MAX_BUFFERS * READ_BUF_SIZE], - }; - let mut wbuf = Buffer { - len: 0, - buf: [0; 128], - }; - + // max message size to receive + // leave some extra space for AT-CMD characters + const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16; + // timeout read + const READ_TIMEOUT: Duration = Duration::from_secs(10); + + let mut rbuf: Vec = Vec::new(); + let mut wbuf: Vec = Vec::new(); loop { - if rbuf.len == 0 { + if rbuf.is_empty() { embedded_hal_async::serial::Write::write( &mut uart, b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n", @@ -86,8 +50,8 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); } else { - wbuf.len = 0; - write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len).unwrap(); + wbuf.clear(); + write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap(); embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice()) .await .unwrap(); @@ -102,14 +66,35 @@ async fn run(mut uart: Uart<'static, UART0>) { .await .unwrap(); - rbuf.len = 0; - while let Ok(Ok(len)) = - with_timeout(READ_TIMEOUT, uart.read(&mut rbuf.buf[rbuf.len..])).await - { - rbuf.len += len; - // if set_at_cmd is used than stop reading - if rbuf.buf[rbuf.len - 1] == AT_CMD || rbuf.is_full() { - break; + // set rbuf full capacity + unsafe { + rbuf.set_len(rbuf.capacity()); + } + let mut offset = 0; + loop { + match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { + Ok(r) => { + if let Ok(len) = r { + offset += len; + if offset == 0 { + rbuf.truncate(0); + break; + } + // if set_at_cmd is used than stop reading + if len < READ_BUF_SIZE { + rbuf.truncate(offset); + break; + } + } else { + // buffer is full + break; + } + } + Err(_) => { + // Timeout + rbuf.truncate(offset); + break; + } } } } @@ -157,7 +142,7 @@ fn main() -> ! { uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16); - esp32s3_hal::interrupt::enable(Interrupt::UART0, esp32s3_hal::Priority::Priority1).unwrap(); + interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { From e38de414e949256120c4e5cea294918ba46bab53 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Mon, 26 Jun 2023 11:33:29 +0000 Subject: [PATCH 6/7] fixed re-opened PR number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8fa9fb9295..2758c1efac5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add CRC functions from ESP ROM (#587) - Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596) - Add initial support for `I2S` in ESP32-H2 (#597) -- Add embassy async `read` support for `uart` (#615) +- Add embassy async `read` support for `uart` (#620) - Fix rom::crc docs - Add octal PSRAM support for ESP32-S3 (#610) From 2e8a197d63b4bd85e5594195c493319716c6160b Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Mon, 26 Jun 2023 14:34:45 +0000 Subject: [PATCH 7/7] changes review no.3 --- CHANGELOG.md | 43 ++++++++++++++++---------- esp-hal-common/src/uart.rs | 27 +++++++--------- esp32-hal/examples/embassy_serial.rs | 4 +-- esp32c2-hal/examples/embassy_serial.rs | 4 +-- esp32c3-hal/examples/embassy_serial.rs | 4 +-- esp32c6-hal/examples/embassy_serial.rs | 4 +-- esp32h2-hal/examples/embassy_serial.rs | 4 +-- esp32s2-hal/examples/embassy_serial.rs | 4 +-- esp32s3-hal/examples/embassy_serial.rs | 4 +-- 9 files changed, 45 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2758c1efac5..493320c12fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,30 +12,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add bare-bones PSRAM support for ESP32 (#506) -- Add initial support for the ESP32-H2 (#513, #526, #527, #528, #530, #538, #544, #548, #551, #556, #560, #566, #549, #564, #569, #576, #577, #589, #591, #597) +- Add initial support for the ESP32-H2 (#513) - Add bare-bones PSRAM support for ESP32-S3 (#517) - Add async support to the I2C driver (#519) +- Add initial support for RSA in ESP32-H2 (#526) +- Add initial support for SHA in ESP32-H2 (#527) +- Add initial support for AES in ESP32-H2 (#528) +- Add blinky_erased_pins example for ESP32-H2 (#530) +- Add initial support for I2C in ESP32-H2 (#538) - Implement Copy and Eq for EspTwaiError (#540) -- Add LEDC hardware fade support (#475) +- Add LEDC hardware fade support - Added support for multicore async GPIO (#542) -- Add a fn to poll DMA transfers (#559) +- Add initial support for MCPWM in ESP32-H2 (#544) +- Add some miscellaneous examples for the ESP32-H2 (#548) +- Add initial support for PCNT in ESP32-H2 (#551) +- Add initial support for RMT in ESP32-H2 (#556) +- Add a fn to poll DMA transfers +- Add initial support for LEDC in ESP32-H2 (#560) +- Add initial support for ASSIST_DEBUG in ESP32-H2 (#566) +- Add all `SPI` examples for the ESP32-H2 (#549) +- Add initial support for ADC in ESP32-H2 (#564) - Simplify the `Delay` driver, derive `Clone` and `Copy` (#568) +- Add `embassy_serial` and `embassy_wait` examples for ESP32-H2 (#569) - Fix Async GPIO not disabling interupts on chips with multiple banks (#572) -- Add unified field-based efuse access (#567) +- Add unified field-based efuse access +- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#576) - Move `esp-riscv-rt` into esp-hal (#578) -- Add CRC functions from ESP ROM (#587) +- Add initial implementation of radio clocks for ESP32-H2 (#577) +- Add initial support for `esp-hal-smartled` in ESP32-H2 (#589) +- Add CRC functions from ESP ROM +- Add initial support for RNG in ESP32-H2 (#591) - Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596) - Add initial support for `I2S` in ESP32-H2 (#597) - Add embassy async `read` support for `uart` (#620) -- Fix rom::crc docs -- Add octal PSRAM support for ESP32-S3 (#610) ### Changed - Move core interrupt handling from Flash to RAM for RISC-V chips (ESP32-H2, ESP32-C2, ESP32-C3, ESP32-C6) (#541) - Change LED pin to GPIO2 in ESP32 blinky example (#581) -- Update ESP32-H2 and ESP32-C6 clocks and remove `i2c_clock` for all chips but ESP32 (#592) -- Use both timers in `TIMG0` for embassy time driver when able (#609) +- Udpate ESP32-H2 and C6 ESP32-clocks and remove i2c_clock for all chips but ESP32 (#592) ### Fixed @@ -47,14 +62,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ADC driver will now apply attenuation values to the correct ADC's channels. (#554) - Sometimes half-duplex non-DMA SPI reads were reading garbage in non-release mode (#552) - ESP32-C3: Fix GPIO5 ADC channel id (#562) -- ESP32-H2: Fix direct-boot feature (#570) -- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions (#593) +- ESP32-H2: Fix direct-boot feature +- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions - Fixed CI by pinning the log crate to 0.4.18 (#600) -- ESP32-S3: Fix calculation of PSRAM start address -- Fixed wrong variable access (FOSC CLK calibration for ESP32-C6 #593) -- Fixed [trap location in ram](https://github.com/esp-rs/esp-hal/pull/605#issuecomment-1604039683) (#605) -- Add embassy async `read` support for `uart` (#615) -- Fixed a possible overlap of `.data` and `.rwtext` (#616) ### Changed @@ -64,7 +74,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Breaking - Significantly simplified user-facing GPIO pin types. (#553) -- No longer re-export the `soc` moduleand the contents of the `interrupt` module at the package level (#607) ## [0.9.0] - 2023-05-02 diff --git a/esp-hal-common/src/uart.rs b/esp-hal-common/src/uart.rs index 08c5781525b..e4ccb0e8b04 100644 --- a/esp-hal-common/src/uart.rs +++ b/esp-hal-common/src/uart.rs @@ -19,7 +19,10 @@ const UART_FIFO_SIZE: u16 = 128; /// Custom serial error type #[derive(Debug)] -pub enum Error {} +pub enum Error { + #[cfg(feature = "async")] + ReadBufferFull, +} /// UART configuration pub mod config { @@ -1000,7 +1003,7 @@ mod asynch { use super::{Error, Instance}; use crate::{ - uart::{RegisterBlock, FIFO_SPEC, UART_FIFO_SIZE}, + uart::{RegisterBlock, UART_FIFO_SIZE}, Uart, }; @@ -1109,12 +1112,6 @@ mod asynch { { pub async fn read(&mut self, buf: &mut [u8]) -> Result { let mut read_bytes = 0; - #[allow(unused_variables)] - let offset = 0; - - // on ESP32-S2 we need to use PeriBus2 to read the FIFO - #[cfg(esp32s2)] - let offset = 0x20c00000; select( UartFuture::new(Event::RxCmdCharDetected, self.inner()), @@ -1122,13 +1119,13 @@ mod asynch { ) .await; - while self.uart.get_rx_fifo_count() > 0 && read_bytes < buf.len() { - buf[read_bytes] = unsafe { - let fifo = (self.uart.register_block().fifo.as_ptr() as *mut u8).offset(offset) - as *mut crate::peripherals::generic::Reg; - (*fifo).read().rxfifo_rd_byte().bits() - }; - read_bytes += 1; + while let Ok(byte) = self.read_byte() { + if read_bytes < buf.len() { + buf[read_bytes] = byte; + read_bytes += 1; + } else { + return Err(Error::ReadBufferFull); + } } Ok(read_bytes) diff --git a/esp32-hal/examples/embassy_serial.rs b/esp32-hal/examples/embassy_serial.rs index eb4ff7df512..f10924fe27c 100644 --- a/esp32-hal/examples/embassy_serial.rs +++ b/esp32-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32c2-hal/examples/embassy_serial.rs b/esp32c2-hal/examples/embassy_serial.rs index b0d14b7e42e..461cfe048ff 100644 --- a/esp32c2-hal/examples/embassy_serial.rs +++ b/esp32c2-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32c3-hal/examples/embassy_serial.rs b/esp32c3-hal/examples/embassy_serial.rs index 337d71fd18c..12bb7c57c7f 100644 --- a/esp32c3-hal/examples/embassy_serial.rs +++ b/esp32c3-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32c6-hal/examples/embassy_serial.rs b/esp32c6-hal/examples/embassy_serial.rs index 8543dfd78e0..1cac300f80a 100644 --- a/esp32c6-hal/examples/embassy_serial.rs +++ b/esp32c6-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32h2-hal/examples/embassy_serial.rs b/esp32h2-hal/examples/embassy_serial.rs index d863c257b31..815cde5e2e3 100644 --- a/esp32h2-hal/examples/embassy_serial.rs +++ b/esp32h2-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32s2-hal/examples/embassy_serial.rs b/esp32s2-hal/examples/embassy_serial.rs index df975476475..49859d8c453 100644 --- a/esp32s2-hal/examples/embassy_serial.rs +++ b/esp32s2-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await { diff --git a/esp32s3-hal/examples/embassy_serial.rs b/esp32s3-hal/examples/embassy_serial.rs index 112f292eb91..08ab771cd30 100644 --- a/esp32s3-hal/examples/embassy_serial.rs +++ b/esp32s3-hal/examples/embassy_serial.rs @@ -67,9 +67,7 @@ async fn run(mut uart: Uart<'static, UART0>) { .unwrap(); // set rbuf full capacity - unsafe { - rbuf.set_len(rbuf.capacity()); - } + rbuf.resize_default(rbuf.capacity()).ok(); let mut offset = 0; loop { match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await {