Comments
Description
Transcript
Ver. 1.6 - インタフェース
RTLinuxによる PCI/CompactPCI/CardBus制御入門書(導入編) RTLinuxによる PCI/CompactPCI/CardBus制御入門書(導入編) TUT-0036 www.interface.co.jp Ver. 1.6 改訂履歴 Ver. 1.0 1.1 年 月 改 訂 内 容 2002年 3月 2002年 6月 1.2 2003年 2月 1.3 2003年 5月 1.4 2004年 1月 1.5 2004年 8月 1.6 2005年 10月 新規作成 ・パフォーマンス比較資料追加 ・RTLinuxプログラミング追加 ・誤記修正 ・URL更新 ・インストールに関する説明の追加 ・URL更新 ・インストールに関する説明の追加 ・CardBus追加 ・URL,インストールに関する説明の更新 ・表1-3 RTLinuxとLinuxの周期実行測定結果 指定 周期の修正 ・技術資料一覧更新 ・誤記修正 ・URL更新 ・技術資料一覧更新 本チュートリアルをご使用の際は、必ず各製品型式の最新のドキュメント(ユーザ ーズマニュアル,オンラインヘルプ)をあわせて参照してください。また、最新のド ライバソフトウェアをご使用ください。ユーザーズマニュアル, ドライバソフト ウェアは弊社Web siteからダウンロードできます。(オンラインヘルプはドライバ ソフトウェアに含まれています) Interface Corporation -1- 商標/登録商標 本チュートリアルに掲載されている会社名、製品名は、それぞれ各社の商標また は登録商標です。 保障の内容と制限 株式会社インタフェースはドキュメント内の情報の正確さに万全を期しています。 万一、誤記または誤植などがあった場合、株式会社インタフェースは予告無く改 訂する場合があります。ドキュメントまたはドキュメント内の情報に起因するい かなる損害に対しても株式会社インタフェースは責任を負いません。 ドキュメント内の図や表は説明のためであり、ユーザ個別の応用事例により変化 する場合があります。 著作権、知的所有権 株式会社インタフェースは本製品に含まれるおよび本製品に対する権利や知的所 有権を保持しています。 本製品はコンピュータ ソフトウェア(プログラム)、 図、 文章、 写真などを 含んでいます。 複製の禁止 株式会社インタフェースの許可なく、本製品(ドキュメント含む)の全て、または一 部に関わらず、複製、改変などを行うことはできません。 責任の制限 株式会社インタフェースは、株式会社インタフェース または再販売者の予見の有 無にかかわらず発生したいかなる特別損害、偶発的損害、間接的な損害、重大な 損害について、責任を負いません。 Interface Corporation -2- −目 次− はじめに 6 第 1 章 RTLinux の導入 7 1.1 RTLinux とは(概要)....................................................................................7 1.2 Linux と RTLinux との違い ............................................................................9 1.3 パフォーマンス比較 .....................................................................................13 1.3.1 DIO ボードのパフォーマンス比較...................................................13 応答性のパフォーマンス比較 ...............................................................13 周期性のパフォーマンス比較 ...............................................................14 1.3.2 調歩同期シリアル通信ボードのパフォーマンス比較 ...................14 応答性のパフォーマンス比較 ...............................................................15 周期性のパフォーマンス比較 ...............................................................15 1.4 RTLinux 導入のメリット............................................................................16 第 2 章 RTLinux のインストール 17 2.1 RTLinux,Linux カーネルソースの入手(ダウンロード).....................17 2.2 作業の前に .....................................................................................................18 2.3 カーネルへのパッチあて作業 .....................................................................19 2.4 Linux カーネルイメージの構築...................................................................20 2.5 カーネルイメージを起動するローダの設定..............................................22 2.6 RTLinux のパッチをあてた Linux の起動 ..................................................23 2.7 RTLinux のコンパイル..................................................................................25 2.8 RTLinux のディレクトリ構成......................................................................28 2.9 RTLinux サンプルプログラムの紹介..........................................................30 第 3 章 初歩の RTLinux プログラミング 32 3.1 プログラミングの前に(RTLinux リアルタイムカーネルの組み込み)....32 用語解説 ..........................................................................................................34 3.2 Hello World プログラム ................................................................................35 3.3 Hello World プログラムの解説 ....................................................................38 3.4 組み込み中にも実行されるプログラムを作る..........................................39 3.5 組み込み中にも実行されるプログラムの解説..........................................41 関数&用語解説 ...............................................................................................45 3.6 Linux プロセスから RTLinux モジュールを制御する ..............................47 Interface Corporation -3- 3.7 Linux プロセスから RTLinux モジュールを制御するプログラムの解説54 3.7.1 RT-FIFO の役割...................................................................................55 3.7.2 共通定義ファイルの役割...................................................................56 3.7.3 RTLinux モジュールの動き ...............................................................58 関数解説 ...................................................................................................62 3.7.4 Linux プロセスの動き ........................................................................62 関数&用語解説 .......................................................................................65 第 4 章 弊社 RTLinux 用ソフトウェアの導入 68 4.1 RTLinux 対応ソフトウェアの特長..............................................................68 4.2 RTLinux 対応ソフトウェアのインストール ..............................................69 4.3 テストドライバを使用した動作確認 .........................................................76 4.4 RTLinux 対応ソフトウェアのアンインストール ......................................77 第 5 章 ドライバモジュールの優先度設定 78 5.1 割り込みハンドラの優先度設定(DPG-0102) ........................................78 第 6 章 RTLinux でのソフトウェア開発 82 6.1 RTLinux プログラムのデバッグ..................................................................82 6.1.1 rtl_printf( ) + 弊社デバイスドライバのデバッグ機能を使用した方法 ..........................................................................................................................82 6.1.2 デバッガ(gdb + RTDebugger)を使用する方法 ............................84 6.2 リアルタイム性の評価 .................................................................................90 6.3 I/O 公開資料(PDF)の利用........................................................................93 第 7 章 組み込み Linux 概要 94 7.1 組込み Linux 概要..........................................................................................94 第 8 章 補足資料 96 8.1 インストールに関する参考情報 .................................................................96 RTLinux 3.2 pre1 の導入について .........................................................96 RTLinux 3.2 pre2 の導入について .........................................................97 Red Hat Linux 7.3/8.0 に RTLinux を導入する際の注意点 ..................98 8.2 その他の Tips .................................................................................................99 insmod 等のコマンドが呼び出せない...................................................99 RTLinux リアルタイムカーネルを組み込もうとするとエラー ........99 ドライバを insmod しようとすると unresolved symbol ....................100 Interface Corporation -4- 技術資料紹介 101 参考文献 102 Interface Corporation -5- はじめに 平素は格別のご高配を賜り、厚くお礼申し上げます。本冊子はRTLinux上で弊社 PCI/CompactPCI/CardBus製品を制御したい方を対象に、RTLinuxの環境構築、弊社 RTLinux対応ソフトウェアのセットアップ、テストドライバによる動作確認方法、 組み込みシステムに使用されるリアルタイムOSについて記載しています。 RTLinux上での弊社製品をはじめとするハードウェア制御のためのプログラミン グにお役に立てれば幸いです。 <ご意見・ご要望> 弊社へのご意見,ご要望がございましたら、下記までお問い合わせください。 www.interface.co.jp E-mail:[email protected] <注意事項> 本冊子はRTLinuxバージョン3.1を対象に作成されています。 使用されるRTLinuxのバージョンが異なる場合、動作保証はいたしかねますので予 めご了承ください。 本冊子は、コマンドの実行例において、行頭に「%」がつく場合は一般ユーザで の実行、「#」がつく場合はrootでの実行を意味します。「%」や「#」は実際に入 力する文字ではありませんのでご注意ください。 Interface Corporation -6- 第1章 RTLinuxの導入 1.1 RTLinuxとは(概要) RTLinux(RealTime Linux)とは、その名前が示しているように、Linuxでリアルタイ ム処理を可能にするOSです。 RTLinux/FreeはFinite State Machine Labs, Inc.(以降、FSMLabs社と記載します)のWeb siteから、Freeで入手することが可能です。本書では、以下特に記載がない限り 「RTLinux」は「RTLinux/Free」のことを指します。 ライセンスに関する詳細な内容については、FSMLabs社のWeb siteもしくはRTLinux 3.1のパッケージに付属するドキュメントをご確認ください。 それでは、リアルタイム処理とはどのようなものなのでしょうか? 「リアルタイム」という言葉には、実時間,同時,即時 等の意味があります。 コンピュータでの処理は基本的にCPUのクロック周波数で時間を離散化し、そのクロ ックにあわせて命令(処理)を実行していますので、現実の実時間ではなくCPUクロ ックが刻む時間にあわせて処理を行っていると言えます。 1つの処理のみを実行する場合は、ハードウェアの処理能力=処理の実行時間と言う関 係が成り立つため、処理が完了するまでにかかる時間を予測することが可能になりま す。 しかし、メインとなる処理の他にも、画面表示や通信等の処理を同時に行いたい場合 には、複数実行している処理の内どれを優先的に行うのかが設定できなければ、実行 時間を予測することができません。 一般的に、リアルタイムOSとは、下記のような要項を満たすOSを示します。 ・規定の時間間隔内での周期実行性が保証されていること。 ・割り込みの応答速度が規定時間内で保証されていること。 加えて、弊社RTLinux対応デバイスドライバ(GPGシリーズ)では、下記の要項をリ アルタイム保証として挙げています。 ・ドライバAPIの実行時間のワースト値を保証。 ・API実行中の割り込み禁止時間のワースト値を保証。 (詳細な値については、各ドライバのHelpをご確認ください。) Interface Corporation -7- RTLinuxは、厳密には単体で機能するOSそのものではなく、Linuxカーネルに適用する パッチとして提供されています。 RTLinuxのパッチを適用したカーネルを実行すると、リアルタイムカーネルが最下層 で動作します。 このリアルタイムカーネルがLinuxカーネル本体やRTLinuxモジュールと内部で動作 するRTLinuxスレッドと呼ばれるRTLinux専用のスレッド(実行単位)をスケジューリン グすることで、任意の処理をリアルタイム制御することが可能になります。(図1-1 参照) Linux プロセス RT-FIFO スケジューラ RTLinux モジュール Linux カーネル RTLinux スレッド 割り込みの ディスパッチ スケジューラ リアルタイムカーネル ハードウェア割り込み 図 1-1 RTLinuxの概要 リアルタイムカーネルから見ると、Linuxカーネル本体はRTLinuxモジュール(および内 部で実行されるRTLinuxスレッド)より優先度の低いプロセスとして動作するため、リ アルタイムで処理を行いたい作業をRTLinuxスレッドに記述することで、通常のLinux とリアルタイム処理を共存させることを可能にしています。 通常のLinuxで使用可能な機能やアプリケーションは、RTLinux上でも同様に動作する ため、Linuxの豊富な機能を生かしつつリアルタイム処理を行える点が特長と言えます。 また、RTLinuxのもう一つの機能として、割り込みのディスパッチがあります。 RTLinuxでは、ハードウェアからの割り込みを受けた場合にそのままLinuxカーネルに 伝えずに、リアルタイムカーネルが一度割り込みを受けてからLinuxカーネル本体に伝 えます。 Interface Corporation -8- Linuxカーネル本体ではスケジューリング間隔が10ms程度であるため、割り込みを受 けてからISR(Interrupt Service Routine)を実行するまでに600µs∼20ms程度かかり、ば らつきがある上に応答性能もかなり低いといえます。 これに対して、RTLinux下で割り込み処理を実行すれば、15μs程度で応答することが 可能になります。 ★スレッド プログラム実行の、ある最小単位です。 文脈次第では、タスクと呼ばれることもあります。 Linux や Windows 等のマルチタスク OS では、これら複数のスレッドを時分割に実行させ、 並列して動作するように見せかけています。 (MS-DOS は、基本的に 1 つのタスクしか動作できないのでシングルタスク OS と呼ばれま す) 本書では、RTLinux モジュール内で動作するスレッドのことを、特に RTLinux スレッドと 呼んでいます。 複数のスレッドを同時に動作させる状態を、マルチスレッドと呼びます。 極端な例えですが、C 言語の main 関数が、幾つも同時に動いているのだと思ってくださ い。 1.2 LinuxとRTLinuxとの違い 先に示した説明を元に、Linuxの構造とRTLinuxの構造を比較し、違いを見ていきます。 まず、Linuxでのユーザアプリケーションとデバイスドライバとの関係を図1-2に示し ます。 アプリケーション ライブラリ デバイスドライバ ユーザ空間 カーネル空間 PCI/CompactPCI ボード CardBus カード 図 1-2 Linuxでのアプリケーションとデバイスドライバとの関係 Interface Corporation -9- 項目 アプリケーション ライブラリ デバイスドライバ PCI/CompactPCIボード CardBusカード ユーザ空間と カーネル空間 内容 お客様が作られるプログラムを示します。 インタフェースボードを簡単に制御できるよう、アプリ ケーションに対して公開されているAPIを提供している ソフトウェアです。 弊社製品GPG-2000を例にすると、共有ライブラリ libgpg2000.soがこれにあたります。(Windowsに詳しい方 は、DLLファイルを想定してください) 実際にインタフェースボードにアクセスし、ボードの制 御を行うソフトウェアです。 弊社製品GPG-2000を例にすると、ドライバcp2000.oがこ れにあたります。(Windowsに詳しい方は、VxDやSysファ イルを想定してください) インタフェースボードです。 お客様は、このインタフェースボードを使って、何らか の制御を行うことを目的としています。 manやvi等、通常のアプリケーションは、ユーザ空間と呼 ばれるアドレス空間で実行されます。 ハードウェアに関わる処理、例えばカーネルやドライバ 等と呼ばれるものは、カーネル空間で実行されます。 両者の違いを、プログラムの制限事項から捉えると、 ・ユーザ空間のプログラムは、できる内容に制限を加えた 上で、プログラムを安全に動かすことができます。 ・カーネル空間のプログラムは、何でもできる代わりに、 一つ間違えると(例えばポインタを書き間違えるとか)ハ ングアップしてしまいます。 と捉えることができます。 お客様の作られるソフトウェアは、常にユーザ空間にて実行されます。このため、プ ログラムが暴走しても、別のコンソールから、そのプロセスをkillして復旧させること が簡単にできます。 その代わり、お客様の作られるアプリケーションは、ボードを直接制御することがで きない等の、幾つか制限を受けることになります。 このため、通常ライブラリを経由して、インタフェースボードを制御します。 Interface Corporation - 10 - 次に、RTLinuxでのユーザアプリケーションとデバイスドライバとの関係を図1-3 に示します。(先の図 と比較してみてください) アプリケーション RTLinux モジュール ユーザ空間 カーネル空間 デバイスドライバ PCI/CompactPCI ボード CardBus カード 図 1-3 RTLinuxでのアプリケーションとデバイスドライバとの関係 項目 アプリケーション RTLinuxモジュール デバイスドライバ PCI/CompactPCIボード CardBusカード 内容 お客様が作られるプログラムを示します。 お客様がカーネル空間で実行させるソフトウェアです。 この空間で実行されるソフトウェアは、リアルタイム性が 確保されています。 実際にインタフェースボードにアクセスし、ボードの制御 を行うソフトウェアです。Linux版のライブラリとデバイ スドライバが合わさったものと考えてください。 弊社製品GPG-2000を例にすると、rcp2000.oがこれにあた ります。 なお、デバイスドライバ、RTLinuxモジュール共、RTLinux のリアルタイム管理下にて動作します。 インタフェースボードです。 お客様は、このインタフェースボードを使って、何らかの 制御を行うことを目的としています。 お客様の作られるソフトウェアは、ユーザ空間で動作するアプリケーションと、カー ネル空間で動作するRTLinuxモジュールを、実行可能です。 プログラミングスタイルとしては、リアルタイム性を確保したいクリティカルな制御 場面ではRTLinuxモジュール内で処理を行い、回収したデータの画面表示等、リアル タイム性を要求されない場面では、アプリケーションにて処理を行います。 Interface Corporation - 11 - データ表示など、リアルタイム性を要 求しない処理を行う アプリケーション タイムクリティカルな処理を行う RTLinux モジュール RTLinux環境下での、Linuxとの大きな違いを、以下に列挙します。 ・ユーザのRTLinuxモジュールは、カーネル空間に配置されます。 このため、Linuxではカーネル空間からユーザ空間へのスイッチ時に発生して いた時間的なロスがありません。 ・ユーザのRTLinuxモジュールとアプリケーションとの間には、RT-FIFOと呼ばれ る情報交換機能が提供されており、両者を並行して非同期に動作させることが できます。 ・RTLinuxのAPIは、ns(ナノ秒)単位で指定できます。 つまり、RTLinuxスレッドの周期実行時間や、ウェイトの呼び出しを、ns(ナノ 秒)単位で指定することが可能です。 ・Linuxの割込みおよびカーネル処理は、RTLinuxの制御下に置かれています。 ハードウェア割込みは、即座に割込みハンドラに遷移することができます。 使用するCPUにも依りますが、数∼十数μsで割込みハンドラが起動します。 このように、RTLinuxは通常のLinuxに比べ、応答要求の厳しいプログラミング環境に おいて、確実かつ応答性の高いシステムを構築することが可能です。 ★Linux と RTLinux の内部の違い Linux のカーネルは、ノンプリエンプティブです。(ユーザ空間の実行プロセスは、プリエ ンプティブです) また、割り込み処理について、元々リアルタイム処理を考慮した設計にはなっていません。 ノンプリエンプティブなため、カーネルコール中に、他のプロセスに実行権を奪われるこ とはありません。割り込み処理も、リアルタイム OS ならば、割り込み処理中に、より優 先度の高い事象が発生した時、プリエンプトされますが、こういったことはありません。 結果として、プロセスの実行時に予測不可能な遅延が発生する可能性があります。 このことは、事象の変化に対して、要求された時間内で応答しなければならないリアルタ イム処理を実現する上で、大きな妨げとなります。 対して、RTLinux は、割り込み処理はプリエンプトされます。 このため、RTLinux では安定した周期実行と、上に示した高速な割り込み応答を実現して います。 Interface Corporation - 12 - 1.3 パフォーマンス比較 ここでは、RTLinuxとLinuxで、応答性や周期性について、弊社で測定したパフォーマ ンスデータについて、一部ご紹介します。 詳細なパフォーマンスデータについては、弊社お客様相談センタまで、お問い合わせ ください。 1.3.1 DIOボードのパフォーマンス比較 まずは、DIOボードでの応答性と周期性のパフォーマンス比較データを紹介します。 測定環境は次の通りです。 表 1-1 パフォーマンス測定環境 項目 内容 GPG-2000 CTP-PE09 CTP-2703 2.4.4 RTLinux 3.1 デバイスドライバ CPUボード DIOボード Linuxカーネルバージョン RTLinux バージョン 応答性のパフォーマンス比較 汎用入力信号IN1の割り込みが発生してから、コールバック関数内ですぐにデジタル 出力関数を呼び出した場合の応答時間を測定しました。 RTLinux、Linuxともに、1000回応答時間を測定しています。 コールバック関数呼び出し 表 1-2 応答時間のトータル結果 測定環境 デジタル出力処理 RTLinux Linux 9.6 18.8 9.4 0.48 17.3 36.3 16.7 0.92 トータル結果 汎用入力信号 IN1 割り込み 平均(μs) 最大(μs) 最小(μs) 標準偏差(σ) コールバック関数 デジタル出力 時間 この時間を測定 図1-4 応答性の測定 RTLinuxは、Linuxに比べ平均,最大,最小時間共、優れた結果が出ています。 特に、最大応答時間では、Linuxで36.3μsにまで応答時間のぶれが発生しているのに 対し、RTLinuxでは、18.8μsまでしかぶれが発生していません。 Interface Corporation - 13 - 周期性のパフォーマンス比較 指定した周期でデジタル信号出力を繰り返し行い、 その周期性のぶれを測定しました。 こちらも1000回ずつ測定を行っています。 Linuxでは1ms周期を実行しても20msより短い周期実行が行えなかったため、100ms周期に 出力を行う設定で測定しています。 RTLinuxは、1ms周期でも安定した動作が確認できたため、1ms周期の周期性を測定しま した。 表 1-3 RTLinuxとLinuxの周期実行性測定結果 RTLinux Linux 測定環境 指定 周期(μs) 平均 (μs) 最大 (μs) 最小 (μs) 100000 98434.42 98439.98 98431.76 10000 9844.188 9847.56 9839.34 1000 971.8 975.57 967.2 標準 偏差 (σ) 1.794 1.757 0.944 平均 (μs) 最大 (μs) 最小 (μs) 標準 偏差 (σ) 106808.75 106816.08 104424.12 75.56 19686.99 19729.37 19593.74 0.336 19686.93 19723.89 19599.22 10.708 Linuxでは、指定した周期が100msであるにもかかわらず、平均で7ms程度遅れが出て います。また、最大値と最小値のぶれ幅も大きいです。 RTLinuxでは、ほぼ指定周期通り実行され、さらに最大値と最小値のぶれも小さくな っています。 1.3.2 調歩同期シリアル通信ボードのパフォーマンス比較 次に、調歩同期シリアル通信ボードでの応答性と周期性のパフォーマンス比較データ を紹介します。 測定環境は次の通りです。 表 1-4 パフォーマンス測定環境 項目 デバイスドライバ CPUボード 調歩同期シリアル通信ボード Linuxカーネルバージョン RTLinux バージョン Interface Corporation 内容 GPG-4141 CTP-PE09 CTP-4142 2.4.4 RTLinux 3.1 - 14 - 応答性のパフォーマンス比較 データを受信してから、コールバック関数内ですぐにデータ送信関数を呼び出した場 合、データ受信完了から、実際にデータが送信されるまでの時間を測定しました。 RTLinux、Linuxともに、1000回応答時間を測定しています。 表 1-5 応答時間のトータル結果 コールバック関数呼び出し 測定環境 データ送信開始 受信完了 RTLinux Linux 46.957 50 45 0.760085 5089.048 10070 80 2883.494 トータル結果 平均(μs) 最大(μs) 最小(μs) 標準偏差(σ) データ受信 コールバック関数 データ送信 この時間を測定 図 1-5 応答性を測定した時間 RTLinuxは、Linuxに比べ平均,最大,最小時間共、優れた結果が出ています。 特に最大応答時間では、負荷が入った場合、Linuxでは、10msにまで応答時間のぶれ が発生しているのに対し、RTLinuxでは、50μsまでしかぶれが発生していません。 周期性のパフォーマンス比較 指定した周期でデータ送信を繰り返し行い、その周期性のぶれや限界値を測定しまし た。 こちらも各周期で1000回ずつ測定を行っています。 表 1-6 RTLinuxとLinuxの周期実行性測定結果 ネットワーク負荷なし 測定環境 RTLinux Linux 平均 最大 最小 標準偏差 平均 最大 最小 標準偏差 10001.09 1000.11 10005 1004 9997 996 1.15379 1.19387 10001.26 10001.26 10061 10071 9943 9935 5.241171 4.4672 指定周期 10000 1000 Interface Corporation - 15 - ネットワーク負荷あり RTLinux 測定環境 Linux 平均 最大 最小 標準偏差 平均 最大 最小 標準偏差 10001.09 1000.108 10007 1005 9995 996 1.36563 1.183104 10001.22 10001.22 10939 11081 9051 8938 56.60038 50.56933 指定周期 10000 1000 Linuxでは1ms周期を実行しても10ms以下の周期実行は行えておらず、最大値と最小値のぶ れも大きくなっていますが、RTLinuxでは、最大値と最小値のぶれも小さくなっています。 またネットワーク負荷をかけたとき、Linuxではデータばらつきが10倍に増えましたが、 RTLinuxではほとんど増えていません。 1.4 RTLinux導入のメリット RTLinuxを導入するメリットとしては、以下のようなことが挙げられます。 ★ Linuxの機能,アプリケーションをそのまま使用することが可能。 (RTLinuxモジュールは別途作成する必要があります) ★ ソースコードがオープンになっており、自由に参照(改造)することが可能。 ★ 市販のリアルタイムOSに比べて安価(無償)に入手可能。 通常、市販のリアルタイムOSを使用する場合には、高いライセンス料を必要とする場 合がほとんどです。RTLinuxでは、Linuxカーネルはいうまでもなく、RTLinux自体も 無償で提供されていることが大きなメリットとなります。 また、Linux環境で使用可能なツールは、基本的に全てRTLinuxでも使用することが可 能なため、Linuxの資産をそのまま流用して開発を行うことが可能な点もメリットとし て挙げられます。但し、Linux用のアプリケーション,ドライバは優先度の低いLinux カーネル上で動作するため、リアルタイム処理は行われません。 また、組み込み環境で使用するOSに市販のリアルタイムOSを選択した場合には、開 発用のホスト環境にターゲットのOSと異なるOSを使用することとなります。 これらの開発環境を用意することが、さらにコストを押し上げる結果となります。 RTLinuxを組み込み用のOSとして選択した場合、開発用のホスト環境とターゲットに 同じRTLinuxを使用することができます。 ※ 組み込み環境に関しては、『第7章 組み込みLinux』で解説します。 Interface Corporation - 16 - 第2章 RTLinuxのインストール 『1.1 RTLinuxとは(概要)』でも紹介した様に、RTLinuxは通常のLinuxカーネルのさ らに下層に構築されます。そのためRTLinuxを導入する際には、Linuxカーネルのソー スにRTLinuxのパッチを適用してから、Linuxカーネルの再構築(コンパイル)を行う 必要があります。 「難しそう!」と思われるかも知れませんが、実際の作業は定型的なもので、それほ ど難しくはありません。 ここでは、実際にRTLinuxのインストールを順に説明していきます。 手順に沿って進めていけば、RTLinuxのインストールが意外と簡単なことに気付くこ とでしょう。 2.1 RTLinux,Linuxカーネルソースの入手(ダウンロード) RTLinuxは下記のWeb siteから入手することができます。(2005年10月現在) RTLinuxの公式Web site(FSMLabs社のWeb site) 米国Web site http://www.fsmlabs.com/ 日本Web site http://www.fsmlabs.co.jp/ RTLinuxのダウンロード http://www.rtlinuxfree.com まずここで、パッチ用のファイルrtlinux-3.1.tar.gz(またはrtlinux-3.1.tar.bz2)と、ドキュ メントrtldoc-3.1.tar.gz(またはrtldoc-3.1.tar.bz2)をダウンロードします。 (2004年1月現在、RTLinux 3.2 pre2がFSMLabsから公開されています。これらの情報に ついては、『第8章 補足資料』をご覧ください。) また、RTLinuxのパッチを適用するLinuxカーネルのソースを用意する必要があります。 下記のWeb siteからオリジナルのカーネルソースをダウンロードしてください。 Linuxカーネルのダウンロード http://www.kernel.org/ Interface Corporation - 17 - 本書ではRTLinux 3.1が対応しているカーネルバージョン2.4.4を使用して解説を行い ます。 (2005年10月現在で、RTLinux 3.1が対応しているLinuxのカーネルバージョンは、2.2 系では2.2.19、2.4系では2.4.4となっています。) 以降の説明では、以下の2つのファイルを基に説明しております。 ファイル名 linux-2.4.4.tar.gz rtlinux-3.1.tar.gz または rtlinux-3.1.tar.bz2 項目 Linuxのカーネルソースのアーカイブファイル RTLinuxのパッチソースのアーカイブファイル ★参考情報 本章の説明時に用いたコンピュータならびにディストリビューションのスペックを紹介 します。 コンピュータ:エプソンダイレクト MT-3500 ディストリビューション:VineLinux 2.1.5 2.2 作業の前に ここからの作業は、OS本体であるカーネル部分に対する修正が入ります。 万が一のために、必ず起動ディスクを作成してから作業を進めてください。 起動ディスクは、mkbootdiskコマンドを使って作成します。 以下に例を示します。 (カーネルのバージョンはunameコマンドで簡単に調べることができます) # uname –r ← カーネルのバージョンをチェックしています 2.4.7-10 # mkbootdisk 2.4.7-10 ← カーネルのバージョンを指定します Insert a disk in /dev/fd0. Any Information on the disk … また、ここからの作業は、コンパイラやリンカ等の開発ソフトウェアが必須となりま す。 例えば、コンソール画面で、「gcc」と入力した時、「command not found」とプログラ ムが見つからない旨のメッセージが表示されたら、お手持ちのLinuxに対して、開発環 境をインストールしてから作業を進めてください。 (Red Hat等のディストリビューションが用意しているCD-ROMならば、開発環境をイ ンストールするオプション設定が用意されています) もう一つ。以降の作業を進めるには、スーパーユーザである必要があります。 suコマンド等でスーパーユーザになって作業を進めてください。 % su Password: ----- ← root のパスワードを入力します。 Interface Corporation - 18 - 2.3 カーネルへのパッチあて作業 ここからの作業は、元のカーネルソースに影響を及ぼさないよう、既存のカーネルソース のディレクトリとは別のディレクトリを作成し、そこで作業を進めるようにします。 最近のディストリビューションでは、カーネルのソースは、/usr/srcディレクトリ下に配置 されるので、その下にサブディレクトリ(ここではrtlinux)を作成して、進めます。 まず、/usr/srcディレクトリの下に、rtlinuxディレクトリを作成し、そこに前もってダウン ロードしておいた2つのファイルをコピーします。 # cd /usr/src # mkdir rtlinux # cd rtlinux # cp /mnt/cdrom/linux-2.4.4.tar.gz . ← CD-ROM から持って来た例です。 # cp /mnt/cdrom/rtlinux-3.1.tar.gz . 次に、コピーした2つのファイルを展開します。 # tar xzf linux-2.4.4.tar.gz # tar xzf rtlinux-3.1.tar.gz # ls /usr/src/rtlinux linux linux-2.4.4.tar.gz rtlinux-3.1 rtlinux-3.1.tar.gz ★tar.bz2 ファイルの展開方法 ファイルの拡張子が tar.bz2 の場合、以下のコマンドオプションでファイルを展開できま す。 # tar --bzip2 -xvf rtlinux-3.1.tar.bz2 次に、展開したLinuxのソースディレクトリへのシンボリックリンクを張ります。 # cd /usr/src ln –sf /usr/src/rtlinux/linux /usr/src/linux ※カーネルバージョンによっては、ディレクトリ名が「linux-カーネルバージョン」に なっている場合があります。 展開後のディレクトリ構成を示します。 圧縮ファイルを展開した後のディレクトリ /usr /src /rtlinux /linux ← ①linux-2.4.4.tar.gz ファイルの展開後のディレクトリ linux-2.4.4.tar.gz /rtlinux-3.1 ← rtlinux-3.1.tar.gz ファイルの展開後のディレクトリ kernel_patch-2.2.19 ← カーネル 2.2.19 に対応したパッチファイル kernel_patch-2.4.4 ← カーネル 2.4.4 に対応したパッチファイル rtlinux-3.1.tar.gz /linux ← ①に対するシンボリックリンクを張っています。 rtlinux-3.1ディレクトリ直下に、Linuxのカーネルソースに対して、パッチをあてるための パッチファイルがあります。 Interface Corporation - 19 - /usr/src/rtlinuxディレクトリ下に展開したカーネルソース(linux)に対して、RTLinuxのパッチ をあてます。ソースファイルを展開したディレクトリに移動し、patchコマンドを使ってパ ッチを適用します。 (下では、カーネル2.4.4に対してパッチをあてています) # cd /usr/src/rtlinux/linux # patch –p1 < ../rtlinux-3.1/kernel_patch-2.4.4 … patching file scripts/mkdep.c # これで、Linuxカーネルソースに対するRTLinuxのソースパッチは完了しました。 2.4 Linuxカーネルイメージの構築 Linuxカーネルの構築を行うために、コンフィギュレーションを行います。 カーネルソースのディレクトリに移動して、makeコマンドを実行します。 # cd /usr/src/rtlinux/linux # make xconfig X Window用の「Linux Kernel Configration」が起動します。 使用するハードウェア構成に応じた設定を行ってからSave and Exitをクリックすると 「.config」ファイルが生成されます。 (X Window環境がない場合には、「make menuconfig」もしくは「make config」を実行 してください) ★カーネルコンフィギュレーションの注意事項 「make xconfig」の実行時に、サポートするファイルシステムで vfat を選択していなかっ たために、Windows でフォーマットしたフロッピーディスクが使用できなかったり、ネッ トワークカードのドライバを正しく設定していないために、ネットワークが使用できない 等のトラブルが発生することがあります。 必要な設定項目をよく吟味してオプション設定を行ってください。 次に、Linuxカーネルを構築します。 カーネルソースのディレクトリに移動して、依存関係のチェックを行います。 # cd /usr/src/rtlinux/linux # make dep ← 依存性関係のチェック # make clean ← ソースツリーの準備 Interface Corporation - 20 - カーネルイメージを作成します。 # make bzImage ← カーネルの構築 … Root device is (3, 1) Boot sector 512 bytes. Setup is 4528 bytes. System is 1103 kB warning: kernel is too big for standalone boot from floppy # モジュールの作成、インストールを行います。 # make modules ← モジュールの構築 # make modules_install ← カーネルモジュールのインストール モジュールの依存関係ファイルを作成します。 # depmod –a ここまでで、カーネルイメージが以下の生成例に示す、各ディレクトリに生成されま す。 PC/AT互換機および、CPUボード(PentiumⅢ、Geode)での生成例 /usr /src /rtlinux /linux /arch /i386 /boot bzImage ← カーネルイメージファイル /lib /modules /2.4.4-rtl ← ここに、モジュール群が生成されます 該当ディレクトリに、カーネルイメージ(bzImageファイル)が作成されていることを確認 します。(下は参考です。ファイルサイズは、コンフィギュレーション設定によって異 なります) # cd /usr/src/rtlinux/linux/arch/i386/boot # ls –l ・ ・ ・ -rw-r—r-1 root root 464842 Feb 4 9:49 bzImage Interface Corporation - 21 - 2.5 カーネルイメージを起動するローダの設定 OSローダに対し、先ほど作成したカーネルイメージを登録して、起動できるように設 定します。 <grubを使用する場合の設定> カーネルイメージが配置されている「/boot」に移動し、先ほど作成したカーネルイメ ージをコピーします。 # cd /boot # cp /usr/src/rtlinux/linux/arch/i386/boot/bzImage /boot/rtlinuz 「grub.conf」ファイルを以下のように編集します。 # cd /boot/grub # vi grub.conf List 2-1 「grub.conf」の修正 1 2 3 4 5 6 7 8 9 10 default=1 timeout=25 splashimage=(hd0,0)/boot/grub/splash.xpm.gz title linux root (hd0,0) kernel /boot/vmlinuz ro root=/dev/hda1 title rtlinux root (hd0,0) kernel /boot/rtlinuz ro root=/dev/hda1 ↑ ↑ルート位置を指定します。6行目を参考に してください。 カーネルイメージのファイル名を指定します。 <liloを使用する場合の設定> カーネルイメージが配置されている「/boot」に移動し、先ほど作成したカーネルイメージ をコピーします。 # cd /boot # cp /usr/src/rtlinux/linux/arch/i386/boot/bzImage /boot/rtlinuz 「lilo.conf」ファイルを以下のように編集します。 # cd /etc # vi lilo.conf Interface Corporation - 22 - List 2-2 「lilo.conf」の修正 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 boot=/dev/hda map=/boot/map install=/boot/boot.b prompt timeout=25 default=rtlinux image=/boot/vmlinuz label=linux root=/dev/hda1 read-only image=/boot/rtlinuz label=rtlinux root=/dev/hda1 い。 read-only ←カーネルイメージファイル名を指定します。 ← ルート位置を指定します。10行目を参考にしてくださ liloコマンドを実行して、設定を更新します。 # /sbin/lilo 2.6 RTLinuxのパッチをあてたLinuxの起動 OSローダの設定が完了したら、再起動します。 # shutdown –r now ローダが起動したら、先ほど追加した「rtlinux」を選択して起動し、rootでログインします。 login: root Password: ******(パスワードを入力) unameコマンドでカーネルバージョンの確認を行ってください。 # uname –r 2.4.4-rtl ← カーネル 2.4.4 + RTLinux 3.1 の場合です カーネル 2.2.19 の場合は、表示が異なります Interface Corporation - 23 - ★カーネルバージョン uname コマンドで表示されるカーネルバージョンは、どうやって生成されたのでしょう か? 答えは、Linux カーネルを構築する際に使用される Makefile にあります。 /usr/src/rtlinux/linux ディレクトリに、Makefile があるので、これをエディタで開いてみて ください。 そこに、以下の表記があります。 VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 4 EXTRAVERSION = -rtl カーネルバージョンは、この定義の組み合わせなのです。 Interface Corporation - 24 - 2.7 RTLinuxのコンパイル 次に、RTLinuxのコンパイルを行います。 RTLinuxをインストールしたディレクトリに移動して、RTLinuxの設定を行います。 # cd /usr/src/rtlinux/rtlinux-3.1 コンパイルの前に、RTLinux-3.1ディレクトリに対して、Linuxディレクトリへのシン ボリックリンクを張ります。 # ln –s /usr/src/rtlinux/linux linux このシンボリックリンクを正確に張らないと、次のmake xconfigが失敗しますので、注 意してください。シンボリックリンクの関係を以下に示します。 シンボリックリンクの設定関係 /usr /src /rtlinux /linux ← ①Linux 2.4.4 のディレクトリ (前項でコンパイルしたソース類一式がある) /rtlinux-3.1 ← RTLinux 3.1 のディレクトリ /linux ← ①に対するシンボリックリンクを張っています RTLinux用のコンフィギュレーション設定を行います。 # make xconfig THE OPEN RTLINUX PATENT LICENSE … Do you agree to the terms of this license [y/n]? (make xconfigが使用できない環境では、make config、もしくは make menuconfigを実行 してください) make xconfigを実行すると、ライセンス説明と同意を求められます。よく読んで、yキ ーを入力してください。すると、X Window上にRTLinuxのコンパイル時の設定を行う メニューが表示されます。ここで、必要な項目を設定してから、Save and Exitをクリ ックして設定を終了します。 参考に、RTLinux 3.1のコンフィギュレーション設定を一覧として示します。 メニューの右側にヘルプボタンがありますので、これらを参考にしながら、設定を行 ってください。 図2-1 設定画面 Interface Corporation - 25 - xconfigを実行したディレクトリで続けて、RTLinuxのコンパイルを実行します。 # make # make devices # make install 以上でRTLinuxのインストールは完了です。 作成したRTLinuxモジュールを確認することができます。 # cd /usr/src/rtlinux/rtlinux-3.1/modules # ls mbuff.o rtl.o rtl_fifo.o rtl_posixio.o rtl_sched.o rtl_time.o 次に、RTLinuxのモジュールをシステムに組み込みます。 以下のようにして、ロード用のスクリプトを実行します。 # cd /usr/src/rtlinux/rtlinux-3.1 # sh scripts/insrtl ← RTLinuxのトップディレクトリで実行してください 下記の方法で、システムに組み込まれたモジュールを確認できます。 <方法1:ログ出力を確認する> # cat /var/log/messages … RTLinux Extensions Loaded (http://www.fsmlabs.com/) ↑RTLinuxのモジュールがロードされている旨のメッセージが表示されています。 rtl 27184 0 [rtl_sched rtl_fifo rtl_posixio rtl_time] ↑RTLinuxのモジュール名が列挙されています。 ログ出力の中に「RTLinux Extensions Loaded…」を確認します。 <方法2:ロードされているモジュールを一覧表示> # lsmod Module Size Used by rtl_sched 43104 0 (unused) rtl_fifo 9968 0 (unused) rtl_posixio 7184 0 [rtl_fifo] rtl_time 10000 0 [rtl_sched rtl_posixio] rtl 27184 0 [rtl_sched rtl_fifo rtl_posixio rtl_time] ↑RTLinuxのモジュール名が列挙されています。 一覧表示の中に、「rtl_sched」「rtl_fifo」「rtl_posixio」「rtl_time」「rtl」の5つのモジ ュール名があることを確認します。 Interface Corporation - 26 - モジュールの組み込みのために、何度もコマンドラインから打ち込むのは、結構手間 な作業です。 シェルスクリプトを作って、作業を効率化できます。 vi等のエディタを使い、以下のファイルを作成し、保存します。 #!/bin/sh # example: RTLinux install module script cd /usr/src/rtlinux/rtlinux-3.1 sh scripts/insrtl これをシェルスクリプトとして実行すれば、より簡単にモジュールを組み込むことが できます。 # sh runrtl.sh ← シェルスクリプト名 あるいは、OSが起動する際に、自動的に組み込むよう設定するのも良いでしょう。 # cd /etc/rc.d/rc3.d # ln -s ../init.d/rtlinux ./S99rtlinux 上の例は、ランレベル3で起動する時、rtlinuxスクリプトを優先順位99で起動するよう に、指定しています。 こうすることで、Linuxにてログインする際に、既にRTLinuxカーネルが組み込まれた 状態にすることができます。 Interface Corporation - 27 - 2.8 RTLinuxのディレクトリ構成 RTLinux 3.1のインストール後のディレクトリ構成は、以下のようになっています。 /rtlinux-3.1 -/debugger/ -/doc/ -/drivers/ -/examples/ -/fifos/ -/include/ -/main/ -/measurement/ -/modules/ -/psc/ -/regression/ -/schedulers/ -/scripts/ -/semaphores/ -/system/ -/tracer/ - kernel_patch-2.4.0-test1 - kernel_patch-2.4.4 - kernel_patch-2.2.19 - FAQ.pdf - Rules.make - Installation.txt - CREDITS - Makefile - PATENT - README - RELEASENOTE - UPGRADING - rtl.config - rtl.mk RTLinux用のデバッガのディレクトリ RTLinuxのドキュメントディレクトリ ドライバのディレクトリ サンプルプログラムのディレクトリ RT-FIFOのディレクトリ インクルードファイルのディレクトリ RTLinuxリアルタイムカーネルが生成されるディレクトリ リアルタイムスケジューラのディレクトリ スクリプトのディレクトリ セマフォモジュールのディレクトリ トレーサのディレクトリ カーネル2.4.0用の(テスト)パッチファイル カーネル2.4.4用のパッチファイル カーネル2.2.19用のパッチファイル FAQのドキュメント(PDF形式) インストール方法のドキュメント インストール用のメイクファイル readmeファイル 改訂履歴 リアルタイムカーネルの設定ファイル RTLinuxの環境変数の設定ファイル ◆ 「debugger」ディレクトリ 「debugger」ディレクトリにはRTLinux用のデバッガが用意されています。RTLinux モジュールのデバッグを行うことが可能になります。 デバッガの使用方法については『6.1 RTLinuxプログラムノデバック』を参照して ください。 ◆ 「examples」ディレクトリ 「examples」ディレクトリにはRTLinuxの各サンプルプログラムが用意されていま す。RTLinuxスレッドやRT-FIFO等の基本的な使用方法が例題として用意されてい ますので、インストール後に是非一度動かしてみてください。 Interface Corporation - 28 - ◆ RTLinuxインストール後に追加されるファイル(ディレクトリ) で網掛けされたファイルは、『2.7 RTLinuxのコンパイル』のRTLinux のコンパイル後に追加されるファイルです。 RTLinuxのルートディレクトリでは、コンパイルの実行後にmodulesディレクトリ と、rtl.config, rtl.mkが作成されています。 modulesディレクトリには、make実行時に作成されたRTLinuxのリアルタイムカー ネルが格納されています。RTLinuxでリアルタイム処理を行う場合には、このリア ルタイムカーネルをあらかじめ組み込んでおく必要があります。 rtl.configファイルは、make xconfigを実行後に作成されるファイルで、RTLinuxの コンパイル時のオプション情報や設定が記録されています。 rtl.mkファイルは、RTLinuxモジュールを自作した際に使用する、コンパイルオプ ション等が指定されています。Makefileにインクルードして使用します。 rtl.mkはincludeディレクトリの中にもコピーされています。 make installを実行した際に、/usr/include/rtlinuxにrtlinux-3.1/includeへのシンボリッ クリンクが張られますので、Makefileには、 include /usr/include/rtlinux/rtl.mk を記述することでRTLinuxモジュールのコンパイルが可能になります。 その他のディレクトリの詳細については、各ディレクトリの中にドキュメント (README等)が用意されていますので、そちらをご参照ください。 Interface Corporation - 29 - 2.9 RTLinuxサンプルプログラムの紹介 それでは、RTLinuxに付属されているサンプルプログラムを実際に動かします。 まず、『第2章 RTLinuxのインストール』でRTLinuxのインストールを行ったディレク トリに移動します。 ここで、下記のRTLinuxの各リアルタイムカーネルが組み込まれていることを確認し ます。 # cd /usr/src/rtlinux/rtlinux-3.1 # lsmod Module Size Used by psc 18656 0 (unused) rtl_sched 42496 0 [PSC] rtl_fifo 9792 0 [PSC] rtl_posixio 7120 0 [rtl_fifo] rtl_time 9872 0 [psc rtl_sched rtl_posixio] rtl 26368 0 [psc rtl_sched rtl_fifo rtl_posixio rtl_time] もし、必要なモジュールが組み込まれていなかった場合は、インストール用のシェル スクリプトを実行して、モジュールの組み込みを行ってください。 # sh scripts/insrtl RTLinux Extensions Loaded (http://www.fsmlabs.com/) ★RTLinux モジュールの自動組み込み 上記の方法でモジュールの組み込みを行った場合、OS の再起動を行うと再びモジュール の組み込み作業を行う必要があります。 RTLinux 用のソフトウェアの開発作業中には、再起動が必要になることも多くありますが、 非常に面倒な作業となってしまいます。 RTLinux に必要なモジュールを、起動時に自動的に組み込みたい場合は、 # cd /etc/rc.d/rc3.d # ln -s ../init.d/rtlinux ./S99rtlinux この様に設定しておけば、次回 RTLinux 起動時から自動的にモジュールが組み込まれ、 RTLinux 起動時に毎回、手動でシェルスクリプトを実行する必要がなくなります。 (rc3.d にリンクを用意すると、ランレベル 3 で起動した場合にのみ組み込まれます) 次に、サンプルプログラムがインストールされたディレクトリに移動します。 # cd examples # ls README cpp fp frank hello measurements misc mutex old sound v1api Interface Corporation - 30 - この中で、frankと言うサンプルプログラムを動かします。 『第2章 RTLinuxのインストール』の手順が完了していれば、サンプルプログラムの コンパイルも同時に行われ、実行に必要なRTLinuxモジュール(frank_module.o)とLinux プログラム(frank_app)が作成されています。 RTLinuxのリアルタイムカーネルを組み込んで、frank_appを実行してください。 # cd frank # insmod frank_module.o # ./frank_app もし、RTLinuxモジュールとLinuxプログラムが作成されていなければ、makeを実行し てサンプルプログラムをコンパイルしてください。 実行に成功した場合は、下記のように表示されます。 FIFO handler: sending the “1” command to task0; period 500000 task0: executing the “1” command to task0; period 500000 FIFO handler: sending the “1” command to task1; period 200000 task1: executing the “1” command to task1; period 200000 ・ ・ FIFO 1: Frank FIFO 2: Zappa FIFO 2: Zappa FIFO 1: Frank FIFO 2: Zappa FIFO 2: Zappa FIFO 2: Zappa FIFO 1: Frank FIFO 2: Zappa FIFO 2: Zappa FIFO 1: Frank FIFO 2: Zappa FIFO 2: Zappa FIFO 2: Zappa ・ ・ ・ X Windowシステム上の端末で実行している場合には、2つのRTLinuxスレッドと my_handlerからの出力(rtl_printf関数を使用した出力)は表示されません。 しばらくすると、表示が止まってプログラムが完了します。 frank_app: now sending commands to stop RT-tasks FIFO handler: sending the “2” command to task0; period 200000 task0: executing the “2” command to task0; period 200000 FIFO handler: sending the “2” command to task1; period 200000 task1: executing the “2” command to task1; period 200000 # 次章では簡単なRTLinuxのプログラミングについて説明します。 Interface Corporation - 31 - 第3章 初歩のRTLinuxプログラミング ここでは、簡単ながらRTLinux上で動くRTLinuxモジュールを作り、実際に動かします。 これにより、LinuxプログラムとRTLinuxプログラムの違いについて、理解が深まると 思います。 3.1 プログラミングの前に(RTLinuxリアルタイムカーネルの組 み込み) これ以降の、実際のプログラミング作業では、suコマンドを使う等して、スーパーユ ーザにて作業を行ってください。(例えば、ドライバの組み込みは、スーパーユーザで ないと実行できません) suコマンドでスーパーユーザになるには、コンソールで、以下のように入力します。 % su Password: ----- root のパスワードを入力してください。 次に、RTLinuxのリアルタイムカーネルを組み込み、これから作成するRTLinuxモジュール が動かせるようにします。 RTLinuxがインストールされたディレクトリに移り、RTLinuxリアルタイムカーネル組み込 み用のシェルスクリプトを実行します。 # cd /usr/src/rtlinux/rtlinux-3.1 # sh scripts/insrtl ★RTLinuxリアルタイムカーネルが組み込みできない!? シェルスクリプトで RTLinux リアルタイムカーネルを組み込む時、スーパーユーザでない と、組み込みエラーが発生します。 間違いやすいので、組み込み時エラーが発生したら、慌てずスーパーユーザかどうか確認 してください。 これでRTLinuxリアルタイムカーネルが組み込まれます。 ちゃんと組み込まれたかどうか、ロードされているモジュールを一覧表示するlsmodコマ ンドを使って確認します。 Interface Corporation - 32 - # lsmod Module rtl_sched rtl_fifo rtl_posixio rtl_time rtl Size 43104 9968 7184 10000 27184 Used 0 0 0 0 0 by (unused) (unused) [rtl_fifo] [rtl_sched rtl_posixio] [rtl_sched rtl_fifo rtl_posixio rtl_time] 5つのモジュールが組み込まれていることが分かります。 RTLinuxでは、これら5つのリアルタイムカーネルが組み込まれることで、ユーザの作 成するRTLinuxモジュールを実際に動かすことができるようになります。 lsmod コマンド実行時の表示内容 rtl rtl_fifo rtl_posixio rtl_sched rtl_time モジュール名 rtl.o rtl_fifo.o rtl_posixio.o rtl_sched.o rtl_time.o これで、RTLinuxプログラミングの準備が整いました。 Interface Corporation - 33 - 用語解説 先ほど出た用語について、幾つか簡単に解説します。 ★シェルスクリプトについて シェルスクリプトとは、コンソールから打ち込むコマンドを、まとめて実行させるように 記述したファイルです。高機能なバッチ処理を行うことができます。 (Windows では、bat ファイルや wsh ファイル等が、それにあたります) ここで、insrtl が scripts ディレクトリにあるのならば、なぜ #cd /usr/src/rtlinux/rtlinux-3.1/scripts #sh insrtl としないのでしょうか? 実は、/usr/src/rtlinux/rtlinux-3.1/scripts からスクリプトを実行すると、RTLinux のリアルタ イムカーネルを格納しているディレクトリへのパスが、insrtl スクリプト内で設定している パスと一致せず、エラーとなってしまうからなのです。 また、RTLinux リアルタイムカーネルは insmod で組み込むことができますが、それぞれの モジュールは、順番が決まっているため、間違った順番でモジュールを組み込めません。 用意されている insrtl シェルスクリプトを使用することで簡単にモジュールを組み込むこ とができます。 実際に組み込みシステムを運用する場合は、いちいちコマンドを打ち込むことはできない ので、RTLinux 起動時、自動的にシェルスクリプトを実行するよう設定するのが良いでし ょう。 ★RTLinux リアルタイムカーネルが公開している関数を確認するには? 5 つのリアルタイムカーネルを組み込んだ後、 #less /proc/ksyms を実行すると、これらのモジュールが公開している関数等を確認することができます。 これにより、どのモジュールがどのような役割を持っているかが分かります。 Interface Corporation - 34 - ★rtlinux スクリプトを使って組み込む 先の説明では、insrtl スクリプトを使って、リアルタイムカーネルを組み込んでいますが、 rtlinux スクリプトを使ってリアルタイムカーネルを組み込むこともできます。 # rtlinux start rtlinux スクリプトを使うと、簡単にリアルタイムカーネルを組み込むことができます。 単に rtlinux と入力すると、詳しい説明が表示されます。 # rtlinux USAGE: rtlinux {start│stop│status} [module(s)] EXAMPLES: To insert RTLinux only --> ./rtlinux start To remove RTLinux modules only --> ./rtlinux stop To check status of RTLinux only --> ./rtlinux status To insert RTLinux and foo{1,2}.o modules --> ./rtlinux start foo1 foo2 To remove foo{1,2}.o and RTLinux modules --> ./rtlinux stop foo1 foo2 To check status of RTLinux and foo{1,2}.o modules --> ./rtlinux status foo1 foo2 Copyright 2000, Finite State Machine Labs, Inc. Questions? Contact Edgar F. Hilton <[email protected]> 3.2 Hello Worldプログラム まずは古くからの慣例に従い、「Hello World」をコンソールに表示させてみます。 エディタを立ち上げ、List3-1に示すプログラムを入力し、ファイル名を「sample1.c」 として保存してください。これは、一番単純なRTLinuxプログラムです。 ★プログラム中のコメントについて サンプルプログラムには、理解し易いよう、日本語コメントを用いています。 しかし、プログラム中に日本語を用いてコンパイルすると、正常にコンパイルできないこ とがあります。その時は、日本語コメントを削除してコンパイルしてください。 List3-1 sample1.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <rtl.h> /* 初期化関数(insmodコマンドでモジュールを読み込む時、呼ばれる関数) */ int init_module(void) { rtl_printf("Hello World!!¥n"); return 0; } /* 終了関数(rmmodコマンドでモジュールを排除する時、呼ばれる関数) */ void cleanup_module(void) { rtl_printf("bye bye¥n"); } Interface Corporation - 35 - 次に、 またエディタを立ち上げ、 List3-2に示すプログラムを入力し、 ファイル名を 「makefile」 として保存してください。 これは、上記プログラムをコンパイルするメイクファイルです。 List3-2 makefile 1 2 3 4 5 include /usr/include/rtlinux/rtl.mk all: sample1.o sample1.o:sample1.c $(CC) $(INCLUDE) $(CFLAGS) -o sample1.o -c sample1.c ★include /usr/include/rtlinux/rtl.mk は何のためにある? このメイクファイルでインクルードしている/usr/include/rtlinux/rtl.mk というファイルは、 私たちの RTLinux モジュールをコンパイルするために必要な定義を、全て行ってくれてい ます(ヘッダファイルのインクルード等)。 この方法でコンパイルを行うのもよいですが、作成する RTLinux モジュール名とソースフ ァイル名とが同じ場合(拡張子は除く。例えば test.c と test.o のような場合)、暗黙的ルー ルを使用することで、メイクファイルは、 include /usr/include/rtlinux/rtl.mk all: test.o test.o: test.c のみでもコンパイル可能となります。 それでは、コンパイルして動かします。 コンソールに以下を入力し、Enterキーを押します。 # make すると、次のファイルができ上がります。 # ls makefile sample1.c sample1.o この「sample1.o」ファイルが、RTLinuxモジュールです。 それでは、早速RTLinuxモジュールを、組み込んでみます。 X Windowで使用されている方は、rtl_printf関数の出力内容が画面で確認できるよう、コン ソールをもう一つ立ち上げ、次のコマンドを入力してください。 # tail –f /var/log/messages コンソール画面で作業されている方は、次のように打ち込んでください。 # tail –f /var/log/messages & これにより、rtl_printf関数が出力する内容が画面で確認できます。 Interface Corporation - 36 - ★/var/log/messages syslogやcron等で実行されたサービスのログ等の情報は、「/var/log/」に保存されます。通常、 ログは「/var/log/messages」に保存されます。 RTLinuxでは、rtl_printf関数を使って、ここに出力し、デバッグプリントができるようになっ ています。 (そのままコンソール画面に出力されるようには、なっていません) 上の用例では、tailコマンドを使って、このログ出力を常に表示状態にしています。 コンソール画面で用いた&(アンパサンド)コマンドはジョブコマンドの一種で、tailコマンドを バックグランドで実行させています。 コンソール画面では、X Windowのように幾つもコンソールを起動することができないので、 こうやって対処しています。 準備ができたら、RTLinuxモジュールを組み込みます。 コンソールに以下を入力し、Enterキーを押します。 # insmod sample1.o すると、コンソール画面に、以下のメッセージが表示されます。 (X Windowでは、メッセージは、tailコマンドを実行中の画面に表示されます) # insmod sample1.o Hello World!! このメッセージが表示された時、作ったRTLinuxモジュールが動いています。 次に、組み込んだRTLinuxモジュールを一覧で確認します。 確認は、lsmodコマンドで行います。 # lsmod Module sample1 rtl_sched rtl_fifo rtl_posixio rtl_time rtl rtl_posixio Size 320 43104 9968 7184 10000 27184 Used 0 0 0 0 0 0 by (unused) ← 組み込んだモジュール名 (unused) (unused) [rtl_fifo] [rtl_sched rtl_posixio] [sample1 rtl_sched rtl_fifo rtl_time] リストの中に「sample1」の名前が見て取れます。組み込まれていることが確認できました。 次に、組み込んだRTLinuxモジュールを削除します。 コンソールに以下を入力し、Enterキーを押します。 # rmmod sample1 Interface Corporation - 37 - すると、コンソール画面は、以下のメッセージが表示されます。 # rmmod sample1 bye bye RTLinuxモジュールが削除されたことが判ります。 何度か、insmodコマンドによるモジュール組み込みとrmmodコマンドによるモジュール削 除を繰り返してみてください。 その都度、メッセージが表示されることがわかります。 3.3 Hello Worldプログラムの解説 それでは、先ほどのプログラムの動きを解説します。 先ほど、コンパイルしたプログラムを組み込むと称して、「insmod sample1.o」をコン ソールで入力しました。 insmodコマンドは、作ったRTLinuxモジュール(sample1.o)を、RTLinuxに組み込む専用 のコマンドです。 このコマンドを入力した時、コンソールに「Hello World」と表示されました。 sample1.cリストを読み直してください。同じ内容が、init_module関数の6行目に有りま す。 つまり、insmodコマンドを使ってRTLinuxモジュールを組み込むと、init_module関数が 呼び出されます。ここで、コードの中のrtl_printf関数が呼び出され、コンソールにメ ッセージを表示させることができるのです。 (実際には、/var/log/messagesにログ出力しています) init_module関数は、RTLinuxモジュールをシステムに登録する際、1回だけ呼ばれる専 用の関数です。通常、ここはRTLinuxモジュールの初期化を行うコードを記述します。 (C++のクラスで言うコンストラクタのようなものです) RTLinux モジュール sample1.o 組み込み(insmod) init_module 関数 解除(rmmod) cleanup_module 関数 リアルタイムカーネル 図 3-1 RTLinuxモジュールの呼び出し関係 Interface Corporation - 38 - 次に、「rmmod sample1」をコンソールに入力しました。 このrmmodコマンドは、組み込んだRTLinuxモジュール(sample1.o)を、RTLinuxカーネル空 間から削除するためのコマンドです。 このコマンドを入力した時、コンソールに「bye bye」と表示されました。 これと同じ内容が、cleanup_module関数の13行目に有ります。 cleanup_module関数は、RTLinuxモジュールをシステムから解除する時、1回だけ呼ばれる 専用の関数です。 通常、ここはRTLinuxモジュールの終了処理を行うコードを記述します。 (C++のクラスで言うデストラクタのようなものです) どうですか?RTLinuxプログラミングって、意外と簡単ですね。 3.4 組み込み中にも実行されるプログラムを作る 先ほどのプログラムは、RTLinuxモジュールをシステムに組み込んでいる間、何も コンソールに表示しませんでした。 それは、組み込んでいる間、動作するコードを何も書いてなかったからです。 では、組み込んでいる間、周期的にメッセージを出力するプログラムを作ります。 エディタを立ち上げ、List3-3に示すプログラムを入力し、ファイル名を「sample2.c」 として保存してください。 List3-3 sample2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include #include #include <rtl.h> <rtl_sched.h> <rtl_time.h> pthread_t argo_task_info; /* 周期実行を行うRTLinuxスレッド */ void* argo_task(void* arg) { struct sched_param p; rtl_printf("argo_task called arg=%d¥n", arg); /* 自スレッドに対する優先順位や周期の設定 */ p.sched_priority = 5; pthread_setschedparam(pthread_self(), SCHED_FIFO, &p); pthread_make_periodic_np(pthread_self(), gethrtime(), 1 * 1000 * 1000 * 1000); Interface Corporation - 39 - 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 /* RTLinuxスレッドが登録中、動作する永久ループ */ while(1){ /* 周期的なメッセージ表示 */ struct timespec t; t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME)); rtl_printf("now clock=%d:¥n", t.tv_sec); /* 自スレッドをスリープさせる */ pthread_wait_np(); } return 0; } /* 初期化モジュール(insmodコマンドでモジュールを組み込む時、呼ばれる関数) */ int init_module(void) { int ret; rtl_printf("init_module called¥n"); EXPORT_NO_SYMBOLS; /* スレッドを作成、起動する */ ret = pthread_create(&argo_task_info, NULL, (void*)argo_task, 0); return ret; } /* 終了モジュール(rmmodコマンドでモジュールを削除する時、呼ばれる関数) */ void cleanup_module(void) { rtl_printf("cleanup_module called¥n"); /* スレッドを終了させる */ pthread_cancel(argo_task_info); pthread_join(argo_task_info, NULL); } 同じように、「sample2.c」をコンパイルするメイクファイル(makefile)を示します。 List3-4 makefile 1 2 3 4 5 include /usr/include/rtlinux/rtl.mk all: sample2.o sample2.o: sample2.c $(CC) $(INCLUDE) $(CFLAGS) -o sample2.o -c sample2.c コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。 # make # ls makefile sample2.c # insmod sample2.o Interface Corporation sample2.o - 40 - 登録した瞬間から、メッセージが表示されだしました。 # insmod sample1.o init_module called argo_task called arg=0 now clock=7905 now clock=7906 now clock=7907 now clock=7908 <以下略> lsmodコマンドで、RTLinuxモジュールをリスト表示させてみます。 # lsmod Module sample2 rtl_sched rtl_fifo rtl_posixio rtl_time rtl rtl_posixio Size 976 43104 9968 7184 10000 27184 Used 0 0 0 0 0 0 by (unused) ← 組み込んだモジュール名 [sample2] (unused) [rtl_fifo] [sample2 rtl_sched rtl_posixio] [sample2 rtl_sched rtl_fifo rtl_time] rmmodコマンドで、RTLinuxモジュールを削除します。 # rmmod sample2 cleanup_module called メッセージの表示がストップしました。 3.5 組み込み中にも実行されるプログラムの解説 それでは、先ほどのプログラムの動きを解説します。 まず、このサンプルの大まかな動きを以下の図に示します。 argo_task pthread_create pthread_cancel init_module cleanup_module insmod コマンド rmmod コマンド 図 3-2 sample2.oの動き Interface Corporation - 41 - 1. insmodコマンドでsample2モジュールを組み込む時、init_module関数が呼ばれま す。その中で、pthread_create関数により、argo_task関数がRTLinuxスレッドとし て生成、起動されます。 2. argo_taskスレッドは、pthread_make_periodic_np関数により、自身の実行周期を、 1秒に設定します。 3. argo_taskスレッドの、whileループ内では、rtl_printf関数により、システム起動時 からの時間を秒単位で表示します。その後、pthread_wait_np関数により、自身の RTLinuxスレッドをスリープさせ、システムから次の周期呼び出しまで待機しま す。 (周期呼び出しは、先に設定したように、1秒間隔です) 4. whileループ自体は永久ループなので、特に指示ない限り、回り続けます。 5. rmmodコマンドでsample2モジュールをRTLinuxから削除する時、cleanup_module 関数が呼ばれます。 その中で、pthread_cancel関数により、argo_taskスレッドに対してスレッド終了 の通知が発せられ、argo_taskスレッドは終了します。 6. 全ての終了処理を終え、sample2モジュールの解除は完了します。 では、上の図に沿って、もう少し詳しくプログラムを読み解きます。 まず、init_module関数から行きます。 (38行目:EXPORT_NO_SYMBOLSマクロ) EXPORT_NO_SYMBOLSマクロは、このRTLinuxモジュールのグローバルシンボ ルを非公開にするためのマクロです。 Interface Corporation - 42 - ★グローバルシンボル モジュールがカーネル内に組み込まれると、公開されたシンボル(グローバル変数や、グロ ーバル関数等)は、他のモジュールから参照できるようになっています。それを防ぐために EXPORT_NO_SYMBOLS マクロを定義します。 もし、これを行わないと、どうなるのでしょうか? 例えば、A のモジュールで count 変数を定義し、B のモジュールで何の気なしに参照する と、B のモジュールは A のモジュールの count 変数と共有してしまうことになります。 この共有をプログラマが意図してなかった場合どうなるでしょうか? 恐らく、原因不明のバグとして、悩みつづけることになるでしょう。 EXPORT_NO_SYMBOLS マクロは、これら意図しないシンボルの共有を防ぐためのもので す。 なお、グローバルシンボルは、/proc/ksyms で確認することができます。 以下に、EXPORT_NO_SYMBOLS を付けた場合と、付けない場合のシンボルを比較します。 <EXPORT_NO_SYMBOLS なし> <EXPORT_NO_SYMBOLS あり> c88e8000 c88e8000 __insmod_sample2_O/root/test/sample2. __insmod_sample2_O/root/test/sample2.o_M 3CBF8491_V132100 [sample2] o_M3CBF7E4C_V132100 [sample2] c88e8060 __insmod_sample2_S.text_L384 c88e83a8 argo_task_info [sample2] c88e83a8 __insmod_sample2_S.bss_L4 [sample2] c88e838c __insmod_sample2_S.bss_L4 [sample2] [sample2] c88e8060 argo_task [sample2] c88e8060 __insmod_sample2_S.text_L384 [sample2] (41行目:pthread_create関数) pthread_create関数では、RTLinuxモジュールを組み込んでいる間、動作し続ける RTLinuxスレッドを生成しています。 ここでは、argo_task関数をスレッドの実行単位として指定しています。 ★RTLinux スレッドを作らずに動かすことはできるか? RTLinux スレッドを作るのが面倒だからと言って、pthread_create 関数を省き、argo_task 関 数の処理内容を、init_module 関数内に持って来てはいけません。 これを行うと、プログラムが完全に停止状態に陥ります。 これは、init_module の処理が、RTLinux のカーネルスケジューラに戻らないためです。 (注意!:真似をしないでください。本当に何のキーも受け付けなくなります) 次は、argo_task関数本体に移ります。 Interface Corporation - 43 - (15,16行目:pthread_setschedparam、pthread_make_periodic_np関数) ここでは、自身のRTLinuxスレッドに対する、スケジューリング、優先度の設定およ び、実行周期を設定しています。 実行周期は、pthread_make_periodic_np関数で設定します。 周期は第3引数で、ns(ナノ秒)単位で設定します。サンプルプログラムでは、”1 * 1000 * 1000 * 1000 = 1s”とし、1秒の周期を設定しています。 (19~27行目:whileループ) while文により、永久ループしているのが目に付きます。 これは特に指示されない限り、RTLinuxスレッドを実行し続けるための工夫です。 もし、このwhileループを外してしまうと、すぐに終了してしまいます。 (RTLinuxスレッドと言っても、中身はただの関数です) (21~23行目:clock_gettime関数等) 21~23行は、現在のタイマー値を読み取り、rtl_printf関数でデバッグプリントを行って います。 (26行目:pthread_wait_np関数) whileループ中のpthread_wait_np関数は、実行中のRTLinuxスレッドをスリープさせ、 他のRTLinuxスレッドに対する実行権を明示的に渡す関数です。 システムは、他のRTLinuxスレッドへ実行権を渡し処理を続けます。 他のRTLinuxスレッドの処理が終わると、システムは優先度の兼ね合いを判定し、こ のRTLinuxスレッドに再び実行権を渡します。 ★pthread_wait_np を外すと、どうなるか? ところで、このサンプルから、pthread_wait_np 関数を排除するとどうなるでしょう? 結果は、他のどの RTLinux スレッドにも実行権が移らなくなり、いわゆる固まった状態に 陥ります。 (注意!:真似をしないでください。本当に何のキーも受け付けなくなります) 通常の Linux プログラムならば、別途シェルを起動して、永久ループに陥ったプロセスを kill して復帰することも可能ですが、RTLinux プログラムでは、そんなに甘くありません。 文字通り固まります。 これは、見方を変えると、RTLinux では、他の何者に対しても優先的に処理することが可 能だと言う証拠でもあります。 (他のプロセスを立ち上げkillできるということは、実行しているプロセスより優先的 に動くプロセスが存在するということです) 最後に、cleanup_module関数に目を向けます。 Interface Corporation - 44 - (51,52行目:pthread_cancel関数、pthread_join関数) これは、このRTLinuxモジュールをシステムから削除するので、実行中のRTLinuxスレ ッドを終了させるための指令です。 この関数により、argo_taskスレッドに対して終了通知が発せられ、argo_taskスレッド は、終了通知を検知した時、自身のスレッドを終了します。 どうでしたか?一見複雑そうに見えるサンプルプログラムも、 順に追いかけていくと、 簡単に読み取ることができます。 関数&用語解説 先ほど出た用語について、幾つか簡単に解説します。 ★init_module での禁止事項 RTLinux モジュールは、カーネル空間に存在するため、ユーザ空間でできないことができ る反面、一歩間違えると、カーネルやファイルシステムを破壊してしまう恐れがあります。 代表的な禁止事項として、init_module や割り込みハンドラ内で usleep 関数を呼び出しては いけません。Linux が起動しなくなってしまう場合があります。 他にも、禁止事項が幾つかあります。RTLinux 関連のドキュメントをよく読んでください。 ★pthread_create RTLinux スレッドを作成する関数です。 第 1 引数には RTLinux スレッドの ID を格納する pthread_t 変数へのポインタを指定します。 第 2 引数には RTLinux スレッドの属性を指定する pthread_attr_t 変数へのポインタを指定し ます。 第 3 引数には作られた RTLinux スレッドで処理する関数を指定します。 第 4 引数にはその関数に渡す引数を指定します。 プログラム例では、RTLinux スレッドの属性は指定しないため、NULL を指定しています。 ★pthread_self 呼び出した自身の、RTLinux スレッドの ID を取得することができます。スレッド ID を引 数パラメータに指定する関数に対して自身のスレッド ID を指定する場合等に使用します。 ★pthread_setschedparam RTLinux スレッドのスケジューリング方法、優先度の設定を行う関数です。 第 1 引数では、RTLinux スレッドの ID を指定します。(ここでは、自身のスレッド ID を返 す pthread_self 関数により、自身の ID を取得しています) 第 2 引数では、スケジューリング方法を指定します。ここでは SCHED_FIFO をパラメー タ値に指定しています。 第 3 引数では、プライオリティ等の設定を行う sched_param 構造体のポインタを渡してい ます。ここではプライオリティ値を 5 に設定しています。 なお、プライオリティとは日本語で「優先度」を意味し、複数のスレッドを動かした際、 どのスレッドから実行を行うか、指定を行うことができます。 Interface Corporation - 45 - ★pthread_make_periodic_np ある RTLinux スレッドに対し、実行周期の間隔を指定する関数です。 第 1 引数にはスレッドの ID を指定します(ここでは、自身のスレッドの ID を返す pthread_self 関数により、自身の ID を取得しています)。 第 2 引数には、リアルタイム処理の実行を開始する時間を hrtime_t 型で指定します(ここで はシステム起動からの絶対時間を取得する gethrtime 関数を用いて、開始時間を関数呼び出 しと同時にしています)。 第 3 引数には、リアルタイム処理を実行する周期を ns(ナノ秒)単位で設定します。おなじ く hrtime_t 型で指定します。 リストでは、pthread_wait_np によるスレッドの待機箇所を起点として、指定された周期で while ループ中の処理が実行されます。 ★pthread_wait_np pthread_wait_np 関数は、pthread_make_periodic_np 関数により、指定された周期まで待つ関数 です。 例えば、pthread_make_periodic_np 関数により 10ms の周期を指定された場合、10ms が経過 するまで、この pthread_wait_np 関数で待つことになります。 また、pthread_wakeup_np 関数を呼ぶことにより、実行を再開することもできます。 (但し、別の RTLinux スレッドからスリープ状態の RTLinux スレッドに対して、 pthread_wakeup_np 関数で呼び起こす必要があります) ★終了時の関数 pthread_cancel 関数は、引数に終了要求を出すスレッド ID を指定します。pthread_join 関数 も第 1 引数に同じくスレッド ID を指定します。第 2 引数は、ここでは NULL にしていま す。 なお、pthread_exit 関数で RTLinux スレッドの処理を終わらせた場合、pthread_exit 関数の 引数が、pthread_join 関数の第 2 引数に格納されます。 以下に例を示します。 void* input_task(void *arg) { int status = 10; ・・・ pthread_exit(status); ・・・ } void cleanup_module(void) { int value; pthread_join(send_thread, &value); // value には 10 が格納されます ・・・ } Interface Corporation - 46 - 3.6 LinuxプロセスからRTLinuxモジュールを制御する 今までのプログラムは、登録したら最後、誰からの命令を受けることも無く、永 遠に同じことを繰り返すだけのプログラムでした。 実際の組み込みプログラミングでは、こんなことはありません。 誰かから(大抵は上位アプリケーション)指令を受け、その指令に従って何らかのア クションを起こすのが普通です。 ここでは、Linuxプロセスから、RTLinuxモジュールを制御します。 まずは、4つのファイルを作成します。 ファイル名 備考 sample3.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル sample3.c Linuxプロセスのソースコード module3.c RTLinuxモジュールのソースコード makefile 上記ソースコードをコンパイルするためのmakefile List3-5は、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルで す。ファイル名を「sample3.h」として入力、保存してください。 List3-5 sample3.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /* sample3.h 共通定義ヘッダファイル Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___SAMPLE3_H) #define ___SAMPLE3_H /* const defines -------------------------------------------------------------- */ #define GET_HANDLER_FIFO 1 /* Linuxプロセスから指令を受 け取るFIFOチャネル */ #define GET_TASK_FIFO 2 /* ハンドラから指令を受け渡しするFIFOチャ ネル */ #define SET_TASK_FIFO 3 /* Linuxプロセスへ結果を送るFIFOチャネル */ #define BUFF_SIZE ネルのサイズ */ 100 /* Linuxプロセスへ結果を送るFIFOチャ /* type defines --------------------------------------------------------------- */ /* コマンドID群(RTLinuxスレッドへの指示用) */ enum CMD_IDS { ID_START, /* スタート指示 */ ID_STOP /* ストップ指示 */ }; Interface Corporation - 47 - 27 28 29 /* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ long value; /* 設定用パラメータ*/ }; #endif List3-6は、Linuxプロセスのソースファイルです。ファイル名を「sample3.c」とし て入力、保存してください。 List3-6 sample3.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 /* sample3.c Linuxプロセスのソースコード Copyright 2002 Interface Corporation. All rights reserved. */ #include #include #include #include #include #include #include <stdio.h> <fcntl.h> <unistd.h> <sys/time.h> <sys/ioctl.h> <rtl_fifo.h> "sample3.h" /* Linuxプロセスのメインルーチン */ int main(void) { int fd_ret, fd_ctrl; fd_set rfds; struct timeval tv; struct CMD_STRUCT cmd; long counter = 0; */ /* 周期スレッドのチェック用カウンタ /* RTLinuxスレッドに指令を送るFIFOチャネルのオープン */ if((fd_ctrl = open("/dev/rtf1", O_WRONLY)) < 0){ fprintf(stderr, "failed to open /dev/rtf1¥n"); return -1; } /* RTLinuxスレッドからの結果を受け取るFIFOチャネルのオープン */ if((fd_ret = open("/dev/rtf3", O_RDONLY)) < 0){ fprintf(stderr, "failed to open /dev/rtf3¥n"); return -1; } /* RTLinuxスレッドへの実行開始の指示 */ cmd.id = ID_START; cmd.value = 500; /* 500ms周期実行に設定 */ if(write(fd_ctrl, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "failed to send the start command¥n"); Interface Corporation - 48 - 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 return -1; } /* RTLinuxスレッドのカウンタが10になるまで取得のループ */ do { FD_ZERO(&rfds); FD_SET(fd_ret, &rfds); tv.tv_sec = 30; /* select関数のタイムアウト値の設定:30秒 */ tv.tv_usec = 0; /* RTLinuxスレッドからのデータ受け取り */ if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){ if(FD_ISSET(fd_ret, &rfds)){ /* fd_retに対してFIFOの書き込みがあ った */ read(fd_ret, &counter, sizeof(counter)); printf("counter:%ld¥n", counter); } } }while(counter < 10); /* RTLinuxスレッドへの停止指示 */ cmd.id = ID_STOP; cmd.value = 0; if(write(fd_ctrl, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "failed to send the stop command¥n"); return -1; } printf("The Linux process is successfully completed.¥n"); return 0; } List3-7は、RTLinuxで動作するRTLinuxモジュールのソースファイルです。ファイル名 を「module3.c」として入力、保存してください。 List3-7 module3.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /* module3.c RTLinuxモジュール Copyright 2002 Interface Corporation. All rights reserved. */ #include #include #include #include <rtl.h> <rtl_sched.h> <rtl_fifo.h> "sample3.h" pthread_t my_task_info; /* 周期実行を行うRTLinuxスレッド */ void* my_task(void* arg) { int err; Interface Corporation - 49 - 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 struct CMD_STRUCT cmd; long counter = 0, temp_counter; rtl_printf("call my_task arg=%d¥n", arg); /* RTLinuxスレッドが組み込み中、動作する永久ループ */ while(1){ /* 自スレッドをスリープさせる */ pthread_wait_np(); /* FIFOチャネルからの取り込み */ if((err = rtf_get(GET_TASK_FIFO, &cmd, sizeof(cmd))) == sizeof(cmd)){ rtl_printf("my_task: get command id=%d value=%d¥n", cmd.id, cmd.value); switch(cmd.id){ case ID_START: /* 周期実行の設定と開始 */ rtl_printf("my_task: start!!¥n"); pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.value * 1000 * 1000); counter = 0; /* 周 期 カ ウ ン タ の リ セ ッ ト (ms) */ break; case ID_STOP: /* 周期実行の停止 */ rtl_printf("my_task: stop!!¥n"); pthread_suspend_np(pthread_self()); break; default: rtl_printf("my_task: unknown command!!¥n"); break; } } /* 周期カウンタのカウントアップ */ counter++; rtl_printf("my_task: counter=%d¥n", counter); /* カウンタ値を、LinuxプロセスへのFIFOチャネルに書き込み */ temp_counter = counter; rtf_put(SET_TASK_FIFO, &temp_counter, sizeof(temp_counter)); } return 0; } /* Linuxプロセスからの指令を受け取るハンドラ */ int my_handler(unsigned int fifo) { int ret; struct CMD_STRUCT cmd; rtl_printf("call my_handler fifo:%d¥n", fifo); /* Linuxプロセスからの指示を、RTLinuxスレッドのFIFOチャネルに横流しす る */ Interface Corporation - 50 - 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 while((ret = rtf_get(GET_HANDLER_FIFO, &cmd, sizeof(cmd))) == sizeof(cmd)){ rtf_put(GET_TASK_FIFO, &cmd, sizeof(cmd)); rtl_printf("my_handler: get command id=%d value=%d¥n", cmd.id, cmd.value); pthread_wakeup_np(my_task_info); } if(ret != 0){ rtl_printf("my_handler: error!!(%d)¥n", ret); return -EINVAL; } return 0; } /* 初期化モジュール(RTLinuxモジュールが起動する時、呼ばれる関数) */ int init_module(void) { rtl_printf("call init_module¥n"); EXPORT_NO_SYMBOLS; /* Linuxプロセスからの指示を受け取るハンドラとFIFOチャネルを生成する */ rtf_destroy(GET_HANDLER_FIFO); rtf_create(GET_HANDLER_FIFO, sizeof(struct CMD_STRUCT)); rtf_create_handler(GET_HANDLER_FIFO, my_handler); /* ハンドラとLinuxプロセスの間のFIFOチャネルを生成する */ rtf_destroy(GET_TASK_FIFO); rtf_create(GET_TASK_FIFO, sizeof(struct CMD_STRUCT)); /* Linuxプロセスへ結果を送るFIFOチャネルを生成する */ rtf_destroy(SET_TASK_FIFO); rtf_create(SET_TASK_FIFO, sizeof(long) * BUFF_SIZE); /* スレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了モジュール(RTLinuxモジュールが終了する時、呼ばれる関数) */ void cleanup_module(void) { rtl_printf("call cleanup_module¥n"); /* FIFOチャネルを閉じる */ rtf_destroy(GET_HANDLER_FIFO); rtf_destroy(SET_TASK_FIFO); rtf_destroy(GET_TASK_FIFO); /* スレッドを終了させる */ pthread_cancel(my_task_info); pthread_join(my_task_info, NULL); } Interface Corporation - 51 - List3-8は、上記ファイルをコンパイルするメイクファイルです。ファイル名を 「makefile」として入力、保存してください。 List3-8 makefile 1 2 3 4 5 6 7 8 include /usr/include/rtlinux/rtl.mk all: module3.o sample3 sample3: sample3.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o sample3 sample3.c module3.o: module3.c $(CC) $(INCLUDE) $(CFLAGS) -o module3.o -c module3.c コンパイルし、insmodコマンドでRTLinuxモジュールを登録します。 # make # ls makefile sample3 module3.c module3.o sample3.c sample3.h # insmod module3.o ← RTLinux モジュールを組み込んでいます 次に、Linuxプロセスを実行します。 # ./sample3 ← Linux プロセスを実行しています ★./を何故付けるか? 上の例で、Linux プロセスを実行させるのに、「./」を付けて、実行ファイルがカレントディレクト リ上にあることを明示しています。 もし、これを付けないと、「command not found」となってしまいます。 Windows や MS-DOS では、相対/絶対パスを付けずに、実行ファイルを呼び出すと、カレントディ レクトリから実行ファイルを検索しますが、Linux(Unix)では、そうはならず、設定されたパス通り に検索が行われます。 カレントディレクトリ上にあるファイルを実行させるには、必ず「./」を付加してください。 Interface Corporation - 52 - 実行画面を以下に示します。 (画面左上のウィンドウがLinuxプロセスを実行しているコンソール。画面右下のウィンド ウはRTLinuxモジュールのログメッセージを表示させているコンソールです) 図 3-3 sample3実行時の画面 sample3を実行させると、「get counter」の値がカウントアップしていき、10を表示し た後、プログラムが終了します。 Interface Corporation - 53 - 3.7 LinuxプロセスからRTLinuxモジュールを制御するプログ ラムの解説 それでは、先ほどのプログラムの動きを解説します。 まず、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。 main rtf1 ユーザ空間 sample3 カーネル空間 module3.o 指令 結果の通知 my_handler rtf3 生成 破棄 rtf2 init_module cleanup_module 指令の転送 生成 my_task 破棄 図 3-4 LinuxプロセスとRTLinuxモジュールの相関関係 ・RTLinuxモジュール(module3.o)では、init_module関数呼び出し時に、my_handler とmy_taskを生成します。cleanup_module関数は、逆に2つを破棄します。 ・my_handlerは、Linuxプロセスからの指令を受け取る専用のハンドラです。 ・my_taskは、周期的な処理を行う専用のRTLinuxスレッドです。プログラムでは、 スレッドのスタートとストップをサポートし、指定間隔の周期スレッドがスタ ートされると、ストップ指令を受けるまで、内部のカウンタをアップカウント し、結果を書き込むという単純なものです。 ・Linuxプロセス(sample3)のmain関数内では、RTLinuxモジュール(module3.o)に対 して、my_taskへのスタートおよびストップを指令します。 Linuxプロセスのmain、RTLinuxモジュールのmy_handler、my_taskの各ブロック間 の、情報のやり取りは、RT-FIFOと呼ばれる専用の通信路を使って、やり取りさ れます。 RT-FIFOは、mainとmy_handler間にrtf1、my_handlerとmy_taskの間にrtf2、my_task とmainの間にrtf3の、合計3つのRT-FIFOが設定されます。 各スレッドおよびプロセスは、このRT-FIFOを情報の通信路として利用します。 詳細は後述しますが、このRT-FIFOを用いることで、RTLinuxスレッドはLinuxプ ロセスの動きに引っ張られることなく、確実な周期実行を可能にしています。 Interface Corporation - 54 - 3.7.1 RT-FIFOの役割 RT-FIFOとは、双方のスレッドがメッセージをやり取りする際の、一種の緩衝領 域です。 この機構を用いることで、双方のスレッドが非同期的に処理することが可能です。 例を示します。下図は、指令を出すスレッドAと、指令を受け取るスレッドBを仮 定しています。 <スレッドAの動き> <スレッドBの動き> 処理 1 処理 2 処理 1 データ有る? 書き込み RT-FIFO RT-FIFO 取り込み 処理 3 無い データ 有る 処理 2 スレッドAは、一連の処理の中で、RT-FIFOに対して逐次指令を書き込んでいきます。 スレッドBは、一連の処理の中で、スレッドAからの指令を検出すると、RT-FIFOから 指令を取り出して処理し、無ければスキップするという処理を行います。 もし、RT-FIFOを使わずに、2つのスレッド間でやり取りする場合、幾つか方法があり ます。例えば、あるデータ領域に対して、スレッドAが指令を書き込み、スレッドB は、それを読み取る処理を仮定したとします。 多くの場合、2つのスレッドが同一のデータ領域にアクセスするため、データの完全 性を保証するために、セマフォ等の同期オブジェクトを併用してデータを同期します。 ここで問題となるのが、同期オブジェクトによって、ロックしている時間です。 片方のスレッドがロックしている時間が長いと、もう片方は、その間ロック待ちの状 態となります。これは、自身の処理間隔が他方に影響を受ける点で、望ましいとは言 えません。 RT-FIFOは、この手の問題に対する、簡易かつ確実な解決方法を提供します。 Interface Corporation - 55 - 3.7.2 共通定義ファイルの役割 ここでは、共通定義ファイル(sample3.h)の役割について見ます。 共通定義ファイルは、RTLinuxモジュール(module3.c)とLinuxプロセス(sample3.c) の内、共通で使用する定義内容を抜き出したものです。各ファイルの関係を下図 に示します。 sample3.h 共通定義 参照 参照 sample3.c Linux module3.c RTLinux プロセス モジュール 図 3-5 ファイルの参照関係 共通定義ファイルでは、以下のように設定しています。 ・10∼14行目:#define宣言 RT-FIFO番号の定義と、バッファサイズの指定。 ・18~21行目:enum宣言 LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID 値を指定。 ・24∼27行目:struct宣言 LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造 を指定。 ここで重要なのが、LinuxプロセスからRTLinuxモジュールに対して指令を出すために 使用される、コマンドの構造体(CMD_STRUCT)です。 Linuxプロセスでは、この構造体に値をセットしてRTLinuxモジュールに渡します。 RTLinuxモジュールでは、この構造体ごと 受け取って、指示された内容に従って処理 を行います。(実際には、RTLinuxモジュール内のハンドラが受け取っています) Interface Corporation - 56 - Linux プロセス struct CMD_STRUCT { enum CMD_IDS id; long value; }; RTLinux モジュール 図 3-6 LinuxプロセスからRTLinuxモジュールへのコマンドの流れ コマンドの構造体は、簡単な2つのメンバ変数で構成されています。RTLinuxモジュー ルに、どんな作業をして欲しいか指示を出すID値(idメンバ変数)と、ID値に補足する 情報(valueメンバ変数)です。 作業を指示するID値は、18∼21行の列挙体定数、ID_STARTとID_STOPで定義されて います。以下に、LinuxプロセスからRTLinuxモジュールに指示する際の取り決めを、 簡単にまとめます。 id 変数 value 変数 内容 ID_START 周 期 時 間 (ms 単 value で指定し た時 間間 隔で、周 期 スレッ ド 位) (RTLinux スレッド)をスタートする。 ID_STOP 特になし 周期実行スレッドをストップさせる。 この構造体は、後の説明にも出てきますので注意して読み進めてください。 Interface Corporation - 57 - 3.7.3 RTLinuxモジュールの動き ここでは、RTLinuxモジュール(module3.o)の動きに注目して見てみます。 まず、RTLinuxモジュール内の各リソースとRTLinuxスレッド、ハンドラの生成関 係を下図に示します。 RT-FIFO FIFO1(GET_HANDLER_FIFO) FIFO2(GET_TASK_FIFO) 生成 破棄 FIFO3(SET_TASK_FIFO) init_module cleanup_module スレッド&ハンドラのコード ハンドラ(my_handler) RTLinux スレッド(my_task) 図 3-7 RTLinuxモジュール内の生成関係 Linuxプロセスからの指令を受け取るハンドラ(my_handler)と、RTLinuxスレッド (my_task)が生成/破棄されています。 次に、RTLinuxモジュール内での相互関係を示します。 Linux プロセス FIFO1(GET_HANDLER_FIFO) FIFO3(SET_TASK_FIFO) ハンドラ(my_handler) FIFO2(GET_TASK_FIFO) RTLinux スレッド(my_task) ID_START ID_STOP 開始 停止 周期実行 counter 変数 ←インクリメント 図 3-8 RTLinuxモジュール内の処理の流れ Interface Corporation - 58 - RTLinuxモジュール内で中心となるのは、周期実行を行うRTLinuxスレッド (my_task)です。このRTLinuxスレッドは、Linuxプロセスからの指令により、周期 実行のスタート(ID_START)、ストップ(ID_STOP)を行います。スタート後の周期 実行中、RTLinuxスレッドは内部のcounter変数を周期ごとにインクリメントします。 (将来、カスタマイズするならば、例えば、ここにDIOやAD/DA等の周期的な制 御を入れると良いでしょう) LinuxプロセスからRTLinuxスレッドへの指示は、ハンドラ(my_handler)を経由して 行われます。このハンドラは、Linuxプロセスからの指示を、RTLinuxスレッドに、 そのまま送っています。(将来、RTLinuxスレッドを2つ以上に増やした時、このハ ンドラで、操作するスレッドを集中的に管理すると良いでしょう) ハンドラとRTLinuxスレッドは、RT-FIFOによって、情報の交換を行います。 RT-FIFOの生成と削除は、お馴染みのinit_module関数とcleanup_module関数で行っ ています。 以降では、処理順に、これらの処理を解説します。 (89∼99行目:rtf_destroy、rtf_create関数) RT-FIFOを生成するのは、rtf_create関数です。破棄はrtf_destroy関数です。 コードでは、rtf_destroy関数を呼び出した後、rtf_create関数を呼び出しています。 通常であれば、init_module関数を実行する時、RT-FIFOは生成済みということは考 えにくいのですが、ここでは保険として、rtf_destroy関数で明示的に削除を行って います。 RT-FIFOのサイズは、各RT-FIFOごとに変えています。 特にRTLinuxスレッドからLinuxプロセスへ結果を返却するRT-FIFO(99行目の、 SET_TASK_FIFO)では、”sizeof(long:4バイト) * BUFF_SIZE(100個) = 400バイト”の バッファサイズを確保しています。 これは、RTLinuxスレッドに格納した情報を、即座にLinuxプロセス側で取り出せ ることは考えにくいため、ある程度RT-FIFOに情報が溜まっても、処理が続けら れるよう(バッファをオーバーフローしないよう)に、大きめのバッファを確保して います。 Interface Corporation - 59 - 実際のリアルタイムプログラミングでも、2つのプロセス間が非同期に動作する場 合、バッファサイズに、余裕を持たせることは重要です。 (91行目:rtf_create_handler関数) rtf_create_handler関数は、ハンドラ(my_handler)を生成する関数です。 このハンドラでは、指定されたRT-FIFOにメッセージが溜まると呼び出される、 明示的なイベントハンドラと思えば良いでしょう。 (但し、受け取ったメッセージを取り出すコードは必要です) (102行目:pthread_create関数) pthread_create関数は、周期実行を行うRTLinuxスレッドを生成しています。 (69∼73行目:my_handler関数のwhileループ) ハンドラ(my_handler)関数では、このwhileループがメインとなります。 ここでは、Linuxプロセスと繋がるRT-FIFOから送られるデータを受け取るために、 rtf_get関数で待機します。 受け取ったデータは、ここでは、rtf_put関数にて、そのままRTLinuxスレッド (my_task)と繋がるRT-FIFOに送っています。 簡単なイメージを、下図に示します。 rtf_put rtf_get Linux プロセス側 RTLinux スレッド側 my_handler RT-FIFO RT-FIFO ハンドラ 図 3-9 LinuxプロセスからRTLinuxスレッドへのデータのな流れ 将来、RTLinuxスレッドを2つ3つと増やした場合、ここをLinuxプロセスから各 RTLinuxスレッドへメッセージを分配するための、集配所として追加すれば良いで しょう。 Linux プロセス側 RT-FIFO rtf_put rtf_get my_handler RTLinux スレッド側 RT-FIFO ハンドラ RT-FIFO RT-FIFO 図 3-10 将来、RTLinuxスレッドを複数に増やした場合の想定例 Interface Corporation - 60 - (24∼56行目:my_task関数のwhileループ) RTLinuxスレッド(my_task)では、このwhileループがメインとなります。 ここでは、ハンドラと繋がるRT-FIFOから送られるデータをrtf_get関数で受け取り、 その指示に従い、周期実行のスタートおよびストップを行います。 周期実行を動作させている時、内部のcounter変数がインクリメントされていきま す。 このインクリメントされた値は、rtf_put関数を用いて、Linuxプロセスに繋がる RT-FIFOに送られます。 29行目のrtf_get関数は、周期実行が行われている/行われていないに係わらず、こ こでRT-FIFOからのデータ待ちになってしまうと思われるかも知れません。 しかし、実際には、rtf_get関数の呼び出しは、RT-FIFOからのデータがあれば、29 ∼47行の処理を行い、無ければ50行以降の処理を続けます。 33∼46行のswitch文では、Linuxプロセスから送られてきた指示に対する処理が記 述されています。動きを以下に示します。 ID_START value変数の値をms単位の実行周期として、pthread_make_periodic_np 関数を呼び出し、自身の実行周期の間隔を指定する。 ID_STOP pthread_suspend_np関数を呼び出し、自スレッドをスリープ状態にす る。 50∼55行の処理は、周期実行している時の、処理コードです。 内容は、内部counter変数をインクリメントし、counter変数の値を、rtf_put関数を使 って、RT-FIFOに書き込み続けています。 ここでやっているのは、非常に単純な処理ですが、この処理をDIOやAD/DA等に 置き換えて見ると、様々なやり方が想定できることでしょう。 例えば、周期実行の部分に、1件のAD入力関数を配置するだけで、サンプリング 間隔を簡単に可変することが実現できます。 Interface Corporation - 61 - 関数解説 ★rtf_create RT-FIFO を生成します。 第 1 引数で、RT-FIFO の ID 値を。第 2 引数でサイズを指定します。 生成した RT-FIFO を破棄するには、rtf_destroy 関数を用います。 ★rtf_create_handler この関数は、ユーザ空間から RT-FIFO にデータが書き込まれた際に、呼び出される関数を 登録します。 第 1 引数には、RT-FIFO 作成時に指定した ID 値を指定します。 第 2 引数には、RT-FIFO にデータが書き込まれた際に、呼び出される関数を指定します。 この関数は、ユーザ空間から RT-FIFO にデータが書き込まれた際に呼ばれる関数を登録し ますが、カーネル空間からアクセスされた(rtf_put、rtf_get 関数を使用した)場合に呼ばれる 関数を登録するには、rtf_create_rt_handler 関数を使用します。 ★pthread_wakeup_np この関数を呼ぶことで、指定した RTLinux スレッドの実行を再開することができます。 ★pthread_suspend_np 引数により指定した RTLinux スレッドを pthread_wakeup_np が呼び出されるまで中断しま す。 3.7.4 Linuxプロセスの動き ここでは、Linuxプロセスの動きに注目して見てみます。 まず、LinuxプロセスとRTLinuxモジュールとの関係を、下図に示します。 カウンタ値取得 RT-FIFO(rtf3) RTLinux モジュール main コマンド指令 RT-FIFO(rtf1) 図 3-11 LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係 Linuxプロセスは、2つのRT-FIFOをオープンし、それぞれコマンド指令と、RTLinux モジュールからのカウンタ値の取得に使用しています。 以降では、処理順に、これらの処理を説明します。 Interface Corporation - 62 - (25∼33行目:RT-FIFOのオープン) 25∼33行のopen関数は、RTLinuxモジュールのinit_module関数内のrtf_create関数で 作成したRT-FIFOをオープンします。 Linuxプロセスでは、RT-FIFOは、open、read、write、closeの低レベル入出力関数 にてアクセス可能です。 rtf_create関数の第1引数で指定するID値と、open関数で用いるデバイス名は、相対 的な関係があります。 両者の関係を、以下に示します。 Linuxプロセス側 RTLinuxモジュール側 “/dev/rtf1” GET_HANDLER_FIFO = 1 “/dev/rtf2” GET_TASK_FIFO =2 “/dev/rtf3” SET_TASK_FIFO =3 RTLinuxプログラミングでのRT-FIFOは、”/dev/rtfXX”というデバイス名にてアク セス可能です。そして、デバイス名の数値の部分は、rtf_create関数のID値が、そ のまま割り当てられます。 (36∼41行目:RTLinuxモジュールの周期実行開始) 38行目のwrite関数は、RTLinuxモジュールに対してRtlinuxスレッドの周期実行ス タートを指示しています。 CMD_STRUCT構造体のidメンバ変数にID_START、valueメンバ変数に500(実行周 期を500msに指定している)を指定しています。 ここで与えられたパラメータは、RTLinuxモジュールのハンドラ(my_handler)を経 由し、RTLinuxスレッド(my_task)に、コマンドとして伝達されます。 (44∼57行目:RTLinuxモジュールからのカウンタ値取得) 44∼57行の処理は、RTLinuxモジュール内のRTLinuxスレッドからカウンタ値を順 次読み取っていき、読み取った値が10を超えた時点で、whileループを抜けていま す。 もう一度、『3.7.3 RTLinuxモジュールの動き』のRTLinuxスレッドの処理を見返し てみてください。51∼56行で、内部counter変数をインクリメントして、RT-FIFO に値を書き込んでいると思います。ここで書き込んだ値が、この処理の中で読み 取られているのです。 Interface Corporation - 63 - 次に、select関数と一連のマクロの動きを説明します。 この処理は、まずselect関数で、RT-FIFOにデータが入ってくるのを待機し、デー タを受け取ると、FD_ISSETマクロで、確かに自分のRT-FIFOにデータが入ってい ることを確認した上で、データを読み取っています。 select 関数 RT-FIFO のハンドル(fd_ret)に対 し、データ待ちを行う。 有る 読み取り fd_ret データ有り? RT-FIFO(fd_ret)からデータを取 FD_ISSET で検出 り込む 無い 図 3-12 select関数の処理の流れ リストでは、1つのRT-FIFOからしか値を読み取って無いので、わざわざselect関数 を用いる必要はありませんが、複数のRT-FIFOを同時に読み取ろうとした時、こ のselect関数を使用することで、データのあるRT-FIFOからのみデータを読み取る ことが可能となります。 select 関数 複数の RT-FIFO のハンドルに対 し、データ待ちを行う。 有る 読み取り 1 データ有り? RT-FIFO からデータを取り込む FD_ISSET で検出 無い 有る データ有り? 読み取り 2 RT-FIFO からデータを取り込む FD_ISSET で検出 無い 図 3-13 複数のRT-FIFOのselect処理想定例 Interface Corporation - 64 - (60∼65行目:RTLinuxモジュールの周期実行停止) 62行のwrite関数は、RTLinuxモジュールに対してRTLinuxスレッドの周期実行スト ップを指示しています。 先の実行開始の時は、idメンバ変数にID_STARTをセットしていましたが、ここで はID_STOPをセットしています。ここで与えられたパラメータは、RTLinuxモジュ ールのハンドラを経由してRTLinuxスレッドに対して、ストップ命令として伝えら れます。 以上で、基本的なRTLinuxプログラミングは終わりです。 どうでしたか?リアルタイムプログラミングといえど、思ったより難しくなかっ たのでは無いでしょうか? 以降のプログラムは、 本書の最後に挙げた 「参考文献」 や、 インターネット、 RTLinux インストール時のサンプルプログラム、弊社ドライバ付属のサンプルプログラム を参考に進めて行ってください。 関数&用語解説 ★Linux プロセスが終了しても、RTLinux モジュールは自動で取り外されません。 Linux プロセスの実行が終了しても、RTLinux モジュールは自動で取り外されることはあ りません。 Linux プロセスの処理を終了させた後、lsmod コマンドを打ち込んでみてください。RTLinux モジュールが常駐していることに気付くことでしょう。 # lsmod Module module3 rtl_sched rtl_fifo rtl_posixio rtl_time rtl Size 1472 43104 9968 7184 10000 27184 Used 0 0 0 0 0 0 Interface Corporation by (unused) ← RTLinux モジュールが常駐している [module3] [module3] [rtl_fifo] [module3 rtl_sched rtl_posixio] [module3 rtl_sched rtl_fifo rtl_posixio rtl_time] - 65 - ★Linux プロセスは、複数起動が可能か? 先ほどのプログラムを実行していて、疑問に思いませんでしたか。 「sample3 を複数同時に動かすことは、できるのだろうか?」 実際に何度かテストした結果を示します。 ケース1:「fail open /dev/rtf1」と表示されて終了。 ケース2:「get counter:11」と表示されて終了 ケース1は、ある Linux プロセスが RT-FIFO をオープン中かつ使用中なので、オープンで きなかったことを意味します。 これは、このサンプルでは、RT-FIFO がオープンできるプロセスは、たかだか 1 つだけで あり、共有オープンはできないことを意味します。 ケース2は、ちょっと複雑です。これは、以前のプロセスが、RT-FIFO に格納されたバッ ファデータがクリアされない内にオープンし、意図しないデータを読んで終了してしまっ たことを意味します。 このことから、Linux プロセスと RTLinux モジュールを繋ぐ RT-FIFO を複数に増やせば、 複数の Linux プロセスから制御できそうだ、と予想できます。 ★open 第 1 引数には、オープンするデバイスのパスを指定し、第 2 引数には、読み取り用のフラ グ O_RDONLY もしくは、書き込み用のフラグ O_WRONLY を指定しています。 ★ディスクリプタ open 関数の実行が成功すると、戻り値としてファイルディスクリプタが返されますが、こ の値は、現在使用されていないファイルディスクリプタのうち、負でない最小の値が返さ れます。 ★FD_ZERO、FD_SET マクロ ここで使用している FD_ZERO マクロと FD_SET マクロは、select 関数に関係のあるもの です。後方に記述している select 関数は、複数のディスクリプタに変化があるまで待つ関 数です。ここでは、RT-FIFO しか監視する必要はないため、複数のファイルディスクリプ タを監視する必要はありません。そのため、最初に FD_ZERO マクロにより指定したファ イルディスクリプタの集合(ここでは rfds)をクリア(消去)し、次に、先ほどクリアしたファ イルディスクリプタの集合(rfds)に RT-FIFO のディスクリプタ(fd_ret)を設定することによ り、select 関数は、RT-FIFO の変化のみを監視するようになります。 ★タイムアウト select 関数では、指定したファイルディスクリプタの変化を監視する時間を設定すること ができます。 select 関数の第 5 引数として、タイムアウト時間に 0 を指定するとすぐに処理が抜け、NULL を指定すると、指定したファイルディスクリプタに変化があるまでずっと待ちます。 Interface Corporation - 66 - ★select select 関数の第 1 引数には、監視するファイルディスクリプタの個数を指定します。例え ば 5 を指定すると、0∼4 の 5 つのファイルディスクリプタを監視します。ここでは、使用 できるファイルディスクリプタの最大値である FD_SETSIZE を指定しています。 第 2 引数には、読み込み可能かどうかを監視するファイルディスクリプタの集合、第 3 引 数には書き込み可能かどうかを監視するファイルディスクリプタの集合、第 4 引数には例 外の監視を行うファイルディスクリプタの集合を指定します。ここでは、RT-FIFO からデ ータを読み出すので、先ほど FD_ZERO マクロ、FD_SET マクロで設定したファイルディ スクリプタの集合を第 2 引数に設定します。 第 5 引数には、select 関数のタイムアウト時間を設定する timeval 構造体を指定します。こ こを NULL に指定すると、タイムアウトが発生しなくなりますので、ご注意ください。 ★FD_ISSET FD_ISSET マクロは、第 2 引数で指定されるファイルディスクリプタの集合に、第 1 引数 で指定されるファイルディスクリプタが存在するかをチェックします。FD_ISSET が真を 返せば、集合の中に指定したファイルディスクリプタが存在することになります。 ★read read 関数の第 1 引数には読み込みを行うファイルディスクリプタ、第 2 引数には読み込み データを格納するバッファ、第 3 引数には読み込みを行うサイズを指定します。戻り値に は、実際に読み込み取得できたバイト数が返されます。 ★コンパイル時の注意事項 RTLinux のプログラムを作成する際には、Makefile 内で「rtl.mk」を include することで、 コンパイルに必要なフラグや識別子が全てセットされます。 ここで注意が必要なのは、このフラグにコードの最適化を行う-02 や、デバッグ情報を添 付する-g 等がデフォルトで指定されていることです。 rtl.mk をそのまま使用する場合には、使用されているフラグを確認してください。そうし ないと、バグを埋め込む原因になるかもしれません。 (1) 修正前 while(*memadr & CMPL); (2) 修正後 while(1){ BYTE Status; memcopy(&Status, memadr, 1); if(Status & CMPL) break; } 上記(1)のコードでは、アドレス memadr の値を参照して、データが書き込まれた場合にル ープを抜ける処理となっています。 このコードを最適化フラグを有効にしてコンパイルすると、環境によってはメモリの参照 を一度しか行わない場合があります。そうなってしまうと、最初に参照した時点でメモリ の値が 0 であった場合に、無限ループに入ってしまいます。 最適化によるコンパイラの動作は環境にも依存します。一概には言えませんが、デフォル トで設定されているコンパイラのフラグを念頭に置いておくと、デバッグ時に無用な苦労 を減らせるかもしれません。 Interface Corporation - 67 - 第4章 弊社RTLinux用ソフトウェアの導入 4.1 RTLinux対応ソフトウェアの特長 弊社では、Linux/RTLinux対応ドライバソフトウェアとして、下記の製品を用意し ています。 型式 GPG-1604 GPG-1609 GPG-1900 GPG-2000 GPG-2746C GPG-2910C GPG-2x72C GPG-3100 GPG-3300 GPG-3500 GPG-4101 GPG-4115 GPG-4116 GPG-4141 GPG-4301 GPG-4304 GPG-4851 GPG-4910 GPG-5520 GPG-6105 GPG-6106 GPG-6201 GPG-6202 GPG-6204 GPG-7204 GPG-7302 GPG-7400 GPG-8208 GPG-8210 名称 Linux/RTLinux用フラッシュメモリIDEモジュール Linux/RTLinux用PCカードATAドライバセット RASボード Linux/RT対応ドライバソフトウェア デジタル入出力ボード Linux/RT対応ドライバソフトウェア パラレル入出力ボードLinux/RT対応ドライバソフトウェア ロジックアナライザボード Linux/RT対応ドライバソフトウェア バスマスタ方式デジタル入出力ボードLinux/RT対応ドライバソフト ウェア アナログ入力ボード Linux/RT対応ドライバソフトウェア アナログ出力ボード Linux/RT対応ドライバソフトウェア アナログ入出力ボード Linux/RT対応ドライバソフトウェア 無手順通信ボード Linux/RT対応ドライバソフトウェア LAP-B通信ボード Linux/RT対応ドライバソフトウェア HDLC通信ボード Linux/RT対応ドライバソフトウェア 調歩同期シリアル通信ボード Linux/RT対応ドライバソフトウェア GP-IBインタフェースボード Linux/RT対応ドライバソフトウェア GP-IBインタフェースボード Linux/RT対応ドライバソフトウェア CANインタフェース Linux/RT対応ドライバソフトウェア メモリンクボード Linux/RT対応ドライバソフトウェア カラー画像入力ボード Linux/RT対応ドライバソフトウェア パルスジェネレータボード Linux/RT対応ドライバソフトウェア パルスカウンタボード Linux/RT対応ドライバソフトウェア エンコーダカウンタボード Linux/RT対応ドライバソフトウェア ユニバーサルカウンタボード Linux/RT対応ドライバソフトウェア エンコーダカウンタボード Linux/RT対応ドライバソフトウェア モーションコントローラボード Linux/RT対応ドライバソフトウェア DCモータドライバボード Linux/RT対応ドライバソフトウェア モーションコントローラボードLinux/RT対応ドライバソフトウェア プリンタボード Linux/RTLinux対応ドライバソフトウェア プリンタボード Linux/RTLinux対応ドライバソフトウェア Interface Corporation - 68 - 弊社のLinux/RTLinux対応ソフトウェアは、以下の特長があります。 ・RTLinux 3.1に対応したドライバモジュールを提供 ・弊社PCI/CompactPCIボードに対応 ・付属のテストドライバを使用すれば、ボードをコンピュータに実装せずにソフ トウェアの動作を確認することが可能 ・サンプルプログラムにより、具体的なリアルタイム処理の構築例を用意 ・再コンパイルによって様々なカーネルバージョンのLinuxに対応可能 (ディストリビューションに依存しないモジュールを作成可能) ・弊社独自のインストーラを使用して、容易にインストール/アンインストール が可能。ソフトウェアのバージョンチェック等も独自に行います ・PDFとテキストの2種類のヘルプファイルを用意して、コンソール,X Window 両方の開発環境に対応 ・付属のシェルスクリプトをカスタマイズすることで、ターゲット環境用のイン ストーラを作成可能 ・各カテゴリごとにチュートリアルを用意して、具体的なシステムの構築例を 解説 ソフトウェアのインストール方法等は、従来のLinux対応ソフトウェアから変更さ れていますので、『4.2 RTLinux対応ソフトウェアのインストール』をご参照くだ さい。 4.2 RTLinux対応ソフトウェアのインストール それでは、GPG-2000(デジタル入出力ボード Linux/RTLinux対応ドライバソフト ウェア)を例に、インストールの手順を説明します。 (1) ソフトウェアの入手 Linux/RTLinux対応ドライバソフトウェアの入手方法については、弊社技術支援セ ンタまでお問い合わせください。 (2) インストールFD(フロッピーディスク)の確認 インストールFDの準備ができたら、ドライブに挿入してマウントを行い、インス トールFDの内容を確認してください。 # mount –t vfat /dev0/fd0H1440 /mnt/floppy # ls /mnt/floppy pg2000i.tgz gpg2000.ver readme.txt install Interface Corporation - 69 - 展開後のファイル構成が以下のようになっているか確認してください。 rgpg2000.(アーキテクチャ名).tgz RTLinux用アーカイブ common.tgz 共通モジュール用アーカイブ readme.txt 最新情報記載ファイル instal ※1 インストール用シェルスクリプト install_ja.txt インストール補助ファイル product.txt インストール補助ファイル sh4.txt インストール補助ファイル ※2 ※1 Web版には含まれていません。 ※2 IBM PC/AT互換機用には含まれていません。 (3) インストーラの起動 インストールFDからinstallを実行すると、インストール画面が表示されます。 画面の指示に従って、インストールを実行してください。 # sh install ************************************************************** GPG-2000 DIO(PCI/C-PCI)Linux/RT File Name Version : INSTALL : 1.0 Copyright 2003 Interface Corporation. All right reserved. ************************************************************** インストールするドライバを選択してください。 Linux ドライバ(l) RTLinux ドライバ(r) 中止(q) 選択:t Linux用のドライバのみをインストールする場合は「l」、RTLinux用のドライバの みは「r」を入力してEnterキーを押します。 Interface Corporation - 70 - ----------------------------------------GPG-2000 DIO(PCI/C-PCI)Linux/RT アプリケーションのインストール先の選択 ----------------------------------------このディレクトリにインストールするには[OK(y)]を選択 してください 別のディレクトリにインストールする場合は[変更(C)]を 選択してください インストールディレクトリ=/usr/src/interface [OK(y)] [変更(c)] [戻る(b)] [中止(q)] 選択:y 次にインストールを行うディレクトリを決定します。 デフォルトでは「/usr/src/interface」となっていますが、インストール場所を変更した い場合は「c」、そのままデフォルトにインストールする場合は「y」を入力してから、 Enterキーを入力します。 ----------------------------------------GPG-2000 DIO(PCI/C-PCI)Linux/RT セットアップタイプ ----------------------------------------標準(t) カスタム(u) [戻る(b)] [中止(q)] 選択:t セットアップタイプの選択を行います。 「標準(t)」でインストールを行うと、全てのファイルをインストールします。 必要なファイルのみを選択してインストールする場合は、カスタムの「u」を入力して Enterキーを押します。 ----------------------------------------GPG-2000 DIO(PCI/C-PCI)Linux/RT コンポーネントの選択 ----------------------------------------Linux + ■ 開発環境(d) + ■ セットアップ(s) ■:設定 □:解除 [戻る(b)] [中止(q)] 選択: Interface Corporation - 71 - カスタムを選択すると、インストールするコンポーネントを選択する画面が表示され ます。ここで、コンポーネントを選択して、さらに詳細なインストールファイルの選 択へ進みます。 各コンポーネントはそれぞれ以下の様な特長を持ちます。 開発環境 開発用のファイルをまとめたコンポーネントです。ドライバのオブジェクト、ソースフ ァイル、サンプルプログラムのソースファイル、API関数のライブラリ、ドキュメント 等が含まれます。 セットアップ 開発用のファイルをまとめたコンポーネントです。ドライバのオブジェクト、API関 数のライブラリ、デバイス設定ユーティリティ等が含まれます。 ----------------------------------------GPG-2000 DIO(PCI/C-PCI)Linux/RT 開発環境コンポーネントの選択 ----------------------------------------Linux + 開発環境(d) + □ 1: ドキュメント + □ 2: インクルードヘッダ + ■ 3: ドライバソースオブジェクト + □ 4: ライブラリ + ■ 5: サンプルプログラム + ■ 6: 共通モジュール + ■ 7: 共通ユーティリティ ■:設定 □:解除 [OK(y) ] [戻る(b)] [中止(q)] 選択: インストールを行うコンポーネントに対応する番号を入力すると、コンポーネン ト名の左にあるチェックボックスの設定/解除が切り替わります。 全ての設定が完了したら、「b」を入力してコンポーネントの選択から戻ります。 ----------------------------------------GPG-2000 DIO(PCI/C-PCI)Linux/RT ----------------------------------------ファイルをインストールしてよろしければ [OK]を選択してください。 [OK(y) ] [戻る(b)] [中止(q)] 選択: Interface Corporation - 72 - ここで、ファイルをインストールして良いかを確認してきますので、問題なければ「y」 を入力してインストールを開始してください。 ----------------------------------------GPG-2000 DIO(PCI/ C-PCI)Linux/RT ファイルのコピー ----------------------------------------gpg2000/i386/rtl/drivers/ver2404/rcp2000.o 書庫内のファイル = 2002-2-14 16:25:14 /lib/modules/2.4.4-rtl/misc/rcp2000.o インストール先 = 2002-2-14 16:26:42 タイムスタンプが異なりますが上書きしますか? [はい(y) ] [いいえ(n)] [全て上書き(a)] 選択: もし、すでにインストールされているファイルが存在する場合には、タイムスタンプ を表示してファイルの上書きを確認しますので、書庫内のファイルのタイムスタンプ が新しければ上書きするようにしてください。 (後述するデバイス番号の設定ユーティリティは、全カテゴリで共通のプログラムを 使用します。他のGPGシリーズのソフトウェアがインストールされた状態でインスト ールを行うと、上記の様な上書き確認を行いますのでタイムスタンプを確認して新し いバージョンのファイルを残すようにしてください。) ドライバ等のファイルのコピーが完了後、コンポーネントの選択で標準もしくはセッ トアップを選択していた場合は、デバイス番号の設定ユーティリティが起動します。 デバイス番号設定プログラムが起動すると、現在コンピュータもしくはユニットに設 置されている弊社PCIデバイスが表示されますので、各デバイスに対してユニークな デバイス番号を割り振ります。デフォルトで割り振られる番号を使用する場合には、 そのまま終了してください。 デバイス番号の設定が終了すると、GP-IBボード等の一部の型式では、ボードの初期 値を設定する初期設定プログラムが起動します。(GPG-2000をご使用の場合は所期 設定プログラムは起動しません。) Interface Corporation - 73 - 全ての設定が完了後、下記のような画面が表示されます。 ----------------------------------------GPG-2000 DIO(PCI/ C-PCI)Linux/RT インストールファイルの完了 ----------------------------------------readme.txtを表示しますか?[y/n]y 最後にreadme.txtの表示を確認しますので、readme.txtを読む場合は「y」、読まない場 合は「n」を入力してください。 ======================================================= GPG-2000 DIO(PCI/ C-PCI)Linux/RT 最新情報ドキュメント 株式会社インタフェース ======================================================= ● お問い合わせ ● 改訂履歴 +---------+----------------------------------+ | 1.00-01 | 新規作成 | +---------+----------------------------------+ [製品概要] [対象ボード] [ファイル一覧] --続ける-- 「y」を選択すると、readme.txtの内容が表示されますので、Enterキーで画面をスクロ ールさせて読み進んでください。(「q」を入力するとで終了します。) 以上でドライバソフトウェアのインストールは完了です。 (4) ドライバモジュールの組み込みに失敗した場合 インストールの途中でドライバモジュールの組み込みに失敗した場合には、 「gpg-2000.oの組み込みに失敗しました」というようなメッセージが表示されます。 ドライバのコンパイルを行った環境と組み込みを行う環境でカーネルのバージョ ンが異なる場合には、ドライバのモジュール組み込み時にエラーが発生する場合 があります。 弊社が標準で用意しているドライバモジュールの対応カーネルバージョンを表 に示します。 Interface Corporation - 74 - 表 4-1 弊社ソフトウェアの標準対応カーネル カーネルバージョン RTLinux対応ドライバ Linux対応ドライバ 2.2.18 ― ○ 2.2.19 ○ ― 2.4.4 ○ ○ ○:対応ドライバを標準で用意 ※RTLinux 3.1はカーネル2.2.19および2.4.4に対応しています。 ※各ドライバソフトウェア製品と対応カーネルは、各製品のReadmeにてご確認 ください。 これら以外のカーネルバージョンのLinux,RTLinuxにドライバをインストールする場 合には、一度全てのファイルをインストール後に、ドライバモジュールの再コンパイ ルを行うことで、ご使用の環境で使用可能なドライバモジュールを作成できます。 installスクリプトを実行時に、標準もしくは開発環境のコンポーネントを選択してインス トールを行います。 インストールが完了したら、インストールを行ったディレクトリに移動して、ドライバモ ジュールのmakeを実行してください。 # cd /usr/src/interface/gpg2000/i386/rtl/drivers/src # make makeが完了後、/lib/modules/2.4.4-rtl/miscディレクトリに移動して、insmodコマンドを実行 してモジュールの組み込みを行います。 # cd /lib/modules/2.4.4-rtl/misc # insmod rcp2000.o インストール時、当該ディレクトリにパスが追加されているので、次のようにモジュール を組み込むことも出来ます。 # insmod rcp2000 ← .oを付けずに、組み込む モジュールの組み込みに成功したら、GPG-2000の場合、新たにデバイスノードを作成する 必要がありますので、デバイス番号設定ユーティリティ(dpg0101)を実行してデバイス ノードの作成を行ってください。 # dpg0101 ************************************************** Setup Utility -------------------------------------------------Version: 1.03-04 -------------------------------------------------Copyright 2003 Interface Corporation. All rights reserved. ************************************************** Enter the model number of the product: GPG/GPH-2000 Interface Corporation - 75 - デバイス番号設定ユーティリティ(dpg0101)を起動すると上記の様な画面が表示されま す。ここで、設定を行いたいドライバソフトウェアの型式を入力して、デバイス番号の設 定を行ってください。(デバイス番号設定ユーティリティの詳細については、各ソフトウ ェアのHelpをご参照ください。) 以上で、手動によるデバイスドライバの組み込みは完了です。 ※GPG-2000では、デバイスドライバ組み込み用スクリプトinsdio.sh, setup_shを用意してい ます。GPG-2000ではこちらをご利用ください。 4.3 テストドライバを使用した動作確認 弊社Linux/RTLinux対応ソフトウェアには「テストドライバ」が付属しています。 これは、実際にインタフェースボードを実装していない状態でも、サンプルプログラ ムや、ユーティリティを動作させることができます。 (一部ユーティリティやサンプルプログラムでは動作しない場合もあります。) RTLinux用のテストドライバはモジュール形式で提供していますので、insmodコマン ドで組み込みを行います。 # cd /usr/src/interface/gpg2000/i386/rtl/drivers/exp/ver2404 # insmod rcp2000t.o ※正規版のドライバを組み込んでいる場合は、 テストドライバを使用できませんので、 一度rmmodコマンドでモジュールを外してから、テストドライバを組み込んでくだ さい。 テストドライバの組み込みが完了したら、DIOのサンプルプログラムのディレクトリ に移動してコンパイルを行い、サンプルプログラムを起動して動作することを確認し てください。 (テストドライバ機能は、ハードウェアのエミュレートを行うものではありません。各 ドライバソフトウェアのテストドライバ機能については、付属のHelpファイルをご参 照ください。) Interface Corporation - 76 - 4.4 RTLinux対応ソフトウェアのアンインストール ソフトウェアのアンインストール手順は、以下の通りです。 「RTLinux対応ソフトウェアのインストール」でソフトウェアをインストールした ディレクトリに移動します。 # cd /usr/src/interface/gpg2000/i386 インストールを行ったディレクトリの中に、アンインストール用のシェルスクリ プトを用意していますので、実行してください。 # sh UNINSTALL ************************************************************ ** GPG-2000 DIO(PCI/C-PCI)Linux/RT File Name : UNINSTALL Version : 1.0 Copyright 2003 Interface Corporation. All right reserved. ************************************************************ ** GPG-2000 をアンインストールしますか?[y/n]y アンインストールを行うディレクトリを指定してください。 アンインストールするディレクトリ:/usr/src/interface/gpg2000 アンインストールが完了しました。 # 以上で、ソフトのアンインストールは完了です。 指定したディレクトリ内のファイルは全て削除します、開発用のファイル等を保 存されている場合は、アンインストール実行前にバックアップを取るようにして ください。 Interface Corporation - 77 - 第5章 ドライバモジュールの優先度設定 5.1 割り込みハンドラの優先度設定(DPG-0102) 通常、RTLinuxのリアルタイムカーネルで割り込みを使用する場合には、rtl_request_irq 関数を使用して、割り込みハンドラを登録します。 List5-1「rtl_request_irq」による割り込み登録 1 2 3 4 5 6 7 8 1 2 3 4 5 6 #include <rtl_core.h> unsigned int nIRQ = 9; //使用するIRQを9に設定 int rtl_request_irq(nIRG, my_handler ); ・ ・ ・ int rtl_free_irq(nTRQ); //割り込みハンドラの登録 //割り込みハンドラの解除 unsigned int my_handler(unsigned int irq, struct pt_regs *regs) { ・ ・ ・ } List5-1のように、割り込み(IRQ)番号と割り込み発生時に実行したい関数(my_handler) を、rtl_request_irqの引数に指定することでハンドラとして登録します。 割り込みハンドラを解放したい場合には、rtl_free_irq関数にIRQ番号を指定します。 ただし、現時点のRTLinuxの仕様では、IRQ番号に対してハンドラの割り当てを行うと、 別のハンドラを登録できません。(登録しようとしてもエラーを返します。) 一般的なPCを使用している場合、PCI/CompactPCIのバススロットは、複数のスロット でIRQを共有する仕様になっている場合がほとんどですが、RTLinuxでは通常のままだ と割り込みを共有できません。 そこで、弊社のRTLinux対応ドライバソフトウェアでは、独自に割り込みの共有,優 先度切り替えを行うモジュール(dpg0102.o)を用意しており、弊社PCI/CompactPCI ボード間の割り込みの共有をサポートしています。 Interface Corporation - 78 - GPG-2000の割り込みの設定は、下図の様な流れで行います。 割り込み優先度設定 dpg0102 RT-FIFO ユーザモジュール dpg0102p.o API 関数の Call ハンドラの Call dpg0102.o ドライバモジュール rcp2000.o ハンドラの登録 ハードウェア割り込み 図 5-1 割込み設定の流れ RTLinuxに対応したドライバモジュール本体は「rcp2000.o」と言う名称のモジュールにな ります。API関数をRTLinuxモジュールからコールした場合は、このドライバモジュールを 通してデバイスの制御が行われます。 「dpg0102.o」は弊社RTLinux用デバイスドライバで共通の割り込みモジュールとして使用 します。 各ボードごとの割り込みの優先順位を確認、もしくは変更したい場合には、「dpg0102p.o」 が必要となります。このモジュールを組み込んでから、「dpg0102」を実行することで、 割り込みの優先順位を設定することが可能です。 # insmod dpg0102p.o # /usr/bin/dpg0102 IRQ 07 07 10 10 11 DEV 4115 2760 4115 2727 4115 No. 2 2 3 1 1 Pri 1 2 0 1 1 Do you want to change the priority ?[y/n] Interface Corporation - 79 - 「dpg0102」を実行すると上記のような画面になり、現在使用中の弊社PCI/CompactPCIボ ードの一覧が表示されます。表示されるデータの意味は、次のようになります。 項目 IRQ DEV No. Pri. 内容 ボードが使用する割り込みの番号を示します。 上記の例では、IRQ7とIRQ10がそれぞれ2枚のボードから共有されていること がわかります。 ボードのDeviceIDを示します。 弊社PCI/CompactPCIボードでは、型式からアルファベットをのぞいた数字4桁 が、DeviceIDとなります。 例)CTP-4115 → DEV = 4115 PCI-2726C → DEV = 2726 ボードのデバイス番号を示します。 『RTLinux 対応ソフトウェアのインストール』で設定した、各ボードのデバ イス番号が表示されています。上記の例では、4115が3枚使用されていますが、 それぞれ異なるデバイス番号が割り振られていることがわかります。 割り込みのPriority(優先番号)が0∼15の数値で設定されています。 0が最も優先度が高く、15が最も低い値となります。(ここで設定した優先番 号はRTLinuxスレッドの優先度とは関係ありません。IRQが競合している各ボ ードの割り込み処理間での相対的な優先度を示しています。) 以上が、割り込み優先番号情報の見方になります。 優先度の設定を変更したい場合には、上記の表が表示されたあと「y」を入力します。 Do you want to change the priority ?[y/n]y 次に、設定を変更するボードのDeviceID(DEV)を入力します。 Enter the device id : 4115 続けて、デバイス番号(No.)を入力します。 Enter the device number : 2 最後に優先番号(Pri)を0∼15の数値から入力します。 Enter the priority : 3 設定が完了すると、また最初の画面が表示されます。 IRQ DEV No. Pri 07 2760 2 2 07 4115 2 3 10 4115 3 0 10 2727 1 1 11 4115 1 1 Do you want to change the priority ?[y/n] Interface Corporation - 80 - 4115(No.2)の優先番号を、1から3に変更したため、表の順番が2760(No.2)と入れ 変わっているのが分かります。 ここで、設定を終了する場合には、「n」を入力してください。再び設定を変更する場 合には「y」を入力して、先ほどの手順で設定を繰り返します。 この優先番号は「dpg0102.o」を取り外すとクリアされます。再起動時には再び優先番 号の設定を行うようにしてください。 (デバイスドライバの自動組み込みを設定している場合でも、優先番号の設定値は初 期化されます。) また、「dpg0102」を使用しなかった場合には、デフォルト値としてドライバモジュー ルの組み込まれた順番に0から優先番号が割り振られます。 /etc/rc.d/rc.localにドライバの自動組み込みを記述している場合には、各ボード用モジュ ールのinsmodを記述する順番を変更することで、優先番号の設定を行うことも可能で す。 Interface Corporation - 81 - 第6章 RTLinuxでのソフトウェア開発 6.1 RTLinuxプログラムのデバッグ 6.1.1 rtl_printf( ) + 弊社デバイスドライバのデバッグ機能を使用した方法 従来、Linux用のドライバモジュールのデバッグでは、モジュール内でprintk関数を使 用して行っていましたが、RTLinuxプログラムのデバッグではprintk関数の替わりに rtl_printf関数を使用して行います。 rtl_printf関数の使用方法は、ほぼprintf関数と同様です。 注意点としては、カーネル空間では基本的に浮動小数点演算を行うことができないた め、RTLinuxモジュール内で浮動小数点を扱う場合には下記の関数を使用して、明示 的にする必要があります。 int pthread_setfp_np( pthread_t thread, int flag ); また、弊社が提供するLinux/RTLinux用のデバイスドライバにはデバッグを支援する機 能が用意されています。(テストドライバにはこの機能はありません。) insmodでモジュールの組み込みを行う際に、デバッグオプションを指定することで、 API関数実行時のデバッグ情報をmessagesログに出力します。(コンソール上で実行し た場合には、画面上にも表示されます。) 【書式】 # insmod rcp4116 rcp4116_debuglevel = <デバッグレベル> 表 6-1 デバッグ機能の例 デバッグレベル 0 1 2 4 16 32 機能 分類 デバッグ情報を出力しません 関数呼び出しトレース 詳細エラー情報 ボードリソース情報 送信フレーム情報 受信フレーム情報 (デフォルトレベル) 共通デバッグ情報 カテゴリ固有デバッグ情報 ※ オプションを指定しなかった場合には、デフォルトのデバッグレベル0が適用され、デ バッグ情報は出力されません。 ※ 複数のデバッグ情報を表示したい場合には、デバッグレベル値をORした値で指定 してください。 Interface Corporation - 82 - 例)関数呼び出しトレース、ボードリソース情報を出力したい場合は、 # insmod rcp4116 rcp4116_debuglevel = 5 の様にモジュールの組み込みを行います。 デバッグレベル1,2,4,8は、全てのカテゴリで共通のオプションとなります。 具体的に表示する内容は、以下のようになります。 項目 内容 関数呼び出しトレース (デバッグレベル1) API関数の呼び出しを行うと、使用した関数の関数名,入 力パラメータ情報を出力します。 パラメータは、16進数の場合には数値の前に0xが付加さ れ、ポインタ型の場合には[ ]で表示されます。 <例> HdlcOpen( 1, [0xce803b4a]) 関数の戻り値のエラーコードよりも詳細なエラー情報を 出力します。例えば、パラメータエラーの場合には、どの パラメータがエラーになったのかまで出力を行います。 (使用する関数によって、詳細は変更になります。) <例> HdlcOpen : ulLineMode parameter eror 以下のPCIリソース情報を出力します。 デバイスID、サブシステムID、リビジョンID、I/Oアドレ ス、メモリアドレス、IRQ番号などが出力されます。 <例> DeviceID : 4116 , SubSystemID : 0x0101 , RevisionID : 0x0001 I/O Address : 0xd000 , Memory Address : 0x0000 , IRQ : 9 詳細エラー情報 (デバッグレベル2) ボードリソース情報 (デバッグレベル4) デバッグレベル8,16,32,64は、各カテゴリで固有のオプションとなります。 カテゴリごとに異なるデバッグ情報を出力しますので、デバッグ情報の詳細について は、各ソフトウェアに付属するオンラインヘルプをご参照ください。 ここでは、GPG-4116(HDLC)を例に、デバッグ情報の内容を紹介します。 項目 送信フレーム情報 (デバッグレベル16) 受信フレーム情報 (デバッグレベル32) Interface Corporation 内容 送信フレームのフレームサイズ、フレームデータ(先頭4バ イト、16進表示)を出力します。 <例> SendFrame : length=164 data=31 32 33 34 受信フレームのフレームサイズ、フレームデータ(先頭4バ イト、16進表示)を出力します。 <例> ReceiveFrame : length=45 data=54 3A 2D 10 - 83 - ★確認方法 ドライバから出力されたデバッグ情報は/var/log/messages に追加されていきます。 このファイルを参照することで、ドライバのデバッグ情報を取得することができます。 ★注意事項 デバッグ情報の出力を有効にすると、システムの負荷が非常に高くなってしまいます。こ れは、デバッグ情報の出力時にディスクアクセスが発生するために起こる現象です。パフ ォーマンスの低下も起こりますので、デバッグ情報の出力はアプリケーションのバッグの 時のみ有効にし、リリース時では必ず無効にするようにしてください。 6.1.2 デバッガ(gdb + RTDebugger)を使用する方法 次に、デバッガを使用する方法について説明します。 RTLinuxにはRTLinuxモジュールの部分のデバッガが付属しています。 このデバッガは、 gdb やDDDなどのLinux用のデバッガにRTLinuxモジュール部分のトレースを行う機能を拡張 するものです。 これにより、通常のgdbやDDDなどではトレースすることのできない、RTLinuxモジュール の内部のコードについてトレースすることが可能になります。(Linuxカーネル内のトレ ースを行うことはできません。) RTLinux用のデバッガを使用する場合には、RTLinuxのコンパイル(『第2章 RTLinuxのイ ンストール』のRTLinuxのコンパイル)で、「make xconfig」を実行して表示されるRTLinux のオプション設定で、CONFIG_RTL_DEBUGを有効にする必要があります。 「Support option」をクリックして、オプションメニューを開きます 図 6-1 RTLinux Configration メインメニュー画面 make xconfigのメニューダイアログが表示されたら、Support optionsをクリックして、オプ ションメニューを開きます。 Interface Corporation - 84 - 「RTLinux Debugger」をyにします 図 6-2 Support options メニュー画面 オプションメニューのRTLinux Debuggerの項目がyになっていることを確認してくだ さい。デフォルトではyになっています。 図 6-3 RTLinux Debugger のHelp表示 その後は、『RTLinuxのインストール』の手順に従って、RTLinuxのコンパイル/インスト ールを実行すれば、RTLinux用のデバッガが使用可能になります。 Interface Corporation - 85 - (以降の手順は、『RTLinuxのインストール』まで完了しているものとして進めます。) それでは、RTLinuxに付属のサンプルプログラム「hello.c」を使用して、デバッガを動かし ます。 デバッグを開始する前に必要な作業としては、breakpointの設定とコンパイルオプション 「-g」を指定して再コンパイルを行う必要があります。 通常、gdbを使用してデバッグを行う場合には、デバッガ起動中に「run」コマンド等でプ ログラムを開始できるため、元のソースコードには手を加えなくてもデバッグを行えます。 (breakpointはgdb実行中に設定可能です。) ところが、gdb実行中には「.o」モジュールの組み込み(insmod)は、行うことができま せん。 RTLinuxのデバッガは基本的にgdb(DDD)のインタフェースを使用して行うため、モジュ ールを組み込みはデバッガを起動する前に行わなければいけません。 「hello.o」モジュールは、insmodコマンドで組み込みを行うと動作が開始しますので、デ バッグを実行する前に動作を停止させたい部分には、あらかじめbreakpoint( )を挿入してお く必要があります。 それではまず、エディタでhello.cを開き、デバッグに必要なbreakpoint( )とrtl_debug.hを追 加します。 # cd /usr/src/rtlinux/rtlinux-3.1/examples/hello # emacs hello.c List 6-1 「hello.c」のstart_routineの修正箇所 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <rtl.h> #include <time.h> #include <pthread.h> #include <rtl_debug.h> pthread_t thread; void * start_routine(void *arg) { struct sched_param p; p . sched_priority = 1; pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); pthread_make_periodic_np (pthread_self(), gethrtime(), 500000000); breakpoint(); while (1) { pthread_wait_np (); rtl_printf("I'm here; my arg is %x¥n", (unsigned) arg); } return 0; } Interface Corporation - 86 - この、breakpoint( )はi386では単にint3を実行して、例外を発生しているだけですので、0除 算などで例外が発生した場合にも、デバッガにbreakpointとしてアタッチされます。 (「rtlinux-3.1/include/rtl_debug.h」の30行目を参照) 次に、モジュールにデバッグ情報を付加するために、コンパイルオプションに「-g」が必 要になります。 RTLinux用のモジュールをコンパイルする際には、rtl.mkをインクルードしてmakeの設定を 行います。rtl.mkのデフォルト設定にはCFRAGSに「-g」はあらかじめ設定されていますの で、とくに修正の必要はありません。 また、「-fomit-frame-pointer」がフラグに設定されている場合には、それを削除する必要が あります。 # emacs ../../rtl.mk List 6-2 「rtl.mk」 1 2 3 4 5 6 7 8 #Automatically generated by RTLinux Makefile RTL_DIR = /usr/src/rtlinux/rtlinux-3.1 RTLINUX_DIR = /usr/src/linux INCLUDE= -I/usr/src/linux/include -I/usr/src/rtlinux/rtlinux3.1/include -I/usr/src/rtlinux/rtlinux-3.1/include/compat CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -fno-strict-aliasing pipe -march=i686 -DMODULE -DMODVERSIONS -include /usr/src/rtlinux/linux2.4.4/include/linux/modversions.h -g -D__RTL__ -D_LOOSE_KERNEL_NAMES -O2 -I/usr/src/linux/include -I/usr/src/rtlinux/rtlinux-3.1/include -I/usr/src/rtlinux/rtlinux-3.1/include/compat -I/usr/src/rtlinux/rtlinux-3.1/include/posix ARCH = i386 CC = gcc CXXFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe -march=i686 -DMODULE -DMODVERSIONS -include /usr/src/rtlinux/linux2.4.4/include/linux/modversions.h -g -D__RTL__ -D_LOOSE_KERNEL_NAMES -I/usr/src/linux/include -I/usr/src/rtlinux/rtlinux-3.1/include -I/usr/src/rtlinux/rtlinux-3.1/include/compat -I/usr/src/rtlinux/rtlinux-3.1/include/posix -fno-exceptions -fno-rtti 準備が完了しましたら、helloの再コンパイルを行い、「rtl_debug.o」と「hello.o」を順番に 組み込みます。組み込みの順番を間違えると正常に組み込みが行えません。 # make # insmod ../../debugger/rtl_debug.o # insmod hello.o rtl.debug: exception 0x3 in hello (EIP=0xc88de0d0), thread id 0xc44b8000: (re)start GDB to debug Interface Corporation - 87 - ここで、デバッガモジュールのメッセージが表示されて、hello.oの実行が中断されている のがわかります。 次に、gdbを起動して、モジュールのデバッグを開始します。 # gdb hello.o GNU gdb 19990928 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) gdbのプロンプトが表示されますので、ここでgdbのコマンドを実行します。 (gdb)list 1 #include <rtl.h> 2 #include <time.h> 3 #include <pthread.h> 4 #include <rtl_debug.h> 5 pthread_t thread; 6 7 void * start_routine(void *arg) 8 { 9 struct sched_param p; 10 p . sched_priority = 1; まず、「list」を実行して、モジュールのソースコードを表示します。 hello.cのソースコードが表示されます。 モジュールの実行は、RT-FIFOを介して行います。デフォルトではrtf10をデバッグ用の端 末として使用する設定になっていますので、targetコマンドを実行します。 (gdb)target remote /dev/rtf10 start_rutine (arg=0x0) at hello.c:17 17 pthread_wait_np (); (gdb) 「hello.o」のモジュール実行を再開すると、breakpoint( )を設定した次の命令に移ったとこ ろで、実行待ちの状態になります。 ステップ実行でトレースしたい場合には、「step」もしくは「s」コマンドを入力するとス テップ実行を行います。 (gdb)target remote /dev/rtf10 start_rutine (arg=0x0) at hello.c:17 17 pthread_wait_np (); (gdb) Interface Corporation - 88 - さらに、ブレークポイントを追加したい場合には、行数や関数名(スレッド名)を指定し て「breakpoint」(又は「b」)コマンドを実行します。 (gdb)breakpoint 18 Breakpoint 1 at 0xc88de0d5: file hello.c, line 18 (gdb) モジュールをブレークポイントまで実行する場合には、「continue」(又は「c」)コ マンドを実行します。 以下に、gdbの基本的なコマンドについて紹介します。 また、gdbで使用可能なコマンドについては、(gdb)プロンプト上で「help」を実行 することで表示されます。詳細な使用方法についてはそちらをご参照ください。 コマンド breakpoint [line] step [num] continue list [line] run [arg...] backtrace print [symbol] clear [line] 内容 ブレークポイントを[line]行目に設定します。 [line]の代わりに関数名(スレッド名)も使用できます。 break , b [num]行分ステップ実行を行います。 [num]は省略可能です。(省略した場合は1行分) モジュール(プロセス)の実行を再開します ソースコードのリストを表示します。 行数,関数名等を引数にとります。 引数を省略した場合には、前回表示したlistの続きが表示されます。 gdb起動時の引数で指定したプログラムもしくは、 「file」, 「exec-file」 コマンドで設定したプログラムを実行します。※1 引数には実行ファイルに渡す引数を指定できます。 コードのバックトレースを行います。 [symbol]の内容を表示します。 s 指定した行のブレークポイントを解除します。 引数には、関数名等を指定することも可能です。 引数を省略した場合、全てのブレークポイントを解除します。※2 target ターゲットプロセスやマシンを設定します。 [protcol] RTLinuxのモジュールをデバッグする場合は、remoteマシンと /dev/rtf10を介して通信を行う設定でデバッグ実行を行います。 kill gdbの下で動作しているプログラムのプロセスを終了させます。※3 pwd 現在のWorking directoryを表示します。 cd [directory] Working directoryを変更します。 quit gdbを終了します。 ※1 短縮形 c l r bac p cl ta pw q RTLinuxモジュールの実行をrunコマンドで行った場合、モジュールの実行がgdbの制御 下からはずれてしまい、breakpoint等が使用できなくなります。 ※2 RTLinux用にソース中に埋め込んだbreakpoint( )は解除されません。 ※3 RTLinuxのデバッグ中にこのコマンドを実行すると、モジュールがgdbの制御下からは ずれてしまいます。 Interface Corporation - 89 - ★デバッグ使用時の機能 (gdb)の端末下でコマンド入力を行う際に、以下のような機能を使用できます。 ・ コマンドを省略して実行可能。 コマンドが特定可能な字数に達していれば、2,3 文字だけ入力して残りの文字を省略し て実行できます。また、使用頻度の高いコマンド(step,breakpoint 等)に関しては、 「s」や「b」のように一文字で使用することも可能です。 ・ TAB キーの使用 通常のコンソール端末と同じ感覚で、TAB キーを使用したコマンドの補完が可能です。 ・ Enter キーの使用 Enterーキーのみを入力すると、前回実行したコマンドを続けて実行します。たとえば STEP 実行を行う場合に、最初の1回のみ「step」(「s」)コマンドを実行すれば、後 は Enter キーを入力するだけでステップ実行を繰り返し行います。 6.2 リアルタイム性の評価 通常のLinux用ドライバとRTLinux用ドライバを使用した場合の性能の違いについては、各 カテゴリのチュートリアルで詳しく解説を行っています。 性能評価の方法もカテゴリに応じた方法が必要となりますので、そちらをご参照下さい。 (各カテゴリのチュートリアルも、弊社Web siteからダウンロード可能となっておりま す。) ここでは単純に、RTLinuxスレッドを周期実行した場合に、どの程度の精度でRTLinuxスレ ッドが呼ばれているのかを測定します。 Interface Corporation - 90 - RTLinuxスレッドの周期実行は、『6.1.2 デバッガ(gdb + RTDebugger)を使用する方法』 で解説したサンプルプログラムのhelloを使用して確認します。 List 6-3 「hello.c」のソースコード修正 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <rtl.h> #include <time.h> #include <pthread.h> #include <rtl_time.h> pthread_t thread; hrtime_t tasktime[201]; void * start_routine(void *arg) { int I; struct sched_param p; p . sched_priority = 1; pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); pthread_make_periodic_np (pthread_self(), gethrtime(), 100000); for(I = 0; I < 201; i++) { pthread_wait_np (); tasktime = gethrtime(void); } for(I = 1; I < 201; i++) { rtl_printf(“cycle time is : %ld¥n”, tasktime[i] – tasktime[i-1]); } return 0; } int init_module(void) { return pthread_create (&thread, NULL, start_routine, 0); } void cleanup_module(void) { pthread_delete_np (thread); } List 6-3のソースコードの網掛けがしてある部分が、元のサンプルプログラム「hello.c」か ら修正を行った部分です。 周期実行の間隔を100(μs)で実行するように、変更を行います。 元々、周期実行を行うRTLinuxスレッドの中で「I'm here; my arg is %x」と表示を行って いた部分では、替わりにgethrtime( )関数を使用してCPUタイマのカウント値を取得します。 この関数では、起動時からの経過時間を(ns)単位で取得します。 201回ほど取得したあと、カウント値の差分を取り、rtl_printf( )で出力しています。 gethrtime関数を使用するためには、<rtl_time.h>をインクルードする必要があります。(4 行目) Interface Corporation - 91 - 修正が完了したら、makeを行ってRTLinuxモジュールを組み込みます。 # cd /usr/src/rtlinux/rtlinux-3.1/examples/hello # make ・ ・ ・ # insmod hello.o モジュールを組み込んで、しばらくしてからモジュールを取り外します。 (コンソール上で組み込みを行った場合には、画面上にrtl_printf( )の実行結果が表示され ます。) # rmmod hello システムのログに実行結果が残っていますので、表示します。 # tail –20 /var/log/messages Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : Feb 22 20:34:15 linux kernel: cycle time is : 99840(ns) 99296(ns) 99552(ns) 100864(ns) 103616(ns) 94752(ns) 101184(ns) 100512(ns) 100896(ns) 98464(ns) 100576(ns) 100256(ns) 99520(ns) 101248(ns) 99776(ns) 98176(ns) 102496(ns) 98272(ns) 101152(ns) 98336(ns) 上記の様な結果が表示されるはずです。 今回試した環境では、200回の平均値で99964 (ns)、標準偏差値は719.5940577(ns)と言う 結果となりました。 この数値は、周期スレッド内での処理をほとんど行っていませんので、純粋にリアルタイ ムカーネルの処理精度が現れているといえます。 Interface Corporation - 92 - 6.3 I/O公開資料(PDF)の利用 弊社では、ボード制御用のI/Oポート資料を公開しています。 PCI製品のI/O公開資料は、弊社Web siteのダウンロードページから無償でダウンロード可 能となっています。 下記のURLを開き、I/O公開資料の欄にチェックを入れて製品型式を入力してSerchを行っ てください。 ダウンロードページ http://www.interface.co.jp/download/search.asp また、CompactPCIボードについては、製品マニュアルにI/Oポート一覧を記載しています。 詳細な制御方法を記載したI/O公開資料については、別途資料請求を行っていただく必要が ございます。 I/O公開資料はPDF形式で提供致しております。 ご使用になるOS用の「Adobe Reader」を、下記のURLからダウンロードしてご利用くださ い。 Adobe Reader ダウンロードページ http://www.adobe.co.jp/support/downloads/main.html Interface Corporation - 93 - 第7章 組み込みLinux概要 7.1 組込みLinux概要 現在、組み込み環境にLinux系のOSを使用する動きが盛んになっています。 それでは、組み込み環境とは、一体どういった物でしょうか? 一般に、WindowsやLinux等のOSを使用する環境としては、パソコンと呼ばれるPC(主に PC/AT互換機)が有名ですが、それ以外にも、専用のシステムを動かすための組み込み機 器にもOSが使用されている場合があります。 具体的には、産業用のロボットを制御するコントローラや、ルータを制御する為に組み込 まれたOS等もこれに当たります。 組み込み機器の特長としては、使用する目的がはっきり決まっている場合が多いため、そ のシステムの概要にあわせて、ハードウェアの構成が大きく変わってきます。 前述した汎用機のPCを小型化した物を使用する場合もあれば、標準の入出力を持たない装 置に、OSを書き込んだROMが搭載されているような物もあります。 このような組み込み用のOSとしては、VxWorks,ITRON,Windows Embedded等の商用の リアルタイムOSや、自作の専用OS等が使用されてきました。 近年、Linuxがこの様な組み込み分野で使用される機会が増えている理由としては、様々 なアーキテクチャ(x86,Alpha,PowerPC,SPARC等)に対応していることや、強力なネ ットワーク機能を搭載していること等が考えられます。 組み込み用のOSとして必要な機能(要件)としては、次のような事柄があります。 ・ OSを使用するのに必要とするリソース(容量)が少ないこと ・ 必要な機能を選択して、カスタマイズが可能であること。 ・ リアルタイム性を持っていること。 従来の組み込み分野ではハードウェアの機能が非常に制限されており、少ないリソースで 動作する小型の専用OSが使用されることがほとんどでした。 Interface Corporation - 94 - しかし、ハードウェアの機能が強化されるに従って使用可能なリソースが増大し、組み込 み用のOSでも多くの機能が必要とされるようになってきました。 特にネットワーク機能については、家電製品にまで搭載されるようになっており、Linux を組み込みで使用するメリットが増大していると言えます。 また、ソースコードが公開されているため、使用するハードウェア環境にあわせてカスタ マイズが可能な点もメリットとなります。 反面、商用のリアルタイムOSではサポート体制が確立しており、強力な開発環境もセット で用意されていることが多いのですが、フリーのLinux(RTLinux)を使用する場合には環 境に合わせたツールを自分で用意する必要があり、Linuxに関するスキルもある程度必要 になることが問題点といえます。 Interface Corporation - 95 - 第8章 補足資料 8.1 インストールに関する参考情報 ここでは、インストールに関連する参考情報を示します。 RTLinux 3.2 pre1の導入について 2003年1月時点で、RTLinux 3.2 pre1がFSMLabsから公開されています。 (2003年12月現在は、RTLinux 3.2 pre2が公開されています) プレリリース版ですが、先行して導入を試されたいお客様のため、現在 弊社で確認して いる内容について説明します。 導入に必要なファイルは、次の通りです。 ファイル名 rtlinux-3.2-pre1.tar.bz2 Linuxカーネルへのパッチを行うファイルは、patchesディレクトリにあります。 ファイル名 kernel_patch-2.2.19 kernel_patch-2.4.4 kernel_patch-2.4.17-rtl3.2-pre1.bz2 kernel_patch-2.4.18-rtl3.2-pre1.bz2 kernel_patch-2.4.19-rtl3.2-pre1.bz2 項目 カーネル2.2.19に対応したパッチファイル カーネル2.4.4に対応したパッチファイル カーネル2.4.17に対応したパッチファイル (bzip2圧縮されています) カーネル2.4.18に対応したパッチファイル (bzip2圧縮されています) カーネル2.4.19に対応したパッチファイル (bzip2圧縮されています) カーネル2.4.17∼2.4.19用のパッチファイルはbzip2圧縮されており、bunzip2コマンド等を 使用して ファイルを展開する必要があります。 kernel_patch-2.4.19-rtl3.2-pre1.bz2ファイルを展開する例> # bunzip2 kernel_patch-2.4.19-rtl3.2-pre1.bz2 カーネル2.2.19とカーネル2.4.4用のパッチファイルは展開済みであり、そのまま使用でき ます。 インストール作業自体は第2章のRTLinux 3.1のインストール方法と変わりません。 Interface Corporation - 96 - ★カーネル 2.4.17 のパッチについて 弊社では、カーネル 2.4.17 のパッチを導入する際、カーネルの Makefile を以下のように修 正して確認しました。 VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 17 EXTRAVERSION = ↓ VERSION = 2 EXTRAVERSION を指定する PATCHLEVEL = 4 SUBLEVEL = 17 EXTRAVERSION = -rtl3.2-pre1 確認した組み合わせ: コンピュータ:エプソンダイレクト MT-3500 ディストリビューション:VineLinux 2.5 確認したボードとドライバ:PCI-3521、GPG-3100 なお、他にも、カーネル 2.4.17 のみパッチ当て時にエラーが発生するのを確認しています。 RTLinux 3.2 pre2の導入について 2003年12月現在、RTLinux 3.2 pre2がFSMLabsから公開されています。 ここでは、上記RTLinux 3.2 pre1との違いを中心に、現在 弊社で確認している内容につい て説明します。 導入に必要なファイルは、次の通りです。 ファイル名 rtlinux-3.2-pre2.tar.bz2 Linuxカーネルへのパッチを行うファイルは、patchesディレクトリにあります。 ファイル名 kernel_patch-2.4.19-rtl3.2-pre2 kernel_patch-2.4.20-rtl3.2-pre2 kernel_patch-2.4.21-pre5-rtl3.2-pre2 項目 カーネル2.4.19に対応したパッチファイル (bzip2圧縮されています) カーネル2.4.20に対応したパッチファイル (bzip2圧縮されています) カーネル2.4.21-pre5に対応したパッチファ イル (bzip2圧縮されています) pre2では、カーネル2.4.4および2.2.19のパッチは同梱されていません。 インストール作業自体は、第2章のRTLinux 3.1のインストール方法と変わりません。 Interface Corporation - 97 - Red Hat Linux 7.3/8.0にRTLinuxを導入する際の注意点 Red Hat Linux 7.3/8.0にRTLinuxをインストールする際の注意点を説明します。 FSMLabsで公開されている文書には、Red Hat Linux7.x環境下にRTLinux 3.1を導入する際の How-toが掲載されています。 それには、カーネルをコンパイルする際、使用するコンパイラをgccからkgccに変更するよ う促しています。 弊社では、以下のRPMファイルにてkgccをインストールし、RTLinux 3.1の起動を確認しま した。 ファイル名 kgcc-1.1.2-40.i386.rpm 本ファイルは、Red Hat 7.0のCDかインターネット上から入手できます。 ★Red Hat Linux と RTLinux 3.2 pre1 組み合わせについて Red Hat Linux と RTLinux 3.2 pre1 の組み合わせでは、特定のカーネルバージョン(2.4.17 以 降)の組み合わせにおいて、RTLinux リアルタイムカーネルの導入時にハングアップ、また はパッチ当て時にエラー等の現象が出る場合があることを確認しています。 Interface Corporation - 98 - 8.2 その他のTips ここでは、幾つかTipsを紹介します。 insmod等のコマンドが呼び出せない 特定のディストリビューションによっては、insmod等のコマンドを呼び出そうとする と、「command not found」が返ってくる場合があります。 これは、コマンドが格納されているディレクトリに対して検索パスが設定されていな いため、起こることが多いです。 こういった時は、exportコマンド等で検索パスを追加するか、シェルの設定ファイル に検索パスを追加します。 現在の検索パスに、/sbinを追加する例> # export PATH=$PATH:/sbin RTLinuxリアルタイムカーネルを組み込もうとするとエラー RTLinuxリアルタイムカーネルを組み込もうとすると、以下のメッセージに出会うことが あります。 例> # sh scripts/insrtl modules/rtl.o: create_module: Operation not permitted modules/rtl_time.o: unresolved symbol rtl_printf modules/rtl_time.o: unresolved symbol rtl_request_local_irq … これは、このコマンドを実行する権限を持っていないために、起こる場合が多いです。 こういった時は、suコマンドでrootにログインするか、最初からrootでログインします。 Interface Corporation - 99 - ドライバをinsmodしようとするとunresolved symbol ドライバをinsmodしようとすると、次のエラーが発生する場合があります。 ドライバをinsmodする例> # insmod dpg0100.o dpg0100.o: unresolved symbol vsprintf_Rsmp_13d9cea7 dpg0100.o: Hint: You are trying to load a module without a GPL compatible license and it has unresolved symbols. Contact the module supplier for assistance, only they can help you. これは、モジュールをinsmodする際に解決しなければならない関数が見つからなかったこ とを示します。 この場合は、ドライバを再コンパイルし、ファイルをinsmodで組み込みます。 あるいは、Linuxカーネルを構築する際、 「Loadable module support」→「Set version information on all module symbols」を「n」に設定することで、回避できる場合もあります。 Interface Corporation - 100 - 技術資料紹介 弊社では下記の技術資料を提供しております。 詳しくは、弊社Web site(www.interface.co.jp)、または弊社窓口までお問い合わせ下さい。 カタログ PRM-0061 PRM-0062 PRM-0063 CPZカタログ(日本語版) PCIカタログ(日本語版) CSIカタログ(日本語版) チュートリアル TUT-0056 TUT-0055 TUT-0054 TUT-0053 TUT-0050 TUT-0048 TUT-0044 TUT-0043 TUT-0041 TUT-0040 TUT-0039 TUT-0038 TUT-0037 TUT-0036 TUT-0034 TUT-0033 TUT-0032 TUT-0031 TUT-0030 TUT-0029 TUT-0028 TUT-0027 TUT-0026 TUT-0025 TUT-0024 TUT-0023 TUT-0022 TUT-0021 TUT-0020 TUT-0019 TUT-0018 TUT-0017 TUT-0016 TUT-0015 TUT-0014 TUT-0008 TUT-0007 TUT-0006 TUT-0005 TUT-0004 TUT-0003 TUT-0002 TUT-0001 チュートリアル XP Embedded OS構築編 チュートリアル 画像入力ボード CANチュートリアル モーションコントロールチュートリアル RTLinuxによるモーションコントローラボード制御プログラミング チュートリアル(GPG-7400用) RTLinuxによるカウンタボード制御プログラミング チュートリアル RTLinuxによるメモリ共有インタフェースボード制御プログラミング チュートリアル RTLinuxによる調歩同期シリアル通信ボード制御プログラミング チュートリアル RTLinuxによるGP-IBボード制御プログラミング チュートリアル RTLinuxによるDAボード制御プログラミング チュートリアル RTLinuxによるADボード制御プログラミング チュートリアル RTLinuxによるDIOボード制御プログラミング チュ-トリアル RTLinuxによるHDLCボード制御プログラミング チュートリアル RTLinuxによるPCI/CompactPCI/CardBus制御入門書(導入編) Visual C++によるPPI入門書 Visual Basicによるメモリ共有インタフェース入門書 Visual C++によるメモリ共有インタフェース入門書 Visual Basicによるカウンタ入門書 Visual C++によるカウンタ入門書 Visual BasicによるHDLC入門書 Visual C++によるHDLC入門書 Visual BasicによるGP-IB入門書 Visual C++によるGP-IB入門書 Visual BasicによるDIO入門書 Visual C++によるDIO入門書 Visual BasicによるDA入門書 Visual C++によるDA入門書 Visual BasicによるAD入門書 Visual C++によるAD入門書 Visual Basicによるモーションコントローラ入門書 Visual C++によるモーションコントローラ入門書 メモリンクを使用した負荷分散システム事例チュートリアル Visual BasicによるPPI入門書 モーションコントロールチュートリアル Microsoft Visual Studio .NET移行ガイド 拡張ユニット チュートリアル(問題解決編) 拡張ユニットチュートリアル(入門編) C(98)/ISA製品からPCI/CompactPCI製品への移行チュートリアル(DOS編) DOSによるLAP-B入門書 DOSによるAD入門書 LinuxによるPCI/CompactPCI/CardBus制御 入門書 PCI-ISAバスブリッジチュートリアル PCI-Cバスブリッジチュートリアル 技術情報資料 初めてのCANインタフェース Linux, リアルタイムLinux移植(SH-4)経験談及び当社の今後の取り組みについて LinuxからPCI/CompactPCIボードを制御する方法 ActiveXコントロールによるシステム組み込み技術 CompactPCIへの置き換え+システム構築/移行ガイド MS-DOSからPCI/CompactPCIボードを制御する方法 Interface Corporation - 101 - 参考文献 ・ALESSANDRO RUBINI 著、山崎 康宏、山崎 邦子 訳、「LINUXデバイスドラ イバ」オライリー・ジャパン、1998年、ISBN4-900900-73-7 ・舟木 陸議、羅 正華 著、「Linuxリアルタイム計測/制御 開発ガイドブック」株 式会社秀和システム、1999年、ISBN4-87966-849-4 ・森 友一朗、薬師 輝久、馬場 秀忠 著、「RTLinuxリアルタイム処理プログラミ ングハンドブック」株式会社秀和システム、2000年、ISBN4-7980-0056-6 ・藤広 哲也 著、「組み込み型Linux導入・開発ガイド」株式会社すばる舎、2002 年、ISBN4-88399-181-4 ・「Interface 1999年11月号」CQ出版株式会社、1999年、ISSN0387-9569 ・「Interface 2001年6月号」CQ出版株式会社、2001年、ISSN0387-9569 ・「Interface 2002年3月号」CQ出版株式会社、2002年、ISSN0387-9569 Interface Corporation - 102 - RTLinuxによるPCI/CompactPCI/CardBus制御入門書(導入編) 2005年 10月 Ver. 1.6 発行 発行所 〒732-0828 広島県広島市南区京橋町10-21 TEL 082-262-7777 FAX 082-262-5066 ISD-7059-16 価格 ¥2,100 (定価 ¥2,000 + 消費税 ¥100) 本書の内容の一部または全部を、無断で転載することを禁止します。 本書の内容は、将来予告なく変更することがありますので、あらかじめご了承くださ い。© 2002, 2005 Interface Corporation. All rights reserved. チュートリアル チュートリアル RTLinuxによるPCIボード・CompactPCIボード制御(導入編) RTLinuxによるPCI/CompactPCI/CardBus制御入門書(導入編) TUT-0036 Ver. 1.3 TUT-0036 Ver. 1.6 www.interface.co.jp