如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

MicroPython 標準函式庫裡提供的 I2C 模組,只能讓 Raspberry pi pico (RP2040) 做 I2C Master,如果今天要讓 pico 做 Slave 只能改用 C++ 函式庫。真的是這樣嗎?

本文是 AI 神經網路自走車 第三篇,分享如何用 MicroPython 來實現 I2C Slave,並且與 Raspberry pi 做溝通,就讓我們一起學習吧!

準備硬體元件

這次製作需要準備的材料為:

  1. Raspberry pi pico
  2. Raspberry pi

Step 1:使用開源的 I2CResponder

I2C Slave 的實現已經有神人分享 source code 在 github 上面

https://github.com/epmoyer/I2CResponder

大家可以直接把檔案 i2c_responder.py 複製到自己專案裡面,然後我們一步步開始實作。

Step 2:決定 pico 腳位

從 pico 的 pinout 來看,只要是藍色的都可以當作 I2C,而且內建兩組 I2C 供你使用。這邊以 I2C 0 的 GPIO 4, 5 來實作 (對應到 pin 6, 7)。

如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython

Step 3:決定 Raspberry pi 腳位

我們以 Raspberry pi 扮演 I2C Master 的角色,如果你手邊有其他的 SBC 也可以替換使用。我們選擇 I2C 1,也就是 GPIO 2, 3 來實作(對應 pin 3, 5)。

Raspberry pi pinout

Step 4:連結兩者

用跳線將兩者 I2C 的 SCL、SDA 對接,記得也要共接地,不然訊號會過不去哦!

picopi
I2C 0 SDA (pin 6)I2C 1 SDA (pin 3)
I2C 0 SCL (pin 7)I2C 1 SCL (pin 5)
GNDGND

Step 5:Raspberry pi 啟用 I2C 硬體

需特別注意的是,Raspberry pi 預設不會啟動 I2C 1,所以我們需要到 raspi-config 做設定。在 console 裡下

sudo raspi-config

選擇 Interfacing Options

如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

選擇 I2C

如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

確認要 enable I2C

如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

確認後即可啟用 I2C

如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

Step 4:Raspberry pi 安裝 python-smbus

要在 Raspberry pi 的 python 環境下使用 I2C,需要先安裝 library。在 console 輸入

pip3 install python-smbus

Step 5 – 1:撰寫 MicroPython 測試接收

首先進入 pico 的 python console,依照我們使用的 I2C channel 以及 GPIO pin 號下去初始化 I2CResponder。I2C Slave 硬體位置我們以 0x50 為示例。

from i2c_responder import I2CResponder

channel = 0
sda_pin = 4
scl_pin = 5
addr = 0x50

i2c_slave = I2CResponder(channel, sda_pin, scl_pin, addr)

初始化完後,我們使用無窮迴圈來監聽 I2C 是否有收到資料,若有就分批把資料抓出來,每次最多抓五十個,最後再印出來

while True:
    data = []

    while i2c_slave.write_data_is_available():
        data += i2c_slave.get_write_data(50)

    print('receive data', data)

run 下去後,pico 就會在那邊等待,現在我們切換到 pi 那邊發出資料看看。

Step 5 – 2:從 Raspberry pi (I2C Master) 測試發送資料

一樣我們到 python console 下,用以下程式碼測試。其中

  1. pico_addr 是我們在宣告 I2CResponder 指定的 slave address
  2. reg_addr 可以自由給定,這邊以 0x01 為例
  3. 我們以 write_block_data 一次寫入多筆數據測試看看
import smbus

channel = 1
pico_addr = 0x50
reg_addr = 0x01

i2c_master = smbus.SMBus(channel)
i2c_master.write_block_data(pico_addr, reg_addr, [0x30, 0x40, 0x50])

按下 enter 送出後,回到 pico console 如果看到印出以下訊息,表示成功接收!

研究收到的資料,其中:

  1. 陣列第一個值表示 Master write 指令指定的 address,由於我們指定 0x01,所以這邊會顯示為 1
  2. 陣列第二個值表示後面有多少個元素是這次 write 指令所帶的資料,因為我們發送 0x30, 0x40, 0x50,所以為 3
  3. 後面為這次發送的資料
# [<reg_addr>, <data_count>, <data>, ...]
[1, 3, 30, 40, 50]

依照上述原則,如果今天收到以下資料,會是怎麼樣呢?

[1, 2, 32, 12, 5, 4, 32, 21, 23, 67]

解答:

總共收到兩筆 write 指令,分別為

[1, 2, 32, 12]
[5, 4, 32, 21, 23, 67]
  1. 第一筆指令指定位置為 0x01,共帶入兩個資料
  2. 第二筆指令指定位置為 0x05,共帶入四個資料

相對用 C++ 的 arduino 框架寫起來較為麻煩些,需要自行判斷資料斷點。

Step 6 – 1:撰寫 MicroPython 測試發送

剛剛我們測試了 pico I2C Slave 接收資料,但有時候也需要回傳資料到 Master。

流程上必須透過 Master 發出 Read 指令 Slave 才能回送資料,因此 C++ 的實現會透過監聽函數來處理。但 I2CResponder 只能透過迴圈不斷 polling,算是一個小缺點。

我們試著修改剛剛寫的無窮迴圈來實現

while True:
    if i2c_slave.read_is_pending():
        i2c_slave.put_read_data(0xFF)

run 下去後,pico 就會在那邊等待,現在我們切換到 pi 那邊接收資料看看。

Step 6 – 2:從 Raspberry pi (I2C Master) 測試接收資料

一樣我們到 python console ,用以下程式碼測試。

data = i2c_master.read_word_data(pico_addr, reg_addr)
print('receive', data)

按下 enter 後,如果看到印出以下表示成功

receive 255

Step 7:把接收和發送合併再一起

我們修改前面的 code,讓他在同一個迴圈內可以同時處理兩件事

def check_if_need_response():
    if i2c_slave.read_is_pending():
        i2c_slave.put_read_data(0xFF)

def check_receive():
    data = []
    while i2c_slave.write_data_is_available():
        data += i2c_slave.get_write_data(50)
    print('receive data', data)

while True:
    check_receive()
    check_if_need_response()

完成!這樣就能夠在 MicroPython 環境下讓 Raspberry pi pico 做 I2C Slave 了!如果覺得我文章內容對你有幫助的話,請在文章後面幫我按 5 個讚!讓我知道大家都喜歡什麼內容哦!

範例原始碼在此下載:github

AI 神經網路自走車
上一篇:用 Raspberry pi pico 與 HC-SR04 做超音波距離測
下一篇:十分鐘快速認識 ROS (Robot Operating System)

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。