前回はHWスピンロックを試用。処理系が「時々」使うことがあるらしい機能を勝手に直接利用して前回はタマタマ動作しましたが、その後、案の定マズイ場合にも遭遇。そゆときは番号変えると動くかも。さて今回はRISC-Vのプラットフォームタイマを読み出してみます。RISC-VといいつつRP2350ではArmコアでも読めるみたい。
※Pico関係投稿一覧は こちら 『Pico三昧』は一覧の末尾付近にひっそりと。
※Pico2対応のMicroPython処理系(バイナリ、uf2形式)は以下のURLからダウンロード可能です。
https://micropython.org/download/RPI_PICO2/
※動作確認に使用しているMicroPython処理系は以下です。
MicroPython-1.24.0-riscv–with-newlib4.3.0
上記はRISC-Vコア用のバイナリですが、Arm用でも同様に動くかと(確かめてないケド。)
RISC-Vプラットフォームタイマ
RISC-Vプラットフォームタイマは64ビットの長周期のタイマです。システムに唯一無二の時間の基準を与えるためだと思われますが、RISC-V搭載のシステムで必要とされているハードウエアのようです。ラズパイPico2搭載のRP2350においては、コアがRISC-Vの時だけでなく、Armを選択していてもこのタイマは利用可能となってるみたい。
唯一無二ということでコア0とコア1の間に1個だけ存在し、どちらからも読み出し可能。万が一タイミングがぶつかった場合は良きに計らってくれるみたい。また、セキュア、ノンセキュアの区別なく唯一無二。
今回試してみたところでは、ノンセキュアで走っているMicroPython(RISC-V)上から、セキュア側のアドレス使って読み取ることができてます。
今回実験のMicroPythonコード
前回実験のHWスピンロックを使ったコードが危ない(条件不明だがHWスピンロックの0番が処理系に使われていることがあるみたい)ことを経験したので、コンサバに_Threadモジュール内のlockを使用して実験してます。
import time, machine, _thread from micropython import const SIO_BASE = const(0xd0000000) SIO_NONSEC_BASE = const(0xd0020000) MTIME = const(0x1b0) MTIMEH = const(0x1b4) def taskA(): global lock cnt = 0 while cnt < 3: lockP = lock.acquire(1, -1) #wait lock forever if not lockP: print("Task A can not get the lock.") return rvth = 1 while rvth != machine.mem32[SIO_BASE + MTIMEH]: rvth = machine.mem32[SIO_BASE + MTIMEH] rvtl = machine.mem32[SIO_BASE + MTIME] print("Task A RISC-V platform timer: {0:08x}{1:08x}".format(rvth, rvtl)) lock.release() time.sleep(0.5) cnt += 1 _thread.exit() def taskB(): global lock cnt = 0 while cnt < 5: lockP = lock.acquire(1, -1) #wait lock forever if not lockP: print("Task B can not get the lock.") return rvth = 1 while rvth != machine.mem32[SIO_BASE + MTIMEH]: rvth = machine.mem32[SIO_BASE + MTIMEH] rvtl = machine.mem32[SIO_BASE + MTIME] print("Task B RISC-V platform timer: {0:08x}{1:08x}".format(rvth, rvtl)) lock.release() time.sleep(0.5) cnt += 1 def main(): global lock lock = _thread.allocate_lock() print("RISC-V platform timer test:") _thread.start_new_thread(taskA, ()) taskB() if __name__ == "__main__": main()
異なるコアで実行されている2つのTaskから、RISC-Vプラットフォームタイマを読み出してその値を表示してます。実体は同じタイマであるので、どちらから読んでも順番通りに段々大きな数になっていく筈。
実機実験結果
まあ順番通りのようだね。