-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ESP32-S3 USB serial output stops working #9454
Comments
Do you have boards with othert chip families (e.g. RP2040), or do you have an ESP32-S2? Do they have the same behavior? |
I have not noticed this happening on my RP2040 board or my SAMD21 board |
the ESP32 boards I have are all ESP32-S3 |
Another data point... I tried a similar reproducer on an Adafruit Metro ESP32-S3 with an attached Adafruit 2.8" TFT Touch Shield. But, this time I set the display up to echo the serial console. In this case, the TFT console continues working (taking keyboard input from the USB serial connection!), even after the USB serial output to CircuitPython versionAdafruit CircuitPython 9.1.1 on 2024-07-22; Adafruit Metro ESP32S3 with ESP32S3 Code/REPLfrom board import D9, D10, SPI
from digitalio import DigitalInOut, Direction
from displayio import release_displays
from fourwire import FourWire
from time import monotonic, sleep
from adafruit_ili9341 import ILI9341
release_displays()
bus = FourWire(SPI(), command=D9, chip_select=D10)
display = ILI9341(bus, width=320, height=240)
display.rotation = 180 # landscape with Metro S3 USB port on the right
epoch = monotonic()
while True:
print(monotonic() - epoch)
sleep(1) BehaviorExpected: At 1 second intervals, timestamp prints to 2.8" TFT shield and USB serial console. Actual: With the host computer's screen unlocked, the code runs as expected. But, if I lock the macOS screen (apple menu > Lock Screen), wait a few minutes, then log back in, the USB serial output to This is a webcam shot of the REPL on the TFT shield next to my Terminal window running If things were working normally, I would expect the contents of my |
Is there any chance flow control is getting confused? Does a Ctrl-q on the frozen |
Yeah, I agree it does seem a lot like some kind of weird flow control issue. I'm under the impression that when I invoke screen with |
I tried Ctrl-q, but that did not appear to have any effect. It's still the same situation: no local echo and no console output in the |
I did stumble on one post that suggested typing ctrl-A followed by a Q on the frozen screen (I think the caps are significant but 🤷) BTW, I tried reproducing on Linux by minimizing a terminal running tio but no luck... |
Two things I'd try:
|
When I do a detach-screen, lock-mac, wait, unlock-mac, then reattach-screen sequence, the result is the same (output stopped during the time mac was locked, no further output shows in screen window, but typing into screen still works as expected). I don't have |
I tried using the serial monitor of the Mu editor on an old MacBook Air (13-inch Mid 2013) with macOS Big Sur 11.7. The same problem happens (no console output on the mac, but console input works, and TFT console output works). The same problem also happens when using |
FWIW, seeing that Mu and screen act the same way across significantly different hardware/OS combinations, my bet is that this has to do with an edge case on the CircuitPython board that is triggered by a USB power saving feature or perhaps by a full TX buffer. I'm assuming that the Macs are entering a standby or suspend mode that slows or stops the CPU. Maybe some combination of TinyUSB, ESP-IDF USB Device Stack, and CircuitPython aren't on the same page about what should happen if the host computer does not read USB serial data at its normal rate. |
I have run your first test script on an esp32-s3 in a "screen" window on linux with the output paused using ctrl-s for more than 30 minutes and a ctrl-q resumes the output without issue. I wonder if the Mac might be doing something weird to the USB data lines when the screen locks (maybe security to thwart Rubber Ducky or similar attacks?) |
As long as I don't lock the screen, nothing weird happens for me. But, once the screen has been locked for approximately 100 seconds (sometimes less, sometimes more), something breaks. The screen locking is the trigger. An important point to note is that I have my systems set so that they can automatically go to sleep when the display is off. I'm unclear of the details of how Apple implements "automatic sleeping" as they call it in the system settings, but presumably it involves CPU scaling and possibly USB power saving modes. The Linux kernel equivalent of what's likely happening might be something like ramp from Suspend-to-Idle, to Standby, to Suspend-to-RAM, possibly also with some USB power saving stuff too (see System Sleep States and Power Management for USB docs at kernel.org). If I'm able to come up with a reproduction recipe for Linux, I'll post it here. |
Okay, I used the Ubuntu Suspend option and reproduced what you're seeing on Linux. The Neopixel continues to blink but the output is frozen in the screen or tio terminal. |
Edit: I just re-read the linked document and I don't think it applies after all. I was actually able to bring a frozen screen back to life using the following script
I ran dmesg after plugging the controller in to identify the device ID (2-1.1) You have to jump through a few hoops to get the script to run on Ubuntu but when it runs it seems to unlock the screen. I tried for a bit to enable the persist option mentioned in the article but the root object 2-1.1 already had it set and I kept getting permission denied when I tried to create the persist file for the serial usb object. |
One more observation, I don't seem to be able to reproduce the issue using a Feather RP2040 so it may be limited to ESP boards. |
If you folks have time, trying some earlier versions of Python would be interesting, since the underlying TinyUSB software undergoes updates fairly frequently. |
9.0.0 has the same problem on: Adafruit CircuitPython 9.0.0 on 2024-03-19; Adafruit QT Py ESP32-S3 no psram with ESP32S3 |
8.1.0 also has the problem on: Adafruit CircuitPython 8.1.0 on 2023-05-22; Adafruit QT Py ESP32-S3 no psram with ESP32S3 |
I suspect circuitpython/supervisor/shared/serial.c Lines 373 to 382 in bd83418
This is based on the sent line state: I don't know why this would only break on an S3. ESP does run tinyusb processing in a different task. Most run it in the CircuitPython background tasks. |
So far, I don't think we know anything one way or the other about ESP32-S2. The ESP32 boards I have are all S3. If anybody wants to try S2, I'd be curious to hear what happens. These are some other boards I tried, none of which have the problem (timestamps continue printing after screen is unlocked): Adafruit CircuitPython 9.0.5 on 2024-05-22; Raspberry Pi Pico with rp2040
Adafruit CircuitPython 9.0.5 on 2024-05-22; Adafruit Trinket M0 with samd21e18
Adafruit CircuitPython 9.1.1 on 2024-07-22; Adafruit Feather M4 Express with samd51j19 Also, this is an even simpler reproducer that you can run from the REPL: from time import monotonic, sleep
a = monotonic()
while True:
print(monotonic() - a)
sleep(1) fail condition: timestamps stop printing after 2-3 minutes of locked screen with automatic sleeping enabled (mac) or suspend-mode (Ubuntu) |
I reproduced this using an ESP32-S2 board. |
I can't seem to cause the issue using a QTPY ESP32-pico |
That makes sense because that's strictly a USB-serial converter chip, no native USB involved: TinyUSB and its associated code like the |
Modifying this function to always return "false" seems to prevent the issue from occurring. I'm guessing that suggests that either the OS isn't marking the device as no longer suspended or the device isn't recovering properly from the suspended state. Without this function properly operating the ESP32-S3 board continues to output while the computer is suspended, ie there are no skipped counts when scrolling back through the tio window after the computer comes back from suspended standby and the current count corresponds to the number of actual seconds elapsed during the suspension. Edit: |
another data point... I was able to prevent the serial glitch on ESP32-S3 with import usb_hid
import storage
usb_hid.disable()
storage.disable_usb_drive() # CAUTION: THIS WILL HIDE YOUR CIRCUITPY DRIVE!!! For anybody reading this who isn't already familiar with recovering from a disabled CIRCUITPY drive... To fix your f = open('boot.py', 'w')
f.write('import usb_hid\nusb_hid.disable()\n')
f.close() You can also use safe mode to fix it. |
I've debugged this down into TinyUSB. The ESP usb code wasn't detecting a resume correctly. It is fixed in hathach/tinyusb#2784. We'll update CP as soon as that is merged in. |
TinyUSB didn't turn on the interrupt it needed. Fixes #9454
CircuitPython version
Code/REPL
Behavior
Expected: At 1 second intervals, Neopixel should toggle and a timestamp should print. This should continue indefinitely.
Actual: With the host computer's screen unlocked (macOS Sonoma 14.5 + M1 Mac mini), the code runs as expected. But, if I lock the macOS screen (apple menu > Lock Screen), wait about 5 minutes, then log back in, the Neopixel continues blinking but nothing prints to the serial console. (no timestamps, no supervisor messages if I do Ctrl-C, etc).
Description
The USB serial output of my QT Py ESP32-S3 often becomes unresponsive when I leave it plugged into an M1 Mac mini with macOS Sonoma 14.5. This happens both with CircuitPython 9.1.0 and 9.1.1.
Everything is normally fine with the screen unlocked. But, if I lock the screen, then come back a bit later (5 minutes is usually enough), I will often have to reset the board before I can see serial output again (reset button or unplug/replug both work).
The weird thing is that when the USB serial output glitch is happening, my CIRCUITPY drive is still available, my code still runs (LED blinks), and USB serial input (from mac to the ESP32-S3) appears to still work. I say that because, if I do a
screen -fn /dev/tty.usbmodem...
, then type Ctrl-C, it causes the S3's LED to do an intermittent double-red blink in the same manneras Ctrl-C under normal circumstances. But, when I do the Ctrl-C, none of the usual output text appears in screen's terminal window. If I reset or eject the CIRCUITPY drive, unplug the board, then plug it back in, the serial output resumes working normally.
In macOS System Settings > Energy Saver, my settings are:
In System Settings > Lock Screen, my settings are:
After 5 seconds
Additional information
No response
The text was updated successfully, but these errors were encountered: