MicroPython的午睡(87) STM32版、入力キャプチャ割り込み受けで出力コンペア

Joseph Halfmoon

前回Timer1の入力キャプチャを割り込み受け。速度的な制約のあるMicroPythonでも割り込みを使えば、ハードの制御はかなりできるじゃないかと思います。今回は、前々回やった出力コンペアの設定を入力キャプチャ割り込みで制御してみたいと思います。割り込みハンドラでハードを制御できるのでメインは別な仕事をできると。

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

入力キャプチャして出力コンペア

前々回、出力コンペアの使い方を簡単に説明しました。出力コンペアは設定された将来時刻になったらハードウエアのタイミングで出力を行う機能であるので、「ハイスピード・アウトプット」と言われることもあるくらいです。

ただし、前々回のようにポーリングで見張っていたのでは、なけなしのCPU時間をすべて監視に費やしてしまうのでよろしくありません。出力コンペア値は、通常、別な入力信号を入力キャプチャ機能で監視し、入力キャプチャが起こったときにキャプチャ値を元に将来時刻を示すコンペア値を計算して更新すればよいわけです。入力キャプチャ割り込みが使えるのであれば、入力キャプチャ割り込みのハンドラ内で更新すればよいと。

以下のソースは前々回のポーリング版の「ちょい直し」であります。割り込みハンドラ部分は前回のソースを流用している感じ(微妙に違うけれど。)

#STM32: Timer 1 IC-OC Test w/Callback function
#Timer1 CH1 ... PA8(D7)
#Timer1 CH2 ... PA9(D8)
import pyb
import machine
import time
import micropython
import uarray

micropython.alloc_emergency_exception_buf(100)

capV = uarray.array("l", [-1] * 2)

def ch1Intr(tim):
    capV[0] = icCH.capture()
    capV[1] = capV[0] + diffV
    if capV[1] > 0xffff:
            capV[1] -= 0xffff 
    ocCH.compare(capV[1])

tim = pyb.Timer(1, prescaler=1023, period=0xffff, callback=None)
icCH = tim.channel(1, pyb.Timer.IC, polarity=pyb.Timer.RISING, pin=machine.Pin.board.D7,callback=ch1Intr)
ocCH = tim.channel(2, pyb.Timer.OC_TOGGLE, pin=machine.Pin.board.D8)
diffV = 1000

def enCh1Intr(timCH):
    timCH.callback(ch1Intr)

def disCh1Intr(timCH):
    timCH.callback(None)

def main():
    print("STM32F401RE Timer 1 IC-OC Test w/Callback.")      
    print("Source  Freq: {0} Hz".format(tim.source_freq()))
    print("Timer 1 Freq: {0} Hz".format(tim.freq()))
    enCh1Intr(icCH)
    while True:
        pyb.LED(1).on()
        time.sleep(1)
        pyb.LED(1).off()
        time.sleep(1)

if __name__ == "__main__":
    main()

上記のソースでは、割り込みハンドラの設定後、メインルーチンにはやることが無いので、ダラダラとLチカをしています。実際には、もっと有用な他のお仕事をやらせるのが良いと。

出力コンペアの実機動作確認

Timer1のチャネル1に入力キャプチャ機能が仕掛けてあります。チャネル1STM32F401REのPA8端子(Nucleo-F401REボードのD7端子)に出ているので、外部からの入力信号はここに印加します。

Timer1のチャネル2が出力コンペアです。PA9端子(ボードのD8端子)に接続しているので、コンペア結果はこの端子にでてきます。

プリスケーラ1023と、「ゆっくり」回転させているTimer1のカウンタ値をチャネル1の立ち上がりエッジでインプット・キャプチャし、その値に対してdiffVカウント後の「未来」にチャネル2の出力をトグルさせる、という設定です。

まずはdiffV=1000の時の様子。C1黄色が入力信号。C2青色が出力信号です。C1の立ち上がりから決まった時間経過後に青色の出力信号がトグルしているのがわかるかと思います。ICOCintDiff1000

つづいて、diffV=500の時の様子です。青色の出力信号のトグルするタイミングが約半分くらいの位置まで早まったことがわかるかと思います。ICOCintDiff500

今回は入力信号に簡単のため定周期の信号を与えていましたが、実際には変動する(たとえばモータとかエンジンの回転など)信号を与え、そのイベントからxマイクロ秒後とか、yミリ秒後に出力信号にトリガかける、というのが典型的な使い方じゃないかと思います。

MicroPython的午睡(86) STM32版、タイマ・チャネル、割り込み受け TIPS へ戻る

MicroPython的午睡(88) STM32版、SPI接続のSRAM読み書きテスト へ進む