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?

Raspberry Pi Picoに搭載されているPIO(Programable I/O)は万能モジュール。MicroPythonでの実装例。

0
Last updated at Posted at 2026-05-02

はじめに

 Raspberry Pi Picoに搭載されているPIO(Programable I/O)は、精密なGPIOの制御ができる専用のハードウェアモジュール。CPUの処理負荷を使わずに、複雑なタイミングの信号生成や、特殊なプロトコルの実装をできるため、柔軟な I/O を必要とする場面で非常に便利な機能。PIOはC/C++でもMicroPythonどちらでも利用可能。本記事では、MicroPythonを中心にまとめる。

  • C/C++の場合
    *.pio にPIO制御用のアセンブラを記述すると、Build時に *.pio.h のCファイルに変換され、Cから関数としてコールすることができるようになる。公式ドキュメントは下記の「Chapter 3. Using programmable I/O (PIO)」参照。

  Raspberry Pi Pico-series C/C++ SDK

  • MicroPythonの場合
    import rp2でライブラリをインポートすると、*.pyファイル内に直接アセンブラ記述が可能。公式ドキュメントは下記の「3.9. PIO Support」参照。

    RP-008355-DS-1-raspberry-pi-pico-python-sdk.pdf

目次

PIOの仕組み

PIOの構成をまとめる。詳細はデータシート参照。RP2040がPico1でPR2350がPico2。
RP-008371-DS-1-rp2040-datasheet.pdf
RP-008373-DS-2-rp2350-datasheet.pdf

  • HW構造

    • PIOが2ブロック(Pico2 は3ブロック)
    • 4つのステートマシーンと各ステートマシーンごとに32bitのTx/RxのFIFO
    • 4つのステートマシン共有の32命令分のメモリ
    • FIFOはCPUやDMAでデータのやり取りができるバッファ

    image.png
     

  • 機能

    • クロック分周
      クロック分周器でステートマシーンの処理速度を調整する。  
    • OSR(Output Shift Register)
      Tx FIFO→OSR→Pinへ1bitずつH/L出力
    • ISR(Input Shift Register)
      Pinの1bitずつH/L入力→ISR→RX FIFO

    image.png

戻る

アセンブラ命令

アセンブラの命令は9つ準備され、pin/pins/x/y/[delay]と組み合わせて使う。

  • pin/pins
    ステートマシーンで設定するin_base,out_baseで決まる。pinはin_baseで設定したpinで、pinsはそこから連続するpin数を指定する。
     
  • x/y
    32bitの汎用レジスタでPIOの中で値を保持や比較、ループカウンタに使うためにある。2種類存在する。
     
  • [delay]
    各命令の後のdelayを指定する。例えば set(pins,1) [5] とすると、setのあとに5delayかけるという意味。delayは5bit表現で最大[31]まで設定できる。
命令 MicroPython 記法 概要
JMP jmp("label")
jmp(x_dec,
"label")
jmp(not_x, "label")
条件付きジャンプ。x_dec は X-- して 0 でなければジャンプ。not_x は x==0 ならジャンプ。
WAIT wait(1, pin, 0)
wait(0,
irq, 3)
Pin または IRQ の状態待ち。wait(1, pin, 0) は GPIO0 が High
になるまで待つ。
IN in_(pins, 1) Pin やレジスタの値を ISR に取り込む。in_(pins, N) は Nbit の GPIO を読む。
OUT out(pins, 1)
out(x, 1)
OSR のビットを Pin やレジスタへ出力。out(pins, N) は Nbit を GPIO に出す。
PUSH push()
push(block)
ISR → RX FIFO へ転送。block 付きは FIFO が空くまで待つ。
PULL pull()
pull(block)
TX FIFO → OSR へ転送。block 付きは FIFO が空なら停止。
MOV mov(x, y)
mov(pins,
x)
mov(x, invert(x))
レジスタ間コピー、反転、ビット操作。invert(x) は ~x と同じ。
IRQ irq(0)
irq(block, 1)
IRQ フラグのセット/クリア/待ち。irq(block, n) は IRQ n がセットされるまで待つ。
SET set(pins, 1)
set(x,
0)
set(pindirs, 1)
即値を Pin やレジスタへ書き込み。set(pindirs, 1) は GPIO を出力に設定。

戻る

PIOの設定

PIOの制御はデコレータで記載し、StateMachine().active(1) で設定駆動させる。デコレータについてはPythonのデコレーター #Python - Qiitaを参照。

ざっくり下記のような感じになる。

from machine import Pin
import rp2
from rp2 import StateMachine

# デコレータで記述
@rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW))
def pio_test():
    #-------------------
    #ここにアセンブラを書く
    #------------------- 

# StateMachine0 を 2MHzでGPIO0を起点に pio_test()で設定
sm = StateMachine(0, pio_test,freq=2_000_000,set_base=Pin(0))
sm.active(1)

戻る

PIOを使った例

GPIO0/1/2/3/4をPIOで制御する例を示す。GPIO0/1/2/3 をH/L出力させる。GPIO4は入力で値を32bit単位でRxFIFOに詰める例。

from machine import Pin
import rp2
from rp2 import StateMachine
import time

# GPIO 0,1,2,3 を設定 set_initはtapleで使うポート分列挙する
@rp2.asm_pio(set_init=(rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW,rp2.PIO.OUT_LOW))
def pio_toggle():
    # wrap_target()→wrap()でループし続ける。
    wrap_target()
     # GPIO 0,1,2,3の値を同時に設定できる。
    set(pins,  0b0001)
    set(pins,  0b0010) [1]
    set(pins,  0b0100) [2]
    set(pins,  0b1000) [3]
    set(pins,  0b0000) [4]
    set(pins,  0b1111) [6] # GPIO0,1,2,3をHにして6 delayする
    set(pins,  0b0000)
    wrap()

# GPIO 4に32bit ISRにたまったら、自動的に RxFIFOにpushするという設定
@rp2.asm_pio(in_shiftdir=rp2.PIO.SHIFT_LEFT, autopush=True, push_thresh=32)
def pio_read():
    wrap_target()
    in_(pins, 1)
    wrap()

# --- 出力側 SM0 --- 2MHz GPIO 0基点
sm0 = StateMachine(0, pio_toggle,freq=2_000_000,set_base=Pin(0))

# --- 入力側 SM1 --- 2MHz GPIO 4基点
sm1 = StateMachine(1, pio_read,freq=2_000_000,in_base=Pin(4))

sm0.active(1)
sm1.active(1)

# --- 読み取りループ ---
while True:
    if sm1.rx_fifo():
        v = sm1.get()
        print(f'{v:08X}')

 この例の結果をロジアナでとると👇OUT方向のGPIO0,1,2,3は下記の波形となる。H/Lの区間がぴったり制御できる。

image.png

 PIOを使えばどんな複雑な波形でも記述できるので、いろいろな用途に使えそう。またIN方向については、今回DMAを使っていないので、CPUの取りこぼしが出ると思うが、DMAと組み合わせてあげれば取りこぼしなくRAMにポートの状態をコピーし続けることができるので、Picoでロジックアナライザを作ることもできると思う。

戻る

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?