mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-05 03:27:48 +00:00
machine/esp32s3,esp32c3: make USB Serial/JTAG writes non-blocking when FIFO is full
When no USB host is reading (e.g. board not connected to a serial monitor), WriteByte and Write would spin for up to 200k iterations per byte waiting for the FIFO to drain. This stalled the entire application, freezing unrelated peripherals like I2C displays. Reduce flushTimeout from 200,000 to 50,000 iterations (~3ms) which is enough for 2-3 USB frames when a host is connected, but short enough that serial output won't freeze the application when no host is reading. Serial output is best-effort; callers like putchar already ignore write errors. Applies to both ESP32-S3 and ESP32-C3 which share the same USB Serial/JTAG controller design.
This commit is contained in:
@@ -20,8 +20,10 @@ import (
|
||||
const cpuInterruptFromUSB = 10
|
||||
|
||||
// flushTimeout is the maximum number of busy-wait iterations in flush().
|
||||
// Prevents hanging when no USB host is connected.
|
||||
const flushTimeout = 200000
|
||||
// Must be long enough for 2-3 USB frames (~3ms at 160MHz) so data gets
|
||||
// through when a host is connected, but short enough that println doesn't
|
||||
// freeze the application when no host is reading.
|
||||
const flushTimeout = 50000
|
||||
|
||||
type USB_DEVICE struct {
|
||||
Bus *esp.USB_DEVICE_Type
|
||||
@@ -145,7 +147,8 @@ func (usbdev *USB_DEVICE) handleInterrupt() {
|
||||
func (usbdev *USB_DEVICE) WriteByte(c byte) error {
|
||||
usbdev.ensureConfigured()
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
// FIFO full — try flushing first, then recheck.
|
||||
// FIFO not writable — try a short flush to nudge the hardware
|
||||
// (e.g. after reset the FIFO may need WR_DONE to transition).
|
||||
usbdev.flush()
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
return errUSBCouldNotWriteAllData
|
||||
@@ -206,8 +209,9 @@ func (usbdev *USB_DEVICE) RTS() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// flush signals WR_DONE and waits (with timeout) for the hardware to
|
||||
// consume the data. A timeout prevents hanging when no USB host is present.
|
||||
// flush signals WR_DONE and briefly waits for the hardware to accept more
|
||||
// data. The timeout is intentionally short so that serial output never
|
||||
// stalls the application when no USB host is reading.
|
||||
func (usbdev *USB_DEVICE) flush() {
|
||||
usbdev.Bus.SetEP1_CONF_WR_DONE(1)
|
||||
for i := 0; i < flushTimeout; i++ {
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
const cpuInterruptFromUSB = 8
|
||||
|
||||
// flushTimeout is the maximum number of busy-wait iterations in flush().
|
||||
// Prevents hanging when no USB host is connected.
|
||||
const flushTimeout = 200000
|
||||
// Must be long enough for 2-3 USB frames (~3ms at 240MHz) so data gets
|
||||
// through when a host is connected, but short enough that println doesn't
|
||||
// freeze the application when no host is reading.
|
||||
const flushTimeout = 50000
|
||||
|
||||
type USB_DEVICE struct {
|
||||
Bus *esp.USB_DEVICE_Type
|
||||
@@ -123,7 +125,8 @@ func (usbdev *USB_DEVICE) handleInterrupt() {
|
||||
func (usbdev *USB_DEVICE) WriteByte(c byte) error {
|
||||
usbdev.ensureConfigured()
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
// FIFO full — try flushing first, then recheck.
|
||||
// FIFO not writable — try a short flush to nudge the hardware
|
||||
// (e.g. after reset the FIFO may need WR_DONE to transition).
|
||||
usbdev.flush()
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
return errUSBCouldNotWriteAllData
|
||||
@@ -195,8 +198,9 @@ func (usbdev *USB_DEVICE) RTS() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// flush signals WR_DONE and waits (with timeout) for the hardware to
|
||||
// consume the data. A timeout prevents hanging when no USB host is present.
|
||||
// flush signals WR_DONE and briefly waits for the hardware to accept more
|
||||
// data. The timeout is intentionally short so that serial output never
|
||||
// stalls the application when no USB host is reading.
|
||||
func (usbdev *USB_DEVICE) flush() {
|
||||
usbdev.Bus.SetEP1_CONF_WR_DONE(1)
|
||||
for i := 0; i < flushTimeout; i++ {
|
||||
|
||||
Reference in New Issue
Block a user