Skip to content

Commit

Permalink
Implementing async feature for USB Serial/JTAG peripheral. (esp-r…
Browse files Browse the repository at this point in the history
…s#632)

* Implementing ASYNC features for USB_SERIAL_JTAG (work in progress)

Fix: Interrupt name

* Async works for USB Serial/JTAG 

PS. : Yet only for esp32c3, we need to update PACs
Temporary example fix

* Adjustment for different chips

+ Update examples according to upstream
+ Code cleaning


Rust format

* Add record to the CHANGELOG

* Code cleaning, getting rid of useless generic argument


Typo fix


Fix fmt
  • Loading branch information
playfulFence committed Sep 20, 2023
1 parent b7ecc2d commit 1b1ca4e
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add embassy async `read` support for `uart` (#620)
- Add bare-bones support to run code on ULP-RISCV / LP core (#631)
- Add ADC calibration implementation for a riscv chips (#555)
- Add `async` implementation for `USB Serial/JTAG`(#632)

### Changed

Expand Down
137 changes: 136 additions & 1 deletion esp-hal-common/src/usb_serial_jtag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
peripherals::{usb_device::RegisterBlock, USB_DEVICE},
system::PeripheralClockControl,
};

/// USB Serial JTAG driver
pub struct UsbSerialJtag<'d> {
usb_serial: PeripheralRef<'d, USB_DEVICE>,
Expand Down Expand Up @@ -151,6 +150,15 @@ impl<'d> UsbSerialJtag<'d> {
.int_clr
.write(|w| w.serial_out_recv_pkt_int_clr().set_bit())
}
#[cfg(feature = "async")]
pub(crate) fn inner(&self) -> &USB_DEVICE {
&self.usb_serial
}

#[cfg(feature = "async")]
pub(crate) fn inner_mut(&mut self) -> &mut USB_DEVICE {
&mut self.usb_serial
}
}

/// USB Serial JTAG peripheral instance
Expand Down Expand Up @@ -192,6 +200,14 @@ pub trait Instance {

(wr_addr - rd_addr).into()
}

fn txfifo_empty(&self) -> bool {
self.register_block()
.jfifo_st
.read()
.out_fifo_empty()
.bit_is_clear()
}
}

impl Instance for USB_DEVICE {
Expand Down Expand Up @@ -249,3 +265,122 @@ impl embedded_hal_nb::serial::Write for UsbSerialJtag<'_> {
self.flush_tx_nb()
}
}

#[cfg(feature = "async")]
mod asynch {
use core::task::Poll;

use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt;

use super::{Error, Instance};
use crate::UsbSerialJtag;

// Single static instance of the waker
static WAKER: AtomicWaker = AtomicWaker::new();

pub(crate) struct UsbSerialJtagFuture<'d> {
instance: &'d crate::peripherals::USB_DEVICE,
}

impl<'d> UsbSerialJtagFuture<'d> {
pub fn new(instance: &'d crate::peripherals::USB_DEVICE) -> Self {
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
// interrupt
instance
.register_block()
.int_ena
.modify(|_, w| w.serial_in_empty_int_ena().set_bit());

Self { instance }
}

fn event_bit_is_clear(&self) -> bool {
self.instance
.register_block()
.int_ena
.read()
.serial_in_empty_int_ena()
.bit_is_clear()
}
}

impl<'d> core::future::Future for UsbSerialJtagFuture<'d> {
type Output = ();

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
WAKER.register(cx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}

impl UsbSerialJtag<'_> {
async fn write(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = self.usb_serial.register_block();
for chunk in words.chunks(64 as usize) {
unsafe {
for &b in chunk {
reg_block.ep1.write(|w| w.rdwr_byte().bits(b.into()))
}
reg_block.ep1_conf.write(|w| w.wr_done().set_bit());
UsbSerialJtagFuture::new(self.inner()).await;
}
}
Ok(())
}

async fn flush(&mut self) -> Result<(), Error> {
if self.inner().txfifo_empty() {
UsbSerialJtagFuture::new(self.inner()).await;
}
Ok(())
}
}

impl embedded_hal_async::serial::Write for UsbSerialJtag<'_> {
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.write(words).await
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush().await
}
}

#[cfg(esp32c3)]
#[interrupt]
fn USB_SERIAL_JTAG() {
let usb_serial_jtag = unsafe { &*crate::peripherals::USB_DEVICE::ptr() };
usb_serial_jtag
.int_ena
.modify(|_, w| w.serial_in_empty_int_ena().clear_bit());
WAKER.wake();
}

#[cfg(esp32s3)]
#[interrupt]
fn USB_DEVICE() {
let usb_serial_jtag = unsafe { &*crate::peripherals::USB_DEVICE::ptr() };
usb_serial_jtag
.int_ena
.modify(|_, w| w.serial_in_empty_int_ena().clear_bit());
WAKER.wake();
}

#[cfg(any(esp32c6, esp32h2))]
#[interrupt]
fn USB() {
let usb_serial_jtag = unsafe { &*crate::peripherals::USB_DEVICE::ptr() };
usb_serial_jtag
.int_ena
.modify(|_, w| w.serial_in_empty_int_ena().clear_bit());
WAKER.wake();
}
}

0 comments on commit 1b1ca4e

Please sign in to comment.