Skip to content

Commit

Permalink
Add new GPIO tutorials from Jonathan
Browse files Browse the repository at this point in the history
  • Loading branch information
omckeon committed Jul 9, 2024
1 parent 774ba03 commit e91c8b0
Show file tree
Hide file tree
Showing 23 changed files with 1,722 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/gifs/guides/gpio-tutorial-gifs/pwm_led.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/content/docs/guides/json/2-json_writing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ sidebar:
import { Tabs, TabItem } from "@astrojs/starlight/components";

**{frontmatter.description}**
_Written by {frontmatter.author} on {frontmatter.lastupdated}_
Written by: {frontmatter.author}
_Last updated: {frontmatter.lastupdated}_

---

Expand Down
356 changes: 356 additions & 0 deletions src/content/docs/guides/raspberry/0-blink-led.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
---
title: Get Started with SplashKit GPIO
description: General-purpose input/output, or GPIO, pins are a type of pin found on many microcontrollers that can be used for a variety of purposes. In this guide we use them to control the state of an LED
category: Guides
author: Jonathan Tynan
lastupdated: Apr 27 2024
---

import { Tabs, TabItem } from "@astrojs/starlight/components";

**{frontmatter.description}**
Written by: {frontmatter.author}
_Last updated: {frontmatter.lastupdated}_

---

:::caution[Before you begin:]
When working with Raspberry Pi GPIO pins, it's crucial to handle the
setup and cleanup processes carefully.

- Always ensure that the GPIO pins are properly initialised before use and cleaned up afterwards to
prevent any damage to your Raspberry Pi
- Be mindful of static electricity which can pose a serious risk to the sensitive electronic
components on the board
- Before touching the Raspberry Pi or any connected components, ground yourself to eliminate any
static charge that may have accumulated.

These precautions help to ensure your device is protected from potential harm caused by electrostatic
discharges.
:::

General-purpose input/output, or GPIO, pins are a type of pin found on many microcontrollers that
can be used for a variety of purposes. These pins can be used to receive signals from sensors, or
send them to control LEDs or motors, and so much more. The ability to effectively use these
interfaces enables a huge range of interesting projects with real-world impact. In this guide,
we cover the basics of GPIO pins and how to use them in your projects.

In a Raspberry Pi all pins are digital and individual GPIO pins are defined with two unique numbers,
the physical pin number and the Broadcom SOC Channel (BCM) pin number. They can be found on the
internet by searching for a "Raspberry Pi Pinout". In SplashKit, we use the physical pin numbers to
reference the GPIO pins.

:::tip[Digital Signals]
As mentioned previously, the GPIO pins on a Raspberry Pi are all digital, this means that it can
either be powered at a certain voltage or unpowered, which can then be read as a one or zero. In
analog signals the voltage continuously varies, however this needs particular hardware which the
Raspberry Pi lacks and is out of the scope of this guide.
:::

## Components

### Breadboard

Breadboards are reusable devices used to build and test circuits. They are made up of a number of
holes that are connected by hidden metal strips. Along the top and bottoms are the ground and power
rails, and in the middle there are two sections separated by a channel. Each hole in a section is
connected to the adjacent vertical holes. More information can be found at
[How to Use a Breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all).

### LED

An LED (Light Emitting Diode) is a device that emits light when an electric current passes through
it. They feature two legs, a longer positive leg (the [anode](https://en.wikipedia.org/wiki/Anode))
and a shorter negative leg (the [cathode](https://en.wikipedia.org/wiki/Cathode)). The longer leg is
often kinked so that both legs protrude the same distance from the LED. To use it we connect the positive
lead to the GPIO pin and the negative lead to a ground pin. More information can be found at
[Light-Emitting Diodes (LEDs)](https://learn.sparkfun.com/tutorials/light-emitting-diodes-leds/all)

### 220 Ω Resistor

The power that the Raspberry Pi can provide is actually too much for these LEDs. To prevent the LED
from burning out, we must add a resistor to the circuit. The resistor limits the current that
flows through the LED, preventing it from burning out. The exact value of the resistor is not
critical, but too high a value does not allow enough illumination of the LED. A resistor in the
range of 220 Ω to 1 kΩ should work well. More information on resistors can be found at
[Sparkfun - Resistors](https://learn.sparkfun.com/tutorials/resistors/all)

:::tip[Resistor Colour Code]
The colours on a resistor indicate the resistance value. Each coloured band corresponds to specific
numbers and multipliers which can be used to calculate the resistance value. More information
can be found at [Electronic Colour Code](https://en.wikipedia.org/wiki/Electronic_color_code)
:::

### Jumper Wires

Jumper Wires, or DuPont wires, are used to make a temporary connection different components. They
can be M/M, M/F, or F/F. We are using M/F jumper wires in this guide.

## The Circuit

Below we can see the circuit diagram for this project. We have the cathode of the LED connected to
GPIO Pin 11, while the anode is connected to ground pin 6 through a resistor.

![Circuit Diagram for Blinking an LED](./images/circuits/blinkled.png)

And the physical circuit looks like the following image, in which we've connected an M/F jumper wire
from Pin 11 to the cathode of the LED. The anode of the LED is connected to the resistor, which is
then connected to the ground pin through another M/F jumper wire.

![Photograph of a circuit to blink an LED](./images/circuits/blink_led_circuit.jpg)

## Starting the Daemon

:::tip[Daemons]
A daemon is a background process that runs continuously, waiting for requests to
perform some action. In this case, the daemon is waiting for requests to change the state of the
GPIO pins. This allows us to run multiple programs that interact with the GPIO pins.
:::

Underneath SplashKit we use the [Pigpio library](https://abyz.me.uk/rpi/pigpio), specifically its
daemon. To interface with this daemon, it must be running. If it is not running we can expect
some output like the following:

```shell
gpio_init() must be called before any other GPIO functions
```

We can check if its running by using the following command:

```shell
ps aux | grep pigpiod
```

If the daemon is not running, we can start it by using:

```shell
sudo pigpiod
```

To stop the daemon from running we can use the command:

```shell
sudo killall pigpiod
```

## The Code

After the daemon is running, we can then create our program. Below is an example program that
blinks an LED on and off.

<Tabs syncKey="code-language">
<TabItem label="C++">

```cpp
#include "splashkit.h"

int main()
{
raspi_init();
pins led_pin = PIN_11;
raspi_set_mode(led_pin, GPIO_OUTPUT);

open_window("dummy_window", 1, 1);
while(!any_key_pressed())
{
process_events();
raspi_write(led_pin, GPIO_HIGH);
delay(500);
raspi_write(led_pin, GPIO_LOW);
delay(500);
}

close_all_windows();
raspi_cleanup();
return 0;
}
```
</TabItem>
<TabItem label="C#">
```csharp
using SplashKitSDK;
using static SplashKitSDK.SplashKit;
RaspiInit();
Pins ledPin = (Pins)11;
RaspiSetMode(led_pin, (PinModes) 1);
OpenWindow("dummy_window", 1, 1);
while(!AnyKeyPressed())
{
ProcessEvents();
RaspiWrite(led_pin, (PinState) 1);
Delay(500);
RaspiWrite(led_pin, (PinState) 0);
Delay(500);
}
CloseAllWindows();
RaspiCleanup();
```

</TabItem>
</Tabs>

### Understanding the code

To understand this code better, lets break it down and explore each section.

1.
<Tabs syncKey="code-language">
<TabItem label="C++">

```cpp
raspi_init();
pins led_pin = PIN_11;
raspi_set_mode(led_pin, GPIO_OUTPUT);
```

</TabItem>
<TabItem label="C#">

```csharp
RaspiInit();
Pins ledPin = (Pins)11;
RaspiSetMode(led_pin, (PinModes) 1);
```

</TabItem>
</Tabs>

In this bit of the code we're setting up the hardware, we call [Raspi Init](/api/raspberry/#raspi-init) to initialise the GPIO pins,
and then we define the specific pin we're using which is Pin 11 in this case and it is of the [Pins](/api/types/#pins) type.

We pass this value to [Raspi Set Mode](/api/raspberry/#raspi-set-mode) along with `GPIO_OUTPUT` which sets the pin to be ready to output a signal on our command. The `GPIO_OUTPUT` value is one of the [Pin Modes](/api/types/#pin-modes) that can be set. Each pin has alternative modes but we are only interested in the output mode for now.

2.
<Tabs syncKey="code-language">
<TabItem label="C++">

```cpp
open_window("dummy_window", 1, 1);
while(!any_key_pressed())
{
process_events();
...
}

```

</TabItem>
<TabItem label="C#">

```csharp
OpenWindow("dummy_window", 1, 1);
while(!AnyKeyPressed())
{
ProcessEvents();
...
}
```

</TabItem>
</Tabs>

This is a small trick we can do to recognise keyboard inputs. We open up a dummy window using [Open Window](/api/windows/#open-window) and this initialises the backend so that we can detect input. We'll create a loop that runs while [Any Key Pressed](/api/input/#any-key-pressed) returns false. We use [Process Events](/api/input/#process-events) at the start of the loop to actually detect any user input. We can now press a key to end the program and ensure we cleanup correctly.

3.
<Tabs syncKey="code-language">
<TabItem label="C++">

```cpp
raspi_write(led_pin, GPIO_HIGH);
delay(500);
raspi_write(led_pin, GPIO_LOW);
delay(500);
```

</TabItem>
<TabItem label="C#">

```csharp
RaspiWrite(led_pin, (PinState) 1);
Delay(500);
RaspiWrite(led_pin, (PinState) 0);
Delay(500);
```

</TabItem>
</Tabs>

Now that we've setup our pins and defined our end condition, we can now manipulate the LED. Inside the while loop we first use [Raspi Write](/api/raspberry/#raspi-write) to change the output of our pin to `GPIO_HIGH`, one of the [Pin Values](/api/types/#pin-values). Doing this provides electricity to the LED and turn it on. We then wait for half a second using [Delay](/api/utilities/#delay). Then we turn our LED off using [Raspi Write](/api/raspberry/#raspi-write), but now we use `GPIO_LOW`, and wait for another half-second.

4.
<Tabs syncKey="code-language">
<TabItem label="C++">

```cpp
close_all_windows();
raspi_cleanup();
return 0;
```

</TabItem>
<TabItem label="C#">

```csharp
CloseAllWindows();
RaspiCleanup();
```

</TabItem>
</Tabs>

Finally, as we exit the program we must ensure that we cleanup our program properly. We must first close the dummy window we opened use [Close All Windows](/api/windows/#close-all-windows). We then call [Raspi Cleanup](/api/raspberry/#raspi-cleanup) to ensure our pins are turned off and cleaned.

:::tip[Program Shutdown]
It is crucial we plan for the program's shutdown procedure, because if we instead used `CTRL + C` to stop the program then cleanup is not performed and the GPIO pins remain in the same state they were in when the program was stopped. We do not want to unintentionally keep pins active.
:::

### Build and run the code

We can build this program with the following command:

<Tabs syncKey="code-language">
<TabItem label="C++">

```shell
g++ led_blink.cpp -l SplashKit -o led_blink
```

</TabItem>
<TabItem label="C#">

```shell
dotnet build
```

</TabItem>
</Tabs>

Then we run the program with the following command:

<Tabs syncKey="code-language">
<TabItem label="C++">

```shell
./led_blink
```

</TabItem>
<TabItem label="C#">

```shell
dotnet run
```

</TabItem>
</Tabs>

This code blinks the LED on and off as you can see below. This continues until the 10 seconds has
elapsed, and after we exit the while loop, [Raspi Cleanup](/api/raspberry/#raspi-cleanup) is
called and the GPIO pins are reset.

![A GIF of the LED blinking on and off.](/gifs/guides/gpio-tutorial-gifs/blink_led.gif)
Loading

0 comments on commit e91c8b0

Please sign in to comment.