0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「自作OS」ARMv7-M (Cortex-M) 向けにゼロから設計した 教育的リアルタイムOS (RTOS) の作り方

Posted at

こんにちは!
組み込みエンジニアなら誰もが一度は夢見る「OS自作」を実現しました。
本記事では、ARMv7-Mアーキテクチャ(Cortex-Mコア)向けに教育目的でゼロから開発した最小限のリアルタイムOS (RTOS) である「tinyos-rtos」の設計思想と、その核となるタスクスケジューリングの仕組みを徹底解説します。

低レイヤーの仕組みを深く理解したい方、RTOSの仕組みをわずか数百行のコードで学びたい方は、ぜひ最後までご覧ください!

🌟 tinyos-rtos の特徴

特徴 説明
ターゲット ARMv7-M (Cortex-M) 例: STM32, Kinetisなど
目的 RTOSの基礎(タスク管理、スケジューリング)を学ぶための教育用
実装言語 C言語と最小限のインラインアセンブラ
ライセンス MIT License (自由に利用・改変可能)

🔗 GitHubリポジトリはこちら
https://github.com/cmc-labo/tinyos-rtos


🧠 RTOSの核!コンテキストスイッチの仕組み

RTOSの面白さは、複数のタスクが同時に動いているように見せかけるための「コンテキストスイッチ」にあります。

tinyos-rtosでは、このスイッチングにCortex-Mが提供する**例外ハンドラ(割り込み)**を利用しています。

1. PendSV割り込みとタスクスイッチ

タスク切り替えの要求は、ソフトウェアがトリガーできるPendSV (Pendable Service Call) 割り込みによって処理します。

  • タスクA 実行中に切り替えが必要になると(例: タイムアウト)、PendSVをペンディング(保留)します。
  • 現在の処理が完了した後、PendSVハンドラが実行されます。

PendSVハンドラ内で行われるのが、以下の処理です。

  1. 古いコンテキスト(タスクAの状態)の保存
    現在のスタックポインタ(SP)が指すメモリに、タスクAの実行に必要なレジスタの値(R4-R11 など)を保存します。
  2. 次タスクの決定
    スケジューラが次に実行すべきタスク(例: タスクB)を決定します。
  3. 新しいコンテキスト(タスクBの状態)の復元
    タスクBのスタックポインタから、保存されていたレジスタの値(R4-R11 など)をレジスタへ復元します。
  4. タスクBへ制御を移行
    例外ハンドラから復帰する際、スタックからPC(プログラムカウンタ)などが復元され、タスクBの実行が再開されます。

この一連の処理を数百行のCコードとアセンブラで実現している点が、このOSの最もエキサイティングな部分です。

📚 注目ポイント
最小限のコードでタスクスイッチを実現するため、アーキテクチャが自動的に保存するレジスタ(R0-R3, R12, LR, PC, PSR)を最大限活用し、手動で保存するレジスタ数を削減しています。


🛠️ tinyos-rtos のセットアップと実行

実際にこのOSがどのように動くかを確認してみましょう。

1. 必要なツール

  • GCC (ARM Embedded Toolchain)
  • CMake
  • ターゲットマイコン向けの環境(例: OpenOCDなど)

2. ビルドと実行 (例: XXXボード)

# GitHubからクローン
git clone [https://github.com/cmc-labo/tinyos-rtos.git](https://github.com/cmc-labo/tinyos-rtos.git)
cd tinyos-rtos

# ビルドディレクトリ作成とCMake実行
mkdir build && cd build
cmake ..
make

# バイナリの書き込みと実行
# (ご自身の環境に合わせてコマンドを記載。例: openocd -f ... -c "flash_write tinyos.elf")

3.デモコード解説 (Lチカの例)

main.c には、タスク切り替えが目で見てわかるように、異なる速度でLEDを点滅させるデモが含まれています。

// 💡 Task 1: 500ms周期でLEDを点滅
void task_led1(void *arg) {
    // ...
    while (1) {
        // LED点灯/消灯処理
        // os_delay(500); // 500ms待機 (ここでタスクスイッチが発生する)
    }
}

// 💡 Task 2: 250ms周期でLEDを点滅
void task_led2(void *arg) {
    // ...
    while (1) {
        // LED点灯/消灯処理
        // os_delay(250); // 250ms待機 (ここでもタスクスイッチが発生する)
    }
}

それぞれのタスクが独立して実行され、周期的にCPU時間を分け合っていることが確認できます。

今後の展望とコントリビュートのお願い

現在は最小限の機能に絞っていますが、今後は以下の機能を追加する予定です。

  • 動的メモリ管理 (malloc/free) の追加
  • セマフォやミューテックス など、より高度な同期プリミティブの実装
  • デバッグ機能 の強化

この記事を読んで興味を持った方、低レイヤー開発が好きな方は、ぜひGitHubで Star を押したり、Issue や Pull Request で開発に参加していただけると嬉しいです!

🎉 自作OSの世界へようこそ!一緒に tinyos-rtos を育てていきましょう!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?