0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラズパイ5GPIOをPythonで動かす - libgpiommem Wrapper

Last updated at Posted at 2025-03-11

はじめに

ラズパイでGPIOを操作する方法はたくさんありますが、その大部分がラズパイ5では動かないという驚愕の現実がありCで操作する、libgpiommemを制作し公開しました。
少なからず反響があり、「Pythonでもこれを使いたい」という声があったため、Wrapperを作りましたので、公開します。

簡単な使い方

  • libgpiommem.soを書いてある手順で展開しinstallします。
  • ここに書いた手順でPyGpioMmenをDLします。
  • サンプルプログラムを試験します。

GitLabからのFile取得

簡単に使えるようGitLabにもファイルを置きました。ご利用ください。

PyGpioMmem本体

python
# MIT License.
# Copy right 2025 by Shigeru Makino.

import ctypes

# ライブラリのロード
libgpiommem = ctypes.CDLL("libgpiommem.so")

# 戻り値の型を設定
libgpiommem.gpiolib_init.restype = ctypes.c_int
libgpiommem.gpiolib_mmap.restype = ctypes.c_int
libgpiommem.gpio_set_fsel.argtypes = [ctypes.c_uint, ctypes.c_int]  # `GPIO_FSEL_T` は `int`
libgpiommem.gpio_set_pull.argtypes = [ctypes.c_uint, ctypes.c_int]
libgpiommem.gpio_set_drive.argtypes = [ctypes.c_uint, ctypes.c_int]
libgpiommem.gpio_get_level.argtypes = [ctypes.c_uint]
libgpiommem.gpio_get_level.restype = ctypes.c_int

# GPIO 定数
PULL_NONE = 0
PULL_UP = 1
PULL_DOWN = 2
DRIVE_LOW = 0
DRIVE_HIGH = 1

# `GPIO_FSEL_INPUT` と `GPIO_FSEL_OUTPUT` をハードコード(C の定義に基づく)
GPIO_FSEL_INPUT = 16  # `0x10` の値
GPIO_FSEL_OUTPUT = 17  # `GPIO_FSEL_INPUT + 1`

class GPIO:
    def __init__(self):
        """ GPIOライブラリの初期化 """
        ret = libgpiommem.gpiolib_init()
        if ret < 0:
            raise RuntimeError("Failed to initialize gpiolib")

        ret = libgpiommem.gpiolib_mmap()
        if ret < 0:
            raise RuntimeError("Failed to mmap gpiolib")

    def set_mode(self, pin, mode):
        libgpiommem.gpio_set_fsel.argtypes = [ctypes.c_uint, ctypes.c_int]  # `GPIO_FSEL_T` は int
        libgpiommem.gpio_set_fsel.restype = ctypes.c_int  # 戻り値を整数に設定
        ret = libgpiommem.gpio_set_fsel(ctypes.c_uint(pin), ctypes.c_int(mode))
        return ret

    def set_pull(self, pin, pull):
        """ GPIO のプル設定 """
        libgpiommem.gpio_set_pull(pin, pull)

    def write(self, pin, value):
        """ GPIO の出力を設定 """
        libgpiommem.gpio_set_drive.argtypes = [ctypes.c_uint, ctypes.c_int]  # 型を明示
        libgpiommem.gpio_set_drive.restype = None  # C 側で `void` の場合
        libgpiommem.gpio_set_drive(ctypes.c_uint(pin), ctypes.c_int(value))

    def read(self, pin):
        """ GPIO の入力を取得 """
        return libgpiommem.gpio_get_level(pin)

原理と問題点

ctypes を実直に使っています。
C言語側がenumで引数を使っているので、Pythonと齟齬が生じ面倒なのでdefineしてます。大本のpinctrl command で変更があると、追従できません。

Sampleと使い方

blink.py

出力試験です。高速のLチカです。

python
import pygpiogpmem as gpmem

gpio = gpmem.GPIO()

gpio21 = 21

# GPIO の設定
gpio.set_mode(gpio20, gpmem.GPIO_FSEL_INPUT)
gpio.set_pull(gpio20, gpmem.PULL_UP)

gpio.set_mode(gpio21, gpmem.GPIO_FSEL_OUTPUT)

# 初期化チェック
print("GPIO initialized successfully!")

while True:
    gpio.write(gpio21, gpmem.DRIVE_HIGH)
    gpio.write(gpio21, gpmem.DRIVE_LOW)

実行

bash
sudo python3 blink.py

GPIO21に矩形波が出ます。
最大応答速度を計測するため、システムに負荷がかかります。本来はusleep(1)を挟んで、調整してください。
オシロで測って430kHzが出ました。430kHz.png

ring.py

python
import pygpiommem as gpmem

gpio = gpmem.GPIO()

gpio20 = 20
gpio21 = 21

# GPIOの設定
gpio.set_mode(gpio20, gpmem.GPIO_FSEL_INPUT)
gpio.set_pull(gpio20, gpmem.PULL_UP)

gpio.set_mode(gpio21, gpmem.GPIO_FSEL_OUTPUT)
gpio.write(gpio21, gpmem.DRIVE_LOW)

while True:
    if gpio.read(gpio20) == 0:
        gpio.write(gpio21, gpmem.DRIVE_HIGH)
    else:
        gpio.write(gpio21, gpmem.DRIVE_LOW)

2025-03-12-165646.jpg

実行

bash
sudo python3 ring.py

GPIO20,GPIO21をショートするとリング発振器になります。
周波数は133kHzでした。
133kHz.png

まとめ

  • libgipimmem にラッパーをかけ python で使えるようにしました
  • 簡単にPythonでGPIO入出力ができます
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?