ラズピコ(Raspberry Pi Pico)は、SPIコントローラー2系統、I2Cコントローラー2系統、UART2系統、PWM16系統を持つ、小型のマイコンボードです。
I/Oがふんだんに用意されているので、ラズピコ(Raspberry Pi Pico)はマスターとし、複数のデバイスをスレーブとして繋いで制御する用途がメインになります。
実は、ラズピコ(Raspberry Pi Pico)には、スレーブ動作するモードも用意されています。
本記事では、ラズピコ(Raspberry Pi Pico)をスレーブとし、ラズパイ(Raspberry Pi)の信号を受けて動作させる方法を紹介します。
本記事では、下記の内容を紹介します。
この記事で分かること
本記事では、下記の内容を紹介しています。
- 必要な部品
- ラズパイ(Raspberry Pi)とラズピコ(Raspberry Pi Pico)の配線図
- ラズピコ(Raspberry pi pico)をI2Cスレーブ動作させるMicroPythonのサンプルコード
スポンサーリンク
必要な部品
今回使用した部品を紹介します。
ラズピコ(Raspberry Pi Pico)
Amazonは単価は高いですが、送料無料にできるメリットがあります。
秋月電子通商だと、USBケーブルとピンヘッダがセットになったキットなども販売されています。
ブレッドボード
ラズピコ(Raspberry pi pico)を使用する際に、必要になります。
ジャンパワイヤ
オス-オス、オス-メス、メス-メスがセットになったジャンパワイヤです。
スポンサーリンク
ラズパイ(Raspberry Pi)とラズピコ(Raspberry Pi Pico)の配線図
ラズパイ(Raspberry Pi)とラズピコ(Raspberry Pi Pico)の配線について紹介します。
I2C通信に必要な、SDA、SCLのPINを接続するだけなので、とても簡単です。
ラズパイ(Raspberry Pi)のピン配置
ラズパイのピン配置を載せておきます。
知っている方は読み飛ばしてください。
ラズパイのピン配置
ラズピコ(Raspberry Pi Pico)のピン配置
ラズピコのピン配置を載せておきます。
知っている方は読み飛ばしてください。
ラズピコ(Raspberry Pi Pico)のピン配置
ラズパイ(Raspberry Pi)とラズピコ(Raspberry Pi Pico)の配線図
ラズパイと、ラズピコの配線図はこちら。

I2C通信を行うため、ラズパイとラズピコのSDA同士、SCL同士を接続しています。
ラズピコの入力電圧は 1.8~5.5V であるため、ラズパイから5V電源を供給しています。
ラズピコのGNDも忘れずに接続しましょう。
スポンサーリンク
ラズピコ(Raspberry pi pico)をI2Cスレーブ動作させるサンプルコード
ここからは、ラズピコ(Raspberry pi pico)をスレーブ動作させるための、サンプルコードを紹介していきます。
コード紹介前に、いくつか注意点がありますので、順に説明します。
【注意点1】
ラズピコ(Raspberry pi pico)を使用するためには、
はじめにMicroPythonのUF2ファイルをインストールする必要があります。
ラズピコ(Raspberry pi pico)の公式サイトの手順に従い、
UF2ファイルをインストールした後に、以降のコードを保存するようにしてください。
【注意点2】
ラズピコ(Raspberry pi pico)へのコード書き込みは、"Thonny"環境をおすすめします。
"Thonny"は、ラズピコ(Raspberry pi pico)へのコード書き込みを簡単に行えてしまうpythonの統合開発環境です。

Thonnyの使い方に関しては、詳細に解説しているサイトがありますので、探してみてください。
ラズピコ(Raspberry pi pico)に書き込むMicroPythonコード
以下の3つのファイルを用意し、ラズピコ(Raspberry pi pico)に書き込みます。
- i2cSlave.py
- led.py
- main.py
Thonnyから、ラズピコに保存されているファイルを確認すると、このように見えます。

ラズピコの電源投入と同時にmain.pyが立ち上がり、led.py、i2cSlave.pyをコールする仕組みになっています。
なお、i2cSlave.pyの記述には、こちらのサイトを参考にさせて頂いています。
このコードを作成してくださったdanjperron氏に感謝です。
--- i2cSlave.py ---
### i2cSlave.py
from machine import mem32,mem8,Pin
class i2c_slave:
I2C0_BASE = 0x40044000
I2C1_BASE = 0x40048000
IO_BANK0_BASE = 0x40014000
mem_rw = 0x0000
mem_xor = 0x1000
mem_set = 0x2000
mem_clr = 0x3000
IC_CON = 0 #I2C Control Register
IC_TAR = 4 #I2C Target Address Register
IC_SAR = 8 #I2C Slave Address Register
IC_DATA_CMD = 0x10 #I2C Rx/Tx Data Buffer and Command Register
IC_RAW_INTR_STAT = 0x34 # I2C Raw Interrupt Status Register
IC_RX_TL = 0x38 #I2C Receive FIFO Threshold Register
IC_TX_TL = 0x3C #I2C Transmit FIFO Threshold Register
IC_CLR_INTR = 0x40 #Clear Combined and Individual Interrupt Register
IC_CLR_RD_REQ = 0x50
IC_CLR_TX_ABRT = 0x54
IC_ENABLE = 0x6c #I2C ENABLE Register
IC_STATUS = 0x70 #I2C STATUS Register
def write_reg(self, reg, data, method=0):
mem32[ self.i2c_base | method | reg] = data
def set_reg(self, reg, data):
self.write_reg(reg, data, method=self.mem_set) #methodをsetにしている
def clr_reg(self, reg, data):
self.write_reg(reg, data, method=self.mem_clr) #methodをclrにしている
def __init__(self, i2cID = 0, sda=0, scl=1, slaveAddress=0x41):
self.scl = scl
self.sda = sda
self.slaveAddress = slaveAddress
self.i2c_ID = i2cID
if self.i2c_ID == 0:
self.i2c_base = self.I2C0_BASE
else:
self.i2c_base = self.I2C1_BASE
# 1 Disable DW_apb_i2c
self.clr_reg(self.IC_ENABLE, 1)
# 2 set slave address
# clr bit 0 to 9
# set slave address
self.clr_reg(self.IC_SAR, 0x1ff)
self.set_reg(self.IC_SAR, self.slaveAddress &0x1ff)
# 3 write IC_CON 7 bit, enable in slave-only
self.clr_reg(self.IC_CON, 0b01001001)
# set SDA PIN
mem32[ self.IO_BANK0_BASE | self.mem_clr | ( 4 + 8 * self.sda) ] = 0x1f
mem32[ self.IO_BANK0_BASE | self.mem_set | ( 4 + 8 * self.sda) ] = 3
# set SLA PIN
mem32[ self.IO_BANK0_BASE | self.mem_clr | ( 4 + 8 * self.scl) ] = 0x1f
mem32[ self.IO_BANK0_BASE | self.mem_set | ( 4 + 8 * self.scl) ] = 3
# 4 enable i2c
self.set_reg(self.IC_ENABLE, 1)
def anyRead(self):
status = mem32[ self.i2c_base | self.IC_RAW_INTR_STAT] & 0x20
if status :
return True
return False
def put(self, data):
# reset flag
self.clr_reg(self.IC_CLR_TX_ABRT,1)
status = mem32[ self.i2c_base | self.IC_CLR_RD_REQ]
mem32[ self.i2c_base | self.IC_DATA_CMD] = data & 0xff
def any(self):
# get IC_STATUS
status = mem32[ self.i2c_base | self.IC_STATUS]
# check RFNE receive fifio not empty
if (status & 8) :
return True
return False
def get(self):
while not self.any():
pass
return mem32[ self.i2c_base | self.IC_DATA_CMD] & 0xff
if __name__ == "__main__":
import utime
from machine import mem32
from i2cSlave import i2c_slave
s_i2c = i2c_slave(0,sda=0,scl=1,slaveAddress=0x41)
counter =1
try:
while True:
if s_i2c.any():
print(s_i2c.get())
if s_i2c.anyRead():
counter = counter + 1
s_i2c.put(counter & 0xff)
except KeyboardInterrupt:
pass
--- led.py ---
### led.py
import utime
import time
from machine import Pin, Timer
led = Pin(25, Pin.OUT) #GP25を出力モードに設定
def led_power_on() :
for i in range(5) :
led.value(1)
time.sleep(0.5)
led.value(0)
time.sleep(0.5)
led.value(1)
time.sleep(0.5)
led.value(0)
time.sleep(1.0)
def led_on() :
led.value(1)
def led_off() :
led.value(0)
--- main.py ---
### main.py
import utime
import time
from machine import mem32,Pin
import led
from i2cSlave import i2c_slave
### --- check pico power on --- ###
led.led_power_on()
### --- pico connect i2c as slave --- ###
s_i2c = i2c_slave(0,sda=0,scl=1,slaveAddress=0x41)
try:
while True:
data = s_i2c.get()
print(data)
data_int = int(data)
for i in range(data_int):
led.led_on()
time.sleep(0.5)
led.led_off()
time.sleep(0.5)
except KeyboardInterrupt:
pass
ここまでがラズピコ(Raspberry Pi Pico)に書き込むコードです。
※このコードでラズパイ上は動作していますが、サイト移植時にインデントを手打ちしています。
もしエラーが出た場合は、インデント部分を確認いただければと思います。
Raspberry pi picoの公式ホームページのRP2040 Datasheetに、
picoのスレーブ化に関する記述があります。
興味と技術力のある方は、是非確認してみてください。
ラズピコ(Raspberry pi pico)のI2Cアドレス確認
ファイルを保存しmain.pyが読み込まれると、ラズピコのI2Cアドレスが認識されるようになります。
本記事の例では、main.pyでI2Cアドレスを0x41と設定しています。
ラズピコのI2Cアドレスが、ほんとうに0x41に設定されているか確認してみます。
ラズパイのターミナルから下記のコマンドを入力します。
$ sudo i2cdetect -y 1

ラズピコのI2Cアドレスが、0x41として認識されていることを確認できました。
なお、0x29も認識されていますが、
こちらは筆者が別の用途で確認していたToFセンサになので気にしないでください(笑)。
ラズパイ(Raspberry pi)に書き込むpythonコード
次に、ラズパイ側で、ラズピコとI2C通信を行うためのコードを用意します。
--- pi_pico_i2c_test.py ---
### pi_pico_i2c_test.py
import time
import smbus
bus = smbus.SMBus(1)
bus.write_byte(0x41,3) #"3"が送信するデータ
ラズパイ側から、上記コードを実行してやると、
送信データに応じて、ラズピコのLEDが点滅するはずです。
ラズパイ(Raspberry Pi)とラズピコ(Raspberry Pi Pico)がI2C通信している様子
実際に、ラズピコ(Raspberry Pi Pico)がI2C通信でスレーブ動作している動画を紹介します。
スポンサーリンク
まとめ
ラズピコ(Raspberry Pi Pico)をI2C通信でスレーブ動作させる方法を紹介しました。
スレーブ動作できるようになると、ラズピコでできることも広がるので、是非試してみてください。
本記事を最後まで読んでいただき、ありがとうございました。
スポンサーリンク