chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

RP2040/RP2350 PIO において仕様が変わった点

背景:RP2350になってPIOの一部仕様が変わっている。RP2350ではPIOが3つに増えたり、IRQ(4)-IRQ(7)がマイコンに通知可能になったり、PIOを超えて隣のPIOにIRQを送ったりできる。
取り組み:仕様変更点をMicroPythonから確認する(PIO ASMの仕様制限から確認できない点もある)
結論:

  • IRQ(4)~IRQ(7)もマイコン側に通知できるようになったと理解したが、MicroPythonでは対応しておらず、IRQ(4)を発生させても割り込みハンドラは呼び出されない。
  • 3つの目のPIOに対応済み、SM:11を指定するとエラーなく動作(本当にSM_11が動いているのか?までは未確認)
  • PIOを超えて隣のPIOにIRQを送るオプションに関して、PIO Assemblerの仕様では未対応

詳細:

RP2350ではIRQ4~IRQ7もマイコンに通知可能になったが、MicroPythonでも同じ動作になるか?

RP2350のDatasheetより

MicroPythonのIRQ仕様書

RP2350のPIO ASM IRQ命令仕様書

アセンブルすると、0xc004が生成される。indexのフィールドだけ使ってIRQ(4)を表現

>>> import rp2
>>> hex(rp2.asm_pio_encode('irq(4)',0))
'0xc004'

以下のコードではMicroPythonの割込みハンドラ(pio_intr_handler)が呼び出されない。多分、割り込みハンドラ用レジスタに登録していないのでは?と思われる(ソース読んでないので想像)

import time
import micropython
import machine
import rp2

GP_IN_PIN = 0
STATE_MACHINE_ID = 0

sm0 = None


def pio_intr_handler(intr_sm):
    micropython.schedule(pio_handler_scheduled, intr_sm)

def pio_handler_scheduled(intr_sm):
    print('IRQ from SM:', intr_sm)
    if intr_sm == sm0:
        print('--------------------')
        print('IRQ_SM0 is set')
    else:
        print('IRQ_SM0 is not set')    

@rp2.asm_pio()            
def only_irq():
    #irq(0)        # set IRQ(0) flag   ... OK
    irq(4)        # set IRQ(4) flag   ... OK??

def main():
    global sm0

    # to enable 2KHz to StateMachine, set systemclock to 125MHz
    machine.freq(125_000_000)
    sm0 = rp2.StateMachine(STATE_MACHINE_ID, only_irq, freq=2000)
    sm0.irq(handler=pio_intr_handler)
    sm0.active(1)
    time.sleep(10)
    sm0.active(0)

main()

MicroPython側では、IRQ0-3までしか割込みハンドラの対応をしてくれなさそうだ。抜粋したコードは以下。IRQ0-IRQ3までしか対応してないように思える。もし修正するなら、ここをIRQ4-IRQ7までの分を足して、新しい割り込みハンドラ(pio0_irq1)を作り、割り込みベクタテーブルに登録する必要があると思われる。(このままでは不可と分かったので目的は達成したとする(さすがにソースコードは改修しない MergeRequest 出したら喜ばれるのか??多分そうはならないだろう))

https://github.com/micropython/micropython/blob/master/ports/rp2/rp2_pio.c

PIOが3系統になって、SM(8)-SM(11)は使えるか?

以下のLチカプログラムにおいて、StateMachineを11番で指定、rp2.StateMachine()を実行、正常に動作した(LEDが点滅)。だから、、SM8-SM11は指定可能。

#
# test program blink with wait loop
#

import machine
from machine import Pin
import rp2

STATE_MACHINE_ID = 11

SET_BASE_PIN=1
machine.freq(125_000_000)  # set 125MHz to same RP2040

@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink_w_wait():
    set(pins, 1)             # PIN1 <- 1
    mov(x,y)                 # x <- y (0x0300)
    label('wait_loop_0')
    jmp(x_dec,'wait_loop_0') # while x--
    set(pins, 0)             # PIN1 <- 0
    mov(x,y)                 # x <- y (0x0300)
    label('wait_loop_1')
    jmp(x_dec,'wait_loop_1') # while x--


#
# get value from  scratch register [x] or [y] 
#
def get_from_scratch_reg(sm, x_or_y):
    sm.exec(f"mov(isr, {x_or_y})")
    sm.exec("push()")
    return sm.get()

#
#  set value to  scratch register [x] or [y] 
#
def set_to_scratch_reg(sm, x_or_y, val):
    sm.put(val)
    sm.exec("pull()")
    sm.exec(f"mov({x_or_y}, osr)")


sm = rp2.StateMachine(STATE_MACHINE_ID, blink_w_wait, freq=2_000, set_base=Pin(SET_BASE_PIN))
set_to_scratch_reg(sm, 'y', 0x0300)

#
# start StateMachine
#
sm.active(1)

■追記
RP2340 / MicroPython v1.28.0 on 2026-04-06 において、PIO(0)のState machine(1)において、IRQ(0)を発行しても割込みが発生しない。なぜ?
IRQ(1)にすると割込みが発生する。または、 irq(rel(0))でもOK。ステートマシンごとに使えるIRQが決まっている?? ソースから引用したstate_machine_objにおいて、SM番号と想定IRQを一意に決めてしまっている??