Skip to content
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

I2C problems on ESP32-S2 after scan #9561

Open
dhalbert opened this issue Aug 26, 2024 · 5 comments
Open

I2C problems on ESP32-S2 after scan #9561

dhalbert opened this issue Aug 26, 2024 · 5 comments
Assignees
Milestone

Comments

@dhalbert
Copy link
Collaborator

dhalbert commented Aug 26, 2024

Quoting from #9535 (comment):

I'm having a very similar issue with I2C on QT-PY-ESP32-S2. I've come at it all kinds of ways, with one or multiple I2C devices and varying the I2C bus speed from 10_000 to 400_000.

With these i2c devices:

  • adafruit_ssd1306
    
  • adafruit_seesaw (rotaryio: product number 4991)
    

When I do a i2c.scan() it never shows any devices, but I can "speak" to the rotaryio. When I enable the ssd1306, I get:

main.py output:
sys.implementation=(name='circuitpython', version=(9, 1, 1), _machine='Adafruit QT Py ESP32S2 with ESP32S2', _mpy=262)
I2C_FREQ       : 100000
I2C_DO_SCAN    : True
I2C_USE_SSD1306: True
I2C_USE_SEESAW : True
Scanning I2C addresses: []
Position: 0
cnt_loops = 16 / sec
Traceback (most recent call last):
  File "main.py", line 69, in <module>
  File "adafruit_ssd1306.py", line 219, in show
  File "adafruit_ssd1306.py", line 287, in write_framebuf
OSError: [Errno 116] ETIMEDOUT

If I never do the i2c.scan(), seesaw-rotaryio and ssd1306 appear to work fine (I've tried different instances of ssd1306 hardware).

In the case where I use only the seesaw-rotaryio and do i2c.scan(), the scan still shows no devices, I can communicate with the seesaw-rotario and my code speed decreases dramatically, e.g. 100+ loops/second becomes ~15 loops/second.

Code below. Can anyone shed some light on this?

Thanks,
Casa


# ==============================================================================
#
from micropython import const
import busio
import board
import sys
from adafruit_ticks import ticks_ms, ticks_add, ticks_less

I2C_FREQ = const(100_000)
I2C_DO_SCAN: bool = True
I2C_USE_SSD1306: bool = True
I2C_USE_SEESAW: bool = True

MS_ONE_SECOND = const(1000)

# ------------------------------------------------------------------------------
print(f"{sys.implementation=}")
print(f"I2C_FREQ       : {I2C_FREQ:6d}")
print(f"I2C_DO_SCAN    : {I2C_DO_SCAN}")
print(f"I2C_USE_SSD1306: {I2C_USE_SSD1306}")
print(f"I2C_USE_SEESAW : {I2C_USE_SEESAW}")

# ------------------------------------------------------------------------------
def print_I2C_Scan(i2c: busio.i2c) -> None:
    while not i2c.try_lock():
        pass
    print("Scanning I2C addresses:", [hex(i).upper() for i in i2c.scan()])
    i2c.unlock()

# ------------------------------------------------------------------------------
# Set up i2c0, OLED, seesaw rotaryio
#
i2c0 = busio.I2C(board.SCL, board.SDA, frequency=I2C_FREQ)

if I2C_USE_SSD1306:
    import adafruit_ssd1306
    ADDR = const(0x3C)
    WIDTH = const(128)
    HEIGHT = const(64)
    oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c0, addr=ADDR)

if I2C_USE_SEESAW:
    from adafruit_seesaw import seesaw, rotaryio  #, digitalio
    seesaw = seesaw.Seesaw(i2c0, 0x36)
    encoder = rotaryio.IncrementalEncoder(seesaw)
    last_position = None

# ------------------------------------------------------------------------------
if I2C_DO_SCAN:
    print_I2C_Scan(i2c0)    # PROBLEM HERE

# ------------------------------------------------------------------------------
cnt_loops: int = 0
cnt_printed: int = 0
ms_target: int = ticks_add(ticks_ms(), MS_ONE_SECOND)
try:
    while True:
        cnt_loops += 1
        if not ticks_less(ticks_ms(), ms_target):

            ms_target = ticks_add(ticks_ms(), MS_ONE_SECOND)
            if cnt_printed < 10:
                cnt_printed += 1
                print(f"cnt_loops = {cnt_loops} / sec")
            cnt_loops = 0

            if I2C_USE_SSD1306:
                oled.fill(0)
                oled.show()
                # oled.line(X_MAX, Y_MAX, X_MIN, Y_MIN, 1)
                oled.vline(WIDTH // 2, 0, HEIGHT, 1)
                oled.show()

        if I2C_USE_SEESAW:
            if (position := -encoder.position) != last_position:
                last_position = position
                print("Position: {}".format(position))

except KeyboardInterrupt:
    print("Caught KeyboardInterrupt, exiting")

Originally posted by @Casa-Machinalia in #9535 (comment)

@dhalbert
Copy link
Collaborator Author

Could you re-test with 9.2.0-beta.0? Thanks. I am not seeing an issue now. But I don't have an SSD1306 connected, just a seesaw board.

@dhalbert
Copy link
Collaborator Author

dhalbert commented Sep 18, 2024

I tested with an SSD1306 breakout. Interestingly, I have a very simple reproducer, on ESP32-S2 only, with 9.2.0-beta.0:

import board, adafruit_ssd1306
d = adafruit_ssd1306.SSD1306_I2C(128, 32, board.STEMMA_I2C(), addr=0x3c)

produces:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_ssd1306.py", line 262, in __init__
  File "adafruit_ssd1306.py", line 103, in __init__
  File "adafruit_ssd1306.py", line 160, in init_display
  File "adafruit_ssd1306.py", line 219, in show
  File "adafruit_ssd1306.py", line 287, in write_framebuf
OSError: [Errno 116] ETIMEDOUT

There is no error on ESP32-S3 or RP2040.
Also, there is no error when testing on ESP32-S2 on 9.1.4.

@dhalbert dhalbert self-assigned this Sep 18, 2024
@dhalbert
Copy link
Collaborator Author

I looked at this with a Saleae. On ESP32-S2, the I2C bus frequency is only 1.25 kHz (!), even though I requested 100 kHz. This is apparently due to some bug in ESP-IDF v5.3.1 (used in CircuitPython 9.2.0), which switched things around under the covers for the legacy I2C driver. It's fine in ESP-IDF v5.2.2, which is used in CircuitPython 9.1.4.

I reproduced the problem with an ESP-IDF-supplied example and opened an ESP-IDF issue:
espressif/esp-idf#14603

We want to move to the new ESP-IDF I2C driver, and that's possible now that esp-camera has updated. However, there are several open I2C issues for the new driver, so I'm not sure we want to move ahead yet if it may introduce new problems.

@Casa-Machinalia
Copy link

Thank you @dhalbert for wrangling this issue.

I updated to 9.2.0-beta.0 and retried my code with original h/w (QTPY-ESP32-S2, adafruit_ssd1306, adafruit_seesaw (rotaryio, #4991)

Result: Now fails even when I don't do a i2c.scan() -- this succeeded with v9.1.1

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
main.py output:
sys.implementation=(name='circuitpython', version=(9, 2, 0, ''), _machine='Adafruit QT Py ESP32S2 with ESP32S2', _mpy=774)
I2C_FREQ       : 100000
I2C_DO_SCAN    : False
I2C_USE_SSD1306: True
I2C_USE_SEESAW : True
Traceback (most recent call last):
  File "main.py", line 89, in <module>
  File "adafruit_ssd1306.py", line 262, in __init__
  File "adafruit_ssd1306.py", line 103, in __init__
  File "adafruit_ssd1306.py", line 160, in init_display
  File "adafruit_ssd1306.py", line 219, in show
  File "adafruit_ssd1306.py", line 287, in write_framebuf
OSError: [Errno 116] ETIMEDOUT

Code done running.

Also tried I2C freq 40_000 and 10_000, no joy.

@dhalbert
Copy link
Collaborator Author

@tannewt started a branch with an update to the new ESP-IDF driver for I2C: https://github.com/tannewt/circuitpython/tree/idf5.2_i2c. I'm continuing with that on main. Got it working on ESP32-S3 just fine. On ESP32-S2 the clock speed is now correct, but I'm getting errors and crashes which I'm debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants
@dhalbert @Casa-Machinalia and others