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 - Fix rom::crc docs
- Add octal PSRAM support for ESP32-S3 (#610) - Add octal PSRAM support for ESP32-S3 (#610)
- Add MD5 functions from ESP ROM (#618) - Add MD5 functions from ESP ROM (#618)
- Add embassy async `read` support for `uart` (#620)
### Changed ### Changed

View File

@ -19,7 +19,10 @@ const UART_FIFO_SIZE: u16 = 128;
/// Custom serial error type /// Custom serial error type
#[derive(Debug)] #[derive(Debug)]
pub enum Error {} pub enum Error {
#[cfg(feature = "async")]
ReadBufferFull,
}
/// UART configuration /// UART configuration
pub mod config { pub mod config {
@ -994,11 +997,15 @@ mod asynch {
use core::task::Poll; use core::task::Poll;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use embassy_futures::select::select;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt; use procmacros::interrupt;
use super::{Error, Instance}; use super::{Error, Instance};
use crate::{uart::UART_FIFO_SIZE, Uart}; use crate::{
uart::{RegisterBlock, UART_FIFO_SIZE},
Uart,
};
cfg_if! { cfg_if! {
if #[cfg(all(uart0, uart1, uart2))] { if #[cfg(all(uart0, uart1, uart2))] {
@ -1016,6 +1023,8 @@ mod asynch {
pub(crate) enum Event { pub(crate) enum Event {
TxDone, TxDone,
TxFiFoEmpty, TxFiFoEmpty,
RxFifoFull,
RxCmdCharDetected,
} }
pub(crate) struct UartFuture<'a, T: Instance> { pub(crate) struct UartFuture<'a, T: Instance> {
@ -1034,6 +1043,14 @@ mod asynch {
.register_block() .register_block()
.int_ena .int_ena
.modify(|_, w| w.txfifo_empty_int_ena().set_bit()), .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 } Self { event, instance }
@ -1055,6 +1072,20 @@ mod asynch {
.read() .read()
.txfifo_empty_int_ena() .txfifo_empty_int_ena()
.bit_is_clear(), .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 where
T: Instance, T: Instance,
{ {
async fn write(&mut self, words: &[u8]) -> Result<(), Error> { pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
for chunk in words.chunks(UART_FIFO_SIZE as usize) { let mut read_bytes = 0;
for &byte in chunk {
self.write_byte(byte).unwrap() // should never fail 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; UartFuture::new(Event::TxFiFoEmpty, self.inner()).await;
} }
Ok(()) 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)] #[cfg(uart0)]
#[interrupt] #[interrupt]
fn UART0() { fn UART0() {
let uart = unsafe { &*crate::peripherals::UART0::ptr() }; let uart = unsafe { &*crate::peripherals::UART0::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[0].wake(); WAKERS[0].wake();
} }
}
#[cfg(uart1)] #[cfg(uart1)]
#[interrupt] #[interrupt]
fn UART1() { fn UART1() {
let uart = unsafe { &*crate::peripherals::UART1::ptr() }; let uart = unsafe { &*crate::peripherals::UART1::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[1].wake(); WAKERS[1].wake();
} }
}
#[cfg(uart2)] #[cfg(uart2)]
#[interrupt] #[interrupt]
fn UART2() { fn UART2() {
let uart = unsafe { &*crate::peripherals::UART2::ptr() }; let uart = unsafe { &*crate::peripherals::UART2::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[2].wake(); WAKERS[2].wake();
} }
} }
}

View File

@ -47,6 +47,7 @@ sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "xtal40mhz"] default = ["rt", "vectored", "xtal40mhz"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32_hal::{ use esp32_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); 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} sha2 = { version = "0.10.6", default-features = false}
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "xtal40mhz"] default = ["rt", "vectored", "xtal40mhz"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c2_hal::{ use esp32c2_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32c2_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); 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" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c3_hal::{ use esp32c3_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32c3_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); 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" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c6_hal::{ use esp32c6_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32c6_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); 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" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32h2_hal::{ use esp32h2_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32h2_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -50,6 +50,7 @@ ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
usb-device = { version = "0.2.9" } usb-device = { version = "0.2.9" }
usbd-serial = "0.1.1" usbd-serial = "0.1.1"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored"] default = ["rt", "vectored"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32s2_hal::{ use esp32s2_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32s2_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();

View File

@ -52,6 +52,7 @@ ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
usb-device = "0.2.9" usb-device = "0.2.9"
usbd-serial = "0.1.1" usbd-serial = "0.1.1"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored"] default = ["rt", "vectored"]

View File

@ -1,14 +1,16 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32s3_hal::{ use esp32s3_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
@ -20,18 +22,79 @@ use esp32s3_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; 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] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { 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 { 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 .await
.unwrap(); .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) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .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")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); 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(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();