Async serial uart read (#620)

* implement embassy async uart read

* Add embassy async read support for uart

* changes based on review

* fix CI failures

* change review #2

* fixed re-opened PR number

* changes review no.3

---------

Co-authored-by: Scott Mabin <scott@mabez.dev>
This commit is contained in:
Alex Johnson 2023-06-26 18:56:32 +03:00 committed by Scott Mabin
parent 226bdc3038
commit 9f7565440a
16 changed files with 608 additions and 62 deletions

View File

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix rom::crc docs
- Add octal PSRAM support for ESP32-S3 (#610)
- Add MD5 functions from ESP ROM (#618)
- Add embassy async `read` support for `uart` (#620)
### Changed

View File

@ -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 {
@ -994,11 +997,15 @@ mod asynch {
use core::task::Poll;
use cfg_if::cfg_if;
use embassy_futures::select::select;
use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt;
use super::{Error, Instance};
use crate::{uart::UART_FIFO_SIZE, Uart};
use crate::{
uart::{RegisterBlock, UART_FIFO_SIZE},
Uart,
};
cfg_if! {
if #[cfg(all(uart0, uart1, uart2))] {
@ -1016,6 +1023,8 @@ mod asynch {
pub(crate) enum Event {
TxDone,
TxFiFoEmpty,
RxFifoFull,
RxCmdCharDetected,
}
pub(crate) struct UartFuture<'a, T: Instance> {
@ -1034,6 +1043,14 @@ mod asynch {
.register_block()
.int_ena
.modify(|_, w| w.txfifo_empty_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 }
@ -1055,6 +1072,20 @@ mod asynch {
.read()
.txfifo_empty_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(),
}
}
}
@ -1079,11 +1110,42 @@ mod asynch {
where
T: Instance,
{
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
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let mut read_bytes = 0;
select(
UartFuture::new(Event::RxCmdCharDetected, self.inner()),
UartFuture::new(Event::RxFifoFull, self.inner()),
)
.await;
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)
}
async fn write(&mut self, words: &[u8]) -> Result<(), Error> {
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(())
@ -1111,42 +1173,63 @@ mod asynch {
}
}
fn intr_handler(uart: &RegisterBlock) -> bool {
let int_ena_val = uart.int_ena.read();
let int_raw_val = uart.int_raw.read();
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());
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());
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()
{
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 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() };
uart.int_ena.modify(|_, w| {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[0].wake();
if intr_handler(uart) {
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();
if intr_handler(uart) {
WAKERS[1].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();
if intr_handler(uart) {
WAKERS[2].wake();
}
}
}

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -66,7 +129,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32c2_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -66,7 +129,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32c3_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -73,7 +136,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32c6_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -73,7 +136,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32h2_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -73,7 +136,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32s2_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -66,7 +129,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -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"]

View File

@ -1,14 +1,16 @@
//! 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]
#![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,
@ -20,18 +22,79 @@ use esp32s3_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell;
// 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 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<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n")
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",
)
.await
.unwrap();
} else {
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();
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;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
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;
}
}
}
}
}
@ -73,7 +136,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);
interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();