Created
February 25, 2024 19:45
-
-
Save PaulskPt/74a0743edc7fb7cf522de2e621b7ce7e to your computer and use it in GitHub Desktop.
Adafruit GamepadQT with Raspberry Pi 5B-8GB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# _*_ coding: utf-8 _*_ | |
# SPDX-FileCopyrightText: 2024 Paulus Schulinck | |
# | |
# SPDX-License-Identifier: MIT | |
############################## | |
# NOTE: Blinka and other prerequisites have to be installed on the Raspberry Pi | |
# See: https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi | |
# Also: before running this script, activate the venv environment as explained in the Adafruit article. | |
# This script is tested on a Raspberry Pi 5B-8GB and an Adafruit Gamepad QT (product ID 5743), | |
# connected through a Sparkfun Qwiic PiHat (https://www.sparkfun.com/products/14459) | |
import sys, os | |
import time | |
import board | |
import busio | |
from micropython import const | |
from adafruit_seesaw.seesaw import Seesaw | |
from adafruit_platformdetect import Detector | |
detector = Detector() | |
print("Board id: ", detector.board.id) | |
print("Board serial: ", detector.get_cpuinfo_field('Serial')) | |
print("Board rev: ", detector.get_cpuinfo_field('Revision')) | |
i2c = busio.I2C(board.SCL, board.SDA) | |
selected_group = 0 | |
nr_groups = 2 | |
BUTTON_SELECT = const(0) | |
BUTTON_B = const(1) | |
BUTTON_Y = const(2) | |
BUTTON_A = const(5) | |
BUTTON_X = const(6) | |
BUTTON_START = const(16) | |
button_mask = const( | |
( 1 << BUTTON_X) # = 1 << 6 = 64 = 0x00040 | |
| (1 << BUTTON_Y) # = 1 << 2 = 4 = 0x00004 | |
| (1 << BUTTON_A) # = 1 << 5 = 32 = 0x00020 | |
| (1 << BUTTON_B) # = 1 << 1 = 2 = 0x00002 | |
| (1 << BUTTON_SELECT) # = 1 << 0 = 1 = 0x00001 | |
| (1 << BUTTON_START) # = 1 << 16 = 65536 = 0x10000 | |
) # = 65639 dec or 0x10067 | |
# Raspberry Pi 5B-8GB i2c devices found: | |
# /dev/i2c-1 | |
# /dev/i2c-11 | |
# /dev/i2c-12 | |
try: | |
seesaw = Seesaw(i2c, addr=0x50) | |
seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP) | |
qt_btns_present = True | |
except Exception as e: | |
print(f"global(): Error while creating an instance of seesaw class: {e}") | |
qt_btns_present = False | |
raise | |
def ck_usr_answr(): | |
ret = False | |
while True: | |
answer = input("Are you sure? (Y/n)+<Enter>: ") | |
print(f"You answered: \'{answer}\'") | |
if answer == "Y" or answer == "y": | |
ret = True | |
break | |
elif answer == "N" or answer == "n": | |
break | |
return ret | |
def reboot(): | |
print("\nRebooting...") | |
time.sleep(3) | |
os.system('sudo shutdown -r now') | |
def pr_btn_name(res): | |
btns = ["X", "Y", "A", "B", "Select", "Start"] | |
if res >= 0 and res < len(btns): | |
print("Button "+btns[res]+" pressed") | |
def gamepad_test(): | |
TAG= "gamepad_test(): " | |
id = seesaw.chip_id | |
version = seesaw.get_version() # None | |
s_id = "seesaw.chip_id" | |
s = "{:s}= 0x{:x}".format(s_id, id) | |
v = "seesaw._version()= 0x{:x}".format(version) | |
print(TAG+s) | |
print(TAG+v) | |
seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP) | |
last_x = 0 | |
last_y = 0 | |
elapsed_t = None | |
interval_t = 36 | |
interval_cnt = 0 | |
msg1_shown = False | |
nr_btns = 6 | |
res_x = res_y = res_a = res_b = res_sel = res_sta = -1 | |
start_t = time.monotonic() | |
while True: | |
if not msg1_shown: | |
msg1_shown = True | |
print(TAG+"We\'re going to test the gamepad.\n\t\t"+ \ | |
"Press a button on the gamepad...\n\t\t"+ \ | |
"To reboot the Raspberry Pi press gamepad button Start\n") | |
try: | |
x = 1023 - seesaw.analog_read(14) | |
y = 1023 - seesaw.analog_read(15) | |
except Exception as e: | |
if e.errno == 121: # Remote I/O Error | |
print(f"Error: {e}") | |
pass | |
if (abs(x - last_x) > 3) or (abs(y - last_y) > 3): | |
print(f"joystick: (x, y)= ({x}, {y})") | |
last_x = x | |
last_y = y | |
buttons = seesaw.digital_read_bulk(button_mask) | |
if buttons: | |
res = -1 | |
for _ in range(nr_btns): | |
if _ == 0: | |
bz = 1 << BUTTON_X | |
if not buttons & (bz): | |
res = _ | |
if res_x != res: | |
pr_btn_name(res) | |
res_x = res | |
break | |
if _ == 1: | |
bz = 1 << BUTTON_Y | |
if not buttons & (bz): | |
res = _ | |
if res_y != res: | |
pr_btn_name(res) | |
res_y = res | |
break | |
if _ == 2: | |
bz = 1 << BUTTON_A | |
if not buttons & (bz): | |
res = _ | |
if res_a != res: | |
pr_btn_name(res) | |
res_a = res | |
break | |
if _ == 3: | |
bz = 1 << BUTTON_B | |
if not buttons & (bz): | |
res = _ | |
if res_b != res: | |
pr_btn_name(res) | |
res_b = res | |
break | |
if _ == 4: | |
bz = 1 << BUTTON_SELECT | |
if not buttons & (bz): | |
res = _ | |
if res_sel != res: | |
pr_btn_name(res) | |
res_sel = res | |
break | |
if _ == 5: | |
bz = 1 << BUTTON_START | |
if not buttons & (bz): | |
res = _ | |
if res_sta != res: | |
pr_btn_name(res) | |
res_sta = res | |
print("About to reboot the Raspberry Pi") | |
if ck_usr_answr(): | |
reboot() # Reboot the RPi5 | |
else: | |
msg1_shown = False | |
res_sta = -2 | |
break | |
curr_t = time.monotonic() | |
elapsed_t = (curr_t - start_t) * 1000 | |
if elapsed_t >= interval_t: | |
interval_cnt += 1 | |
if interval_cnt >= 100: | |
interval_cnt = 0 | |
res_x = res_y = res_a = res_b = res_sel = res_sta = -2 | |
start_t = curr_t | |
time.sleep(0.01) | |
def main(): | |
TAG= "main(): " | |
loopnr = 0 | |
while True: | |
try: | |
loopnr += 1 | |
# print(TAG+f"\nLoopnr: {loopnr}") | |
if loopnr >= 100: | |
loopnr = 0 | |
gamepad_test() | |
except KeyboardInterrupt: | |
print(TAG+"KeyboardInterrrupt. Exiting...") | |
break | |
if loopnr >= 1000: | |
break | |
sys.exit() | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thursday 2024-02-22 12h49 utc | |
Board: Raspberry Pi 5B-8GB | |
Python script: gamepadqt.py | |
Python print output: | |
(env) paulsk@raspi5B-8GB:~/Adafruit_GamepadQT $ python3 gamepadqt.py | |
Board id: RASPBERRY_PI_5 | |
Board serial: 1169efc3bd80e900 | |
Board rev: d04170 | |
gamepad_test(): seesaw.chip_id= 0x87 | |
gamepad_test(): seesaw._version()= 0x166f7a97 | |
gamepad_test(): We're going to test the gamepad. | |
Press a button on the gamepad... | |
To reboot the Raspberry Pi press gamepad button Start | |
joystick: (x, y)= (504, 511) | |
Button B pressed | |
Button A pressed | |
Button Y pressed | |
Button X pressed | |
Button Select pressed | |
Button Start pressed | |
About to reboot the Raspberry Pi | |
Are you sure? (Y/n)+<Enter>: n | |
You answered: 'n' | |
gamepad_test(): We're going to test the gamepad. | |
Press a button on the gamepad... | |
To reboot the Raspberry Pi press gamepad button Start | |
^Cmain(): KeyboardInterrrupt. Exiting... | |
(env) paulsk@raspi5B-8GB:~/Adafruit_GamepadQT $ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Today I connected the
Sparkfun Qwiic PiHat
and theAdafruit GamepadQT
to aRaspberry CM4
. It worked, however there werespurious keypress events
. I was able to solve these unwanted spurious keypress events by inserting the line:dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,bus=1
to file:/boot/firmware/config.txt
under[cm4]
.