From eb5d89cd8324407eda67066292d4cabbc4ce4cd4 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 20 Nov 2025 17:33:01 +1100 Subject: esp32/usb_serial_jtag: Flush usb_serial_jtag TXFIFO from ISR. This was necessary to un-wedge the USJ TX path on ESP32-P4, I think because the bootloader prints a lot on this chip. I think it might be possible to hit it on other chips, though. The implementation is based on the ESP-IDF driver, which will always add an extra flush when the TXFIFO is empty in case the host is expecting a ZLP. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/usb_serial_jtag.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/ports/esp32/usb_serial_jtag.c b/ports/esp32/usb_serial_jtag.c index c4834e56f..2df7e2008 100644 --- a/ports/esp32/usb_serial_jtag.c +++ b/ports/esp32/usb_serial_jtag.c @@ -71,23 +71,31 @@ static void usb_serial_jtag_handle_rx(void) { static void usb_serial_jtag_isr_handler(void *arg) { uint32_t flags = usb_serial_jtag_ll_get_intsts_mask(); - - if (flags & USB_SERIAL_JTAG_INTR_SOF) { - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF); - } + usb_serial_jtag_ll_clr_intsts_mask(flags); if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); usb_serial_jtag_handle_rx(); mp_hal_wake_main_task_from_isr(); } + + 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 + usb_serial_jtag_ll_txfifo_flush(); + + // Disable this interrupt until next time we write into the FIFO + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } } void usb_serial_jtag_init(void) { + // Note: Don't clear the SERIAL_IN_EMPTY interrupt, as it's possible the + // bootloader wrote enough data to the host that we need the interrupt to flush it. usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_SOF); usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | - USB_SERIAL_JTAG_INTR_SOF); + USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, usb_serial_jtag_isr_handler, NULL, NULL)); } @@ -114,10 +122,11 @@ void usb_serial_jtag_tx_strn(const char *str, size_t len) { } terminal_connected = true; l = usb_serial_jtag_ll_write_txfifo((const uint8_t *)str, l); - usb_serial_jtag_ll_txfifo_flush(); str += l; len -= l; + 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 -- cgit v1.2.3