adafruit / Adafruit_CircuitPython_seesaw

seesaw helper IC driver for circuitPython
MIT License
60 stars 35 forks source link

Gamepad I2C Initialization and read errors #119

Closed EAGrahamJr closed 1 year ago

EAGrahamJr commented 1 year ago

This is regarding the new I2C Gamepad (https://www.adafruit.com/product/5743)

Symptoms

Setup

Synopsis

After running the demo code, I started receiving errors. It required several retries to get the Seesaw to re-initialize properly.

Errors:

$ py gamepad.py
Traceback (most recent call last):
  File "/home/crackers/projects/pobots-devices/./gamepad.py", line 26, in <module>
    seesaw = Seesaw(i2c_bus, addr=0x50)
  File "/home/crackers/projects/pobots-devices/venv/lib/python3.9/site-packages/adafruit_seesaw/seesaw.py", line 150, in __init__
    raise RuntimeError(
RuntimeError: Seesaw hardware ID returned (0x7) is not correct! Expected 0x55 or 0x87. Please check your wiring.
$ py gamepad.py
Traceback (most recent call last):
  File "/home/crackers/projects/pobots-devices/./gamepad.py", line 34, in <module>
    x = 1023 - seesaw.analog_read(14)
  File "/home/crackers/projects/pobots-devices/venv/lib/python3.9/site-packages/adafruit_seesaw/seesaw.py", line 256, in analog_read
    raise ValueError("Invalid ADC pin")
ValueError: Invalid ADC pin

I've attached an "updated" demo code that resets the Seesaw until it responds correctly.

THEN I noted that the button reads were not entirely correct - I was getting sporadic button presses in this much slower loop, as well as some crazy readings from the joystick:

$ ./gamepad.py
Took 0 tries
768 516
515 516
Button X pressed
Button Y pressed
Button Start pressed

THERE WERE NO HANDS ON THE CONTROLLER. During any given run of the application, there will be sporadic button presses printed, as well as joystick movements, without any actual physical contact.

This is repeatable with a completely different Raspberry Pi 4 and the v2 of the Qwiic Hat and multiple STEMMA wires/connectors.

This is also mentioned in https://forums.adafruit.com/viewtopic.php?t=202743

EAGrahamJr commented 1 year ago

Updated Demo Code

#!/bin/env python3

import time
import board
from micropython import const
from adafruit_seesaw.seesaw import Seesaw

BUTTON_X = const(6)
BUTTON_Y = const(2)
BUTTON_A = const(5)
BUTTON_B = const(1)
BUTTON_SELECT = const(0)
BUTTON_START = const(16)
button_mask = const(
    (1 << BUTTON_X)
    | (1 << BUTTON_Y)
    | (1 << BUTTON_A)
    | (1 << BUTTON_B)
    | (1 << BUTTON_SELECT)
    | (1 << BUTTON_START)
)

# i2c_bus = board.STEMMA_I2C()  # The built-in STEMMA QT connector on the microcontroller
i2c_bus = board.I2C()  # Uses board.SCL and board.SDA. Use with breadboard.

count = 0
for i in range(0, 100):
    try:
        seesaw = Seesaw(i2c_bus, addr=0x50)
        print(f"Connected to seesaw after {i} tries.")
        break
    except:
        count = count + 1
        time.sleep(0.1)
else:
    print(f"Failed to connect to seesaw after {i} tries.")
    exit(1)

seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP)

last_x = 0
last_y = 0

last_start = False

while not last_start:
    x = 1023 - seesaw.analog_read(14)
    y = 1023 - seesaw.analog_read(15)

    if (abs(x - last_x) > 3) or (abs(y - last_y) > 3):
        print(x, y)
        last_x = x
        last_y = y

    buttons = seesaw.digital_read_bulk(button_mask)

    if not buttons & (1 << BUTTON_X):
        print("Button X pressed")

    if not buttons & (1 << BUTTON_Y):
        print("Button Y pressed")

    if not buttons & (1 << BUTTON_A):
        print("Button A pressed")

    if not buttons & (1 << BUTTON_B):
        print("Button B pressed")

    if not buttons & (1 << BUTTON_SELECT):
        print("Button Select pressed")

    if not buttons & (1 << BUTTON_START):
        print("Button Start pressed")
        last_start = True

    time.sleep(0.5)
EAGrahamJr commented 1 year ago

Update to this issue: this appears to be affected by the Raspberry Pi I2C bus speed. Changing the "baud rate" to 400000 (from the default of 100000) causes the phantom reads to disappear. This appears to have already been updated in the Gamepad documentation, but should probably be noted in other places as well. This was definitely a bit of a frustrating chase...