Skip to content
4 changes: 4 additions & 0 deletions Documentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ While contributing, you should read the [coding guidelines section](https://gith

### General-Purpose Input/Output (GPIO)

* [GPIO Protocol Guide](./protocols/gpio.md) - Quick start, GpioController usage, and troubleshooting
* [GPIO Basics](./fundamentals/gpio-basics.md) - Digital I/O concepts, pull resistors, voltage levels
* [Choosing the Right Driver](./fundamentals/choosing-drivers.md) - LibGpiodDriver vs SysFsDriver comparison
* [Using libgpiod to control GPIOs](./gpio-linux-libgpiod.md) - libgpiod library versions and installation
* [GPIO Wiki](https://en.wikipedia.org/wiki/General-purpose_input/output)
* [Digital I/O Fundamentals](http://www.ni.com/white-paper/3405/en/#toc1)

Expand Down
168 changes: 168 additions & 0 deletions Documentation/fundamentals/choosing-drivers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Choosing the Right GPIO Driver

When working with GPIO on Linux systems, .NET IoT offers different driver implementations. This guide helps you understand the differences and choose the right driver for your project.

## Quick Answer

For most users, you do not need to choose a driver at all. The parameterless constructor auto-detects the best driver for your board:

```csharp
// Recommended — works on all supported boards
using GpioController controller = new();
```

Read on if you need to understand what happens under the hood, or if auto-detection does not work for your board.

## Available Drivers

### LibGpiodDriver (Recommended)

Uses the modern `libgpiod` library to access GPIO through the Linux character device interface.

**Use LibGpiodDriver when:**

- Using modern Linux kernels (4.8+)
- Running on Raspberry Pi OS (Bullseye, Bookworm, or later)
- Multiple processes may access GPIO simultaneously
- You want the best-maintained and most future-proof solution

### LibGpiodV2Driver

Same concept as `LibGpiodDriver`, but targets libgpiod version 2.x (the library's API changed between v1 and v2).

**Use LibGpiodV2Driver when:**

- Your system has libgpiod 2.x installed (common on newer distributions)

### SysFsDriver (Deprecated)

Uses the older `/sys/class/gpio` interface, which is deprecated in modern Linux kernels.

**Use SysFsDriver when:**

- Stuck on very old Linux kernels (pre-4.8)
- **Not recommended for new projects**

## Driver Comparison

| Feature | LibGpiodDriver | SysFsDriver |
| --- | --- | --- |
| **Status** | Active, Recommended | Deprecated |
| **Kernel Version** | 4.8+ | All |
| **Performance** | Better | Good |
| **Multi-process** | Safe | Unsafe |
| **Resource Cleanup** | Automatic | Manual |
| **Future Support** | Yes | No (being removed) |

## Auto-Detection

When you use `new GpioController()`, the framework automatically selects the best driver:

| Board | Driver selected |
| --- | --- |
| Raspberry Pi 3 / 4 | `RaspberryPi3Driver` |
| Raspberry Pi 5 | `LibGpiodDriver` (with correct GPIO chip) |
| Other Linux boards | Tries `LibGpiodDriver` → `LibGpiodV2Driver` → `SysFsDriver` |

```csharp
// Let the framework choose the best driver for your board
using GpioController controller = new();
```

## Explicit Driver Selection

If auto-detection does not work, pass a driver to the `GpioController` constructor:

```csharp
using System.Device.Gpio;
using System.Device.Gpio.Drivers;

// LibGpiodDriver for libgpiod v1 (chip number 0 on most boards)
using GpioController controller = new(new LibGpiodDriver(gpioChip: 0));

// LibGpiodV2Driver for libgpiod v2
using GpioController controller = new(new LibGpiodV2Driver(chipNumber: 0));
```

### Finding Your Chip Number

Different boards expose GPIO on different chip numbers. Use the `gpioinfo` command to list available chips:

```bash
gpioinfo
```

- **Raspberry Pi 3/4:** chip number **0** (`gpiochip0`)
- **Raspberry Pi 5:** chip number **4** (`gpiochip4`)

## Installing libgpiod

Most Raspberry Pi OS images come with libgpiod pre-installed. If not:

```bash
sudo apt update
sudo apt install libgpiod2
```

To check which version is installed:

```bash
apt show libgpiod2
```

For building from source or more detail on library versions, see [Using libgpiod to control GPIOs](../gpio-linux-libgpiod.md).

## Permission Configuration

If you get "Permission denied" errors when accessing GPIO:

```bash
# Add your user to the gpio group
sudo usermod -aG gpio $USER

# Log out and log back in, then verify
groups
```

## Troubleshooting

### "libgpiod not found" / DllNotFoundException

```bash
sudo apt install libgpiod2
```

### Wrong Chip Number (Raspberry Pi 5)

Raspberry Pi 5 uses chip **4** instead of 0. If auto-detection does not work:

```csharp
using GpioController controller = new(new LibGpiodDriver(gpioChip: 4));
```

### Driver Version Mismatch

If you get errors, check your installed libgpiod version and use the matching driver class:

- libgpiod 0.x–1.x → `LibGpiodDriver`
- libgpiod 2.x → `LibGpiodV2Driver`

## Summary

| Situation | What to use |
| --- | --- |
| New project, any supported board | `new GpioController()` |
| Need a specific chip number | `new GpioController(new LibGpiodDriver(gpioChip: N))` |
| System has libgpiod 2.x only | `new GpioController(new LibGpiodV2Driver(chipNumber: N))` |
| Very old kernel (pre-4.8) | `new GpioController(new SysFsDriver())` |

## Next Steps

- [GPIO Basics](gpio-basics.md) — Fundamentals of digital I/O, pull resistors, voltage levels
- [GPIO Protocol Guide](../protocols/gpio.md) — Quick start example and GpioController usage
- [libgpiod Usage Guide](../gpio-linux-libgpiod.md) — Detailed libgpiod installation and version info

## Additional Resources

- [libgpiod Documentation](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about/)
- [Linux GPIO Documentation](https://www.kernel.org/doc/html/latest/driver-api/gpio/index.html)
200 changes: 200 additions & 0 deletions Documentation/fundamentals/gpio-basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# GPIO Basics

General-Purpose Input/Output (GPIO) pins are the foundation of IoT hardware interfacing. They are programmable electrical pins on single-board computers like the Raspberry Pi that let your .NET code interact with physical hardware — turning LEDs on and off, reading button presses, and communicating with sensors.

This guide explains the essential concepts you need to understand when working with GPIO pins in .NET IoT.

## What is GPIO?

GPIO pins are programmable pins on your single-board computer that can:

- **Output digital signals** — Turn devices on/off (LEDs, relays, motors)
- **Read digital signals** — Detect button presses, sensor states
- **Generate PWM signals** — Control brightness, speed (requires specific PWM-capable pins)
- **Communicate via protocols** — I2C, SPI, UART (requires specific pins)

GPIO pins operate with digital logic levels (HIGH/LOW):

- **HIGH** = 3.3 V on Raspberry Pi (varies by platform)
- **LOW** = 0 V (Ground)

## Pin Numbering

There are two ways to refer to pins, which can be confusing at first:

| Scheme | Example | Description |
| --- | --- | --- |
| **GPIO / BCM** | `18` | The number used by the Broadcom chip — **this is what .NET IoT uses** |
| **Physical / Board** | `12` | The physical position on the 40-pin header |

GPIO 18 and physical pin 12 are the **same pin** — just identified differently. Your code always uses **GPIO (BCM) numbers**.

Use the interactive diagram at [pinout.xyz](https://pinout.xyz/) to look up the mapping for your board.

## Digital Output

Digital output means setting a pin to either HIGH (3.3 V) or LOW (0 V). That is all digital output does: voltage on or voltage off.

```csharp
using System.Device.Gpio;

using GpioController controller = new();
controller.OpenPin(18, PinMode.Output);

controller.Write(18, PinValue.High); // 3.3 V — turns the LED on
controller.Write(18, PinValue.Low); // 0 V — turns the LED off
```

You can use this to drive LEDs, buzzers, relays, and any component that responds to a high/low signal.

### Driving an LED

LEDs require a current-limiting resistor to prevent damage:

```text
GPIO Pin ──► LED (Anode/+) ──► LED (Cathode/−) ──► Resistor (220 Ω) ──► Ground
```

> **Why a resistor?** LEDs need very little current. Without a resistor, the LED draws too much current and can burn out or damage your Pi. A 220 Ω resistor limits the current to a safe level (~6 mA).

## Digital Input

Digital input means reading whether a pin is HIGH or LOW.

```csharp
using System.Device.Gpio;

using GpioController controller = new();
controller.OpenPin(17, PinMode.InputPullUp);

PinValue value = controller.Read(17);
if (value == PinValue.Low)
{
Console.WriteLine("Button is pressed!");
}
```

### Pull-Up and Pull-Down Resistors

When a button is **not** pressed, the pin is not connected to anything. In plain `Input` mode, this leaves the pin "floating" — its voltage drifts randomly, giving unreliable readings.

Pull-up and pull-down resistors solve this by defining a default voltage:

| Mode | Default state (not pressed) | Pressed state | Wiring |
| --- | --- | --- | --- |
| `InputPullUp` | High (3.3 V) | Low (0 V) | Button connects pin to Ground |
| `InputPullDown` | Low (0 V) | High (3.3 V) | Button connects pin to 3.3 V |

`InputPullUp` is the most common choice for buttons. The Raspberry Pi has built-in pull-up resistors that are activated when you use this mode — no external resistor required.

```csharp
controller.OpenPin(17, PinMode.InputPullUp);

// When button is NOT pressed: reads HIGH
// When button IS pressed: reads LOW (inverted logic)
if (controller.Read(17) == PinValue.Low)
{
Console.WriteLine("Button pressed");
}
```

### Button Wiring (with InputPullUp)

```text
GPIO 17 ──► one leg of button
GND ──► other leg of button
```

When the button is pressed, GPIO 17 gets connected to Ground (Low). When released, the internal pull-up resistor pulls it back to High.

## Interrupt-Driven Input (Events)

Instead of checking the pin over and over in a loop (polling), you can register a callback that fires when the pin's value changes. This is more efficient and more responsive:

```csharp
using System.Device.Gpio;

using GpioController controller = new();
controller.OpenPin(17, PinMode.InputPullUp);

controller.RegisterCallbackForPinValueChangedEvent(
17,
PinEventTypes.Falling, // trigger on button press (HIGH → LOW)
(sender, args) =>
{
Console.WriteLine($"Button pressed on pin {args.PinNumber}");
});

Console.WriteLine("Press the button. Ctrl+C to exit.");
Thread.Sleep(Timeout.Infinite);
```

**Event types:**

- `PinEventTypes.Rising` — LOW → HIGH transition
- `PinEventTypes.Falling` — HIGH → LOW transition
- `PinEventTypes.Rising | PinEventTypes.Falling` — both directions

> **Note:** Physical buttons "bounce" — a single press can generate several rapid transitions. If you experience duplicate button events, you need debouncing. A simple approach is to ignore events that arrive within a short time window (e.g., 50 ms) of the previous event.

## Current and Voltage Limitations

### Raspberry Pi GPIO Specifications

- **Output Voltage:** 3.3 V (not 5 V!)
- **Max current per pin:** ~16 mA (safe limit)
- **Max total current (all pins):** ~50 mA
- **Input voltage tolerance:** 0 V to 3.3 V (**5 V will damage the pin!**)

### Connecting 5 V Devices

**Never connect 5 V signals directly to GPIO pins!** Use one of these solutions:

1. **Voltage divider** (for input signals)
2. **Level shifter** (bidirectional, for I2C/SPI)
3. **Transistor/MOSFET** (for high-current outputs)

### Driving High-Current Devices

For loads exceeding 16 mA (motors, relays, high-power LEDs), use a transistor or MOSFET as a switch powered from an external supply. The GPIO pin controls the transistor's gate, not the device directly.

## Pin Mode Summary

| PinMode | Description | Typical Use |
| --- | --- | --- |
| `Output` | Drive pin HIGH or LOW | LEDs, control signals |
| `Input` | Read pin state (floating) | Rarely used |
| `InputPullUp` | Read pin, default HIGH | Buttons (active-low) |
| `InputPullDown` | Read pin, default LOW | Sensors (active-high) |

## Common GPIO Pins on Raspberry Pi

Not all GPIO pins are suitable for general use:

- **GPIO 2, 3:** I2C (have hardware pull-up resistors)
- **GPIO 14, 15:** UART (default serial console)
- **GPIO 9, 10, 11:** SPI
- **GPIO 18, 19:** PWM-capable
- **Safe for general use:** 17, 22, 23, 24, 25, 27

**Tip:** Check your specific Raspberry Pi model's pinout at [pinout.xyz](https://pinout.xyz/).

## Best Practices

1. **Always dispose of GpioController** — Use `using` statements or call `.Dispose()`
2. **Use `InputPullUp` or `InputPullDown`** — Never leave input pins floating
3. **Respect voltage levels** — Raspberry Pi GPIO operates at 3.3 V; connecting 5 V **will damage the pin**
4. **Use resistors with LEDs** — Calculate the value or use 220 Ω as a safe default
5. **Check pin assignments** — Some GPIO pins are shared with I2C, SPI, or UART; using them for general GPIO disables those interfaces
6. **Document your pin usage** — Especially in projects using multiple pins

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot you should mention that this will lead to 15mA current. Therefore a normal 20mA led is expected in this example and that high-brightness leds should not be attached to GPIO directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 7f680f7 — both the "Driving an LED" section and the best practices list now mention the ~15 mA current with a 220 Ω resistor, that this is fine for standard 20 mA indicator LEDs, and that high-brightness/power LEDs should not be connected to GPIO directly.

## Next Steps

- [GPIO Protocol Guide](../protocols/gpio.md) — Quick start, GpioController usage, drivers, and troubleshooting
- [Choosing the Right Driver](choosing-drivers.md) — LibGpiodDriver vs SysFsDriver comparison

## Additional Resources

- [GPIO Wikipedia](https://en.wikipedia.org/wiki/General-purpose_input/output)
- [Raspberry Pi GPIO Pinout](https://pinout.xyz/)
- [Digital I/O Fundamentals](http://www.ni.com/white-paper/3405/en/#toc1)
Loading