TOPPERSコンテスト ITRON OSEK/VDX OS統合 by ChatGPT https://qiita.com/kaizen_nagoya/items/6e2ed59a8291561729c9
では、WithoutOS割り込みと、WithOS割り込みの分類と、
優先度天井規約(priority ceiling protocol)が言及されておらず、
本質的な議論がおきざりになっていました。
追加質問しました。
ChatGPT
TOPPERSコンテスト ITRON OSEK/VDX OS統合 by ChatGPT https://qiita.com/kaizen_nagoya/items/6e2ed59a8291561729c9
の記事で、ChatGPTさんに助けていただいて資料がだいぶできました。
プログラマが意図してやろうとすることを妨げてはいけないというCの精神 に基づいた説明を追加いただけますでしょうか。OSEK/VDX OSの仕様は、かなりCの精神よりです。その利点を強調したいと思います。
ChatGPT:
なるほど、記事の方向性よく理解しました。「Cの精神=プログラマが意図してやろうとすることを妨げてはいけない」という考え方を、OSEK/VDX OSやITRON仕様の説明に組み込みたいということですね。
以下のような補足を記事に加えると、「Cの精神」とOSEK/VDXの親和性がうまく強調できると思います。
Cの精神とOSEK/VDX OSの親和性
C言語は「プログラマが意図してやろうとすることを妨げてはいけない」という設計思想をもっています。これは、プログラマに対して極力制約を課さず、必要ならば低レベルな操作も許す柔軟性を残しているということです。
OSEK/VDX OSの仕様も、この精神に近い特徴を備えています。たとえば次の点です。
必要最小限のAPI
OSEK/VDXは仕様が比較的シンプルで、タスク管理、イベント、リソース、アラームといった最小限の機能に絞られています。これは「余計な機能で縛らず、必要なら自分で追加できる」というCの設計姿勢と通じています。
明確な制約のもとでの自由度
タスクの優先度やリソースの排他制御のルールは厳密に定義されていますが、それは「予測可能な動作」を担保するためであり、逆に言えばプログラマはその枠の中で自由に戦略を組めます。これはC言語における「型安全性の最低限の保証と、その上での自由度」に似ています。
移植性と低レベル操作の両立
OSEK/VDXは自動車業界を中心に広く移植され、異なるマイコン環境でも同一のタスクモデルで動作します。しかし、同時にハードウェア依存部を明確に分ける設計が推奨されており、プログラマが必要に応じて低レベルにアクセスすることも妨げません。これもC言語が「抽象化とハードウェア直接制御の両方を許す」点と一致しています。
つまり、OSEK/VDX OSは「仕様で守るべき部分は厳格に定めるが、それ以上はプログラマの創意工夫に任せる」という思想をもち、これはまさにCの精神に基づいたオペレーティングシステム設計といえます。
👉 この補足を記事に追加すれば、OSEK/VDXが「堅牢でありながらプログラマの自由を尊重している」ことが伝わりやすくなると思います。
ご希望でしたら、この内容を 記事用の整形テキスト(見出し、箇条書き、コード例付き)にしてお渡しできますが、どうなさいますか?
あなた:
はい。お願いします。
ChatGPT:
了解しました!記事用に整形して、見出し・箇条書き・短いコード例を交えて書き直しました。Qiita記事にそのまま追加できる形になっています。
Cの精神とOSEK/VDX OSの親和性
C言語には「プログラマが意図してやろうとすることを妨げてはいけない」という設計思想があります。
これは、最低限の制約で安全性を担保しつつ、細部はプログラマの裁量に委ねる という姿勢です。
OSEK/VDX OSの仕様は、この「Cの精神」に非常に近い特徴を備えています。
- 必要最小限のAPI
OSEK/VDXは仕様が比較的シンプルで、以下のような基本機能に絞られています。
タスク管理(起動、終了、切替)
イベント制御
リソース排他制御
アラーム管理
余計な高機能を追加せず、本当に必要なものだけに絞ることで、プログラマは自由に拡張できます。
/* シンプルなタスク切替例 /
TASK(TaskA) {
ActivateTask(TaskB); / 次のタスクを明示的に起動 */
TerminateTask();
}
このように、タスク切替も「APIを呼ぶ」以外の強制的な制御はなく、自由度が残されています。 - 明確な制約のもとでの自由度
OSEK/VDXでは、タスクの優先度やリソースの排他制御ルールが厳密に定められています。
これは「予測可能な動作」を保証するための枠組みです。
しかし、その枠組みの中では以下の自由が確保されています。
優先度の設計はプログラマが任意に決定できる
リソースの使い方をアプリケーションごとに最適化できる
状態遷移を明示的にコントロールできる
/* 優先度に基づく排他制御 /
GetResource(MyResource);
/ この間は優先度反転が防止される /
DoCriticalWork();
ReleaseResource(MyResource);
「制約を守ることで、逆に意図したとおりに制御できる」点は、C言語の型安全性の最低限保証と似ています。
3. 移植性と低レベル操作の両立
OSEK/VDXは自動車業界を中心に広く使われ、異なるマイコン環境でも同じAPIで動作します。
一方で、ハードウェア依存部を明確に分離しているため、必要なら低レベルにアクセスすることも可能です。
/ OSが抽象化してくれる部分 */
SetEvent(TaskC, Event1);
/* どうしても必要な場合は、ハード依存処理を呼び出すことも可能 */
HW_SpecialRegisterWrite(0x1234);
これはC言語が「抽象化とハードウェア直接制御の両方を許す」点とよく一致しています。
まとめ
OSEK/VDX OSは、
必要最小限のAPIで自由を残す
明確な制約の中で自由度を担保する
移植性と低レベル操作の両立を可能にする
という特徴を持ちます。
これはまさに 「プログラマが意図してやろうとすることを妨げない」Cの精神 に基づいたOS仕様といえるでしょう。
👉 これを記事に加えれば、ITRONやOSEK/VDXが「堅牢でありながらプログラマの自由を尊重している」ことが伝わりやすくなります。
ご希望なら、この記事に 「ITRONとの比較視点」(例えば ITRONの豊富さ vs OSEK/VDXのミニマルさ)も追加してバランスをとる形にしましょうか?
あなた:
はい。お願いします。
ChatGPT:
了解しました!では、先ほどの「Cの精神とOSEK/VDXの親和性」に加えて、ITRONとの比較視点を追加した記事用の補足を作りました。OSEK/VDXのミニマルさと、ITRONの豊富さを対比させることで、両者の良さが際立つようにしています。
ITRONとの比較視点
OSEK/VDX OSとITRONは、いずれも組込みリアルタイムOSの標準仕様ですが、設計思想には違いがあります。
この違いを「Cの精神」の観点から眺めると、両者の特徴がより明確になります。
OSEK/VDX:ミニマルで制約が明快
APIが最小限でシンプル
自動車向けに特化した 「予測可能性」重視の設計
制約が厳しい分、挙動が明快で、プログラマの意図をそのまま表現しやすい
👉 「小さなCプログラムを書くように、余計なものを足さず、必要なものだけでシステムを構築できる」点が強みです。
ITRON:豊富で柔軟
タスク、セマフォ、メールボックス、メッセージバッファ、イベントフラグなど、APIが豊富
産業機器、家電、携帯端末など幅広い分野に適用
豊富さゆえに、設計者が「どの機能を使うか」を選ぶ裁量がある
👉 「C言語が標準ライブラリや拡張ライブラリを通じて幅広い用途に使える」のと同様に、ITRONは「多彩な道具箱を備えた」柔軟な仕様です。
両者の共通点:Cの精神を尊重
プログラマが意図する制御を阻害しない
ハードウェアの能力を隠さずに活かせる設計
システム設計者の裁量を尊重
OSEK/VDXは「最小限で縛らない」ことで、
ITRONは「豊富さで選択を委ねる」ことで、
いずれもCの精神に通じる自由度を提供しています。
比較イメージ(簡単なコード断片)
OSEK/VDX(ミニマルで制約明快):
/* タスク切替とイベント通知だけで同期を実現 /
TASK(TaskA) {
SetEvent(TaskB, Event1);
TerminateTask();
}
ITRON(豊富な機能で柔軟):
/ メールボックスを使ってメッセージ通信 */
void taskA() {
T_MSG msg;
msg.data = 42;
snd_mbx(MBX1, &msg);
}
void taskB() {
T_MSG msg;
rcv_mbx(MBX1, (T_MSG*)&msg);
printf("received: %d\n", msg->data);
}
OSEK/VDXでは「制約の中で直球勝負」、
ITRONでは「多彩な道具を選んで最適解を組み立てる」。
どちらもCプログラマの精神に沿った自由が確保されているのが分かります。
まとめ
OSEK/VDX:ミニマルで予測可能性を重視し、制約の中で意図をそのまま表現しやすい
ITRON:豊富な機能で幅広い用途に対応し、意図に応じて最適な方法を選べる
共通点:いずれも「Cの精神=プログラマの自由を尊重する」設計思想を持つ
👉 この記事にこの比較を加えると、「OSEK/VDXの良さを強調しつつ、ITRONとの関係性も整理されている」形になり、読者が両者の立ち位置を理解しやすくなると思います。
ご提案ですが、このあと 「両者を統合した視点」(今回の記事テーマである ITRONとOSEK/VDX OS統合 に直接つながるまとめ)も書きましょうか?
あなた:
ITRONでは、自動車用プロファイルと最初セットプロファイル(SSP)だけを統合対象にしようと思っています。自動車用プロファイルのオープンソースはみあたらなく、コードとしては最小セットプロファイルだけで作業しようかなって思うんです。
ChatGPT:
なるほどです 👍
方針として 「自動車用プロファイルは仕様的に対象にするが、実装や実験はまずSSP(最小セットプロファイル)」 という整理は、記事にも研究にもとてもわかりやすいと思います。
記事に書き足すとしたら、こんな感じでまとめるとよいかと思います。
統合対象プロファイルの整理
ITRONには多様なプロファイルが定義されていますが、OSEK/VDXとの統合を考える際に特に関係が深いのは次の2つです。
自動車用プロファイル
OSEK/VDXと同様、自動車向けに特化したリアルタイム性・予測可能性を重視
ただし、オープンソース実装は現在のところ見当たらない
最小セットプロファイル(SSP: Smallest Set Profile)
ITOS/SSP としてTOPPERSプロジェクトからオープンソースで提供されている
教育・評価・実験用に向いており、シンプルなタスク・同期機能を持つ
実際のコード作業では、このSSPを対象とするのが現実的
統合の方向性
仕様レベル
自動車用プロファイルとOSEK/VDXを対比・整理し、共通点や差異を明確化する。
(例:タスクモデルの近似性、イベント/リソース管理の対応関係など)
実装レベル
実際のコードは SSPをベース に検討する。
シンプルな機能を利用して統合の試作を進めることで、差異を小さなコード例で確認できる。
メリット
研究・記事執筆
SSPのコードを具体例として示すことで、読者に理解しやすい解説ができる。
実用的展望
SSPで統合の基本構造を検証し、その先に「自動車用プロファイル」という応用を見据える流れにできる。
Cの精神との接続
SSPは余計な機能を持たないため、OSEK/VDXと同じく「必要最小限のAPIでプログラマの自由を残す」点が強調できる。
👉 つまり記事の流れを
OSEK/VDX = ミニマル&自動車向け
ITRON = 豊富だがSSPはOSEK/VDXに近いミニマル性を持つ
統合対象は「自動車用プロファイル」として位置づけ、実際のコード検証はSSPで進める
と整理すると、読者に「なるほど、まずSSPで試してから自動車用へ」と伝わるはずです。
ご希望でしたら、OSEK/VDXのAPIとSSPのAPI対応表(例えばタスク管理API同士のマッピング)を記事用にまとめてみますか? これがあると統合の具体像が見えやすくなると思います。
あなた:
はい。ソースコード付きでお願いします。
ChatGPT:
了解しました!
では、OSEK/VDX と ITRON/SSP の API 対応表 を簡単なソースコード例つきで示しますね。
これを記事に追加すれば「統合対象のイメージ」がグッと掴みやすくなると思います。
OSEK/VDX と ITRON/SSP の API 対応
OSEK/VDX と ITRON/SSP は、いずれも「タスク管理」「同期」「時間管理」を基本機能としています。
以下に、代表的な API の対応関係と、簡単なサンプルコードを示します。
機能 OSEK/VDX API ITRON/SSP API 備考
タスク起動 ActivateTask(TaskID) act_tsk(tskid) 非同期でタスクを起動
タスク終了 TerminateTask() ext_tsk() 自タスクを終了
タスク待機 WaitEvent(EventMask) slp_tsk() / wai_flg(...) OSEKはイベント待ち、ITRONはスリープ/フラグ待ち
イベントセット SetEvent(TaskID, EventMask) set_flg(flgid, pattern) 機能的に近い
リソース獲得 GetResource(ResID) wai_sem(semid) SSPではセマフォで排他制御
リソース解放 ReleaseResource(ResID) sig_sem(semid)
アラーム(時間管理) SetRelAlarm(AlarmID, increment, cycle) sta_alm(alid, tim) 周期/単発のタイマ起動
サンプルコード比較
OSEK/VDX でのタスク切替とイベント同期
/* OSEK/VDX: TaskA が TaskB にイベントを送って起動を促す /
TASK(TaskA) {
ActivateTask(TaskB); / TaskBを起動 /
SetEvent(TaskB, Event1); / TaskBにイベント通知 */
TerminateTask();
}
TASK(TaskB) {
WaitEvent(Event1); /* イベント待ち /
ClearEvent(Event1);
/ ここから実行処理 /
TerminateTask();
}
ITRON/SSP でのタスク起動とフラグ同期
/ ITRON/SSP: TaskA が TaskB を起動し、イベントフラグで同期 /
void taskA(intptr_t exinf) {
act_tsk(TASK_B); / TaskBを起動 /
set_flg(FLG1, 0x01); / TaskBにフラグ通知 */
ext_tsk();
}
void taskB(intptr_t exinf) {
wai_flg(FLG1, 0x01, TWF_ORW, NULL); /* フラグ待ち /
clr_flg(FLG1, ~0x01);
/ ここから実行処理 /
ext_tsk();
}
排他制御(OSEK:リソース, SSP:セマフォ)
/ OSEK/VDX /
TASK(TaskC) {
GetResource(Res1);
/ クリティカル処理 /
ReleaseResource(Res1);
TerminateTask();
}
/ ITRON/SSP /
void taskC(intptr_t exinf) {
wai_sem(SEM1);
/ クリティカル処理 */
sig_sem(SEM1);
ext_tsk();
}
ポイントまとめ
タスク起動/終了 はほぼ一対一で対応可能
イベント(OSEK)とイベントフラグ(ITRON) は役割が似ており統合が容易
リソース制御(OSEK)とセマフォ(ITRON) は同じ排他制御機構としてマッピング可能
アラーム機能 も双方にあり、周期タイマ処理の対応付けが可能
👉 こうしてみると、OSEK/VDX と ITRON/SSP は「Cの精神に基づいた最小構成」で共通しており、統合のベースとして扱いやすいことがわかります。
ご希望でしたら、この対応表を「Qiita記事用に図解」(タスクモデルやイベントとフラグの対応を矢印で示す図)に仕立てることもできますが、表+ソースコードのままの方がよいでしょうか?
あなた:
OSEK/VDX OSの特徴は、WithOS割り込み(Category2)とWithoutOS割り込み(Category1)に分類していることと、Priority Ceiling Protocolでデッドロックが起きないことを保証している点です。これをSSPに組み込む方法をご教示ください。
ChatGPT:
いいですね — 実装レベルで使える形に落とし込みます。
以下では (A) OSEK の Category1 / Category2 割り込みを ITRON/SSP 側でどう扱うか、(B) Priority Ceiling Protocol(PCP)を SSP に組み込む具体的手順とサンプル実装(ソース付き)を提示します。実用的に動くことを念頭に、SSP の一般的な API(act_tsk / set_flg / wai_flg / chg_pri / get_pri / dis_int / ena_int など)で書いています。実際の SSP 実装では関数名が若干違う場合があるので、必要に応じて実環境の API 名に置き換えてください。
A. Category1 / Category2 割り込みの扱い方(設計方針)
OSEK の定義(簡潔)
Category1(Without OS):OS サービスを呼べない割り込み(高速、最小処理)
Category2(With OS):OS サービスを呼べる割り込み(タスク起動やイベントセットが可能)
SSP での実現方針(要点)
**Category1 は「完全に OS 非依存」**にする。ISR 内で OS API を呼ばない。ISR では最小限のハードウェア処理(レジスタ読み書き、バッファにデータ書き込み)だけ行い、後続処理はタスク側で行う。
方法:ISR はリングバッファ/ロックフリーキュー/フラグメモリ にデータを書き込み、Category2 互換のソフト割り込み(または専用の「ハンドラ通知タスク」を使って)で処理を委ねる。
代替:ISR が書き込んだデータをポーリングする専用タスク(高優先度)を用意する。Category1 はポーリング対象のメモリに書くだけで、タスクが定期的にチェックして処理する。
**Category2 は SSP 側で「OS呼出し可能」**にする。ISR 内で act_tsk / set_flg のような API を直接呼んでよい(ただし SSP 実装で割り込みコンテキストから呼べる API に制限があればそれに合わせる)。
実装上の注意:ISR から OS 呼出しを行う場合、呼び出しが割り込み安全であること、再入/優先度の観点で問題がないことを確認する。
設計ルール(運用)
カテゴリ区分はハードウェア設計段階で固定する(どの割り込みを Category1 にするか明確に)。
Category1 割り込みは「ハードリアルタイムで最短応答」を要求する例(外部CAN割り込みの最短受信ACKなど)に使う。
Category2 は「割り込みで OS に処理委譲してよい」もの(イベント通知後、タスクで詳細処理)に使う。
B. Priority Ceiling Protocol(PCP)を SSP に組み込む方法
目標:複数タスクが共有リソースを使うとき,デッドロックが起きず,優先度反転を制御する。OSEK の GetResource / ReleaseResource が実現する PCP を SSP 上で実装する。
考え方(簡潔)
各リソースに「天井優先度(ceiling priority)」を割り当てる。これは「そのリソースを使用する全タスクの中で最も高い(数値が小さい)優先度」のこと。
タスクがリソースを取得すると、自タスクの実効優先度をそのリソースの天井優先度に上げる(必要なら保存しておく)。
リソース解放時に以前の優先度を復元する。
ネストした複数リソースを扱うために、タスクごとに優先度スタック(またはカウンタ)を保つ。
注意:SSP に chg_pri(タスク優先度変更)がある前提です。ない実装では、排他をセマフォで行いかつセマフォ実装で PCP をサポートする形(カーネル拡張が必要)を検討してください。
データ構造(例)
#define MAX_RESOURCES 8
#define MAX_TASKS 16
typedef int Priority; /* 小さいほど高優先度(例: 1 が最高) */
typedef struct {
int owner_task; /* -1 = free, else taskid /
Priority ceiling; / resource ceiling priority */
} Resource;
Resource res_table[MAX_RESOURCES];
/* タスクの優先度スタック(リソース獲得ごとに push/pop) /
Priority task_pri_stack[MAX_TASKS][8];
int task_pri_sp[MAX_TASKS]; / stack pointer */
/* 現行優先度を返す関数(実装に合わせて取得) /
Priority get_current_priority(int tskid); / wrapper around get_pri /
void change_priority(int tskid, Priority p); / wrapper around chg_pri /
GetResource / ReleaseResource の実装例(SSP 上)
以下は概念的で動作する C 実装例です。関数名は実際の SSP に合わせて置き換えてください。
/ 初期化(起動時): 各リソースの ceiling を設定しておく /
void init_resource_table(void) {
for (int i=0; i<MAX_RESOURCES; ++i) {
res_table[i].owner_task = -1;
res_table[i].ceiling = / set to the highest priority among users */;
}
}
/* helper: push current priority */
static void push_task_pri(int tskid, Priority p) {
int sp = task_pri_sp[tskid];
task_pri_stack[tskid][sp] = p;
task_pri_sp[tskid] = sp + 1;
}
/* helper: pop and return previous priority (or -1 if none) */
static Priority pop_task_pri(int tskid) {
int sp = task_pri_sp[tskid];
if (sp == 0) return -1;
sp -= 1;
task_pri_sp[tskid] = sp;
return task_pri_stack[tskid][sp];
}
/* GetResource: raise priority to ceiling and take ownership /
int GetResource_SSP(int resid, int tskid) {
/ 1) 非同期的な割り込みや競合を避けるため、短時間だけCPUロック /
dis_int(); / または loc_cpu() 等の関数 */
if (res_table[resid].owner_task != -1) {
/* OSEK の仕様だとリソース重複取得は禁止(エラー) */
ena_int();
return -1; /* error: already owned */
}
Priority curr = get_current_priority(tskid);
push_task_pri(tskid, curr); /* 後で戻すため保存 */
Priority ceil = res_table[resid].ceiling;
if (curr > ceil) {
/* 数値が小さいほど高優先度なら curr > ceil は低優先度 -> 優先度上げる */
change_priority(tskid, ceil);
}
res_table[resid].owner_task = tskid;
ena_int();
return 0; /* success */
}
/* ReleaseResource: restore previous priority and clear ownership */
int ReleaseResource_SSP(int resid, int tskid) {
dis_int();
if (res_table[resid].owner_task != tskid) {
ena_int();
return -1; /* error: not owner */
}
res_table[resid].owner_task = -1;
Priority prev = pop_task_pri(tskid);
if (prev != -1) {
change_priority(tskid, prev);
} else {
/* 何も保存されていない: leave as-is or set default */
}
ena_int();
return 0;
}
重要ポイント(実装上の注意)
dis_int() / ena_int() は短時間の CPU ロック(割り込み禁止)で競合から保護するために使う。この間は長くしない。
change_priority(chg_pri)がタスクの優先度変更を直ちに反映し、スケジューリング上の即時プリンプトが行われる実装であることを前提。もし chg_pri が即時反映されないカーネルなら別途工夫が必要。
ネストして複数リソースを取る場合、各取得で現在の優先度をスタックに push しておくことで正しく復元できる。
リソースを複数タスクが使用する場合、各リソースの ceiling は そのリソースを使用するタスク群の最も高い優先度 に設定する。
C. Category1 / Category2 と PCP を組み合わせた運用例
割り込み設計
Category1 割り込み(最短応答が必要) → ISR はデータをリングバッファに書くだけ。必要なら簡単な ACK を返して終了。後続処理は専用高優先度タスク(SSP 上)に委譲。
Category2 割り込み → ISR は act_tsk / set_flg でタスクに処理を委譲できる(SSP の API が割り込みコンテキストで安全なら)。
タスク側でのリソース保護
タスクが共有リソースを使う前に GetResource_SSP(resid, tskid) を呼ぶ(上の実装)。処理終了後に ReleaseResource_SSP(resid, tskid) を呼ぶ。
これにより、タスクがリソースを保持している間、優先度が天井に上がりデッドロック・優先度反転を防止できる。
Category1 からの通知
Category1 ISR が書いたリングバッファの処理は、**専用の「割り込み処理タスク」**が担当する。このタスクは必要ならリソースを取得してクリティカル処理を行う。
その専用タスクは高優先度に設定しておき、SSP の wai_flg やポーリングでデータ到着を検出する。
D. サンプル:Category1 -> データバッファ -> ハンドラタスク(簡易)
volatile uint8_t irq_ring_buf[256];
volatile int write_idx = 0;
volatile int read_idx = 0;
/* Category1 ISR (絶対に OS 呼出しをしない) */
void IRQ_cat1_handler(void) {
uint8_t d = HW_READ_REG();
irq_ring_buf[write_idx] = d;
write_idx = (write_idx + 1) & 0xff;
/* (任意)ソフトウェア割り込みを発行してタスクを確実に起こす
ただしソフト割り込みがCategory2相当であることを確認する */
trigger_software_irq_if_available();
}
/* ハンドラタスク(Category2/通常タスク) /
void irq_handler_task(intptr_t exinf) {
for (;;) {
/ ここは wai_flg 等で待つ実装でもよい */
while (read_idx != write_idx) {
uint8_t d = irq_ring_buf[read_idx];
read_idx = (read_idx + 1) & 0xff;
/* 共有リソースを使用するなら GetResource_SSP を使う */
GetResource_SSP(RES_MYBUF, TASK_ID_IRQ_HANDLER);
process_data(d);
ReleaseResource_SSP(RES_MYBUF, TASK_ID_IRQ_HANDLER);
}
/* データがなければ待つ(省略: wai_flg で効率化) */
wai_flg(FLG_IRQ, 0x01, TWF_ORW, NULL);
}
}
E. テストと検証項目(必ずやること)
割り込み優先度と応答性:Category1 の遅延(ISR 実行時間)を計測。割り込みによる最長ブロッキング時間が要求を満たすか確認。
優先度上昇の正当性:多タスクで共有リソースを連続的に使うケースで、優先度が天井に正しく上がり、優先度反転が抑制されることを確認。
ネスト/異常ケース:リソース二重取得、リソース開放忘れ、ISR でのメモリ競合などの異常を試験。エラー処理経路を追加。
リアルターゲットでの動作確認:エミュレータではなくハード上で実際の割り込み/キャッシュ/メモリバリアの影響を確認。
F. まとめ(実務的なチェックリスト)
割り込みを Category1 / Category2 に明確に割り当てる(設計書に記載)
Category1 ISR は OS 呼出し禁止、最小処理に抑える(バッファ書き込み等)
Category2 ISR は OS 呼出し可能にし、必要なら act_tsk / set_flg を行う
各共有リソースに対して天井優先度を算出して設定する
GetResource_SSP / ReleaseResource_SSP を実装し、タスクに適用する
優先度変更(chg_pri)の即時反映をカーネルで確認する
実機での遅延・優先度反転試験を実施する
必要なら、あなたの SSP 実装(関数名、割り込み登録方法、優先度の値域、タスク ID の定義)に合わせて上のコードを具体的に書き換えます。実装環境の API 名を教えていただければ、そのままコピペで動く形に合わせて差し替えます。どうしますか?