はじめに
Azure RTOS(ThreadX)とは
Azure RTOS(ThreadX) は、Microsoft が提供する組み込みシステム向けリアルタイム OS スイートです。中核となるカーネル ThreadX を中心に、ファイルシステムの FileX、TCP/IP スタックの NetX Duo、USB スタックの USBX、GUI ライブラリの GUIX などをワンパッケージで提供し、マイコン単体で必要となる RTOS 機能を包括的にカバーします。
もともとは Express Logic 社が 1990 年代に開発した ThreadX がベースで、航空宇宙・医療機器・産業機器など数十億台のデバイスで実績を積んできました。2019 年に Microsoft が買収し Azure RTOS(ThreadX) として無償公開されたことで、商用利用を含め追加費用無しで採用できるようになりました。Azure IoT 向けのミドルウェアやセキュリティ機能ともシームレスに統合でき、クラウド接続を前提とした最新の IoT ソリューションを短期間で構築できます。
ThreadX カーネルはおよそ 2 KB 程度の RAM で動作し、サブマイクロ秒レベルの高速コンテキストスイッチ、100% 決定論的スケジューリング、MISRA 準拠コードベースなどを特徴としています。また、主要半導体ベンダの BSP/SDK に標準で組み込まれているため、評価ボードを接続してすぐに動作確認できる点も大きな利点です。
ThreadXの特徴と利点
ThreadX カーネルは、組み込み開発者が小規模リソースでも高いリアルタイム性を実現できるように設計されています。主な特徴と利点は次のとおりです。
| 特徴 | 説明 | 利点 |
|---|---|---|
| 小フットプリント | コードサイズ 2〜6 KB、RAM 使用量 2 KB 程度 | メモリが限られた MCU でも採用可能 |
| 高速・決定論的スケジューリング | サブマイクロ秒のコンテキストスイッチ、すべての API が O(1) で実行 | タイミング精度が重要な制御系でも安心 |
| 優先度継承ミューテックス | 優先度反転を自動的に回避 | リアルタイム特性の劣化を防止 |
| 豊富な同期/通信 API | メッセージキュー、セマフォ、イベントフラグ、ブロックプールなど | アプリ要件に合わせた最適な IPC を選択可能 |
| 自動エラーチェック機能 | API 呼び出し時にパラメータや状態を検証 | バグの早期検出、開発効率向上 |
| 統合ツールチェーン | TraceX、GUIX Studio などの可視化ツールを提供 | 実行時挙動の解析が容易 |
| 安全認証実績 | DO-178C (航空機)、IEC 61508 (産業)、ISO 26262 (自動車) など | ミッションクリティカル用途での採用実績 |
| マルチコア/AMP 対応 | コアごとに独立したカーネルを動作可能 | Heterogeneous な SoC でスケールしやすい |
ThreadX は API がシンプルで学習コストが低く、一度習得すれば他 MCU へも移植しやすいのが大きな魅力です。これらの特徴により、開発期間の短縮と高い品質を両立できる RTOS として幅広い分野で利用されています。
使用ハードウェア
ボード: NXT社製i.MX RT1170リファレンスボード
プロセッサ: ARM Cortex-M7 (最大1GHz動作)
開発環境: MCUXpresso IDE 11.9.0
「Hello World」アプリケーションの実装
プロジェクト構造の理解
ThreadX アプリケーションは、以下の基本的な構造を持ちます:
プロジェクト/
├── source/
│ └── threadx_demo.c # メインアプリケーション
├── board/ # ボード固有の設定
├── drivers/ # ハードウェアドライバ
└── azure_rtos/ # ThreadX ライブラリ
今回は threadx_demo.c ファイルを中心に、シンプルな「Hello World」アプリケーションを実装していきます。
main()関数の役割
ThreadX アプリケーションの main() 関数は、従来の C プログラムとは少し異なる役割を持ちます:
int main()
{
/* ボードハードウェアの初期化 */
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("Azure RTOS ThreadX Hello World Demo\r\n");
PRINTF("====================================\r\n");
/* ThreadXカーネルに制御を移す */
tx_kernel_enter();
return 0;
}
重要なポイント:
- 1. ハードウェア初期化: ボードの基本設定(クロック、ピン、デバッグコンソールなど)
- 2. 初期メッセージ: アプリケーションの開始を知らせる
- 3. カーネル起動:
tx_kernel_enter()でThreadXに制御を渡す - 4. return文: 実際には到達しない(カーネルが制御を持ち続ける)
tx_kernel_enter()の意味
tx_kernel_enter() は ThreadX カーネルを起動する最も重要な関数です:
tx_kernel_enter();
この関数が呼ばれると:
- 1. カーネル初期化: ThreadX の内部データ構造を初期化
- 2. アプリケーション定義呼び出し:
tx_application_define()を自動実行 - 3. スケジューラ開始: 作成されたスレッドの実行を開始
- 4. 制御移譲: この関数から戻ることはない
重要:
tx_kernel_enter() 以降のコードは実行されません。すべてのアプリケーションロジックはスレッド内で実装する必要があります。
tx_application_define()の実装
tx_application_define() は ThreadX アプリケーションの心臓部です。この関数は tx_kernel_enter() によって自動的に呼び出されます:
void tx_application_define(void *first_unused_memory)
{
CHAR *thread_stack_pointer = TX_NULL;
/* 未使用メモリパラメータを無視 */
TX_THREAD_NOT_USED(first_unused_memory);
PRINTF("ThreadXアプリケーションの初期化を開始...\r\n");
/* バイトメモリプールを作成(スレッドスタック用) */
tx_byte_pool_create(&byte_pool, "main byte pool",
(VOID *)memory_pool, BYTE_POOL_SIZE);
/* Hello Worldスレッド用のスタックメモリを割り当て */
tx_byte_allocate(&byte_pool, (VOID **)&thread_stack_pointer,
HELLO_THREAD_STACK_SIZE, TX_NO_WAIT);
/* Hello Worldスレッドを作成 */
tx_thread_create(&hello_thread, /* スレッド制御ブロック */
"Hello World Thread", /* スレッド名 */
hello_thread_entry, /* スレッドエントリ関数 */
0, /* スレッド入力パラメータ */
thread_stack_pointer, /* スタックの開始アドレス */
HELLO_THREAD_STACK_SIZE, /* スタックサイズ */
1, /* 優先度(1が最高) */
1, /* プリエンプション閾値 */
TX_NO_TIME_SLICE, /* タイムスライス無効 */
TX_AUTO_START); /* 自動開始 */
PRINTF("Hello Worldスレッドが作成されました\r\n");
}
この関数の役割:
- 1. メモリプール作成: スレッドスタック用のメモリ領域を管理
- 2. メモリ割り当て: 各スレッドに必要なスタックメモリを確保
- 3. スレッド作成: アプリケーションのスレッドを定義・作成
- 4. 初期化完了: カーネルにスレッド実行の準備完了を通知
最初のスレッド作成
tx_thread_create() 関数は ThreadX の核となる API です。各パラメータの意味を詳しく見てみましょう:
UINT tx_thread_create(
TX_THREAD *thread_ptr, // スレッド制御ブロックへのポインタ
CHAR *name_ptr, // スレッド名(デバッグ用)
VOID (*entry_function)(ULONG), // スレッドエントリ関数
ULONG entry_input, // エントリ関数への入力パラメータ
VOID *stack_start, // スタック領域の開始アドレス
ULONG stack_size, // スタックサイズ(バイト)
UINT priority, // 優先度(0-31、0が最高)
UINT preempt_threshold, // プリエンプション閾値
ULONG time_slice, // タイムスライス(0で無効)
UINT auto_start // 自動開始フラグ
);
パラメータの詳細:
- priority: 0が最高優先度、31が最低優先度
- preempt_threshold: この値以上の優先度でないとプリエンプトできない
- time_slice: 同じ優先度のスレッド間でのタイムシェアリング
- auto_start:
TX_AUTO_STARTで作成と同時に実行開始
デバッグメッセージの出力方法
ThreadX アプリケーションでは、PRINTF() マクロを使ってデバッグメッセージを出力します:
#include "fsl_debug_console.h" // PRINTF マクロの定義
// 使用例
PRINTF("Hello, ThreadX World!\r\n");
PRINTF("カウンタ値: %lu\r\n", counter);
PRINTF("スレッド名: %s\r\n", tx_thread_identify()->tx_thread_name);
重要な注意点:
- 改行コード:
\r\nを使用(シリアル通信の慣例) - フォーマット指定子:
%lufor ULONG、%sfor 文字列 - スレッドセーフ: 複数スレッドから同時呼び出し可能
実際のコード解説
完成した Hello World スレッドのエントリ関数を詳しく見てみましょう:
void hello_thread_entry(ULONG thread_input)
{
ULONG counter = 0;
/* スレッド入力パラメータを無視 */
TX_THREAD_NOT_USED(thread_input);
/* 美しいバナー表示 */
PRINTF("\r\n");
PRINTF("*********************************************\r\n");
PRINTF("* Azure RTOS ThreadX Hello World! *\r\n");
PRINTF("*********************************************\r\n");
PRINTF("\r\n");
/* スレッド情報の表示 */
PRINTF("Hello Worldスレッドが開始されました\r\n");
PRINTF("スレッド名: %s\r\n", tx_thread_identify()->tx_thread_name);
PRINTF("優先度: %d\r\n", tx_thread_identify()->tx_thread_priority);
PRINTF("\r\n");
/* メインループ */
while (1)
{
counter++;
PRINTF("[カウンタ: %lu] Hello, Azure RTOS ThreadX World!\r\n", counter);
/* 1秒間スリープ(100 ticks = 1秒、デフォルト設定では100Hz) */
tx_thread_sleep(100);
/* 10回ごとにシステム情報を表示 */
if (counter % 10 == 0)
{
PRINTF("\r\n--- システム情報 ---\r\n");
PRINTF("システムタイマー: %lu ticks\r\n", tx_time_get());
PRINTF("スレッド実行回数: %lu\r\n", counter);
PRINTF("\r\n");
}
}
}
コードのポイント:
- 1. 無限ループ: スレッドは通常、無限ループで動作
- 2. tx_thread_sleep(): 指定したtick数だけスレッドを休止
- 3. tx_thread_identify(): 現在実行中のスレッド情報を取得
- 4. tx_time_get(): システム起動からの経過tick数を取得
- 5. カウンタ: スレッドの実行回数を追跡
実行結果の例
Azure RTOS ThreadX Hello World Demo
====================================
ThreadXアプリケーションの初期化を開始...
Hello Worldスレッドが作成されました
*********************************************
* Azure RTOS ThreadX Hello World! *
*********************************************
Hello Worldスレッドが開始されました
スレッド名: Hello World Thread
優先度: 1
[カウンタ: 1] Hello, Azure RTOS ThreadX World!
[カウンタ: 2] Hello, Azure RTOS ThreadX World!
[カウンタ: 3] Hello, Azure RTOS ThreadX World!
...
[カウンタ: 10] Hello, Azure RTOS ThreadX World!
--- システム情報 ---
システムタイマー: 1000 ticks
スレッド実行回数: 10
このシンプルな例を通じて、ThreadX の基本的なプログラム構造とスレッドの動作原理を理解できます。
学習のポイント:
- ThreadXの起動シーケンス(main → tx_kernel_enter → tx_application_define → スレッド実行)
- メモリ管理の基本(バイトプールとメモリ割り当て)
- スレッドの作成と実行制御
- システム情報の取得方法
- デバッグ出力の効果的な使用法
ビルドと実行
プロジェクトのビルド方法
1. プロジェクトをクリーン&ビルド
- MCUXpresso IDE の Project Explorer で本プロジェクトを右クリック → Clean Project を実行。
- 続けて Build Project を実行し、
"Finished building target"メッセージがコンソールに表示されれば成功です。
2. エラー確認
- エラーログがないことを確認してください。Warning のみであればそのまま進めても問題ありません。
デバッグ設定
1. Debug 構成の作成
- プロジェクトを右クリック → Debug As → Debug Configurations... を開きます。
- MCUXpresso IDE LinkServer Debug を選択し、
evkbmimxrt1170_threadx_demo構成を作成。 - J-Link など他のプローブを使用する場合は該当オプションを選択してください。
2. フラッシュオプション
- Program Flash オプションにチェックを入れると、デバッグ開始時に自動でフラッシュ書き込みが行われます。
3. シリアルポート設定
115200 8N1をデフォルトとします(NXP SDK のサンプルと同じ)。
プログラムの書き込みと実行
1. ボードを USB で接続
- Debug ポート(JTAG/SWD)と UART ポートの両方を PC に接続します。
2. Debug ボタンをクリック
- ビルド済みバイナリがフラッシュに書き込まれ、IDE が自動でデバッガをアタッチします。
3. Run/Resume (F8)
- 初期ブレークポイントで停止したら
F8で実行を開始します。
シリアル出力の確認
1. ターミナルソフトの起動
- Tera Term, PuTTY などお好みのターミナルを使用。
- 対応 COM ポートを選択し、ボーレート
115200、データビット8、パリティNone、ストップビット1を設定します。
2. 出力の確認
- 以下のように Hello World メッセージとカウンタが 1 秒おきに表示されれば成功です。
おわりに
この記事では、Azure RTOS(ThreadX) を使った最初のステップとして、シンプルな「Hello World」アプリケーションの作成から実行までを解説しました。
学んだこと:
- ThreadX の基本的なプログラム構造(main → tx_kernel_enter → tx_application_define → スレッド実行)
- メモリ管理の基礎(バイトプールとメモリ割り当て)
- スレッドの作成と実行制御
- システム情報の取得とデバッグ出力
このシンプルな例を理解することで、ThreadX アプリケーション開発の基盤が身につきました。次のステップでは、複数のスレッド間での通信やスケジューリングなど、より実践的な機能を学んでいきます。
ネクスティ エレクトロニクスの取り組み
株式会社ネクスティ エレクトロニクスは、豊田通商グループのエレクトロニクス事業の中核企業として、カーエレクトロニクスの分野においてトップクラスの規模を誇ります。
技術と商材を核として、幅広い分野でお客さまや世の中のニーズに応え、 社会課題のソリューションを提供し、より善き社会の実現に貢献していきます。
また、ネクスティ エレクトロニクスの開発部隊では、取り扱い商材を活用した自社開発、受託開発(ハードウェア、ソフトウェア開発)なども実施しています。
お客様の困りごとなどの解決なども含め寄り添って対応いたしますので、お気軽にお問合せください。
お問い合わせ
関連技術コラム
関連製品情報

ネクスティ エレクトロニクス制作 NXP車載マイコンS32K311評価ボード
S32K311は、小パッケージで高性能、最新機能を安価に利用できるNXPの最新車載マイコンです。特徴と、当社制作のS32K評価ボードを紹介します。
- NXP Semiconductors N.V.
- NEXT Mobility

NXPの車載ミリ波レーダー製品の紹介
先進運転支援システム(ADAS)において重要なセンサー車載ミリ波レーダーの概要と、その市場をリードするNXPの先進的なレーダー製品ファミリーをご紹介します。
- NXP Semiconductors N.V.
- NEXT Mobility
- ICT・インダストリアル
- スマートファクトリー・ロボティクス

NXPの車載汎用マイコン製品の紹介
NXPの車載汎用マイコンは、S32K1、S12 MagniV、S32K3ファミリーをラインナップし、高性能、セキュリティ、コスト効率を兼ね備え自動車技術の進化を支えます。
- NXP Semiconductors N.V.
- NEXT Mobility

NXPの車載統合マイコンS12 MagniVの魅力を徹底解説
NXPの統合マイコンS12 MagniVは、ECUの小型化と短期開発を実現し、車載システムの電動化に貢献します。S12 MagniVの特長や利点を解説しています。
- NXP Semiconductors N.V.
- NEXT Mobility
- ICT・インダストリアル

NXPのNPUを搭載したi.MX/MCXによるエッジAIソリューションをご紹介
利用が急増しているエッジAIについて、実際の機器を踏まえて解説します。NXPがリリースしている、NPUを搭載したプロセッサー、マイコンをご紹介します。
- NXP Semiconductors N.V.
- NEXT Mobility
- ICT・インダストリアル
- スマートファクトリー・ロボティクス

NXPの車載CAN/LINトランシーバー製品の特徴を徹底解説
車載ネットワーク製品をお探しのECU開発メーカー様向けに、車載環境の厳しい条件に耐えることのできる、NXPの車載CAN/LINトランシーバー製品の特徴について解説します。
- NXP Semiconductors N.V.
- NEXT Mobility
- ICT・インダストリアル




