Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions ports/esp32/usb_serial_jtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,14 @@ static void usb_serial_jtag_isr_handler(void *arg) {
}

if (flags & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
// As per the ESP-IDF driver, allow for the possibility the USJ just sent a full
// 64-bit endpoint to the host and now it's waiting for another ZLP to flush the result
// to the OS
// This interrupt is only enabled after we've sent a full IN EP buffer to the host.

// As per the ESP-IDF driver, this is necessary if the USJ has just
// sent a full 64-byte EP to the host and now the host is waiting
// for another ZLP to signal that the transfer is actually done.
usb_serial_jtag_ll_txfifo_flush();

// Disable this interrupt until next time we write into the FIFO
// Disable this interrupt until the next time we write a full EP buffer
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
}
Expand Down Expand Up @@ -113,7 +115,7 @@ void usb_serial_jtag_tx_strn(const char *str, size_t len) {
TickType_t start_tick = xTaskGetTickCount();
while (!usb_serial_jtag_ll_txfifo_writable()) {
TickType_t now_tick = xTaskGetTickCount();
if (!terminal_connected || now_tick > (start_tick + pdMS_TO_TICKS(200))) {
if (!terminal_connected || (now_tick - start_tick) > pdMS_TO_TICKS(200)) {
terminal_connected = false;
return;
}
Expand All @@ -122,9 +124,22 @@ void usb_serial_jtag_tx_strn(const char *str, size_t len) {
l = usb_serial_jtag_ll_write_txfifo((const uint8_t *)str, l);
str += l;
len -= l;
}

// Clear any old "serial in empty" interrupt, as we're about to either
// manually flush or enable the interrupt if the TXFIFO is full (no risk of
// a lost flush as we check if the TXFIFO is full after we do this.)
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);

if (usb_serial_jtag_ll_txfifo_writable()) {
// If we haven't written a full EP buffer, manually flush it to send to the host
usb_serial_jtag_ll_txfifo_flush();
} else {
// If we have written a full EP buffer to send to the host then the hardware will flush
// automatically, but enable the "serial in empty" interrupt so we will send a ZLP once
// the full buffer has been sent.
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
usb_serial_jtag_ll_txfifo_flush();
}

#endif // MICROPY_HW_ESP_USB_SERIAL_JTAG
33 changes: 28 additions & 5 deletions tests/serial_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@

from test_utils import test_instance_epilog, convert_device_shortcut_to_real_device

TEST_READ_TIMEOUT = 1

# For ESP32 boards with both native/USJ USB and a UART serial port, soft
# reset may flush the UART buffer before it completes - this can be quite large
# if it's backed up a lot of data during the previous test.
SOFT_RESET_TIMEOUT = 5

echo_test_script = """
import sys
bytes_min=%u
Expand Down Expand Up @@ -98,9 +105,25 @@ def drain_input(ser):
time.sleep(0.1)


def reset_into_raw_repl(ser):
try:
ser.timeout = SOFT_RESET_TIMEOUT
ser.flushInput()
ser.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot
EXPECTED1 = b"MPY: soft reboot\r\n"
EXPECTED2 = b"raw REPL; CTRL-B to exit\r\n>"
r1 = ser.read_until(EXPECTED1)
r2 = b""
if r1.endswith(EXPECTED1):
r2 = ser.read_until(EXPECTED2)
if not r2.endswith(EXPECTED2):
raise TestError("could not reset to raw REPL", r1 + r2)
finally:
ser.timeout = TEST_READ_TIMEOUT


def send_script(ser, script):
ser.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot
drain_input(ser)
reset_into_raw_repl(ser)
chunk_size = 32
for i in range(0, len(script), chunk_size):
ser.write(script[i : i + chunk_size])
Expand Down Expand Up @@ -270,13 +293,13 @@ def write_test(ser_repl, ser_data, bufsize, nbuf, verified):
def do_test(dev_repl, dev_data=None, time_per_subtest=1):
if dev_data is None:
print("REPL and data on", dev_repl)
ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1)
ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=TEST_READ_TIMEOUT)
ser_data = ser_repl
else:
print("REPL on", dev_repl)
print("data on", dev_data)
ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1)
ser_data = serial.Serial(dev_data, baudrate=115200, timeout=1)
ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=TEST_READ_TIMEOUT)
ser_data = serial.Serial(dev_data, baudrate=115200, timeout=TEST_READ_TIMEOUT)

# Do echo test first, and abort if it doesn't pass.
echo_test(ser_repl, ser_data)
Expand Down
Loading