SparkFun Top pHAT Hookup Guide

Pages
Favorited Favorite 1

Button Controller

Note: This tutorial assumes you are using the latest version of Python 3. If this is your first time using Python or I2C hardware on a Raspberry Pi, please checkout our tutorial on Python Programming with the Raspberry Pi and the Raspberry Pi SPI and I2C Tutorial.

We've written a Python package to easily get setup and take readings from the button controller on the Top pHAT. There are two methods for installing the Python package for the button controller.

  1. Install the all inclusive SparkFun Qwiic Python package.
  2. Independently install the SparkFun Top pHAT Button Python package.

The all inclusive SparkFun Qwiic Python package, is recommended as is also installs the required I2C driver as well.

Note: Don't forget to double check that the hardware I2C connection is enabled on your Raspberry Pi or other single board computer.

SparkFun Qwiic Package

This repository is hosted on PyPi as the sparkfun-top-phat-button package. On systems that support PyPi installation via pip3 (use pip for Python 2) is simple, using the following commands:

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install sparkfun-qwiic

For the current user:

language:bash
pip3 install sparkfun-qwiic

Independent Installation

You can install the sparkfun-top-phat-button Python package independently, which is hosted by PyPi. However, if you prefer to manually download and install the package from the GitHub repository, you can grab them here (*Please be aware of any package dependencies. You can also check out the repository documentation page, hosted on ReadtheDocs.):

PyPi Installation

This repository is hosted on PyPi as the sparkfun-top-phat-button package. On systems that support PyPi installation via pip3 (use pip for Python 2) is simple, using the following commands:

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install sparkfun-top-phat-button

For the current user:

language:bash
pip3 install sparkfun-top-phat-button

Local Installation

To install, make sure the setuptools package is installed on the system.

Direct installation at the command line (use python for Python 2):

language:bash
python3 setup.py install

To build a package for use with pip3:

language:bash
python3 setup.py sdist

A package file is built and placed in a subdirectory called dist. This package file can be installed using pip3.

language:bash
cd dist
pip3 install sparkfun_top_phat_button-<version>.tar.gz

Python Package Operation

Before we jump into getting readings, let's take a closer look at the available functions in the Python package. Below, is a description of the basic functionality of the Python package. This includes the package organization, built-in methods, and their inputs and/or outputs. For more details on how the Python package works, check out the source code, the firmware, and package documentation.

Dependencies

This Python package has a very few dependencies in the code, listed below:

language:python
from __future__ import print_function
import qwiic_i2c

Default Variables

The default variables, in the code, for this Python package are listed below:

language:python
# Some devices have multiple availabel addresses - this is a list of these addresses.
# NOTE: The first address in this list is considered the default I2C address for the
# device.
_AVAILABLE_I2C_ADDRESS = [0x71]

# Register codes for the Joystick
BUTTON_ID               = 0x00
BUTTON_VERSION1         = 0x01
BUTTON_VERSION2         = 0x02
BUTTON_PRESSED          = 0x03
BUTTON_CLICKED          = 0x04
BUTTON_INTERRUPT        = 0x05
BUTTON_DEBOUNCE         = 0x06
BUTTON_CHANGE_ADDREESS  = 0x1F

# Define the bit positions of the buttons and interrupt flag
A                     = 0
B                     = 1
UP                    = 2
DOWN                  = 3
LEFT                  = 4
RIGHT                 = 5
CENTER                = 6
EVENT_AVAILABLE       = 7

# Define the positions of the Interrupt Enable Bits
CLICKED_INTERRUPT_ENABLE        = 0
PRESSED_INTERRUPT_ENABLE        = 1

Class

ToppHATButton() or ToppHATButton(address)
This Python package operates as a class object, allowing new instances of that type to be made. An __init__() constructor is used that creates a connection to an I2C device over the I2C bus using the default or specified I2C address.

The Constructor

A constructor is a special kind of method used to initialize (assign values to) the data members needed by the object when it is created.

__init__(address=None, i2c_driver=None):

Input: value
The value of the device address. If not defined, the Python package will use the default I2C address (0x71) stored under _AVAILABLE_I2C_ADDRESS variable.
Input: i2c_driver
Loads the specified I2C driver; by default the Qwiic I2C driver is used: qwiic_i2c.getI2CDriver(). Users should use the default I2C driver and leave this field blank.

Functions

A function that is an attribute of the class, which defines a method for instances of that class. In simple terms, they are objects for the operations (or methods) of the class.

.is_connected()
Determines if the button controller device is connected to the system.

Output: Boolean

True: Connected to I2C device on the default (or specified) address.
False: No device found or connected.

.begin()
Initialize the operation of the button controller. (Basically tests the connection to the button controller.)

Output: Boolean

True: The initialization was successful.
False: Initialization failed.

.get_button_pressed()
Updates and returns buffer for all buttons and whether or not they are pressed as well as the pressed interrupt flag.

    Reading this register also clears it.
    7(MSB)  6    5    4    3    2    1    0(LSB)
      INT  CTR  RGT  LFT  DWN   UP   B    A

Returns 1 bit when a button is currently being pressed, based on the mapping above. The interrupt must be cleared by the user.

Output: Integer

0: No interrupt; no buttons currently pressed.
1: No interrupt; only Button A is currently being pressed.
2: No interrupt; only Button B is currently being pressed.
3: No interrupt; Button A and Button B are currently being pressed./br> .
.
.
195: Interrupt; Button A and Button B are currently being pressed. The 5-way switch is currently being pressed with the Center pad.
196-255: Are not possible as the 5-way switch cannot indicate multiple directions.

.get_button_clicked()
Updates and returns buffer for all buttons and whether or not they have been clicked as well as the clicked interrupt flag.

    Reading this register also clears it.
    7(MSB)  6    5    4    3    2    1    0(LSB)
      INT  CTR  RGT  LFT  DWN   UP   B    A

Returns 1 when a button has received a full click cycle (press and release). The interrupt must be cleared by the user.

Output: Integer

0: No interrupt; no buttons were clicked.
1: No interrupt; only Button A was clicked.
2: No interrupt; only Button B was clicked.
3: No interrupt; Button A and Button B were clicked.
.
.
.
254: Interrupt; Button B was clicked. The 5-way switch, was clicked in all directions, including the Center pad.
255: Interrupt; Button A and Button B were clicked. The 5-way switch, was clicked in all directions, including the Center pad.

.get_version()
Returns a string of the firmware version number.

Output: String

The firmware version

.get_pressed_interrupt()
Returns the status of the pressed interrupt enable.

Output: Boolean

The value of the interrupt enable bit.

.set_pressed_interrupt(bit_setting)
Sets the status of the pressed interrupt enable bit.

Input: Boolean

0: The pressed interrupt enable bit.
1: The pressed interrupt enable bit.

Output: Boolean

0: I2C transaction failed, the interrupt enable bit wasn't set.
1: I2C transaction succeeded, the interrupt enable bit was set.

.get_clicked_interrupt()
Returns the status of the clicked interrupt enable.

Output: Boolean

The value of the clicked interrupt enable bit.

.set_clicked_interrupt(bit_setting)
Sets the status of the clicked interrupt enable bit.

Input: Boolean

0: The clicked interrupt enable bit.
1: The clicked interrupt enable bit.

Output: Boolean

0: I2C transaction failed, the interrupt enable bit wasn't set.
1: I2C transaction succeeded, the interrupt enable bit was set.

Upgrading the Python Package

In the future, changes to the Python package might be made. Updating the installed packages has to be done individually for each package (i.e. sub-modules and dependencies won't update automatically and must be updated manually). For the sparkfun-top-phat-button Python package, use the following command (use pip for Python 2):

For all users (note: the user must have sudo privileges):

language:bash
sudo pip3 install --upgrade sparkfun-top-phat-button

For the current user:

language:bash
pip3 install --upgrade sparkfun-top-phat-button

Python Examples

There are two examples written for the Top pHAT using this Python package. They can be found in the GitHub repository or viewed in the ReadtheDocs documentation

Example 1

Example 1 utilizes the interrupt for more immediate responses.

#!/usr/bin/env python
#-----------------------------------------------------------------------------
# top_phat_button_ex1.py
#
# Polling example for the Top pHAT Buttons
#------------------------------------------------------------------------
#
# Written by  SparkFun Electronics, April 2020
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 1
#

from __future__ import print_function
import top_phat_button
import time
import sys

myButtons = top_phat_button.ToppHATButton()

def runExample():

    print("\nSparkFun Top pHAT Button  Example 1\n")

    if myButtons.is_connected() == False:
        print("The Top pHAT Button device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return

    myButtons.pressed_interrupt_enable = False
    myButtons.clicked_interrupt_enable = False

    while True:
        myButtons.button_pressed #These functions must be called to update button variables to their latest setting
        myButtons.button_clicked #These functions must be called to update button variables to their latest setting  
        if myButtons.a_pressed == True:
            print("A Pressed")
        if myButtons.a_clicked == True:
            print("A Released")
        if myButtons.b_pressed == True:
            print("B Pressed")
        if myButtons.b_clicked == True:
            print("B Released")
        if myButtons.up_pressed == True:
            print("Up Pressed")
        if myButtons.up_clicked == True:
            print("Up Released")
        if myButtons.down_pressed == True:
            print("Down Pressed")
        if myButtons.down_clicked == True:
            print("Down Released")
        if myButtons.left_pressed == True:
            print("Left Pressed")
        if myButtons.left_clicked == True:
            print("Left Released")
        if myButtons.right_pressed == True:
            print("Right Pressed")
        if myButtons.right_clicked == True:
            print("Right Released")
        if myButtons.center_pressed == True:
            print("Center Pressed")
        if myButtons.center_clicked == True:
            print("Center Released")

        time.sleep(.1)


if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 1")
        sys.exit(0)

Example 2

Example 2 doesn't utilize the interrupt and must constantly ping the button controller for updates on potential actions performed on the buttons.

#!/usr/bin/env python
#-----------------------------------------------------------------------------
# top_phat_button_ex2.py
#
# Interrupt example for the Top pHAT Buttons
#------------------------------------------------------------------------
#
# Written by  SparkFun Electronics, April 2020
# 
# This python library supports the SparkFun Electroncis qwiic 
# qwiic sensor/board ecosystem on a Raspberry Pi (and compatable) single
# board computers. 
#
# More information on qwiic is at https://www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================
# Example 2
#

from __future__ import print_function
import top_phat_button
import time
import sys
import RPi.GPIO as GPIO

INTERRUPT_PIN = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(INTERRUPT_PIN, GPIO.IN)

myButtons = top_phat_button.ToppHATButton()

def interruptCallback(channel):
    myButtons.button_pressed
    myButtons.button_clicked #Both interrupts are configured, so we need to read both registers to clear the interrupt and update our button data.   
    if myButtons.a_pressed == True:
        print("A Pressed")
    if myButtons.a_clicked == True:
        print("A Released")
    if myButtons.b_pressed == True:
        print("B Pressed")
    if myButtons.b_clicked == True:
        print("B Released")
    if myButtons.up_pressed == True:
        print("Up Pressed")
    if myButtons.up_clicked == True:
        print("Up Released")
    if myButtons.down_pressed == True:
        print("Down Pressed")
    if myButtons.down_clicked == True:
        print("Down Released")
    if myButtons.left_pressed == True:
        print("Left Pressed")
    if myButtons.left_clicked == True:
        print("Left Released")
    if myButtons.right_pressed == True:
        print("Right Pressed")
    if myButtons.right_clicked == True:
        print("Right Released")
    if myButtons.center_pressed == True:
        print("Center Pressed")
    if myButtons.center_clicked == True:
        print("Center Released")

GPIO.add_event_detect(INTERRUPT_PIN, GPIO.FALLING, callback=interruptCallback, bouncetime=5)

def runExample():

    print("\nSparkFun Top pHAT Button  Example 1\n")

    if myButtons.is_connected() == False:
        print("The Top pHAT Button device isn't connected to the system. Please check your connection", \
            file=sys.stderr)
        return

    myButtons.pressed_interrupt_enable = True
    myButtons.clicked_interrupt_enable = True #Enable both hardware interrupts

    while True:

        time.sleep(.1)


if __name__ == '__main__':
    try:
        runExample()
    except (KeyboardInterrupt, SystemExit) as exErr:
        print("\nEnding Example 1")
        sys.exit(0)