ITRON入門 OSタイマによる時間生成の仕組みと設定方法

ITRON入門カリキュラム
この記事は約9分で読めます。

こんにちは、ナナです。

リアルタイムOSにおける時間管理の仕組みを紹介しましょう。

ここまでにタスクの実行を遅延させるdly_tskや周期ハンドラなど、時間を意識したサービスコールが登場しました。このような時間をどのようにリアルタイムOSは把握しているのでしょうか?

本記事では次の疑問点を解消する内容となっています。

本記事で学習できること
  • リアルタイムOSが時間を管理する方法とは?
  • OSタイマとは何なのか?
  • OSタイマの定義方法とはどのようにするのか?
  • OSタイマとITRONにおける割込みハンドラの登録方法とは?

では、OSタイマの仕組みを学んでいきましょう。

スポンサー

OSタイマの役割

組み込み機器で時間を作り出すとは

マイコン入門編のタイマ機能を実施された方は、マイコンにおいて時間を作り出すことは専門的な知識が必要になることを経験されていることでしょう。

マイコンで時間を作り出すためには、マイコンが持つタイマ機能を利用するしかありません。

しかし、組み込み開発用の機器はマイコンが異なることなんて当たり前のことであり、マイコン毎に時間を作りだす仕組みは変化します。

マイコン毎に異なるタイマ機構

リアルタイムOSといっても時間を作り出すことはできない

リアルタイムOSといっているくらいですから「時間を作ることなんて当たり前にできるでしょ」と思われるかもしれません。

しかし、世の中に無数にある組み込み機器に対して、「ITRONカーネルを動かしたから、時間は自動で作り出してくれるんだよね」なんて夢の機構は存在しません。

機器ごとに異なる時間生成の仕組みを、ITRONカーネル側のプログラムで管理することなどできるわけがないのです。

OSはなんでもできるわけじゃない

やはりそこにはリアルタイムOSが時間を管理するための明確なカラクリが存在します。

それがOSタイマです。

OSタイマとは

OSタイマはリアルタイムOSに対して時間を供給するためのタイマ機構のことです。

リアルタイムOSはOSタイマからの時間供給を元にシステム時間を管理します。

OSタイマの機構

対象の組み込み機器に対してリアルタイムOSをポーティングする作業者が、OSタイマの設定をする必要があります。これを忘れるとdly_tskといった時間に関わるサービスコールが一切使えないため注意が必要です。

スポンサー

OSタイマの定義方法

イメージだけ語っていてもなかなか理解できないため、具体的なプログラムからOSタイマを知っていきましょう。

OSタイマの詳細と具体例

皆さんが動かしているビュートローバーのシステムにはすでにこの仕組みが組み込まれています。それがHEWのプロジェクトに登録されているostimer.cです。

ostimer.c

//------------------------------------------------
//  概  要:OSタイマ初期化
//------------------------------------------------
void Ostimer_init(VP_INT exinf)
{
    // 1msのオーバーフロー割り込み用の設定
    TB1.TMB1.BIT.RLD = 1; // オートリロード機能有効
    TB1.TMB1.BIT.CKS = 4; // 分周φ/16を選択
    TB1.TCB1 = 256 - 187; // リロードカウント値

    //  タイマB1オーバーフロー割り込み許可
    IENR2.BIT.IENTB1 = 1;

    return;
}

//------------------------------------------------
//  概  要:オーバーフロー割り込みハンドラ
//          1ms間隔で割り込みハンドラからコールされる
//          OSタイマとしてOSへタイムティックを供給
//  引  数:なし
//------------------------------------------------
void Ostimer_interruptHandler(VP_INT exinf)
{
    // 割り込み要求フラグクリア
    IRR2.BIT.IRRTB1 = 0;

    // 1msのタイムティック供給
    isig_tim();
}

Ostimer_init関数の解説

Ostimer_init関数はH8/36064マイコンに搭載されたタイマB1機能の初期化を行っています。この設定により約1ms間隔でタイマオーバーフロー割り込みが入るようになっています。

レジスタの詳細に関してはマイコン入門編のタイマ機能の記事を見てください。1msを作り出す仕組みが解説してあります。

Ostimer_interruptHandler関数の解説

この関数はタイマオーバーフローに対する割り込みハンドラです。

よく見ていただきたいのが、isig_timというサービスコールを呼んでいることです。割り込みハンドラのため「i」が先頭に付いているサービスコールになっていますね。

isig_timサービスコールとは

このisig_timサービスコールこそがITRONカーネルに対して時間を供給するためのものです。ITRONの仕様をみてみましょう。

4.7.1 システム時刻管理

システム時刻は、システム初期化時に0に初期化し、以降、アプリケーションによってタイムティックを供給するサービスコール(isig_tim)が呼び出される度に更新する。

isg_timが呼び出される度にシステム時刻をどれだけ更新するか、言い換えるとアプリケーションがisig_timを呼び出すべき周期は実装定義で定める。

システム時刻とはITRONが管理するシステムの時間のことです。

この時間の更新はアプリケーションからisig_timによって更新されるとされています。

つまり、時間更新の役目はリアルタイムOSではなく、皆さんの作るアプリケーションにて実現しなさいとされています。

OSタイマの全体構成

この時間供給のことを「タイムティックの供給」と呼びます。

スポンサー

OSタイマの初期化と割り込みハンドラの登録方法

Ostimer_init関数とOstimer_interruptHandler関数を定義したのはよいですが、関数というのは呼ばれないと動きません。

これらの関数はいつ呼ばれるようになっているのでしょうか?

実はコンフィギュレーションファイルに呼ばれる仕組みが設定されています。コンフィギュレーションファイルが何かわからない方は、こちらの記事を参照してください。

コンフィギュレーションファイルの中身を見ていきましょう。

初期化処理の定義

システムには起動時に初期化したいものってよくあります。グローバル変数だったり、特定のハードウェアのレジスタ値だったり、初期化時にはこうなっていてほしいという要望はあるものです。

ITRONにはコンフィギュレーションファイルで静的APIによる初期化処理が定義できるようになっています。

system.cfg(一部抜粋)

//------------------------------------------------
//  初期化
//------------------------------------------------
ATT_INI({TA_HLNG, 0, Main_init});
ATT_INI({TA_HLNG, 0, Ostimer_init});

ATT_INIで指定された関数はITRONカーネルが起動したタイミングで1度だけ呼ばれる仕組みになっています。ITRON仕様では次のように説明されています。

ATT_INI:初期化ルーチンの追加(静的API)
ATT_INI({ATR iniatr, VP_INT exinf, FP inirtn});

初期化ルーチンを指定される各パラメータに基づいて追加する。

intatrは初期化ルーチンの属性、exinfは初期化ルーチンを起動する時にパラメータとして渡す拡張情報、inirtnは初期化ルーチンの起動番地である。

本例ではmain.cに定義されたMain_init関数とostimer.cに定義されたOstimer_init関数が登録されています。皆さんも初期化処理をしたければ同じように追加することができます。

これがOstimer_init関数が呼ばれる仕組みです。

割り込みハンドラの呼び出し定義

ostmer.cのOstimer_interruptHandler関数の定義はありますが、割り込みハンドラというものをタイマB1のオーバーフロー割り込み発生時に呼ばせる仕組みが必要です。

マイコン入門編ではintprg.cというHEW独自の割り込みハンドラ登録処理の仕組みを使いましたが、HOSには割り込みハンドラを簡単に登録できる仕組みが用意されています。

//------------------------------------------------
//  割り込み
//------------------------------------------------
ATT_ISR({TA_HLNG, 0, 29, Ostimer_interruptHandler});
ATT_ISR:割込みサービスルーチンの追加
ATT_ISR({ATR isratr, VP_INT exinf, INTNO intno, FP isr});

【機能】

isratrは割込みサービスルーチンの属性、exinfは割込みサービスルーチンを起動する時にパラメータとして渡す拡張情報、intnoは割込みサービスルーチンを起動する割込みを指定する割り込み番号、isrは割込みサービスルーチンの起動番地である。

特徴的なのがintnoとして指定する割り込み番号です。タイマB1のオーバーフローは割り込み番号29に紐づいているためその番号を指定しています。

つまり、皆さんがその他の割り込みハンドラを利用したければ、この割り込み番号をマイコンのマニュアルから調べて同じように登録すればよいのです。

割り込み番号の詳細が知りたい方は、H8/36064のマニュアル「3.1 例外処理要因とベクタアドレス」を見よう!

スポンサー

タイムティック供給値の調整方法

ITRONのシステム時刻はミリ秒という単位が基本になっています。dly_tskといったサービスコールも時間の単位はミリ秒になっていますね。

そのため、OSタイマで供給するisig_timの呼び出し間隔は1ミリ秒になるようにタイマを設定するのがよいです。

しかし、ハードウェアによってはタイマの精度上の問題で3ms周期で割り込みをいれるのが精いっぱいなんてこともあったりします。そんな時は次のHOS独自の静的APIにて時間調整をします。

HOS_TIM_TIC(1, 1);          //  タイムティックの設定(省略時 1/1 )

左がタイムティック周期の分子、右がタイムティック周期の分母の数字です。

もしも3ms周期の割込みの場合はHOS_TIM_TIC(3, 1); とすることで、3 ÷ 1 = 3msとなり1回の割込みで3msのシステム時刻が加算されるようになります。

3.3333msといった小数点を含むような割り込み周期だった場合はこの時間を作り出す分子と分母の組み合わせを指定します。10 ÷ 3 = 3.33333… のような数字ですね。

この場合はHOS_TIM_TIC(10, 3);と指定することでタイムティックを供給することができます。