Video summary
In this episode of CircuitPython Parsec, the focus is on integrating a Seesaw Gamepad into a CircuitPython project to efficiently read both analog joystick data and digital button inputs. The gamepad features a PCB with six buttons and an analog thumbstick that functions essentially as two potentiometers for X and Y axes. Rather than requiring complex wiring with multiple individual connections, the device utilizes a simple STEMMA QT cable connected via I2C, making it easy to interface with boards like the Metro M7. This setup allows the microcontroller to quickly capture real-time data, displaying analog values ranging from 0 to 1023 for the joystick and simultaneously monitoring the states of all six buttons, including directional keys and action buttons like start and select.
The core functionality is achieved through the Adafruit Seesaw library, which leverages the onboard coprocessor to handle input/output checking without burdening the main processor. The code establishes an I2C bus connection to the Seesaw chip and configures specific pins for bulk reading, ensuring that all six button states are captured simultaneously as a single bit mask. Additionally, the analog sensors are configured with a "slop" factor of three, meaning the system only registers a change in joystick position if the value shifts by at least that amount, which helps filter out minor electrical noise or jitter. This efficient communication method allows for rapid data transmission over I2C, containing all necessary information about button presses and analog adjustments in compact messages.
To process this incoming data, the script initializes lists to map pin numbers to their corresponding button names, enabling a user-friendly readout that displays readable labels instead of raw pin indices. Within the main loop, the code reads the analog values from specific pins for the X and Y axes, inverting the logic so that 0 represents one extreme of the stick and 1023 the other. The program then compares current readings against previously stored values to detect changes; if the joystick position shifts significantly or any button state toggles, the system updates the display with the new thumbstick coordinates and the list of currently pressed buttons.
By storing the last known states for both analog positions and button inputs, the code ensures that text is only printed when actual changes occur, preventing screen clutter from constant noise. This approach simplifies the process of reading gamepad states within a CircuitPython environment, demonstrating how the Seesaw board can serve as a versatile input device for various projects. Ultimately, this tutorial provides a clear and practical method for developers to implement responsive game controls using I2C communication, highlighting the efficiency of the Seesaw architecture in handling multiple inputs with minimal code complexity.
Read the full video transcript
For the Circuit Python Parsec today, I
wanted to talk about using the Seesaw
Gamepad inside of Circuit Python to read
analog joystick and digital buttons. So,
you can see what I'm talking about right
here. This is a little Gamepad PCB that
will more put together that has six
buttons on it and it has a little thumb
stick, which is essentially two
potentiometers for X and for X to the
side and Y up down. However, simplified
wiring it's not
a series of eight or 10 things plugged
into the board. It's just I squared C.
So, it uses little STEMMA QT cable. You
can also break it out out down across
the bottom. I have it plugged into a
Metro M7 here just for fun. Why not? The
M7 doesn't get enough love. And the way
this works, if you look in my REPL,
you're going to see I'm recording the XY
values of 0 to 1023 and 0 to 1023 and a
mix of those. And then if I press
buttons, we've got the B button, the A
button, the X, the Y, all four of those
as well as start and select. So, I can
press any and all of those buttons and
you can see I can read them really,
really quickly. The way that we do this
is in Circuit Python. Let me make this a
little bigger.
Oops.
Like that. In Circuit Python, I am
importing this library, Adafruit Seesaw.
Seesaw allows us to use the little
coprocessor on here to do all of the IO
checking to see when buttons have been
pressed or when the analog sensors
are are adjusted or the analog voltages
are adjusted. And then send out little
contained messages over I squared C very
quickly that contain all of that info.
It's actually three little interactions.
We get all of the buttons as a bit mask.
So, hey, any button state, we're going
to get them all. And then what's Y up to
and what's X up to on the analog. Uh to
do this, I'm setting up a little list
here of the button numbers or pin
numbers on the seesaw chip, as well as
their button names, so that I can print
those out. And then I'm creating this
button mask that'll return the state of
all six buttons uh all at once anytime I
press one or or more of them. And then
I'm setting up the I2C bus to connect
creating the seesaw object as seesaw I2C
bus and the address that it's on. Uh I
think this one you might be able to use
multiple of them with a address jumper.
We have probably do like four of them.
There's two address jumpers there. And
then I am setting the pin mode bulk, and
that's what says I'm going to check all
six of those
uh button pins, and this is as a input
pull-up. They're all input pull-ups.
Then I'm doing a little bit of setup for
uh state on the analog sensors, so that
we only update when it's changed by
enough by uh a value of three is just
the little slop factor that I have on
there. And then for printing, we have a
couple of lines that we're going to
fill, and that's uh
that's these initially blank lines here
that get filled by the print. Uh in the
main loop, I'm saying X is equal to 1023
minus the seesaw analog read on pin 14,
and Y is 1023 minus the seesaw analog
read on 15. And then the buttons are
this bulk read. I say that set of of
pins, and it grabs them all.
Uh then in a
uh another list I create called pressed,
I have the names of the pins uh for the
names of the buttons, and that's what
gives me a nice readout down at the
bottom here, uh where we see, rather
than pin numbers, we get the pin names.
Uh and then here's where we check to see
if anything changes. So, we're only
going to print new text if something has
changed, uh and that is if the
uh
essentially X is different enough from
the last read uh by three or more and
same with the Y or if any of the pressed
states have changed. When that happens,
we're then going to grab this joy line
and construct the thumb stick X equals
whatever that value was and the thumb
stick Y from whatever that value was and
then the buttons line is any of those
buttons state pressed or not. And then
the
state is set for last X and last Y and
last pressed. So that's how we can very
simply read the state of any of the
buttons on a little seesaw board in this
case the game pad cutie over I squared C
inside of circuit python. And that's
your circuit python parsec.