Module usb_serial_jtag

Source
Available on crate feature unstable only.
Expand description

USB Serial/JTAG Controller (USB_SERIAL_JTAG)

§Overview

The USB Serial/JTAG controller can be used to program the SoC’s flash, read program output, or attach a debugger to the running program. This is possible for any computer with a USB host (hereafter referred to as ‘host’), without any active external components.

This peripheral integrates the functionality of both a USB-to-serial converter as well as a USB-to-JTAG adapter. As this device directly interfaces with an external USB host using only the two data lines required by USB 2.0, only two pins are required to be dedicated to this functionality for debugging.

The USB Serial/JTAG controller boasts the following features:

  • Hardwired for CDC-ACM (Communication Device Class - Abstract Control Model) and JTAG adapter functionality
  • Integrates CDC-ACM adherent serial port emulation (plug-and-play on most modern OSes); supports host controllable chip reset and entry into download mode
  • Allows fast communication with CPU debugging core using a compact representation of JTAG instructions
  • Two OUT Endpoints and three IN Endpoints in addition to Control Endpoint 0; Up to 64-byte data payload size
  • Internal PHY means that very few or no external components needed to connect to a host computer

§Usage

The USB Serial/JTAG driver implements a number of third-party traits, with the intention of making the HAL inter-compatible with various device drivers from the community. This includes, but is not limited to, the embedded-hal and embedded-io blocking traits, and the embedded-hal-async and embedded-io-async asynchronous traits.

In addition to the interfaces provided by these traits, native APIs are also available. See the examples below for more information on how to interact with this driver.

§Examples

§Sending and Receiving Data

use esp_hal::usb_serial_jtag::UsbSerialJtag;

let mut usb_serial = UsbSerialJtag::new(peripherals.USB_DEVICE);

// Write bytes out over the USB Serial/JTAG:
usb_serial.write(b"Hello, world!")?;

§Splitting the USB Serial/JTAG into TX and RX Components

use esp_hal::usb_serial_jtag::UsbSerialJtag;

let mut usb_serial = UsbSerialJtag::new(peripherals.USB_DEVICE);
// The USB Serial/JTAG can be split into separate Transmit and Receive
// components:
let (mut rx, mut tx) = usb_serial.split();

// Each component can be used individually to interact with the USB
// Serial/JTAG:
tx.write(&[42u8])?;
let byte = rx.read_byte()?;

§How to output text using USB Serial/JTAG.


let delay = Delay::new();

let mut usb_serial = UsbSerialJtag::new(peripherals.USB_DEVICE);
usb_serial.set_interrupt_handler(usb_device);
usb_serial.listen_rx_packet_recv_interrupt();

critical_section::with(|cs|
USB_SERIAL.borrow_ref_mut(cs).replace(usb_serial));

loop {
    println!("Send keystrokes to see the interrupt trigger");
    delay.delay(Duration::from_secs(1));
}

static USB_SERIAL:
    Mutex<RefCell<Option<UsbSerialJtag<'static, esp_hal::Blocking>>>> =
        Mutex::new(RefCell::new(None));

#[handler]
fn usb_device() {
    critical_section::with(|cs| {
        let mut usb_serial = USB_SERIAL.borrow_ref_mut(cs);
        if let Some(usb_serial) = usb_serial.as_mut() {
            println!("USB serial interrupt");

            while let nb::Result::Ok(c) = usb_serial.read_byte() {
                println!("Read byte: {:02x}", c);
            }

            usb_serial.reset_rx_packet_recv_interrupt();
        }
    });
}

Structs§

UsbSerialJtag
USB Serial/JTAG (Full-duplex)
UsbSerialJtagRx
USB Serial/JTAG (Receive)
UsbSerialJtagTx
USB Serial/JTAG (Transmit)