Skip to content

Instantly share code, notes, and snippets.

@PaulskPt
Last active February 28, 2024 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PaulskPt/60deb9dd3761b2a6486cb4ef40c25070 to your computer and use it in GitHub Desktop.
Save PaulskPt/60deb9dd3761b2a6486cb4ef40c25070 to your computer and use it in GitHub Desktop.
gamepadqt for CircuitPython
"""
Platform: Pimoroni Pico DV Demo Base (PIM588) + Pimoroni Pico Lipo board 16MB (PIM560) (RP2040)
Date: 2021-08-24
System flashed: adafruit-circuitpython-pimoroni_picolipo_16mb-en_GB-7.0.0-beta.0.uf2
This script is to test the functionality of the 'board.USER_SW' which I, @paulsk, happened to discover
during a REPL session, after issuing 'import board' followed by 'dir(board)'.
In the list of resulting functions/classes was: 'USER_SW'.
The command: 'dir (board.USER_SW)' results in: ['__class__'].
The test below shows that board.USER_SW can be defined as an OUTPUT. This test also proves that the value can be set. And the value can be read.
See: circuitpython/ports/raspberrypi/boards/pimoroni_picolipo_16mb/mpconfigboard.h for the following 4 defines
# MICROPY_HW_BOARD_NAME "Pimoroni Pico Lipo (16 MB)"
# MICROPY_HW_MCU_NAME "rp2040"
# DEFAULT_I2C_BUS_SCL (&pin_GPIO5)
# DEFAULT_I2C_BUS_SDA (&pin_GPIO4)
Update 2024-02-12.
Modifications to connect to the Pico Lipo, via I2C, an Adafruit Gamepad QT board and use its buttons X, Y, A and B.
Firmware flashed into Pico Lipo 16MB:
Adafruit CircuitPython 9.0.0-beta.0 on 2024-01-27; Pimoroni Pico dv Base with rp2040
Note: board.USERSW does not exist any longer: now it are: board.BUTTON_A, board.BUTTON_B and board.BUTTON_C.
Update 2024-02-28.
Today received from Pimoroni a replacement board: Pico DV Demo Base for a faulty board (USERSW Button C not working).
Modified the script to use all buttons of the Adafruit Gamepad QT and added functionality to perform a soft reset
when pressing the Gamepad QT Start button.
"""
import board
import digitalio
import time
import sys
import busio
from micropython import const
from adafruit_seesaw.seesaw import Seesaw
import gc
#import microcontroller
import supervisor
id = board.board_id
print(f"board ID: {id}")
my_debug = False
selected_group = 0
nr_groups = 2
msg1_shown = False
last_x = last_y = 0
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
SCL = board.GP5
SDA = board.GP4
try:
i2c = busio.I2C(SCL, SDA)
seesaw = Seesaw(i2c, addr=0x50)
seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP)
qt_btns_present = True
print(f"global: seesaw.chip_id= {hex(seesaw.chip_id)}")
except Exception as e:
print(f"global(): Error while creating an instance seesaw class: {e}")
qt_btns_present = False
raise
"""
+--------+--------+----------------------------+
| BUTTON | VALUE | Value in CPY when pressed |
+--------+--------+----------------------------+
| SELECT | 1 | 65638 |
+--------+--------+----------------------------+
| B | 2 | 65637 |
+--------+--------+----------------------------+
| Y | 4 | 65635 |
+--------+--------+----------------------------+
| ? | 8 | ? |
+--------+--------+----------------------------+
| ? | 16 | ? |
+--------+--------+----------------------------+
| A | 32 | 65607 |
+--------+--------+----------------------------+
| X | 64 | 65637 !
+--------+--------+----------------------------+
| START | 65636 | 103 |
+--------+--------+----------------------------+
"""
btn_a = digitalio.DigitalInOut(board.BUTTON_A) # was: (GP14)
btn_a.direction = digitalio.Direction.INPUT
btn_a.pull = digitalio.Pull.DOWN
btn_b = digitalio.DigitalInOut(board.BUTTON_B) # GP15)
btn_b.direction = digitalio.Direction.INPUT
btn_b.pull = digitalio.Pull.DOWN
btn_c = digitalio.DigitalInOut(board.BUTTON_C) # GP16)
btn_c.direction = digitalio.Direction.INPUT
btn_c.pull = digitalio.Pull.DOWN
on_off_led = digitalio.DigitalInOut(board.GP23)
on_off_led.direction = digitalio.Direction.OUTPUT
led = digitalio.DigitalInOut(board.LED) # LED = GPIO25 (see same file: pins.c)
led.direction = digitalio.Direction.OUTPUT
led_state = 0
#
# blink_led
#
def blink_led(nr_times, bi_led=False, blink_slow=True):
global led_state
curr_state = led_state
# print(f"blink_led(): nr_times: {nr_times}, bi_led= {bi_led}, blink_slow= {blink_slow}")
if nr_times is None:
nr_times = 1
if blink_slow:
delay = 0.5 # was 0.5
else:
delay = 0.1 # was 0.1
if curr_state == 1:
if bi_led:
led.value = False # first switch the led off
on_off_led.value = False
time.sleep(delay)
for _ in range(nr_times):
if bi_led:
led.value = True
#conn_led.value = True
on_off_led.value = False
time.sleep(delay)
if bi_led:
led.value = False
on_off_led.value = False
time.sleep(delay)
if curr_state == 1: # if the led originally was on, switch it back on
if bi_led:
led.value = True
on_off_led.value = False
def test_msg():
global msg1_shown
TAG = "gamepad_test(): "
if not msg1_shown:
msg1_shown = True
print(TAG+f"We\'re going to test the Gamepad QT and the {id}.\n\t\t"+ \
f" Press any of the buttons (A, B or C) on the {id}")
print("\t\t or press any of the buttons (X, Y, A, B, Select or Start)\n\t\t"+ \
f" or move the joystick on the Gamepad QT.\n\t\t" + \
f" To soft rerset {id} press Gamepad QT button Start.\n\t\t"+ \
f" To hard reboot {id} press the \'run\' button on the base.")
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("\nSoft reset...")
time.sleep(3)
# os.system('sudo shutdown -r now') # for Raspberry Pi boards
# microcontroller.reset() # for CircuitPython boards
supervisor.reload() # do a software reset for CircuitPython boards
def pr_btn_name(res):
btns = ["X", "Y", "A", "B", "Select", "Start"]
if res >= 0 and res < len(btns):
print("Button "+btns[res]+" pressed")
# Check for button presses on the Gamepad QT
def ck_qt_btns():
global selected_group, led_state, msg1_shown, last_x, last_y
if not qt_btns_present:
return
TAG = "ck_qt_btns(): "
s_btn = "Gamepad QT button "
s_pre = " pressed"
nr_btns = 6
res_x = res_y = res_a = res_b = res_sel = res_sta = -1
elapsed_t = None
interval_t = 36
interval_cnt = 0
gc.collect()
time.sleep(0.2)
test_msg()
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 x >= last_x:
diff_x = abs(x - last_x)
else:
diff_x = abs(last_x - x)
if y >= last_y:
diff_y = abs(y - last_y)
else:
diff_y = abs(last_y - y)
if (diff_x > 3) or (diff_y > 3):
print(f"joystick: (x, y)= ({x}, {y})")
# print(TAG+f"diff_x= {diff_x}, diff_y= {diff_y}")
last_x = x
last_y = y
# Get the button presses, if any...
buttons = seesaw.digital_read_bulk(button_mask)
if my_debug:
print("\n"+TAG+f"buttons = {buttons}")
if buttons == 65639:
if my_debug:
print(TAG+f"Gamepad QT: no button pressed")
return
# time.sleep(0.5)
start_t = time.monotonic()
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(f"About to soft reset the {id}")
if ck_usr_answr():
reboot() # Reboot the board
else:
msg1_shown = False
res_sta = -2
test_msg()
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)
led.value = False
led_state = 0
def ck_base_btns():
delay = 0.008
a_val = btn_a.value
time.sleep(delay)
b_val = btn_b.value
time.sleep(delay)
c_val = btn_c.value
time.sleep(delay)
usw = "Base user switch "
# print()
if a_val:
print(usw+f"A: {a_val}")
blink_led(3, True, False)
elif b_val:
print(usw+f"B: {b_val}")
blink_led(3, True, False)
elif c_val:
print(usw+f"C: {c_val}")
blink_led(3, True, False)
time.sleep(delay)
def main():
TAG= "main(): "
loopnr = 0
while True:
try:
loopnr += 1
# print(f"\nLoopnr: {loopnr}")
if loopnr >= 100:
loopnr = 0
ck_qt_btns()
ck_base_btns()
#time.sleep(0.5)
except KeyboardInterrupt:
print(TAG+"KeyboardInterrrupt. Exiting...")
break
if loopnr >= 1000:
break
sys.exit()
if __name__ == '__main__':
main()
2024-02-28 14h30 utc
Board: Pimoroni pico DV Demo Base + Pimoroni Pico Lipo 16MB
Attached hardware: Spakfun qwiic Multiport and an Adafruit Gamepad QT
IDE: mu-editor V 1.2.0
>>>
soft reboot
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
board ID: pimoroni_pico_dv_base
global: seesaw.chip_id= 0x87
gamepad_test(): We're going to test the Gamepad QT and the pimoroni_pico_dv_base.
Press any of the buttons (A, B or C) on the pimoroni_pico_dv_base
or press any of the buttons (X, Y, A, B, Select or Start)
or move the joystick on the Gamepad QT.
To soft rerset pimoroni_pico_dv_base press Gamepad QT button Start.
To hard reboot pimoroni_pico_dv_base press the 'run' button on the base.
joystick: (x, y)= (504, 511)
Button X pressed
Button Y pressed
Button A pressed
Button B pressed
Button Start pressed
About to soft reset the pimoroni_pico_dv_base
Are you sure? (Y/n)+<Enter>: n
You answered: 'n'
gamepad_test(): We're going to test the Gamepad QT and the pimoroni_pico_dv_base.
Press any of the buttons (A, B or C) on the pimoroni_pico_dv_base
or press any of the buttons (X, Y, A, B, Select or Start)
or move the joystick on the Gamepad QT.
To soft rerset pimoroni_pico_dv_base press Gamepad QT button Start.
To hard reboot pimoroni_pico_dv_base press the 'run' button on the base.
main(): KeyboardInterrrupt. Exiting...
Code done running.
Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 9.0.0-beta.0 on 2024-01-27; Pimoroni Pico dv Base with rp2040
>>> [D
>>>
@PaulskPt
Copy link
Author

Image of the used: hardware

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