組み込み界で定番のマルチタスクOSを移植!!

dsPICマイコン用μITRONの制作(補足記事)

森 久直

Hisanao Mori

■はじめに

 dsPICにリアルタイムOSを実装することができたのは,スタック・ポインタが使える ようになったことが大きな要因です.これまでのPICシリーズでは,循環バッファと して動作するハードウェアにリターン・アドレスを格納していました.例えば,8レベ ルのハードウェア・スタックでは,9回目のプッシュによって,1回目にプッシュした 値が上書きされてしまうのです.

 それがdsPICでは,スタック・ポインタのおかげで,タスク毎のスタック・エリアをRAM 上に確保できるようになりました.スタック・ポインタは,リアルタイムOSを実装する ためには必要なものです.

■実装したリアルタイムOSの概要

 製作例に実装したリアルタイムOSは,表1に示したシステム・コールをサポートしています. 2[KB]というRAMの容量を考慮した上で,マルチタスクが実現できるように必要最低 限のものを揃えました.

 タスクの切替制御,タスク間の同期,タスク間の条件付き同期,ハードウェア資源 の排他制御,時間管理,等の機能が使用できます.

 システム・コールの詳細は,「μITRON3.0標準ハンドブック」をご覧下さい.書籍が 販売されていますが,(社)トロン協会のホームページからもPDF版(日本語版)を 入手することができます.

(社)トロン協会 -> http://www.tron.org/ TOPページのTRON関連資料というリンクをたどっていくとダウンロードできます.


表1 サポートしているシステム・コール
システム・
コール名
機能概要/引数
slp_tsk 自タスクを待ち状態にする
ex)slp_tsk();
wup_tsk 指定したタスクの待ち状態を解除する
ex)wup_tsk(task2);

引数=task1,task2,task3,...
wai_flg 待ち解除条件のビット・パターンを設定して待ち状態になる
ex)wai_flg(&c,flgid1,0x07,0x01);

第1引数=char型のポインタ.待ち解除時にイベント・フラグ・パターンが入る
第2引数=flgid1,flgid2(この2つのみ)
第3引数=イベント・フラグ待ちビット・パターン
第4引数=待ちモード 0x00:AND, 0x01:CLEAR, 0x02:OR
クリア無しAND待ち:0x00
クリア無しOR待ち :0x02
クリア有りAND待ち:0x01
クリア有りOR待ち :0x03
set_flg 指定したビットをセットする
ex)set_flg(flgid1,0x04);

第1引数=flgid1,flgid2(この2つのみです)
第2引数=イベント・フラグ・ビット・パターン
wai_sem ハードウェア資源の獲得
ex)wai_sem(semid1);

引数=semid1,semid2(この2つのみです)
sig_sem ハードウェア資源の返却
ex)sig_sem(semid1);

引数=semid1,semid2(この2つのみです)
dly_tsk 指定した時間だけ待ち状態にする
ex)dly_tsk(1000);

引数=16bit長の数値,時間単位はms
get_tim システム・クロックを取得する
ex)get_tim( &gettime );

引数=timedef.hで定義される構造体型変数のアドレス
set_tim システム・クロックを設定する
ex)set_tim( &testtime );

引数=timedef.hで定義される構造体型変数のアドレス
dis_dsp タスク切替を禁止する
ex)dis_dsp();
ena_dsp タスク切替を許可する
ex)ena_dsp();
loc_cpu 割込みとタスク切替を禁止する
ex)loc_cpu();
unl_cpu 割込みとタスク切替を許可する
ex)unl_cpu();

●登録できるタスク数は7つ

 登録できるタスクは7つまでです.はじめからRAM上にタスクのスタック領域を確保する仕組みにしたことと,RAMの容量による制約です.ただし,スタック領域を動的に確保するように,ソース・コードを変更することにより,登録できるタスク数を増やすことができます.

●8ビット長のイベント・フラグが2つ

 使用できるイベント・フラグは2つで,8ビット長です.初期のビット・パターンは0にクリアされています.AND待ち,OR待ち,待ち解除時のビット・パターンのクリアの有無,等を設定できます.

 なお,待ち行列を生成しないので,同じイベント・フラグを同時に使用することはできません.

●計数型セマフォが2つ

 使用できるセマフォは2つまでです.計数型セマフォと呼ばれるタイプで,0〜255の範囲をカウントできます.初期のカウントの値は1になっています.ソース・コードrtosconf.hの変更により,初期値の変更ができます.

 なお,待ち行列を,8タスク分まで生成できます.

●Timer1以外の割込みは全て使用できる

 Timer1はリアルタイムOSの時間管理機能に使用しています.したがって,このモジュ ールをアプリケーションの中で使用することはできません.

 しかし,残りのUSART,Timer2,Timer3,A/D等の割込みは全て使用できます.

●リアルタイムOSを6つのプログラムで構成

 実装したリアルタイムOSの構造は,図1に示すようにOSの起動やシステム・コールなど,主に6つのプログラムで構成されています.これらは,C言語でプログラムを作成しました.

 電源がONになってから,スタートアップルーチンを経過して,最初に走るのが「リアルタイムOS起動」です.ここでは主に,スタック・ポインタの設定,タスクの登録,タスク毎のスタック領域の初期化,システム・クロックをカウントするタイマの初期設定と起動,起/動タスクへの分岐などを行います.

 一度,起動タスクに分岐した後は,主にタスクや割込みハンドラが走ります.その時のリアルタイムOSは,システム・クロックをタイマ割込みによってカウントしているか,システム・コールの要求に対応した処理を行います.スケジューリングの結果,必要ならばタスク切換えを実行します.

図1 リアルタイムOSの構造

●レディ・キューへの接続と切り離し処理がスケジューリング処理になる

 製作例に実装したリアルタイムOSのタスクには,図2に示すように「実行可能状態(READY)」,「実行状態(RUN)」,「待ち状態(WAIT)」の3つの状態があります.

図2 最低限必要なタスクの状態

 そして,READY状態のタスクはレディ・キューと呼ばれる行列につながれ,優先度ベースのスケジューリングにより管理されます.このレディ・キューは,タスク・コントロール・ブロックTCBの行列とも言えます.これを表したのが図3です.

図3 レディ・キューをTCBの行列で形成する

 TCBとは,タスクを管理するために必要な情報をまとめたものです.その情報には,タスクを識別するID,タスクの優先度,タスクの状態などがあります.

 レディ・キューは,HEADという変数を開始点にして,TCBの中のNEXTが次TCBの先頭アドレスを指すという構造をしています.HEADはRUN状態のTCBを指します.こうして,複数のTCBは一つの行列を形成します.後は,TCB間の接続の仕方を変えることにより,レディ・キューへの接続と切離しを行います.

 レディ・キューに接続するときは,TCBの中の優先度PRIとNEXTを先頭から順番に参照していきます.そして,接続しようとするTCBのPRIが,参照しているTCBのPRIより小さくなったとき,その参照しているTCBの前に接続します.

 レディ・キューから切離すときは,切離すTCBを探し出して,そのTCBのNEXTをNULL(値0)にします.そして,切離すTCBの前後にあるTCB同士を接続します.

 このように,レディ・キューへのタスクの接続と,レディ・キューからのタスクの切離しによって,スケジューリングが行われます.

●タスク切替え処理にはアセンブラが必要

 ステータス・レジスタSRと,ワーキング・レジスタWの退避と復帰の処理をしなければならないので,インライン・アセンブラを用いました.また,フレーム・ポインタW14とスタック・ポインタW15の退避場所については,プログラムにおける退避と復帰の処理を容易にするためにTCBの中に確保しました.W14とW15の退避先となるアドレスが固定ですので,操作し易くなります.

 基本的な処理の流れは,次のようになります.

  1. SRを退避する
  2. W0〜W13を退避する
  3. フレーム・ポインタ,スタック・ポインタを退避する
  4. 次に実行するタスクのフレーム・ポインタとスタック・ポインタを復帰する
  5. 次に実行するタスクのW0〜W13を復帰する
  6. 次に実行するタスクのSRを復帰する

 タスクの切替え処理を終えた後には,リターン命令が実行され,次に実行するタスクに移ります.

●リアルタイムOSを走らせるために,RAMをギリギリまで使う!

 タスクごとのスタック・エリア,タスク・コントロール・ブロック(TCB),セマフォ,フラグのRAM上の配置は図4のようになります.

 dsPIC30F3013のRAMのうち,ユーザーが使用できるのは,0x0800〜0x0FFF番地です.この中で,タスク毎のスタック・エリアのメモリ容量を200[byte]にし,タスク毎のTCBのメモリ容量を32[byte]にすることで,タスクを7つ使用できるようにしました.

 セマフォは6[byte],イベント・フラグは8[byte]のメモリ容量で,それぞれ2つずつ確保しています.

 最終的には,リアルタイムOSとタスクのコード・サイズは約8[KB]になりました.ROMは24[KB]ですので,まだ余裕があります.

図4 スタック・エリアやTCBをすき間なく配置したときのRAMの状態
図をクリックすると拡大表示します
Copyright (C) 2007. Hisanao Mori All Rights Reserved.
Copyright (C) 2007. CQ Publishing Co., Ltd. All Rights Reserved.