.. _beagley-ai-using-gpio: Using GPIO ################# .. todo:: Add information about software image used for this demo. **GPIO** stands for **General-Purpose Input/Output**. It's a set of programmable pins that you can use to connect and control various electronic components. You can set each pin to either **read signals (input)** from things like buttons and sensors or **send signals (output)** to things like LEDs and motors. This lets you interact with and control the physical world using code! A great resource for understanding pin numbering can be found at `pinout.beagley.ai `_ .. warning:: BeagleY-AI GPIOs are 3.3V tolerant, using higher voltages **WILL DAMAGE** the processor! Pin Numbering ********************** You will see pins referenced in several ways. While this is confusing at first, in reality, we can pick our favorite way and stick to it. The two main ways of referring to GPIOs is **by their number**, so GPIO 2, 3, 4 etc. as seen in the diagram below. This corresponds to the SoC naming convention. For broad compatibility, BeagleY-AI re-uses the Broadcom GPIO numbering scheme used by RaspberryPi. The second (and arguably easier) way we will use for this tutorial is to use the **actual pin header number** (shown in dark grey) So, for the rest of the tutorial, if we refer to **hat-08-gpio** we mean the **8th pin of the GPIO header**. Which, if you referenced the image below, can see refers to **GPIO 14 (UART TX)** .. figure:: ../images/gpio/pinout.png :align: center :alt: BeagleY-AI pinout BeagleY-AI pinout If you are curious about the "real" GPIO numbers on the Texas Instruments AM67A SoC, you can look at the board schematics. Required Hardware ****************** For the simple blink demo, all that is needed is an LED, a Resistor (we use 2.2K here) and 2 wires. Similarly, a button is used for the GPIO read example, but you can also just connect that pin to 3.3V or GND with a wire to simulate a button press. .. todo:: Add fritzing diagram and chapter on Pin Binding here GPIO Write *********** .. figure:: ../images/gpio/led-pin8.* :align: center :alt: LED connected to HAT Pin8 (GPIO14) LED connected to HAT Pin8 (GPIO14) At it's most basic, we can set a GPIO using the **gpioset** command. - To set HAT **Pin 8** (GPIO14) to **ON**: .. code:: console gpioset $(gpiofind GPIO14)=1 .. figure:: ../images/gpio/on.png :align: center :alt: GPIO ON state GPIO ON state - To set HAT **Pin 8** (GPIO14) to **OFF**: .. code:: console gpioset $(gpiofind GPIO14)=0 .. figure:: ../images/gpio/off.png :align: center :alt: GPIO OFF state GPIO OFF state Blink an LED ************** Let's create a script called **blinky.sh**, - Create the file, .. code:: console touch blinky.sh - Open the file using ``nano`` editor, .. code:: console nano blinky.sh - Copy paste the code below to ``blinky.sh`` file, .. code:: bash #!/bin/bash while : do gpioset $(gpiofind GPIO14)=1 sleep 1 gpioset $(gpiofind GPIO14)=0 sleep 1 done - Close the editor by pressing ``Ctrl + O`` followed by ``Enter`` to save the file and then press to ``Ctrl + X`` exit - Now execute the ``blinky.sh`` script by typing: .. code:: console bash blinky.sh .. figure:: ../images/gpio/blinky.gif :align: center :alt: LED blinking LED blinking - You can exit the ``blinky.sh`` progrm by pressing ``CTRL + C`` on your keyboard. Understanding the code ====================== .. callout:: .. code-block:: bash #!/bin/bash while : do gpioset $(gpiofind GPIO14)=1 <1> sleep 1 <2> gpioset $(gpiofind GPIO14)=0 <3> sleep 1 <4> done .. annotations:: The script is an infinite ``while`` loop in which we do the following: <1> set the HAT Pin 8 (GPIO14) as 1 (HIGH) <2> Wait 1 Second <3> set the HAT Pin 8 (GPIO14) as 0 (LOW) <4> Wait 1 Second Read a Button ************** A push button simply completes an electric circuit when pressed. Depending on wiring, it can drive a signal either "Low" (GND) or "High" (3.3V). We will connect our Button between HAT Pin 12 (GPIO18) and Ground (GND). .. figure:: ../images/gpio/switch-pin12.* :align: center :alt: Button connected to HAT Pin12 Button connected to HAT Pin12 (GPIO18) The cool part is since we have an internal pull-up resistor, we don't need an external one! The pull resistor guarantees that the Pin stays in a known (HIGH) state unless the button is pressed, in which case it will go LOW. - Reading GPIOs can be done using the ``gpioget`` command .. code:: console gpioget --bias=pull-up $(gpiofind GPIO18) Results in ``1`` if the Input is held ``HIGH`` or ``0`` if the Input is held ``LOW`` Let's create a script called ``button.sh`` to continuously read an input pin connected to a button and print out when it's pressed! - Create the file, .. code:: console touch button.sh - Open the file using ``nano`` editor, .. code:: console nano button.sh - Copy paste the code below to ``button.sh`` file, .. code:: bash #!/bin/bash while : do if (( $(gpioget --bias=pull-up $(gpiofind GPIO18)) == 0)) then echo "Button Pressed!" fi done - Close the editor by pressing ``Ctrl + O`` followed by ``Enter`` to save the file and then press to ``Ctrl + X`` exit - Now execute the ``button.sh`` script by typing: .. code:: console bash button.sh - You can exit the ``button.sh`` by pressing ``Ctrl + C`` on your keyboard. Combining the Two ********************** .. figure:: ../images/gpio/switch-pin12-led-pin8.* :align: center :alt: Button connected to HAT Pin12 (GPIO18) & LED connected to HAT Pin8 (GPIO14) Button connected to HAT Pin12 (GPIO18) & LED connected to HAT Pin8 (GPIO14) Now, logically, let's make an LED match the state of the button. Let's create a script called **blinkyButton.sh**: - Create the file, .. code:: console touch blinkyButton.sh - Open the file using ``nano`` editor, .. code:: console nano blinkyButton.sh - Copy paste the code below to ``blinkyButton.sh`` file, .. code:: bash #!/bin/bash while : do if (( $(gpioget --bias=pull-up $(gpiofind GPIO18)) == 0)) then gpioset $(gpiofind GPIO14)=1 else gpioset $(gpiofind GPIO14)=0 fi done - Close the editor by pressing ``Ctrl + O`` followed by ``Enter`` to save the file and then press to ``Ctrl + X`` exit - Now execute the ``blinkyButton.sh`` script by typing: .. code:: console bash blinkyButton.sh This means when we see HAT Pin 12 (GPIO18) go LOW, we know the button is pressed, so we set HAT Pin 8 (GPIO14) (our LED) to ON, otherwise, we turn it OFF. .. figure:: ../images/gpio/BlinkyButton.gif :align: center :alt: LED is ON when button is pressed LED is ON when button is pressed - You can exit the ``blinkyButton.sh`` program by pressing ``Ctrl + C`` on your keyboard. Understanding Internal Pull Resistors ******************************************* Pull-up and pull-down resistors are used in digital circuits to ensure that inputs to logic settle at expected levels. * ``Internal pull-up resistors`` connects the pin to a high voltage level (e.g., 3.3V) to ensure the pin input reads as a logic high (1) when no active device is pulling it low. * ``Internal pull-down resistors`` connects the pin to ground (GND) to ensure the input reads as a logic low (0) when no active device is pulling it high. These resistors prevent floating inputs and undefined states. By default, all GPIOs on the HAT Header are configured as **Inputs with Pull-up Resistors Enabled**. This is important for something like a button, as without it, once a button is released, it goes in an "undefined" state! To configure Pull-ups on a per-pin basis, we can use pass the following arguments within **gpioget or gpioset**: .. code:: console -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is') The "Bias" argument has the following options: * **as-is** - This leaves the bias as-is... quite self explanatory * **disable** - This state is also known as High-Z (high impedance) where the Pin is left Floating without any bias resistor * **pull-down** - In this state, the pin is pulled DOWN by the internal 50KΩ resistor * **pull-up** - In this state, the pin is pulled UP by the internal 50KΩ resistor For example, a command to read an input with the Bias intentionally disabled would look like this: .. code:: bash gpioget --bias=disable $(gpiofind GPIO14) Pull resistors are a foundational block of digital circuits and understanding when to (and not to) use them is important. This article from SparkFun Electronics is a good basic primer - `Link `_ Troubleshooting ******************* - **My script won't run!** Make sure you gave the script execute permissions first and that you're executing it with a ``./`` before - To make it executable: .. code:: bash chmod +X scriptName.sh - To run it: .. code:: bash ./scriptName.sh Bonus - Turn all GPIOs ON/OFF ******************************* .. figure:: ../images/gpio/allonoff.gif :align: center :alt: All HAT GPIO toggle All HAT GPIO toggle - Copy and paste this with the button on the right to turn **all pins ON**. .. code:: bash gpioset $(gpiofind GPIO14)=1 ;\ gpioset $(gpiofind GPIO15)=1 ;\ gpioset $(gpiofind GPIO17)=1 ;\ gpioset $(gpiofind GPIO18)=1 ;\ gpioset $(gpiofind GPIO27)=1 ;\ gpioset $(gpiofind GPIO22)=1 ;\ gpioset $(gpiofind GPIO23)=1 ;\ gpioset $(gpiofind GPIO24)=1 ;\ gpioset $(gpiofind GPIO10)=1 ;\ gpioset $(gpiofind GPIO9)=1 ;\ gpioset $(gpiofind GPIO25)=1 ;\ gpioset $(gpiofind GPIO11)=1 ;\ gpioset $(gpiofind GPIO8)=1 ;\ gpioset $(gpiofind GPIO7)=1 ;\ gpioset $(gpiofind GPIO1)=1 ;\ gpioset $(gpiofind GPIO6)=1 ;\ gpioset $(gpiofind GPIO12)=1 ;\ gpioset $(gpiofind GPIO13)=1 ;\ gpioset $(gpiofind GPIO19)=1 ;\ gpioset $(gpiofind GPIO16)=1 ;\ gpioset $(gpiofind GPIO26)=1 ;\ gpioset $(gpiofind GPIO21)=1 - Similarly, copy and paste this to turn **all pins OFF**. .. code:: bash gpioset $(gpiofind GPIO14)=0 ;\ gpioset $(gpiofind GPIO15)=0 ;\ gpioset $(gpiofind GPIO17)=0 ;\ gpioset $(gpiofind GPIO18)=0 ;\ gpioset $(gpiofind GPIO27)=0 ;\ gpioset $(gpiofind GPIO22)=0 ;\ gpioset $(gpiofind GPIO23)=0 ;\ gpioset $(gpiofind GPIO24)=0 ;\ gpioset $(gpiofind GPIO10)=0 ;\ gpioset $(gpiofind GPIO9)=0 ;\ gpioset $(gpiofind GPIO25)=0 ;\ gpioset $(gpiofind GPIO11)=0 ;\ gpioset $(gpiofind GPIO8)=0 ;\ gpioset $(gpiofind GPIO7)=0 ;\ gpioset $(gpiofind GPIO1)=0 ;\ gpioset $(gpiofind GPIO6)=0 ;\ gpioset $(gpiofind GPIO12)=0 ;\ gpioset $(gpiofind GPIO13)=0 ;\ gpioset $(gpiofind GPIO19)=0 ;\ gpioset $(gpiofind GPIO16)=0 ;\ gpioset $(gpiofind GPIO26)=0 ;\ gpioset $(gpiofind GPIO21)=0 Going Further ******************* * `pinout.beagley.ai `_ * `GPIOSet Documentation `_ * `GPIOGet Documentation `_