Raspberry Pi Pico:這片 4 美元、可跑 MicroPython 的小開發板有什麼特別?

昨天拿到了我訂的 RPi Pico,多花了一點銀子,但新玩意總得親自動手玩才能有點概念。

2021 年 1 月下旬,樹莓派基金會出人意表地發表了 Raspberry Pi Pico — — 一款小型、便宜的微控制器,搭載自家研發的 RP2040(雙核 Cortex M0+,最高時脈 133 HMz)。而且不僅如此:MicroPython 的開發者 Damien George 已經替它設計了專屬的韌體,可直接從樹莓派單板電腦 OS 內附的 Thonny IDE 連線,連官方書籍都準備好了。此外,包括 Arduino、Adafruit、Sparkfun 和 Pimoroni 都會用 RP2040 生產自己的開發板。

(Pico 只裝有一個類比溫度感應器。寫這篇文時,Arduino 的版本 Arduino Nano RP2040 Connect 尚未公開,但它將會擁有 ESP32 WiFi/BLE 模組、麥克風、九軸加速計。)

樹莓派的愛好者發瘋了:「哇,史上最小最便宜的樹莓派!這是什麼東東?太神奇了!」玩過微控制器的人則心想,這是怎樣?雙核 133 MHz 難道會強過雙核 240 MHz、價格又不會貴到哪去的 ESP32 麼?

不只是開發板,更能當成一個元件

近年來使用 3.3V 電壓的低耗能 32 位元處理器越來越流行,幾乎所有電子元件都能在 3.3V 下運作,Arduino AVR 家族和樹莓派單片電腦那過度強大的 5V 腳位輸出反而就不再那麼方便。

但看了一些影片後,我才意識到其實還有另一個趨勢:有越來越多開發板的腳位採用 castellated hole,底部也是完全平的,沒有任何元件。

簡單地說,castellated hole 就是腳位接點延伸到板子邊緣,這麼一來就能焊接在 PCB 板上。換言之:你能先用麵包板和杜邦線開發雛形,然後將完全一樣的板子放進整合好的電路板。

像是 Arduino 的 Nano 33 家族、Seeeduino 的 XIAO、DFRobot 的 Firebeetle Board-M0 等都已經使用這種設計,而 RPi Pico 僅僅 4 美元的超低成本(雖然加上運費就會多上不少)意味著你能大量採購和使用在各種地方。說真的,我就一直很難理解樹莓派愛好者為何總會特地拿一片 25 美元的小電腦來做些小型專案,甚至直接在其腳位上焊接元件。

其實從 RPi Pico 的包裝也能看出來有意壓低成本,不會再像以往的樹莓派產品配有漂亮的盒子跟說明書了。

RPi 單板電腦的重新定位?

過去樹莓派常被視為創客教育產品,因為你能透過它的 GPIO 腳位控制外部裝置。然而,除了前面提到的成本以外,用樹莓派控制裝置總有點不便 — — 要開機得花時間,要讓程式自動執行也需要額外的設定步驟,更別提供電的要求更高。而每當有新產品出現時,YouTube 上的影片多半也只是在討論拿它來看影片、聽音樂夠不夠順暢。

(就筆者所見,樹莓派更大的價值是當成放在家或辦公室某處的影音處理裝置,這樣就不需要占用你自己的電腦。它也比較適合用於做跟視覺或聲音有關的 AI 辨識應用。)

RPi 4 似乎印證了這種路線:它們的雙 HDMI 接頭和更大的記憶體,正是為了讓你當成桌機使用,而 RPi 400 更直接包成鍵盤的形狀。就算背後有保留 GPIO,這個用途也被忽略不提了。

因此,樹莓派基金會也許是想將 RPi 單板電腦當成真正的電腦,讓使用者從它對一個微控制器寫程式。過去有段時間,從樹莓派電腦給 Arduino Uno 寫程式相當流行,連台灣的書都會列入教學,所以幹嘛不把 Uno 換成自家產品、一條龍全包了呢?

從官方書籍的內容來看,顯然他們也想吃下孩童程式/創客教育這一塊:

頭號潛力:UF2 bootloader

我在「初玩 CircuitPython」這篇文章曾提過,UF2 乃微軟與 Adafruit 給特定微控制器產品所設計的燒錄器韌體,能將板子變成一個 USB 磁碟區,直接將新韌體拖拉進去就能改變板子的用途,且仍支援 Arduino C++等程式的寫入。就筆者所見,這正是 RPi Pico 有別於 ESP32 等的最大優勢。

ESP8266/ESP32 不支援原生 USB,因此板子上必須有 USB 晶片(通常是 CP2102 或 CH340G),並得使用 esptool.py 來協助燒錄韌體或程式,這在一些編輯器或工具都會內建。不過,現在 RPi Pico 的 MicroPython 以及 CircuitPython 韌體都可以直接透過拖拉檔案的方式燒錄,等於是跳過了需要外部燒錄程式的步驟,燒錄速度也很快。這對於從樹莓派電腦來操作 Pico,無疑就會容易許多。

當然,目前 UF2 的最大使用者仍是 CircuitPython,很難說將來會有其他語言加入這個行列。但,這仍使得 RPi Pico 成為一個真正同時支援 MicroPython 及 CircuitPython 的產品,而這兩個姊妹語言的特性跟生態系是有些差異的。

燒錄韌體

如果要燒錄新韌體,你必須先進入燒錄模式,辦法是「按住 BOOTSEL 鍵並接上 USB 線」(這點很像 BBC micro:bit),而不是像 SAMD21/51 微處理器那樣按兩下 reset:

燒錄模式的磁碟區會顯示 bootloader 版本

只要將新韌體的 .uf2 檔在這個「磁碟區」貼上,就能更換或更新韌體了。

韌體下載處:

  • MicroPython(如 rp2-pico-20210202-v1.14.uf2)
  • CircuitPython(如 adafruit-circuitpython-raspberry_pi_pico-en_US-6.2.0.uf2)

MicroPython v1.14 穩定版有缺少像是 array 之類的模組,請使用 v1.15 或更新版。

將 .uf2 檔案複製貼上或拖曳到燒錄模式的磁碟區,等板子重開即可。

Raspberry Pi OS(舊稱 Raspbian)會內建 Thonny IDE,沒有的話自己到Thonny.org 下載,版本至少得為 v3.3.3。打開編輯器後到工具(Tools)→選項(Options)→直譯器(Interpreter)選擇目標:

  • MicroPython 選 MicroPython (Raspberry Pi Pico)
  • CircuitPython 選 CircuitPython

按確定後,應該會看見 REPL(即「互動視窗」)跟板子的直譯器連線。沒有的話按按看編輯器上方的停止鈕,或在 REPL 視窗按 Ctrl+C:

MicroPython v1.14 on 2021-02-02; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>>

Adafruit CircuitPython 6.2.0-beta.1 on 2021-01-27; Raspberry Pi Pico with rp2040
>>>

本文撰寫時,CircuitPython 仍在 6.2.0 beta,這個版本加入了對 RPi Pico 支援,目前已有正式 6.2.0 版。

若想在板子上保存程式,MicroPython 必須在編輯器中用儲存複本的方式寫入到 main.py。CircuitPython 則是只要修改磁碟區中的 code.py 或直接覆蓋即可,然後在 REPL 按 Ctrl+D 重啟板子。其他細節網路上很多教學,這邊就不多討論了。

Hello World

來個最基本的程式,讓板子內建的 LED 閃動吧。

MicroPython:

from machine import Pin
import time
led = Pin(25, Pin.OUT)while True:
led.value(not led.value()) # 也可直接寫 led.toggle()
time.sleep(0.5)

CircuitPython:

import board, digitalio, timeled = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = not led.value
time.sleep(0.5)

使用雙核運算

官方範例簡單示範了雙核運算,或者應該說怎麼在另一個核心跑一個執行緒(主程式會在第一個核心執行,所以你也只能啟用一個 thread)。thread 模組是 Python 3 早期的多執行緒模組,這在 ESP32 上也有。

import time, _thread, machinedef task(n, delay):
led = machine.Pin(25, machine.Pin.OUT)
for i in range(n):
led.high()
time.sleep(delay)
led.low()
time.sleep(delay)
print('done')
_thread.start_new_thread(task, (10, 0.5))

隱藏選手:Programmable I/O state machine

另一個可能同等重要的是 PIO — — Programmable I/O,即可程式化 GPIO。就筆者的超外行知識所能理解,PIO 就是 GPIO 加裝超簡化版的處理器,你能給它們實作 I2C、SPI、UART 以外的一些特殊硬體協定,例如控制 SD 卡或 VGA 輸出。RP2040 有兩個 PIO 介面(輸出和輸入),每個各有 4 個 state machine,每個 state machine 可存 32 KB 指令。

RPi Pico 搭配 Pimoroni Pico VGA Demo Base,從 SD 卡輸出 VGA 影像

我們不妨來看看官方教材的 NeoPixel 範例,就用了 PIO 來實作其驅動程式(所以,RPi Pico 的 MicroPython 韌體沒有附 NeoPixel module 也許是故意的):

# Example using PIO to drive a set of WS2812 LEDs.
# 這支程式我砍了一部分以便簡化
import array, time
from machine import Pin
import rp2
# Configure the number of WS2812 LEDs.
NUM_LEDS = 8
PIN_NUM = 28 # GPIO 28
brightness = 0.5
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
T1 = 2
T2 = 5
T3 = 3
wrap_target()
label("bitloop")
out(x, 1) .side(0) [T3 - 1]
jmp(not_x, "do_zero") .side(1) [T1 - 1]
jmp("bitloop") .side(1) [T2 - 1]
label("do_zero")
nop() .side(0) [T2 - 1]
wrap()
# 用 ws2812() 創造 state machine 並於指定的 Pin 輸出
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))
# 啟動 state machine 並等待 FIFO (first-in, first-out) 資料
sm.active(1)
# NeoPixel 的顏色與亮度資料 (GGRRBB)
ar = array.array("I", [0 for _ in range(NUM_LEDS)])
##################################################
def pixels_show():
dimmer_ar = array.array("I", [0 for _ in range(NUM_LEDS)])
for i,c in enumerate(ar):
r = int(((c >> 8) & 0xFF) * brightness)
g = int(((c >> 16) & 0xFF) * brightness)
b = int((c & 0xFF) * brightness)
dimmer_ar[i] = (g << 16) + (r << 8) + b
sm.put(dimmer_ar, 8)
def pixels_set(i, color):
ar[i] = (color[1] << 16) + (color[0] << 8) + color[2]

def wheel(pos):
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return (0, 0, 0)
if pos < 85:
return (255 - pos * 3, pos * 3, 0)
if pos < 170:
pos -= 85
return (0, 255 - pos * 3, pos * 3)
pos -= 170
return (pos * 3, 0, 255 - pos * 3)
def rainbow_cycle(wait):
for j in range(255):
for i in range(NUM_LEDS):
rc_index = (i * 256 // NUM_LEDS) + j
pixels_set(i, wheel(rc_index & 255))
pixels_show()
time.sleep(wait)
while True:
rainbow_cycle(0.001)

可見 PIO 其實是用組合語言來寫的(ws2812() 的部分),並在 pixels_show() 將資料寫入 state machine。資料格式是 uint16 array(來自 array 模組),用 GGRRBB 的格式。剩餘的程式碼(wheel() 與 rainbow_cycle())則是取自 Adafruit 的 NeoPixel 彩燈旋轉範例。

對,這是我的 RPi Pico

我想一般使用者應該沒辦法寫 PIO 程式(官方的 Python SDK 顯然寫得沒有非常詳細;事實上你也許得讀 C++ SDK),但官方或許會鼓勵開發商用這種方式撰寫驅動程式。

此外奇怪的是官方範例裡有 SSD1306 的範例,可是 RPi Pico 的 MicroPython 目前卻沒有這個模組,而我安裝 ESP8266 的官方版本也跑不起來。所以硬體架構的差異有可能將是導致你非用 PIO 不可的原因?

補:後來發現是現在 MicroPython 把 I2C(硬體 I2C)和 SoftI2C(軟體 I2C)分開,而硬體 I2C() 呼叫時第一個參數要給 ID。換成 SoftI2C 就能正常作用了。你能在此找到驅動程式:https://github.com/stlehmann/micropython-ssd1306

電壓和腳位設計

軟體部分還有待觀察,這裡先來說說硬體。RP2040 只有 4 個 ADC 類比輸入腳位(這些腳位不建議輸入超過 300 mA 電流),算不上很多,而在 RPi Pico 上其中一個 ADC 還分給溫度感測器,故沒有接出到外界。這點無疑會在應用範圍上帶來一些限制。

且注意 RP2040 的腳位無法容忍 5V 電壓,這表示你不能直接使用會輸出 5V 的感測器。至於板子本身能輸出多大電流量呢?文件的說法是這取決於輸入電量,但最好不要從 3.3V 腳位汲取超過 300 mA。

VBUS 和 USB 頭連接,我還沒試過但應該是能直接輸出 5V。VSYS 用來對板子輸入供電,跟 VBUS 隔著一個二極體。RPi Pico 的輸入電壓範圍是 1.8~5.5V,彈性很大,想用 3.7V 鋰電池或三個 AA 電池都行。

其他嘛,我不是很喜歡腳位號碼寫在板子底下,這樣還要常常查腳位圖。此外一邊有 20 個腳位,若你想配迷你麵包板(17 x 10),一邊就要犧牲三個腳位了。我有一片 ESP32-Pico-Kit 買來時就是這樣的。

另外板子沒有 reset 鈕,但你可以在 Run 腳位(GPIO 22/26 中間)和 GND 之間接一個按鈕。

效能比一比:MicroPython vs. CircuitPython

CircuitPython 早期曾經支援過 ESP8266/ESP32,但後來因為支援度不佳(正是因為它們缺乏原生 USB)而放棄。現在,RPi Pico 成了第一個正式橫跨兩種嵌入式 Python 的硬體,那麼兩者的執行效能有沒有差別呢?

筆者拿了手邊現成的程式跑了點測試(除了少數像是 time 模組取時間的語法不同外,其餘程式完全修同):

解 8 皇后問題(單 list 跑遞迴,整數資料)

  • ESP32 (MicroPython): 2100.727 ms
  • RPi Pico (MicroPython): 2284.749 ms
  • Metro M4/SAMD51 (CircuitPython): 1575.32 ms
  • RPi Pico (CircuitPython): 1956.05 ms

康威生命遊戲(64 x 32,bytearrays,boolean 資料)跑一回合的大概時間

  • ESP32 (MicroPython): 561~564 ms
  • RPi Pico (MicroPython): 739~742 ms
  • Metro M4 (CircuitPython): 496~501 ms
  • RPi Pico (CircuitPython): 583~584 ms

SEFR 線性分類演算法對鳶尾花資料集(150 筆浮點數資料 x 4 特徵,3 個分類)做訓練

  • ESP32 (MicroPython): 178.024 ms
  • RPi Pico (MicroPython): 182.918 ms
  • Metro M4 (CircuitPython): 124.39 ms
  • RPi Pico (CircuitPython): 167.969 ms

非常有趣的是我的 Adafruit Metro M4(SAMD51 處理器,120 HMz)表現居然最好,而 RPi Pico 和 ESP32 這兩個雙核處理器的表現非常接近。RPi Pico 當然沒有 WiFi 和藍芽,但在運算能耐上似乎不俗。

當然我沒有使用任何特殊設定,所以無法得知它們運行時是否有用到雙核心。但也許有吧。另外 MicroPython 與 CircuitPython 都指出 RPi Pico 的時脈為 125 MHz。這應該才是它正常的運作速度。

初期而言,CircuitPython 也許是更實用的 Python 選擇

很快的 Arduino IDE 應該就也有官方或第三方的 RPi Pico 或其他 RP2040 開發板支援了(C++),TinyGo 或許也許會跟進,不過這裡我們就只先討論兩個嵌入式 Python 吧。

當然,為什麼要用 Python 替微控制寫程式?Python 比 C++慢很多不是嗎?其實,如果你不需要做非常密集的運算,Python 高度彈性的語法、能做錯誤攔截等等就會使開發過程簡單許多,特別是你能直接從電腦對開發板直譯程式,等到確定都 ok 了再上傳。相對於正規 Python 學習已經一面倒向資料科學/機器學習的現況,嵌入式 Python 反而是更好玩和用途更廣泛的。

除了運算速度稍稍略勝外,CircuitPython 有個比 MicroPython 更實務的地方:儘管其周邊裝置的驅動程式也不能說是包山包海,但一直以來也是由 Adafruit 與 CP 社群積極維護,所以就生態系、現成函式庫甚至說明文件來說,比起硬體相容性可能仍有疑問的 MicroPython,CircuitPython 反而能更快投入應用。

再者,如我在其他文章所提的,CircuitPython 韌體會讓開發板變成真正的 USB 碟,這表示你能同樣用複製貼上來新增驅動程式、甚至上傳影音跟文件等。只要實際使用過,你就會發現那真是方便到不可思議。MicroPython 則和 ESP 家族一樣,仍得透過編輯器的介面來上傳和瀏覽檔案。

最後,CircuitPython 韌體還包含一項秘密武器:ulab 模組,也就是簡化版的 NumPy,能用來提高某些數學處理的速度。以前面的 SEFR 分類演算法來說,若用 ulab 來改寫,所需時間就會降到 1/3 不到!ulab 在諸如 SADM51、ESP32-S2 和 RPi Pico 的韌體都有提供,且當然也有初步的 NeoPixel 支援。

不服氣的 MicroPython 則指出它有 machine.Timer 模組,可輕鬆地實現平行運算,甚至比正規版 Python 還簡單。有個有趣的點是,RPi Pico 的 MicroPython 有某些語法已經跟 ESP 家族的不太一樣,在某些方面反而還更接近 CircuitPython。這或許顯示樹莓派基金會在軟體開發上向 Adafruit 借了不少力吧。

你該買 Raspberry Pi Pico 嗎?

如果你不是樹莓粉,那麼當然不見得 — — RPi Pico 身為進口貨,要賣到僅僅 4 美元是不可能的,而 ESP 家族在亞洲依舊享有效能與價格的優勢(更別提其 IoT)。

當然,如果之後台灣貨源多,價格能壓在 200 再低幾十塊的話,它或許就能拿來取代 Arduino Nano/Micro Pro 這類開發板,對於做小型專案就會蠻方便的。別忘了,很多 ESP32 開發板體型偏大,且最便宜也要 300、400 以上,有時用起來難免就是有點顧忌。

若想玩 CircuitPython,它也會是個不錯的選擇,至少比 Adafruit 產品便宜,快閃記憶體也比 Seeeduino XIAO 大。UF2 bootloader 能讓你很快的切換到不同語言,使你有更多的開發選擇。

至於現在要觀察的,是 RPi Pico 的 PIO 和 MicroPython 生態系能否達到超越 ESP 家族現有的程度,以及 Arduino Nano RP2040 Connect 的實際售價。說不定等到 RP2040 處理器開放其他廠商使用後,中國那邊會順勢做出更便宜和更強大的新品也說不定吧。

目前仍只聞樓梯響的 Arduino Nano RP2040 Connect

(2/10 補:Arduino 在推特上貼出了 RP2040 Connect 的照片:)

考慮到 RP2040 的執行速度比 Nano 33 BLE 的 nRF52840(64 MHz)快,Tensorflow Lite 也已經支援 Pico,RP2040 Connect 應該會成為接下來 TinyML 領域的新寵。

--

--

--

My writing power is 100% generated by free coffee. (github.com/alankrantas, www.hackster.io/alankrantas)

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alan Wang

Alan Wang

My writing power is 100% generated by free coffee. (github.com/alankrantas, www.hackster.io/alankrantas)

More from Medium

How To Mine Monero On A Raspberry Pi in 2022

from cryptoandpi.cf

Installing Solana ToolChain Natively on MacBook M1, M1 Pro and M1 Max

After the Raspberry Pi comes the LX2 Honeycomb

Humble Bundle Drops Linux and macOS, Gives Customers Mere Weeks to Save Their Games