Raspberry Pi Picoのマルチコアと割り込み処理の相性
妻の要望でキッチンタイマーの制作をしている。ハードウェアはraspberry pi pico、 開発言語はmicropythonです。
今回、初めてmicropythonを使ってみたのですが、楽ちんの一言。
しかし、raspberry pi picoとmicropythonの組み合わせでは、デバッグ時のステップ実行ができないのが少々難点。
キッチンタイマーの機能について妻からの要望は、ボタン式のタイマーは面倒くさいので、時間のセットはダイヤル式であること。時間の表示はデジタルであること。
そして、自分自身が欲しい機能のして、タイマー値のメモリー機能。
メモリー機能が欲しいのは、5年くらい前に炊飯器が壊れ、ガスコンロで米を焚いている。「始めちょろちょろ中ぱっぱ赤子泣くとも蓋取るな」で、複数通りタイマーが必要なのです。後、蒸らしの時間も。それで毎回時間をセットするのは面倒くさい! コンロの前に張り付いていれば、タイマーなんぞは必要ないけれどが、それでは他の作業ができない。
それで、前から思っていた機能盛沢山のキッチンタイマーの制作に取り掛かったのです。
そして、開発途中で問題にブチあたった。キッチンタイマーがフリーズする。キッチンタイマーにとって、タイマーが止まるのは致命的だよね。
デュアルコア(演算処理装置が2個)、タイマー、温度センサー、PIOと資源をフル活用しようと思っていたのですが問題が発生した。デュアルコアとタイマー割り込み、そして入力ピンの割り込みを同時に使用すると、何かのタイミングでraspberry pi picoがフリーズするのです。入力ピンにはダイヤル式のスイッチが繋がっている。
逃げ道としては、raspberry pi picoをシングルコアで動す。もしくは、入力ピンの割り込みやめて、入力ピンの状態をポーリングしてボタンスイッチの状態を確認する方法でフリーズは回避する。
でも折角のデュアルコアをシングルコアで動かすのはもったいない。またポーリングして、ピンの状態を張り付いて監視するのは馬鹿らしい。
ハードウェアの状況確認のため、不具合確認用のプログラムを書いた。そして分かったことは、10ミリ秒で割り込みが発生するタイマー作動中に、ボタンを1秒間に25回から40回を連打する動作をすると、picoがプリーズする。
一秒間に25回もボタンを連打するなんて、16回連打できる高なんとか名人でも無理なのですが、ロータリースイッチだったら可能。しかし、ロータリースイッチをゆっくり回してもフリーズする時はするので、よくわからない。
下記は確認用のコード。
ロータリースイッチの代わりにPIOの機能を使て、1秒間に数十回スイッチをOn/Offするプログラムを独立して動かす。(PIOはCOREと独立しているので、COREが停止してもPIOは動き続ける)
ハード的にはOn/Offを繰り返しているピンを、ロータリースイッチの入力するピンにジャンパーピンでつなげる。
だた、根本的な不具合の解決策は見つかっていない。
下記のコードは不具合の原因を探るために、コードをダイエットしたもの。メイン処理は何もせずに、ただ割り込みを受け付けるだけのコードです。
from machine import Pin, Timer
from rp2 import PIO, StateMachine, asm_pio
import micropython
import _thread
led25 = machine.Pin(25, machine.Pin.OUT)
led25.value(0)
PIO_SIGNAL_PIN = 11
SW_PIN_A = 13
timertalbe = [-1,-1,-1,-1,-1]
TIMER_ALARM_IDX = 0
@asm_pio(set_init=PIO.OUT_LOW)
def blink():
set(pins, 1)
set(x, 5)[10]
label('loop_high')
jmp(x_dec, 'loop_high')[5]
set(pins, 0)
set(x, 5)[10]
label('loop_low')
jmp(x_dec, 'loop_low')[5]
# freqが2400~4000 の範囲でフリーズする (25-42Hz)
sm = StateMachine(1, blink, freq=6_000, set_base=Pin(PIO_SIGNAL_PIN))
sm.active(1)
def decTimerFunc(timer):
for num in range(5):
if timertalbe[num] > 0:
timertalbe[num] -= 1
def switchTest( pin ):
led25.toggle()
def core0():
while True:
None
def core1():
while True:
None
def main():
decTimer = Timer()
decTimer.init(period=10, callback=decTimerFunc )
rotarySwA = machine.Pin(SW_PIN_A, machine.Pin.IN, machine.Pin.PULL_DOWN )
rotarySwA.irq(trigger=Pin.IRQ_RISING, handler=switchTest)
# CORE 0
_thread.start_new_thread(core0, ())
# CORE 1
core1()
if __name__ == "__main__":
main()
解決方法:
Raspberry Pi Picoをシングルコアで動かす
micropythonの問題と思われるので、開発環境と言語を変える(C++、Rust)
Raspberry Pi Picoをゴミ箱に捨ててESP32にする
この記事が気に入ったらサポートをしてみませんか?