Raspberry Pi Picoでモータを動かす⑤(PIOで動かす③)でようやくパルスを指定した数だけ動かせたが、一方向にしか動かなかった。
今回は実用により近づけるためCW/CCWが切り替えて使えるようにしていきたい。
方針
前回のコードに更に命令を追加して対応するというのは、インストラクションメモリの容量からしてなかなか厳しい。
そのため、PIOを2つ使って出力を切り替えて強引に望みの動作を実現する方法で検討する。
イネーブルを切り替える
データシートを読むと、出力はステートマシンの番号が大きいほうが優先されるとある。
まずは、(多分出来ないとは思うが)使っていないときに出力をOFFにすることで出力のマルチプレクスできないかを試してみる。
from rp2 import PIO, StateMachine, asm_pio
import time
from machine import Pin
@asm_pio(set_init=(PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW), out_shiftdir=PIO.SHIFT_LEFT, autopull=False)
def cw():
# wrap_target()~wrap()までが無限ループになる
set(x, 0)
wrap_target()
jmp(x_dec, "step1")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step1")
set(pins, 0b1001)[3]
jmp(x_dec, "step2")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step2")
set(pins, 0b0011)[3]
jmp(x_dec, "step3")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step3")
set(pins, 0b0110)[3]
jmp(x_dec, "step4")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step4")
set(pins, 0b1100)[3]
wrap()
@asm_pio(set_init=(PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW), out_shiftdir=PIO.SHIFT_LEFT, autopull=False)
def ccw():
# wrap_target()~wrap()までが無限ループになる
set(x, 0)
wrap_target()
jmp(x_dec, "step1")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step1")
set(pins, 0b1100)[3]
jmp(x_dec, "step2")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step2")
set(pins, 0b0110)[3]
jmp(x_dec, "step3")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step3")
set(pins, 0b0011)[3]
jmp(x_dec, "step4")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step4")
set(pins, 0b1001)[3]
wrap()
cw = StateMachine(0, cw, freq=2000, set_base=Pin(2))
cw.active(1)
ccw = StateMachine(4, ccw, freq=2000, set_base=Pin(2))
ccw.active(1)
cw.put(0x200)
time.sleep(5)
ccw.put(0x200)
結論から言うとCCWしか回らない。
これはまぁ納得の行く話で、cwのステートマシン番号が0なのに対してccwは4で大きいため(0~3のステートマシンと4~7のステートマシンはインストラクションメモリを共用するようだ)pindirsの出力設定もccwが優先されたというだけの話かと思う。
ワイアードORみたいな真似はできないってことですね。
アクティブでなくする
ならばということで自分の中で本命のステートマシンをactive(0)にして落とす作戦を行う。
コードは下記
from rp2 import PIO, StateMachine, asm_pio
import time
from machine import Pin
@asm_pio(set_init=(PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW), out_shiftdir=PIO.SHIFT_LEFT, autopull=False)
def cw():
# wrap_target()~wrap()までが無限ループになる
set(x, 0)
wrap_target()
jmp(x_dec, "step1")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step1")
set(pins, 0b1001)[3]
jmp(x_dec, "step2")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step2")
set(pins, 0b0011)[3]
jmp(x_dec, "step3")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step3")
set(pins, 0b0110)[3]
jmp(x_dec, "step4")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step4")
set(pins, 0b1100)[3]
wrap()
@asm_pio(set_init=(PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW, PIO.OUT_LOW), out_shiftdir=PIO.SHIFT_LEFT, autopull=False)
def ccw():
# wrap_target()~wrap()までが無限ループになる
set(x, 0)
wrap_target()
jmp(x_dec, "step1")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0b1111)
label("step1")
set(pins, 0b1100)[3]
jmp(x_dec, "step2")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step2")
set(pins, 0b0110)[3]
jmp(x_dec, "step3")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step3")
set(pins, 0b0011)[3]
jmp(x_dec, "step4")
set(pindirs, 0)
pull()
out(x, 32)
set(pindirs, 0x1111)
label("step4")
set(pins, 0b1001)[3]
wrap()
cw = StateMachine(0, cw, freq=2000, set_base=Pin(2))
cw.active(1)
ccw = StateMachine(4, ccw, freq=2000, set_base=Pin(2))
cw.put(0x200)
time.sleep(5)
cw.active(0)
ccw.active(1)
ccw.put(0x200)
time.sleep(5)
ccw.active(0)
満を持して実行したが…これもccwしか回らない。
実験の結果ステートマシン間でのピンの共有は出力ディセーブルだろうがステートマシンがアクティブで無かろうが不可能ということが分かった。
引き続きCW/CCWが切り替えられる方法を探っていくが、もうこれは駄目かも分からんね…。