Control Any Raspberry Pi GPIO Pin from Linux Userspace via Sysfs
A minimal three-step workflow to toggle GPIO pins from userspace, with pin muxing warnings, current limits, and cleanup patterns so you avoid export errors and hardware conflicts.
13 Jul 2026, 00:03 UTC

The three-command workflow
- Export the pin:
echo 24 > /sys/class/gpio/export(run as root). If successful,/sys/class/gpio/gpio24/appears. - Set direction:
echo out > /sys/class/gpio/gpio24/direction - Write value:
echo 1 > /sys/class/gpio/gpio24/valuefor high,echo 0 > /sys/class/gpio/gpio24/valuefor low
# As root, to turn GPIO24 high:
echo 24 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio24/direction
echo 1 > /sys/class/gpio/gpio24/value
After the last command, verify with:
cat /sys/class/gpio/gpio24/value
Pin muxing and UART conflicts
Raspberry Pi physical header pins 11 and 13 map to GPIO17 and GPIO18, which are multiplexed as UART TX and RX by default. Using these as general-purpose GPIO can disable the serial console on boots without a console=serial0,115200 kernel parameter, or conflict with serial hardware.
Before exporting a pin, confirm its function: gpio readall (from the wiringPi utility) maps physical pin numbers to GPIO indices and flags UART muxing. If you need GPIO17 or GPIO18 for other purposes, add console=serial0,115200 to your boot configuration or avoid using them as GPIO.
You can check whether a pin is already claimed by reading /sys/class/gpio/gpioXXX/active (if your kernel exports it) or reviewing dmesg for GPIO-related messages after a failed export attempt.
Current and safety limits
Each GPIO pin sources approximately 16 mA of current. Driving loads beyond this rating can overheat the SoC pin, cause voltage droop, or produce unreliable behavior. For example, a red LED lighted with a 220 ohm resistor limits current to about 15 mA, which is safe; a yellow LED may draw near 20 mA, pushing the pin close to its limit. For relays, LEDs above 20 mA, or any load exceeding 50 mA, use a transistor driver (e.g., NPN switching a separate supply) or an optocoupler. The Pi's 3.3 V logic level also means you cannot directly interface with 5 V tolerant inputs without level shifting.
Verification and common checks
- After export, confirm the directory exists:
ls /sys/class/gpio/gpio24/should listdirectionandvalue. - Check direction:
cat /sys/class/gpio/gpio24/directionshould outputout. - Check value:
cat /sys/class/gpio/gpio24/valueshould reflect the last written0or1. - Cross-reference physical pin numbering with
gpio readallto avoid confusing GPIO indices with header pin positions.
Cleanup and rollback
Exporting a pin modifies sysfs state. On reboot the pin returns to the kernel's default mux, but if your script exits without unexporting, the pin may remain in the last driven state until the next power cycle. Integrate cleanup in a try/finally block or use Python's atexit:
import os, atexit
GPIO = '24'
def cleanup():
try:
with open('/sys/class/gpio/unexport', 'w') as f:
f.write(GPIO)
except OSError:
pass
atexit.register(cleanup)
with open('/sys/class/gpio/export', 'w') as f:
f.write(GPIO)
with open('/sys/class/gpio/gpio{GPIO}/direction', 'w') as f:
f.write('out')
# ... your code ...
This ensures that when your program terminates—whether normally or via signal—the pin is unexported and returns to an undefined (input) state, preventing unexpected hardware behavior on the next boot or re-run.
Version assumption: This behavior is consistent across Raspberry Pi OS releases from 2019 onward, relying on the Linux GPIO sysfs kernel interface present since kernel 4.10. Newer kernels may restrict export of pins already claimed by device tree overlays.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.