adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.1k stars 1.22k forks source link

Reading I2C bus in code.py interferes with auto-reload leaving attached displays inactive #9253

Open RetiredWizard opened 5 months ago

RetiredWizard commented 5 months ago

CircuitPython version

Adafruit CircuitPython 9.1.0-beta.2 on 2024-05-15; LILYGO T-DECK with ESP32S3
Adafruit CircuitPython 9.0.4 on 2024-04-16; LILYGO T-DECK with ESP32S3
Adafruit CircuitPython 9.1.0-beta.2 on 2024-05-15; Adafruit Feather ESP32S3 4MB Flash 2MB PSRAM with ESP32S3

Code/REPL

import board
from adafruit_bus_device.i2c_device import I2CDevice

# Featherwing TFT (Comment out these lines if not testing on Featherwing TFT)
import adafruit_ili9341
import fourwire
import displayio
spi = board.SPI()
cmd = board.D10
cs = board.D9
rst = board.D6
bl = None
displayio.release_displays()
disp_bus=fourwire.FourWire(spi,command=cmd,chip_select=cs,reset=rst)
display=adafruit_ili9341.ILI9341(disp_bus,width=320,height=240,backlight_pin=bl)
# Address of MSA301 sensor
_ADDRESS_KBD = 38

# Comment out following line if not using lilygo T-Deck
#_ADDRESS_KBD = 0x55

_i2c = I2CDevice(board.I2C(), _ADDRESS_KBD)

i = 0
while True:
    i+= 1
    _key=bytearray(1)

    with _i2c as i2c:
        try:
            i2c.readinto(_key)
        except:
            _key=bytearray(1)

    if chr(_key[0]) == "\n":
        print(chr(_key[0]))
    if _key[0] != 0:
        print(chr(_key[0]),end="")
    print(f'{i}.',end="")

Behavior

Sequence of numbers are displayed on both USB serial terminal and attached display. When a file is written to the microcontroller flash the attached TFT display stops updating and serial terminal output speeds up.

Description

This was originally discovered on the Lilygo T-Deck board where the keyboard is the I2C device that was being read in a loop. When the host computer signals CircuitPython that the flash file system has been updated, no Auto-reload would occur and the display would stop updating however the I2C keyboard would continue to function and if a USB serial terminal was connected it would show the I2C keyboard input and any ongoing output. If the code.py program terminated (either normally, or by a keyboard interrupt) the auto-reload would be triggered.

When the display was in this hung state, manually releasing the display and re-initializing it from the REPL had no effect, the screen continue to show whatever was on the display at the moment it hung.

Additional information

Modifying the try/except block as follows seems to prevent the issue from occuring:

        try:
            i2c.readinto(_key)
        except Exception as err:
            _key=bytearray(1)

Some testing was done with auto-reload disabled and it appeared the problem could still occur although I haven't looked into what could be triggering it.

I also tested the code.py from above using a Featherwing TFT and ESP32-S3 Feather 4/2 and a stemma MSA301 sensor. I wasn't able to get the problem to happen using the released 9.0.4 version of CircuitPython with the Featherwing/MSA301 combination but it did reliably occur using the 9.1.0 beta 2 version. The code.py file does reliable produce the issue on both 9.1.0 beta 2 and 9.0.4 versions with the Lilygo T-Deck.

jepler commented 2 months ago

Oh yeah, KeyboardInterrupt (ctrl+c) and ReloadException are exceptions, so this code with a bare except is functioning exactly as standard Python. So this is likely not a fixable bug, it's just part of how ReloadException works. However, maybe there's a spot in the documentation where this could be better explained -- https://docs.circuitpython.org/en/latest/docs/library/builtins.html#builtins.ReloadException doesn't directly mention anything for example.

One (probably not particularly high quality) stack overflow thread about it: https://stackoverflow.com/questions/54948548/what-is-wrong-with-using-a-bare-except

RetiredWizard commented 2 months ago

Okay.... If I'm remembering properly, I originally thought the issue was tightly associated with the auto-reload but then I thought I re-created it with auto-reload disabled so I was just using the auto-reload as an easy trigger to reproduce the error. When I get a chance to dig back into this, I'll have confirm the problem happens with auto-reload disabled and then see if an auto-reload is somehow being triggered even though they've been disabled or if there's another path to hanging the display.

Thanks!