読者です 読者をやめる 読者になる 読者になる

不確定特異点

広く深く、ところどころ超深く

軽量 RTOS の開発 (2)

OS ARM C

SysTick タイマ

Cortex-M コアには SysTick というタイマが内蔵されてます。今回はこの SysTick タイマによる割り込みを受けて、タスクを切り替えられるようにしてみました。

SysTick タイマはリロード値から開始して 0 になるまでダウンカウントしていき、0 になったら再びリロード値からカウントを開始します。同じリロード値でも当然クロック周波数によりカウンタが回る速度が変わりますので、通常はチップのクロック周波数から実際のリロード値を計算することになります。

ところが、SysTick には TENMS 較正値という 10 ms に相当するリロード値をレジスタとして読めるようになっており、Cortex-M コアのチップ設計者が提供することになっているようです。したがって、TENMS を SYST_CALIB (0xE000E01C 番地) から読み、その値をそのままリロード値レジスタ SYST_RVR (0xE000E014 番地) に設定するだけで、10 ms で 1 周回るカウンタの設定ができます。(エミュレータで開発しているので実機では試してないけど、この較正値レジスタって実際どのくらい提供されているのだろう?)

あとは、実際にカウンタ動作を開始させるために、NVIC の SYST_CSR (0xE000E010 番地) レジスタの下位 3 bit にあたる CLKSOURCE(外部クロック or コアクロック), TICKINT(割り込みを生成しない or 生成する), ENABLE(タイマを動作させない or 動作させる) の各ビットを 1 にセットします。これで 10 ms ごとに割り込みがかかるようになりました。

SYST_RVR = SYST_CALIB; /* リロードを 10 ms 較正値に設定 */
SYST_CSR = 0x00000007; /* コアクロック、割り込み生成許可、タイマ動作許可 */

コンテキスト切り替え

タスクの管理領域に SysTick 割り込みを受けた回数を計測するカウンタを設けておき、ある閾値を超えたら再スケジューリングする仕組みを入れました。実際のスケジューリングとコンテキスト切り替えは SysTick 割り込みから保留した PendSV ハンドラの中で行うようにしました。これは、他の例外処理も同様なのですが、優先度の高い処理を真っ先に行い、時間のかかるコンテキスト切り替えは後回しにする方針のためです。

PendSV 例外を起こすには割り込み制御・ステータスレジスタ (ICSR: 0xE000ED04) の PENDSVSET をセットするだけです。割り込みを抜けると自動的に保留状態は解除されるため、PENDSVCLR によるクリア操作は不要なもよう。

ICSR |= (1<<28); /* PENDSVSET (bit 28) をセット */

というわけで、タイマ割り込みを受けて 2 つのタスクがプリエンプティブに並行動作するようになりました!ただ、いずれのタスクも特権モードで動作しているので、今度はそこを真面目に対応しようと思います。

github.com