3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

記事投稿キャンペーン 「2024年!初アウトプットをしよう」

Raspberry Pi のペリフェラル制御(GPIO/I2C/SPI)

Last updated at Posted at 2024-01-01

はじめに

ラズベリーパイ(Raspberry Pi / Raspberry Pi Zero) のGPIO、I2C、SPIをPythonで制御する方法をまとめる。PythonのライブラリにはGPIO(RPi.GPIO)、I2C(smbus2)、SPI(spidev)等あるが、それぞれ使い分けが必要となる。本記事では、GPIO、I2C、SPI全てが一つにまとまっているpigpioで制御する。

RaspberryPi Picoの場合はmicropythonなので、別記事の下記参照。

目次

Raspberry Piのピン配置

5Vと3.3Vの電源出力を備えている。GPIOは3.3V。GPIOはシリアル通信のI2C/SPI/UARTを兼ねている。ピン配置はRaspberry Pi/Raspberry Pi Zero共通。下図は公式サイトより。

種別 Pin.No GPIO.No
I2C Pin3:SDA
Pin5:SCL
GPIO2
GPIO3
UART(シリアルコンソールと兼用) Pin8:TXD
Pin10:RXD
GPIO14
GPIO15
SPI Pin19:MOSI
Pin21:MISO
Pin23:SCLK
Pin24:CE0(チップセレクト0)
Pin26:CE1(チップセレクト1)
GPIO10
GPIO9
GPIO11
GPIO8
GPIO7
GPIO Pin.11
Pin.13
Pin.15
Pin.29
Pin.31
Pin.37
GPIO17
GPIO27
GPIO22
GPIO5
GPIO6
GPIO26
GPIO Pin.16
Pin.18
Pin.22
Pin.36
GPIO23
GPIO24
GPIO25
GPIO16

image.png

image.png

戻る

ペリフェラル通信の設定

[設定]→[Raspberry Piの設定]→[インターフェース]でSPIとI2Cとを有効にする。シリアルポートはUARTのこと。

image.png

戻る

pigpio

pigpioはRaspberryPiでGPIO/I2C/SPIの制御ができるPythonライブラリ。RaspberryPiにデフォルトでインストールされている。使用する場合は、sudo pigpiodを打つ必要がある。起動時に自動起動させたい場合はsystemctl enable。解除したい場合はdisable。

pigpioの自動起動
systemctl enable pigpiod

戻る

GPIO制御基本

pigpioでGPIO制御するためのAPIは下記の通り。基本のGPIO制御を列挙しているがPWMの制御もできる。

設定内容 API パラメータ
初期化 pi=pigpio.pi()
IN/OUT設定 pi.set_mode(gpio,mode) gpio:
 GPIO番号
mode:
 pigpio.INPUT
 pigpio.OUTPUT
プルアップ・ダウン pi.set_pull_up_down(gpio,pud) gpio:
 GPIO番号
pud:
 pigpio.PUD_UP
 pigpio.PUD_DOWN
 pigpio.PUD_OFF
GPIO状態確認 ret=pi.get_mode(gpio) gpio:
 GPIO番号
ret:
 0:IN/1:OUT
Write pi.write(gpio,level) gpio:
 GPIO番号
level:
 0:low/1:high
Read level=pi.read(gpio) gpio:
 GPIO番号
level:
 0:low/1:high

GPIO17とGPIO27を線で直結、GPIO5をOpenにしている状態で動作確認。

pigpio_gpio_test.py
import pigpio

pi = pigpio.pi()
#GPIO17をOUT設定
pi.set_mode(17, pigpio.OUTPUT)
#GPIO27をIN設定
pi.set_mode(27, pigpio.INPUT)
#GPIOのモード確認
print(f'# {pi.get_mode(17)=}/{pi.get_mode(27)=}')
# pi.get_mode(17)=1/pi.get_mode(27)=0

#GPIO17=Low
pi.write(17,0)
print(f'# {pi.read(27)=}')
# pi.read(27)=0

#GPIO17=High
pi.write(17,1)
print(f'# {pi.read(27)=}')
# pi.read(27)=1

#GPIO5 PullUp
pi.set_mode(5, pigpio.INPUT)
pi.set_pull_up_down(5,pigpio.PUD_UP)
print(f'# {pi.read(5)=}')
# pi.read(5)=1

戻る

GPIOの割り込み

pigpioは入力信号のエッジ割り込みによって、コールバック関数を呼ぶこともできる。

設定内容 API パラメータ
初期化 pi=pigpio.pi()
コールバック設定 pi.callback(gpio, edge, cb_func) gpio:
 GPIO番号
edge:
 pigpio.FALLING_EDGE(↓)
 pigpio.RISING_EDGE(↑)
 pigpio.EITHER_EDGE((↓↑))
cb_func:
 コールバック関数

コールバック関数の型は

cb_func
def cb_func(gpio, level, tick):
    #gpio : gpio番号
    #level: 0:low_edge/1:high_edge
    #tick : bootからの時間 usec 72minでオーバフロー

GPIO17とGPIO27を線で直結、GPIO17を1秒毎にHigh/Lowさせ、GPIO27に1秒毎に割り込みを発生させたときの例。

pigpio_gpioint_test.py
import pigpio
import time

#GPIO27のコールバック関数
def cb_gpio27(gpio, level, tick):
    print (f'# {gpio=} : {level=} : {tick/(1000*1000)=}s')

pi = pigpio.pi()
#GPIO27をINでPullUp設定。両エッジでコールバック。
pi.set_mode(27, pigpio.INPUT)
pi.set_pull_up_down(27,pigpio.PUD_UP)
cb = pi.callback(27, pigpio.EITHER_EDGE, cb_gpio27)

#GPIO17=Low
#GPIO17をOUT設定
pi.set_mode(17, pigpio.OUTPUT)
pi.write(17,1)

while(1):
    #1秒毎にトグル
    time.sleep(1)
    pi.write(17,0)
    time.sleep(1)
    pi.write(17,1)

# gpio=27 : level=1 : tick/(1000*1000)=540.658528s
# gpio=27 : level=0 : tick/(1000*1000)=541.659448s
# gpio=27 : level=1 : tick/(1000*1000)=542.660413s
# gpio=27 : level=0 : tick/(1000*1000)=543.661243s
# gpio=27 : level=1 : tick/(1000*1000)=544.662802s
# gpio=27 : level=0 : tick/(1000*1000)=545.664352s
# gpio=27 : level=1 : tick/(1000*1000)=546.665922s
....

戻る

I2C制御

I2Cは、組み込みデバイスを制御するときに使う通信手段。通信速度は数100kbps程度。組み込みデバイスのアドレスを指定して通信を行う。アドレスは7bitで、下位1bitでRead(1)、Write(0)を切り替える。I2Cアドレスがわからない場合は下記で確認できる。下記例では0x1Aと0x50のI2Cデバイスが接続している結果。

i2c
sudo i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --       
設定内容 API パラメータ
初期化 pi=pigpio.pi()
I2C Open handle=pi.i2c_open(ch, addr) ch:チャネル1に設定
addr:アドレス7bit
handle:Openハンドル
書き込み pi.i2c_write_device(handle,data) handle:
 i2c_openの戻り値
data:
 bytearray型
読み出し (cnt,data)=
pi.i2c_read_device(handle,size)
handle:
 i2c_openの戻り値
size:
 Readバイト数
(cnt,data):
 読込データtupple型

例として、EEPROM 24FC1025のI2Cアクセス例を示す。

pigpio_i2ctest.py
import pigpio
import time

pi = pigpio.pi()

#open adddre=0x50
h = pi.i2c_open(1, 0x50)

#write:offset 0x0000から3byte 0xAA,0xBB,0xCCを書き込む。
pi.i2c_write_device(h, b'\x00\x00\xAA\xBB\xCC')
time.sleep(0.01) #10ms wait EEPROMの書き込み時間用。

#read:offset 0x0000を設定してから3byte読み込む。
pi.i2c_write_device(h, b'\x00\x00')
print(f'# {pi.i2c_read_device(h, 3)=}')

# pi.i2c_read_device(h, 3)=(3, bytearray(b'\xaa\xbb\xcc'))

戻る

SPI制御

SPIは、組み込みデバイスを制御するときに使う通信手段。通信速度は数Mbps程度。高速通信が可能。1対1で通信することが多いが、チップセレクトを使えば、デバイスを指定して通信することもできる。SPIは通信なし時の極性(POL)と通信取り込みエッジ(PHA)の組み合わせで4種類のモードがある。

Mode POL(通信なし時の極性) PHA(通信取り込みエッジ)
0 0 0
1 0 1
2 1 0
3 1 1

SPIのAPIは下記。spi_open()のspi_flagsは、22bitで詳細設定ができるが、今回はModeを設定する下位3bitを使う。詳細は https://abyz.me.uk/rpi/pigpio/python.html 参照。

設定内容 API パラメータ
SPI Open spi_open(spi_channel, baud, spi_flags) spi_channel:
CE0(0)/CE1(1)選択
baud:
通信速度bps
spi_flags:
Mode設定(0/1/2/3)
書き込み pi.spi_write(handle, data) handle:
spi_openの戻り値
data:
書込データbytearray型
読み込み (cnt, data) =
pi.spi_read(handle, size)
handle:
spi_openの戻り値
size:
Readバイト数
(cnt,data):
読込データtupple型
読み書き (cnt, data) =
pi.spi_xfer(handle, data)
handle:
spi_openの戻り値
data:
書込データbytearray型
(cnt,data):
読込データtupple型

読み書きは、書き込んだByte数分、読み出しができる。

pigpio_spitest.py
import pigpio
import time

pi = pigpio.pi()

#open CE0 1000000bps Mode=3
h = pi.spi_open(0, 1000000, 3)

#write 3byte 0x40.0x09.0xFF を書き込み
pi.spi_write(h, b'\x40\x09\xFF') # write 3 bytes

#read 3byte
read_data=pi.spi_xfer(h, 3)
print(f'# {read_data=}')
# read_data=(3, bytearray(b'\x00\x00\x00'))

#write/read 3byte 0x41.0x09.0x00 を書き込み 同時に3byte読み出し
read_data=pi.spi_xfer(h, b'\x41\x09\x00')
print(f'# {read_data=}')
# read_data=(3, bytearray(b'\x00\x00\xFF'))

戻る

おまけ1:UART制御

ラズベリーパイでUART制御が一筋縄でいかなかったので、下記記事にまとめた。

戻る

おまけ2:bytearray型の扱いについて

bytearray⇔HEX文字列の変換例を下記に示す。

変換
#HEX文字列 → bytearray 変換
hex_string='ABCDEF01ABCDEF01ABCDEF01'
binary=bytes.fromhex(hex_string)
print(type(binary),binary)
# <class 'bytes'> b'\xab\xcd\xef\x01\xab\xcd\xef\x01\xab\xcd\xef\x01'

#bytearray → HEX文字列変換
binary=b'\xab\xcd\xef\x01\xab\xcd\xef\x01\xab\xcd\xef\x01'
hex_string=binary.hex()
print(type(hex_string),hex_string)
# <class 'str'> abcdef01abcdef01abcdef01

その他、数値関連の変換は下記にまとめる。参考に。

戻る

以上

3
3
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
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?