Pico三昧(56) ラズパイPico2:RP2350、HWスピンロックの試用

Joseph Halfmoon

前回はMicroPython処理系が備えているlockをつかって2コアの排他制御を試みました。今回はラズパイPico/Pico2に特有なハードウエア・スピンロック機構を使ってみます。RP2040のときには有用であったHWスピンロックですが、RP2350では後ろ向きの機能になってます。でも使えることに変わりありませぬ。

※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用でも同様に動くかと(確かめてないケド。)

HWスピンロック

ラズパイPicoのRP2040ではArm Cortex-Mシリーズの末弟 Cortex-M0+を2個搭載してました。もともとマルチコアを狙っていないと思われるM0+は排他制御向けのATOMIC命令を備えていませぬ。ATOMIC命令なしに「カッコよく、効率的な」制御を実現するためだと思いますが、RP2040の2コア間に存在するSIO(シングル・サイクルIO)ブロック内に32個のHW spinlock機構が備えつけられています。

一方、ラズパイPicoのRP2350では、Arm Cortex-M33も、RISC-V Hazard3も、ATOMIC命令を備えてます。フツーのメモリ上でフツーに「効率的な」排他制御機構を実装できる筈。よってRP2350では、わざわざHW spinlock機構を使わなくてもよいと思われます。しかし、互換性のためにこの機構はRP2350でも生かされておるようです。

そこで今回は「前回 MicroPython処理系の lock 機構で行った制御をHWスピンロックで書き替えたらどうよ」ということで実験してみます。

なお、以下のように考えました。

    1. RP2350のHWスピンロック機構は、セキュア/ノンセキュアで2重化されている
    2. MicroPython処理系上のスクリプトは「ノンセキュア」な側で動作しているみたい
    3. よって「ノンセキュア」な側のHWスピンロック機構を使用する
    4. 過去回のPicoで行った実験では、MicroPython処理系自身がHWスピンロック機構を使う場合がある(目撃したのは真ん中ちかくの2つ)
    5. そこで「被らない」ように一番端の0番のHWスピンロック機構を指定してみる(ソース読んだわけでないので、被るかもだけれども。)
今回実験のMicroPythonコード

前回実験のコード(_Threadモジュール内のlockを使用)を、HWスピンロックで書き替えただけのものです。

import time, machine, _thread
from micropython import const

SIO_BASE = const(0xd0000000)
SIO_NONSEC_BASE = const(0xd0020000)
SPINLOCK_ST = const(0x05c)
SPINLOCK0 = const(0x100)

def taskA():
    cnt = 0
    while cnt < 10:
        while machine.mem32[SIO_NONSEC_BASE + SPINLOCK0] == 0:
            pass
        print("Task A gets HW spinlock 0.")
        for i in range(1, 10):
            print(i+100," ",end="")
        print()
        print("Task A SPINLOCK_ST: {0:08x}".format(machine.mem32[SIO_NONSEC_BASE + SPINLOCK_ST]))
        machine.mem32[SIO_NONSEC_BASE + SPINLOCK0] = 1
        time.sleep(0.5)
        cnt += 1
    _thread.exit()

def taskB():
    cnt = 0
    while cnt < 20:
        while machine.mem32[SIO_NONSEC_BASE + SPINLOCK0] == 0:
            pass
        print("Task B gets HW spinlock 1.")
        for i in range(1, 10):
            print(i+200," ",end="")
        print()
        print("Task B SPINLOCK_ST: {0:08x}".format(machine.mem32[SIO_NONSEC_BASE + SPINLOCK_ST]))
        machine.mem32[SIO_NONSEC_BASE + SPINLOCK0] = 1
        time.sleep(0.5)
        cnt += 1
    print("END.") 

def main():
    print("HW spinlock test:")
    _thread.start_new_thread(taskA, ())
    taskB()
 
if __name__ == "__main__":
    main()
実機実験結果

上記のソースをPico2上で走らせた様子(の上の方)が以下に。HWspinlockResults

 

HWスピンロック機構を使っても、交通整理は上手くいっておるようです。

Pico三昧(55) ラズパイPico2:RP2350、MicroPythonで排他制御再び へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です