MicroPython的午睡(20) ラズパイPico、PIO操作は最大8ビット?

Joseph Halfmoon

Raspberry Pi PicoのPIO(Programmable IO)は、Picoのユニークな機能であり、かつ適応能力最強の「ペリフェラル」だと思います。勿論MicroPythonからも利用できます。しかし前回、普通のSRAMをPIO経由で制御しようとしてトラぶりました。今回は釈然としない部分に絞ってその動作を実機確認してみたいと思います。

※「MicroPython的午睡」投稿順 Indexはこちら

前回トラブった問題をまとめると、合計14本の端子を一度に操作しようとしたのですが思ったように動作してくれない、ということになります。ラズパイPico上で、MicroPythonを記述する場合の拠り所となる文書、

raspberry-pi-pico-python-sdk

の “3.9 PIO Support” を眺めたところではその辺の制限についての言及は無いように思います(見落としていたらすみません。)そして細かいところは、RP2040のデータシート(またはC-SDK)を参照せよ、という感じです。

rp2040-datasheet

そしてRP2040 データシートの “Chapter 3.PIO” をみれば、PIO操作のビット数指定フィールドは5ビットあり、32ビット幅の操作まで行えるような「命令セット」になっているように見えるのです。疑いは、

MicroPython上では8ビットまでしか操作できんのじゃなかろうか?

ということに尽きます。

そこでRaspberry Pi PicoのGP0からGP13まで14本の端子をDigilent Analog Discovery2のDIO(デジタルIO)0から13までに直結し、ロジアナ機能を使って出力操作を確認してみることにいたしました。接続の様子はアイキャッチ画像に掲げた通りです。

テストに使用したMicroPythonコード全文は末尾にあります。ハード上14端子を接続しましたが、問題は8ビットと9ビットの間にあるので

  • SM(ステートマシン)0 で8ビット出力
  • SM(ステートマシン)1 で9ビット出力
  • 動作周波数10kHz、適宜1ms程度の待ちを挟む

という方法で、動作を観察しました。期待される動作は、GP0をLSB、GP8をMSBとしたとき、以下の値が以下の順番で出力されることです。

  1. 0x0FF
  2. 0x080
  3. 0x17F
  4. 0x010

実際にロジアナ機能で得た結果がこちら。

PIObit8NOTWORK
結果を値に直せば

  1. 0x0FF
  2. 0x080
  3. 0x07F
  4. 0x010

下の8ビットは期待通りの動作をしているのですが、MSBの9ビット目がピクリとも動きませぬ。9ビット出力と8ビット出力の差は、「9」ビットという指定のみ。どこか書き方が悪いのか。。。ともあれ、

この書き方では8ビットまでの操作しかできない

というのが、今日のところの結論であります。とほほ。

MicroPython的午睡(19) ラズパイPico、「普通の」SRAM接続に手こずる に戻る

MicroPython的午睡(21) ラズパイPico、M5Atom LiteとUART通信 へ進む

テストに使用したMicroPythonコード
from rp2 import PIO, asm_pio
from machine import Pin, Timer
import time

@asm_pio(out_init=(rp2.PIO.OUT_LOW,)*8, out_shiftdir=PIO.SHIFT_RIGHT)
def writeB8():
    pull()
    out(pins, 8)

@asm_pio(out_init=(rp2.PIO.OUT_LOW,)*9, out_shiftdir=PIO.SHIFT_RIGHT)
def writeB9():
    pull()
    out(pins, 9)

sm0 = rp2.StateMachine(0, writeB8, freq=10000, out_base=Pin(0))
sm1 = rp2.StateMachine(1, writeB9, freq=10000, out_base=Pin(0))

while True:
    sm0.active(1)
    sm0.put(0xFF)
    sm0.put(0x80)
    time.sleep_ms(1)
    sm0.active(0)
    time.sleep_ms(1)
    sm1.active(1)
    sm1.put(0x17F)
    sm1.put(0x010)
    time.sleep_ms(1)
    sm1.active(0)
    time.sleep_ms(1)