チュートリアル - インタフェース

チュートリアル
RTLinuxによる調歩同期シリアル通信ボード
制御プログラミング チュートリアル
www.interface.co.jp
商標/登録商標
本ドキュメントに掲載されている会社名,製品名は、それぞれ各社の商標または登録商標です。
保障の内容と制限
弊社はドキュメント内の情報の正確さに万全を期しています。万一、誤記または誤植等があった
場合、弊社は予告なく改訂する場合があります。ドキュメントまたはドキュメント内の情報に起
因するいかなる損害に対しても弊社は責任を負いません。
製品に含まれるバグ、あるいは製品の供給(納期遅延),性能、もしくは使用に起因する付帯的損害
もしくは間接的損害に対して、弊社に全面的に責がある場合でも、弊社はその製品に対する改良
(正常に動作する)、代品交換までとし、金銭面での賠償の責任は一切負わないものとしますので、
予めご了承ください。
ドキュメント内の図や表は説明のためであり、ユーザ個別の応用事例により変化する場合があり
ます。
著作権,知的所有権
弊社は本製品に含まれるおよび本製品に対する権利や知的所有権を保持しています。
本製品はコンピュータ ソフトウェア(プログラム),図,文章,写真等を含んでいます。
複製の禁止
弊社の許可なく、本製品(ドキュメント含む)の全て、または一部に関わらず、複製,改変等を行う
ことはできません。
責任の制限
弊社は、弊社または再販売者の予見の有無に関わらず、発生したいかなる特別損害,偶発的損害,
間接的な損害,重大な損害について、責任を負いません。
補償の内容
本ドキュメントで使用している弊社製品の補償については、各製品のマニュアルを参照してくだ
さい。
本書の内容の一部または全部を、無断で転載することを禁止します。
本書の内容は、将来予告なく変更することがありますので、予めご了承ください。
© 2002, 2007 Interface Corporation. All rights reserved.
www.interface.co.jp
TUT-0043
改訂履歴
年 月
Ver.
1.5
2007年1月
1.4
2005年 10月
1.3
2004年 9月
1.2
1.1
2003年 9月
2002年 9月
1.0
2002年 6月
改 訂 内 容
●対応型式追加。
●マルチメータ型式変更。
HP34401A→Agilent34401A
●技術資料一覧更新。
●対応型式追加。
●誤記修正。
●技術資料一覧更新。
●対応型式追加。
●技術資料一覧更新。
●誤記修正。
●対応型式追加。
●誤記修正。
新規作成
本チュートリアルをご使用の際は、必ず各製品型式の最新のドキュメント(ユーザーズマニュア
ル,Help)をあわせて参照してください。また、最新のドライバソフトウェアをご使用ください。
ユーザーズマニュアル,ドライバソフトウェアは弊社Web site(www.interface.co.jp)からダウンロー
ドできます。(Helpはドライバソフトウェアに含まれています)
-1-
Interface Corporation
TUT-0043
目 次
第1章
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
第2章
調歩同期通信の概要
7
シリアル通信................................................................................................................................. 7
RS-232CとRS-485.......................................................................................................................... 8
同期方式 ......................................................................................................................................... 9
調歩同期通信................................................................................................................................. 9
データ長 ....................................................................................................................................... 10
パリティビット........................................................................................................................... 10
通信速度(bps)とスループット .................................................................................................. 10
その他の用語解説....................................................................................................................... 11
調歩同期通信を行うにあたってのアドバイス ...................................................................... 11
調歩同期通信 on RTLinux
13
2.1
パフォーマンス........................................................................................................................... 13
2.1.1 応答性 ................................................................................................................................ 13
2.1.2 周期性 ................................................................................................................................ 15
2.2 RTLinuxによる調歩同期通信I/Oモジュール制御 .................................................................. 16
2.3 シリアルポート制御概略........................................................................................................... 17
第3章
3.1
3.2
3.3
第4章
シリアルポート制御の第一歩
18
RTLinux調歩同期通信ドライバの組み込み............................................................................ 19
シリアルポートの情報を列挙する .......................................................................................... 21
シリアルポートの情報を列挙するプログラムの解説 .......................................................... 24
より高度な処理を行おう
26
4.1
4.2
周期的なデータの送受信........................................................................................................... 26
周期的なデータの送受信の解説............................................................................................... 34
4.2.1 調歩同期通信ドライバモジュールの役割.................................................................... 36
4.2.2 共通定義ファイルの役割................................................................................................ 37
4.2.3 RTLinuxモジュールの動き ............................................................................................. 38
4.2.4 Linuxプロセスの動き ...................................................................................................... 42
4.3 マルチメータからのデータの取り込み .................................................................................. 43
4.4 マルチメータからのデータの取り込み解説 .......................................................................... 51
4.4.1 sample2/module2 との違い .............................................................................................. 53
4.4.2 RTLinuxモジュールの動き ............................................................................................. 53
第5章
5.1
デバッグ手法
57
ドライバデバッグ支援機能を使ってみる .............................................................................. 57
5.1.1 関数呼び出しトレース .................................................................................................... 58
5.1.2 エラー情報 ........................................................................................................................ 59
5.1.3 I/Oモジュールリソース情報 .......................................................................................... 60
5.1.4 制御信号情報 .................................................................................................................... 61
Interface Corporation
-2-
TUT-0043
第6章
6.1
6.2
リファレンス
62
関数一覧 ....................................................................................................................................... 62
戻り値一覧 ................................................................................................................................... 62
技術資料紹介
63
-3-
Interface Corporation
TUT-0043
はじめに
平素は格別のご高配を賜り、厚くお礼申し上げます。本冊子はRTLinux/Free上で弊社
PCI,CompactPCI 調歩同期 I/Oモジュールを制御したい方を対象に、調歩同期 I/Oモジュールの概
要,ソフトウェアのインストール方法,プログラミング方法を記載しています。
RTLinux上での弊社調歩同期 I/Oモジュールを使ったプログラミングにお役に立てれば幸いです。
本書では、以下記載がない限り、「RTLinux」は「RTLinux/Free」のことを指します。
なお本冊子はRTLinuxバージョン3.1を対象に作成されています。RTLinuxのバージョンが異なる場
合、動作保証はいたしかねますので予めご了承ください。
●ご意見・ご要望
弊社へのご意見,ご要望がございましたら、下記までお問い合わせください。
www.interface.co.jp
E-mail:[email protected]
●本冊子で扱うソフトウェア
本冊子で扱うソフトウェア製品は下記の通りです。
ソフトウェア製品名
調歩同期シリアル通信ボード Linux/RT対応ドライバソフトウェア
型 式
GPG-4141
●ソフトウェアの入手方法について
ソフトウェアは弊社Web siteよりダウンロード(無料)できます。
CD-ROM等、媒体による提供は有償となります。価格に送料,消費税は含まれません。
※ ダウンロードするためには、ユーザID登録が必要になります。
Interface Corporation
-4-
TUT-0043
●調歩同期 I/OモジュールのLinux/RTLinux対応ドライバソフトウェア(GPG-4141)のドキュメント
構成について
各ドキュメントに掲載している内容は下記のとおりです。
ドキュメント
内 容
Readme
製品のインストール方法や、アンインストール方法,ファイル構成の他、製品
に関する最新情報を掲載しています。
このドキュメントを最初に確認してください。
Help
ドライバソフトウェアの仕様,関数の個別説明、および使用方法等の説明を掲載し
ています。プログラム作成時に確認してください。
チュートリアル
本ドキュメントです。初めてRTLinux上で調歩同期 I/Oモジュールを制御する
時や、調歩同期 I/Oモジュールを使用したシステム構築時の参考として確認
してください。
本ドキュメントの他、RTLinuxの導入編のチュートリアルを合わせて参照して
ください。
RTLinuxのインストールや、基本的なプログラミング等が記載されています。
また、
本ドキュメントは、
予めRTLinuxのインストール、
および使用されるソフトウェア(GPG-4141)
のインストールを済ませた方を対象に記述しています。
●本書での表記について
コマンドの実行例において、行頭に「%」がつく場合は一般ユーザでの実行、「#」がつく場合
はrootでの実行を意味します。「%」や「#」は実際に入力する文字ではありませんのでご注意
ください。
-5-
Interface Corporation
TUT-0043
対象環境
本チュートリアルは以下の制約事項があります。
PCI-4141PE
PCI-4141P
PCI-4141
対象型式
PCI-4142PE
PCI-4142P
PCI-4142
(PCI)
PCI-4146
PCI-4145
PCI-4144
PCI-4149C
PCI-4148C
PCI-4147
PCI-4161
PCI-4155
PCI-4150
PCI-466102P
PCI-466102
PCI-4646
PCI-466104P
PCI-466104A
PCI-466104
PCI-466120
PCI-466108
PCI-466104PA
PCI-466140A
PCI-466140
PCI-466120P
PCI-466180
PCI-466140PA
PCI-466140P
CPZ-4142
CPZ-4141P
CPZ-4141
対象型式
CPZ-4145
CPZ-4144
CPZ-4142P
(CPZ)
CPZ-4148
CPZ-4147
CPZ-4146
CPZ-466102P
CPZ-466102
CPZ-4149
CPZ-466104P
CPZ-466104A
CPZ-466104
CPZ-466120
CPZ-466108
CPZ-466104PA
CPZ-466140A
CPZ-466140
CPZ-466120P
CPZ-466180
CPZ-466140PA
CPZ-466140P
CTP-4142
CTP-4141P
CTP-4141
対象型式
CTP-4145
CTP-4144
CTP-4142P
(CTP)
CTP-4148
CTP-4147
CTP-4146
CTP-466120
CTP-466102
CTP-4149
CSI-466120
CSI-466202
CSI-466302
対象型式
CSI-466402
(CSI)
PEX-466102
PEX-466104
PEX-466120
対象型式
PEX-466140
(PEX)
LPC-466102
LPC-466104
LPC-466120
対象型式
LPC-466140
(LPC)
対象ユーザ 制御用電子機器および、コンピュータ等に関して基本的な知識を有している方。
※ 本冊子は上記の弊社製品型式のみに対応しています。
製品の詳細は弊社Web siteを参照してください。
Interface Corporation
-6-
TUT-0043
第1章 調歩同期通信の概要
本章では、コンピュータや計測器等の装置との間で、データをやり取りする方法の1つである調歩
同期通信について概要を説明します。
この調歩同期通信とは、「シリアル通信」と呼ばれる通信方式で、データをやり取りするために
用いる同期方式の一種です。
コンピュータで、アナログモデムやISDNのTA(ターミナルアダプタ)を使って通信を行う場合、
「シリアルポート」と呼ばれるインタフェースの口に、「シリアルケーブル」と呼ばれるケーブ
ルを挿して、機器と繋ぐと思います。
こうして通信を行う時、コンピュータと通信機器の間では、データのやり取りが行われています。
このやり取りは、実は「調歩同期通信」と呼ばれる方式でデータのやり取りが行われています。
弊社では、この調歩同期通信が行えるインタフェース製品を提供しております。
このインタフェース製品を使用することで、お客様は、複数の機器とデータのやり取りが行える
ようになります。
1.1 シリアル通信
シリアル通信とは、1本の線を使ってデータをやり取りする通信方式です。対語として、パラレル
通信があり、これは複数の線を使ってデータをやり取りする通信方式です。
コンピュータに接続する機器は、シリアル通信かパラレル通信と呼ばれる通信方式で、データを
やり取りします。
シリアル通信は、1 本の線でデータを
送る方式。
パラレル通信は、複数の線でデータを
送る方式。
シリアル通信とパラレル通信の違い
-7-
Interface Corporation
TUT-0043
一般に、シリアル通信方式を採用した通信インタフェースは、他の通信インタフェースに比べ、
ケーブル敷設等のコストが安価であることが多いです。逆に、パラレル通信方式を採用した通信
インタフェースは、高価であることが多いですが、一度に複数のデータを送ることが可能なため、
大量のデータを高速に送るのに向いていると言われています。
しかし最近では、高速なシリアル通信方式が開発され、このようなことは 一概には言えなくなっ
てきました。
シリアル通信方式の代表的なものとしては、RS-232C,RS-485,USB,Ethernet等が挙げられます。こ
の内、調歩同期通信をサポートする通信方式は、RS-232CとRS-485です。
1.2 RS-232CとRS-485
RS-232Cとは通信インタフェースの規格の一つです。電気的仕様,信号線の種類,機能,特性等が規定
されています。
この規格は、米国電子工業会(EIA = Electronic Industries Association)が定めました。
なお、RS-232Cという呼び方は正式なものではなく、ANSI/TIA/EIA-232-Fと言います。日本規格で
は、JIS X5101(旧名:JIS C6361)が、これにあたります。
しかし、今でもRS-232Cと呼ばれることが多いです。
コンピュータで、シリアルポートと一般に呼ばれているものは、このRS-232Cを通信インタ
フェースに採用したシリアル通信を指しています。
RS-485も同じくEIAが規定した規格です。RS-422(ANSI/EIA/TIA-422-B)という規格があり、その上
位に相当する規格です。
RS-232Cに比べ、以下の特長を有しています。
・長距離の通信が可能
RS-232Cは最大15mまで、RS-485では最大1.2kmまで通信可能です。
・1対n接続が可能
RS-232Cは1対1の通信しかできませんが、RS-485は1対31までの多点間(マルチドロップ)の通信
が行えます。下図に示すように、1本のシリアル・バスに複数のドライバ/レシーバを接続して、
任意のドライバ,レシーバ間でデータの送信を行います。
1 本のバスを複数のドライバ/レシーバで
共用する
シリアル・バス
終端抵抗R
終端抵抗R
任意 のド ラ イ
バか ら任 意 の
レシーバにデ
ータ を送 る こ
とができる
レシーバ
ドライバ
ドライバレシーバ間でのデータ転送
この接続では複数のドライバが動作するとバス上でデータが衝突しますので、送信を行うときの
みドライバをデータラインに接続し、送信を行わないときはデータラインから切り離す必要があ
ります。
Interface Corporation
-8-
TUT-0043
1.3 同期方式
ある機器から別の機器にデータを送る時、2つの機器はタイミングを合わせて、データの受け渡し
を行う必要があります。
タイミングを合わせないと、受け手はどの時点が受け取るべきデータなのか判断することができ
ません。このタイミングを合わせることを「同期を取る」と言います。
同期の方法は千差万別です。RS-232CやRS-485の通信インタフェースで使用される同期方法は、
大きく分けて、調歩同期,キャラクタ同期,フラグ同期が挙げられます。
調歩同期は、1キャラクタのデータを送るごとに、データの先頭にスタートビット、末尾にストッ
プビットと呼ばれる制御ビットを挿入して同期を取る方式です。
受け手側では、この特定のビットを検出することで、1キャラクタの受信データの始まりと終わり
を認識します。
キャラクタ同期は、ブロックと呼ばれる複数キャラクタの集まりの先頭に、特定のコードを付加
して同期を取る方式です。
フラグ同期は、フラグと呼ばれる特定のビット列で、フレームと呼ばれるデータ列を挟んで同期
を取る方式です。
本書では、この内、調歩同期を使用する通信制御について解説します。
1.4 調歩同期通信
調歩同期は、通信の効率という面から見ると、キャラクタごとにスタートビット,ストップビット
を挿入しなくてはならないため、通信効率は、他の同期方式に比べて良くありません。
ただしデータに同期したクロックを送信する必要がなく、装置が簡略化できるため、現在のコン
ピュータ通信で広く普及している通信方式です。
スタート データビット
ビット
H
L
start
0
1
パリティ ストップ
ビット ビット
2
3
4
5
6
7
parity stop
調歩同期通信のデータ構成
データがやりとりされていないとき(アイドル時)、データを送る信号線は、High状態 即ち”1”にな
っているため、最初のデータが”1”の場合には、アイドル時との区別がつきません。
そこで、データの送信開始を受信装置に知らせるために、まずLow状態 即ち”0”を1ビット送信し
ます。この最初に送信する”0”がスタートビットです。
スタートビットに続いて送信するビット列をデータビットと呼びます。
送信側は、まずスタートビットを送り、次に1データを最下位ビット(LSB)から送信します。
最後のデータビットを送り終わるとデータラインを再び“1”(High状態)に戻し、次のデータが連続
している場合は、一定時間待ってから次のスタートビットを送信します。
この最後に送信する”1”がストップビットです。ストップビットの長さは、1 / 1.5 / 2ビットの中か
ら選択できます(通信コントローラによっては選択できない長さもあります)。
-9-
Interface Corporation
TUT-0043
1.5 データ長
データ長は、スタートビットとストップビットの間のパリティビットを除いた、データビット数
のことです。
コンピュータ間の通信では、7ビットまたは8ビットが よく使用されます。
一般的なデータ通信は、送信するキャラクタをキャラクタコードで表し、1キャラクタずつ送りま
す。キャラクタとキャラクタコードの対応は、キャラクタ符号規格で定められています。昔は5
ビット符号もありましたが、現在は7ビットまたは8ビット符号(ASCII/JIS符号)が使用されます。
バイナリデータを送信する場合は、データ長は8ビットにする必要があります。
1.6 パリティビット
パリティビットは、通信においてあるデータを送信するとき、データが正確に送られたかどうか
検査するためのものです。
例えばASCII 7ビットコードの“a”は16進数で61h、2進数で1100001bとなります。
ここでパリティチェックを偶数パリティに設定した場合、送信側は、転送する“1”の総数が偶数個
になるようにします。この例では“1”の数が3個ですので、8ビット目を“1”にして、11100001bとな
る8ビットのデータ列を作り、“1”の数を4個(偶数)にして転送します。受信側では、“1”の数を数え、
偶数であるか確認します。もし、“1”の数が奇数の場合、データの受信に失敗したと判断できます。
このようにデータビットの後にパリティ情報として付加されるビットを、パリティビットと呼び
ます。
パリティには偶数と奇数があり、奇数パリティの場合は、転送する“1”の数が奇数になるようにパ
リティビットを付加します。
1.7 通信速度(bps)とスループット
シリアル通信では、データを送る速さの指標として、“bps”がよく使われます。
“bps”は1秒間に送れるビット数を表す単位です。SI単位系の原則からいえば“bit/s”と書くべきです
が、“bps”を使うのが一般的です。
通信速度が9600bpsの時、1ビットの時間幅が1/9600 sということを表し、
この速度でデータビットを連続して送ることができれば、9600ビット/秒の実効通信速度
(スループット)が得られます。しかし、調歩同期通信の場合、1キャラクタのデータビットには最
低2ビット(1ビットのスタートビットと、1ビットのストップビット)が付加されます。
そのため8ビット送るのに少なくとも10ビット分の時間がかかることから、キャラクタ間が隙間な
く連続して送ったとしても、実効通信速度は7680bpsしか得られません。
Interface Corporation
- 10 -
TUT-0043
1.8 その他の用語解説
その他、調歩同期通信を行う際に、出てくる用語について解説します。
用 語
解 説
シリアルポート シリアル通信を行う際、送受信を行う口を、一般に「シリアルポート」と呼び
ます。
個々のシリアルポートは、ドライバソフトウェアから見た場合、独立しており、
個別に取り扱うことが可能です。
カタログ等の仕様では、チャンネル数が2チャンネル,4チャンネルと記載して
いますが、これを2ポート,4ポートと呼ぶ書籍等もあります。
本書では、通信を行う1つの口を特に、シリアルポートと称しています。
全二重/半二重
全二重通信とは両方向通信が可能で、かつ送受信が同時に行える通信方式で
す。半二重通信における送受信切り替えの時間的ロスがなく、データの送信効
率を高めることができます。
半二重通信とは両方向通信が可能で、かつ送受信を同時に行えないものをいい
ます。送受信が同時に行えないため、送受信の切り替えを行う必要があります。
RS-232Cインタフェースを搭載した半二重モデムと接続する場合、制御信号(一
般にはRS信号)により送受信の切り替えを行います。
RS-485マルチドロップ接続の場合、ドライバ・レシーバの接続変更により、送
受信を切り替えます。
1.9 調歩同期通信を行うにあたってのアドバイス
調歩同期通信I/Oモジュールを使って調歩同期通信を行う際、知っておくとためになる事項を以下
に列挙します。
項 目
RS-232CとRS-485の
どちらを使うべき
か?
家電品店で売ってい
るシリアルケーブル
は使用できるか?
内 容
RS-232CとRS-485のどちらを通信方式として採用すべきかについては、接続相
手,使用用途,環境等を鑑みる必要があります。
例えば、計測器や接続相手が決まっている時は、相手の通信インタフェース
に合わせる必要があります。
通信インタフェースを自由に選択できる場合は、使用用途で選択した方が良
いと思われます。
・ コンピュータのシリアルポートの口を増やしたいのならば、RS-232Cをお奨
めします。
・ 接続相手との距離が15mを越えるようならば、RS-485を選択してください。
・ 1対1の接続でなく、1対2∼1対31の接続を行いたいならば、RS-485を選択し
てください。
・ 通信速度が1Mbpsを越えるような場合、RS-485を選択してください。
家電品店で一般にシリアルケーブルとして売られているものは、RS-232C用の
ものがほとんどです。
コンピュータとモデムを接続する場合は、ほとんどの場合、ストレートタイ
プのケーブルを使用します。
機器同士を直接接続する場合は、リバース(クロス)タイプのケーブルを使用し
ます。
ただし、購入前に結線図をよく確認して、使用目的と合致するケーブルを選
択してください。
- 11 -
Interface Corporation
TUT-0043
項 目
送受信バッファメモ
リとは、何のために
あるのか?
内 容
シリアル通信でよく問題となるのが、データの受け取り側が、今あるデータ
を取り出す前に、次のデータが送られる状況が発生することです。
これは、ベルトコンベアに載せられて送られてくる物品を、捌くのが追いつ
かなくなる状況に似ています。これを俗に「取りこぼしが発生した」と言い
ます。
取りこぼしが発生する状況としては、幾つか原因が考えられます。代表的な
例としては、CPUの処理速度が遅いために取りこぼしたり、OSがリアルタイ
ムに受け取り処理に入らないため、取りこぼすといったものです。
受け取ったデータを内部で溜め込んでおき、一括して取り出すことができれ
ば、取りこぼしを回避できると思われます。
送受信バッファメモリは、この送受信するデータを溜め込む領域です。この
サイズが多ければ多い程、受け取り処理に入るまでの反応が遅いOSでも、よ
り確実にデータを受け取ることが可能となります。
標準COMポート互換 PC/AT互換機のPCに内蔵されているシリアルポートは、標準COMポートと呼
とは、どういう意味 ばれます。
か?
シリアル通信I/Oモジュールの中で、PC/AT互換機のシリアルポートの通信コ
ントローラ16550と互換の通信コントローラを搭載したI/Oモジュールを、標準
COMポート互換通信I/Oモジュールと呼んでいます。
またWindowsのシリアルポート(COMポート)とAPI互換であるという意味で
使用されることもあります。
通信を行うために、 全二重の場合、送信ライン,受信ライン,グランドの3本のラインを接続すれば、
最低何本の線が必要 最低限の通信は行えます。
か?
ハードウェアフロー制御等通信制御を行う場合、制御信号を別途接続する必
要があります。
接続する制御信号は、接続相手の通信機器の仕様により変わります。
詳細については、ハードウェアマニュアルを参照してください。
通信速度は、1bpsずつ 通信に使用するクロックは、I/Oモジュールに搭載されている基準クロックを
変更することは可能 分周して生成されます。
か?
分周するため、ビットレートは全ての整数値に設定することはできません。
次の計算式の結果が整数値になる値が、設定できる通信速度となります。
[基準クロック]
―――――――――
[通信速度(bps)] × 16
Interface Corporation
- 12 -
TUT-0043
第2章 調歩同期通信 on RTLinux
RTLinuxは、Linux上でリアルタイム処理を可能にするOSです。そのRTLinux上で調歩同期通信I/O
モジュールを動かすことにより、リアルタイム性が要求されるシステムを構築することが可能に
なります。
2.1 パフォーマンス
実際にどの程度のリアルタイム性が保証されているかを測定した結果を見てみます。通常のLinux
上での結果と比較しています。
2.1.1 応答性
データを受信してから、コールバック関数内ですぐにデータ送信関数を呼び出した場合、データ
受信完了から、実際にデータが送信されるまでの時間を測定しました。
RTLinux,Linuxともに、1000回応答時間を測定しています。
コールバック関数呼び出し
データ送信開始
受信完了
データ受信
コールバック関数
データ送信
この時間を測定
応答性を測定した時間
- 13 -
Interface Corporation
TUT-0043
応答時間の分布
データ区間
(μs)
44
45
46
47
48
49
50
51∼999
1000∼1999
2000∼2999
3000∼3999
4000∼4999
5000∼5999
6000∼6999
7000∼7999
8000∼8999
9000∼
件 数
RTLinux
0
10
254
529
186
18
3
0
0
0
0
0
0
0
0
0
0
Linux
0
0
0
0
0
0
0
92
96
102
102
97
103
99
100
99
110
RTLinuxでは、平均応答時間,最大応答時間,最小応答時間の全てにおいてLinuxよりも優れた結果が
出ています。
特に注目されるのが、最大応答時間です。負荷が入った場合、Linuxでは、10msにまで応答時間の
ぶれが発生しているのに対し、RTLinuxでは、50μsまでしかぶれが発生していません。
最悪値の保証が、RTLinuxとLinuxでは相当の差があるわけです。
応答時間のトータル結果
測定環境
トータル結果
平均(μs)
最大(μs)
最小(μs)
標準偏差(μs)
RTLinux
Linux
47.0
50.0
45.0
0.8
5089.0
10070.0
80.0
2883.5
拡
大
600
600
RTLinux の応答時間はぶれが少ない。
500
500
件数
400
400
300
300
600
500
400
200
200
100
100
件数
0
0
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
300
RTLinux
Linux
データ区間(μs)
200
Linux の応答時間はぶれが大きい。
100
9720
1004
3240
3564
3888
4212
4536
4860
5184
5508
5832
6156
6480
6804
7128
7452
7776
8100
8424
8748
9072
9396
0
324
648
972
1296
1620
1944
2268
2592
2916
0
データ区間(μs)
RTLinuxとLinuxの応答時間の比較
Interface Corporation
- 14 -
TUT-0043
2.1.2 周期性
次に、指定した周期でデータ送信を繰り返し行い、その周期のぶれや限界値を測定しました。
こちらも各周期で1000回ずつ測定を行っています。
ネットワーク負荷なし
測定環境
指定周期
10000
1000
Linux
平均
(μs)
最大
(μs)
最小
(μs)
標準偏差
平均
(μs)
最大
(μs)
最小
(μs)
標準偏差
(μs)
10001.1
1000.1
10005.0
1004.0
9997.0
996.0
1.2
1.2
10001.3
10001.3
10061.0
10071.0
9943.0
9935.0
5.2
4.5
ネットワーク負荷あり
測定環境
指定周期
10000
1000
RTLinux
RTLinux
(μs)
Linux
平均
(μs)
最大
(μs)
最小
(μs)
標準偏差
10001.1
1000.1
10007.0
1005.0
9995.0
996.0
最大
(μs)
最小
(μs)
標準偏差
(μs)
平均
(μs)
1.4
1.2
10001.2
10001.2
10939.0
11081.0
9051.0
8938.0
56.6
50.6
(μs)
Linuxでは1ms周期を実行しても10ms以下の周期実行は行えておらず、最大値と最小値のぶれも大
きくなっていますが、RTLinuxでは最大値と最小値のぶれも小さくなっています。
またネットワーク負荷をかけたとき、Linuxではデータばらつきが10倍に増えましたが、RTLinux
ではほとんど増えていません。
違いを分かりやすくするために、10ms(ネットワーク負荷あり)での周期実行の違いを図に示しま
した(縦軸は、件数、横軸は測定時間を示しています)。
LinuxよりもRTLinuxのほうが、ぶれが小さいことが分かります。
件数
データ区間(μs)
RTLinuxとLinuxの周期性測定結果
- 15 -
Interface Corporation
TUT-0043
2.2 RTLinuxによる調歩同期通信I/Oモジュール制御
RTLinux上で弊社 調歩同期通信I/Oモジュールを制御するには、お客様の作成するRTLinux
モジュールからRTLinux対応 調歩同期通信ドライバソフトウェアの関数を呼び出すことで行いま
す。通常、RTLinuxモジュールではRTLinuxスレッドを生成し、ここから関数を呼び出して処理を
行います。
また、RTLinuxモジュールとLinuxアプリケーションがデータのやりとりを行う場合は、RT-FIFO
を使用します。
制御構成を簡単に示すと、下図のようになります。
リアルタイム
FIFO
Linux
アプリケーション
RTLinuxモジュール
RTLinuxスレッド
RTLinux対応
ドライバモジュール
(rcp4141.o)
データ送信
通信機器
データ受信
シリアル通信
I/Oモジュール
RTLinux上での調歩同期通信I/Oモジュール制御構成
●RTLinuxモジュール
リアルタイム処理を行うモジュール本体です。お客様はRTLinux対応 調歩同期通信ドライバソフト
ウェアを使って、シリアルポートを制御するために、このモジュールを作成する必要があります。
●RTLinuxスレッド
実際にリアルタイム処理を行う際、RTLinuxモジュール下で動作するRTLinuxスレッドを作成します。
このRTLinuxスレッドは通常のLinuxのプロセスよりも優先して実行されます。
●RT-FIFO
リアルタイムFIFOとも呼ばれます。RTLinuxスレッドとLinuxアプリケーション、またはRTLinuxス
レッド同士のデータの受け渡しを行うために使用されます。
★RT-FIFO
RT-FIFO はデバイスとして扱われており、/dev/rtf0 等という名前で存在しています。
Interface Corporation
- 16 -
TUT-0043
2.3 シリアルポート制御概略
調歩同期通信I/Oモジュールでは、制御はシリアルポート単位に行います。
シリアルポートの制御は、下記の制御シーケンス(順番)で行います。
(1)
シリアルポート
初期化
(2)
各種処理
(3)
終了処理
シリアルポートの制御シーケンス
①シリアルポートの初期化
シリアルポートへの操作を行うため、まず、シリアルポートを利用可能な状態にします。この処理
がシリアルポートの初期化です。I/Oモジュールの初期化を行うと、プログラムはシリアルポートへ
のアクセスが可能となります。本処理が行われないとシリアルポートへのアクセスは行えません。
②各種処理
シリアルポートから、データの送信および受信を行います。
③終了処理
シリアルポートの使用終了を行うための手続きです。プログラム終了時に行います。
- 17 -
Interface Corporation
TUT-0043
第3章 シリアルポート制御の第一歩
ここでは、実際に弊社 調歩同期通信I/Oモジュールを用いて、シリアルポートの制御プログラム
を作成します。
この章では例として、以下の製品を使用しています。
PCI-4141
1枚:調歩同期通信I/Oモジュール
下図に、設定例を示します。
PCI-4141
RSW1:0
I/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに調歩同期シリアル通
信製品を実装します。
(この章では、ケーブル等を接続して通信を行いません)
I/Oモジュールをシステムに組み込んでから、動かすまでの流れは下記のようになります。
各項目に従って、RTLinux上でのシリアルポート制御プログラミングを行います。
RTLinux リアルタイムカーネルの
組み込み
RTLinux 調歩同期通信ドライバ
組み込み
プログラミング
コンパイル
実行
RTLinux上でのシリアルポート制御までの流れ
Interface Corporation
- 18 -
TUT-0043
3.1 RTLinux調歩同期通信ドライバの組み込み
RTLinuxの調歩同期通信ドライバを組み込む前に、RTLinux導入編のチュートリアルを参照し、
RTLinuxのインストールとRTLinuxモジュールを動かすために必要なリアルタイムカーネルのイ
ンストールを行ってください。
参照箇所:
RTLinuxのインストール
リアルタイムカーネルの組み込み
第1章 RTLinuxの導入
第2章 RTLinuxのインストール
リアルタイムカーネルの組み込み例:
← リアルタイムカーネルを組み込むため、
スーパーユーザになります。
Password: ----← root のパスワードを入力します。
# cd /usr/src/rtlinux/rtlinux-3.1
# sh scripts/insrtl← リアルタイムカーネルの組み込みスクリプトを実行します。
# 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]
↑rtl、rtl_time 等のリアルタイムカーネルが組み込まれています。
リアルタイムカーネルは正常に組み込まれています。
% su
リアルタイムカーネルを組み込んだ後に、調歩同期通信ドライバモジュールを組み込むことによ
り、シリアルポートのリアルタイム制御が行えるようになります。
シリアルポートを実際に制御するには、ドライバモジュールを事前に組み込む必要があります。
組み込み方法は、Readme,Helpを参照してください。
例として、PCI-4141を組み込んだ場合を記載します。
# lsmod
Module
Size Used
by
rcp4141
22000
0
(unused)
dpg0102
790448
0
[rcp4141]
rcpcom
9088
1
[rcp4141]
rtl_sched 42720
0
[rcp4141]
rtl_fifo
9824
0
(unused)
rtl_posixio 7136
0
[rcp4141 rcpcom rtl_fifo]
rtl_time
9872
0
[rcp4141 rcpcom rtl_sched rtl_posixio]
rtl
26432
0
[rcp4141 dpg0102 rtl_sched
rtl_fifo rtl_posixio rtl_time]
mbuff
6048
0
(unused)
dpg0102,rcpcom.o,rcp4141が組み込まれていることが分かります。
- 19 -
Interface Corporation
TUT-0043
/procファイルシステムを参照することにより、各シリアルポートのポート番号を確認します。
RTLinux調歩同期通信ドライバの各関数はポート番号で、制御を行うポートを指定します。
行頭の数値がポート番号になります。
#cat /proc/tty/driver/rcpcom
0: PCI-4141(bid=0h)CH1 [9600bps] tx:0 rx:0
1: PCI-4141(bid=0h)CH2 [9600bps] tx:0 rx:0
以上で、シリアルI/Oモジュールのリアルタイム制御を行うプログラミングまでの準備が整いまし
た。
取り外すときは以下のように実行します。
# modprobe –r rcp4141
以上で準備は終わりです。次からいよいよプログラミングを行っていきます。
★modprobe コマンドを使わずに組み込むには?
modprobe コマンドを使うと、ドライバモジュールの組み込みが簡単になりますが、他の組み込み方法も
あります。
以下に insmod コマンドを使った場合の組み込み例を示します。
insmod コマンドを使って、ドライバモジュールを組み込む場合>
例)
# insmod dpg0102
# insmod rcpcom
# insmod rcp4141
rmmod コマンドを使って、ドライバモジュールを取り外す場合>
例)
# rmmod rcp4141
# rmmod rcpcom
# rmmod dpg0102
Interface Corporation
- 20 -
TUT-0043
3.2 シリアルポートの情報を列挙する
ここでは、ComRTGetPortInformation関数を使って、システム内のシリアルポートの情報を列挙す
るプログラムを作成します。
エディタを起動し、Lsit3-1に示すプログラムを入力して、ファイル名を「sample1.c」として保存
してください。
★プログラム中のコメントについて
サンプルプログラムには、理解し易いよう、日本語コメントを用いています。
しかし、プログラム中に日本語を用いてコンパイルすると、正常にコンパイルできない場合があります。
その時は、日本語コメントを削除してコンパイルしてください。
List 3-1 sample1.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
41
42
43
44
45
46
47
48
49
50
51
#include
#include
<rtl.h>
"pcicomrt.h"
int
g_port_no = -1;
/* 調歩同期通信I/Oモジュールのシリアルポート番号 */
/* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */
int init_module(void)
{
int
port_no;
COMRT_PORTINFO port_info;
int
ret;
rtl_printf("init_module called¥n");
EXPORT_NO_SYMBOLS;
/* オープン可能なシリアルポートと、その情報を調べます */
for(port_no = 0; port_no < COMRT_MAX_PORTS; port_no++) {
ret = ComRTGetPortInformation(port_no, &port_info);
if(ret == 0){
rtl_printf( "----- Serial Port Information -----¥n"
"PortNo:%d¥n"
"VendorID:%04lxh¥n"
"DeviceID:%04ld¥n"
"SubsystemID:%04lxh¥n"
"RevisionID:%ld¥n"
"BoardID:%ld¥n"
"ChannelNumber:%ld¥n"
"BaseAddress:%04lxh¥n"
"IRQ No:%ld¥n",
port_no,
port_info.VendorID, port_info.DeviceID,
port_info.SubsystemID, port_info.RevisionID,
port_info.BoardID, port_info.ChannelNumber,
port_info.BaseAddress, port_info.IrqNumber);
}
}
/* オープン可能なポート番号を記録する */
if(g_port_no < 0) g_port_no = port_no;
/* 最初に見つかったシリアルポートのオープン */
ret = ComRTOpen(g_port_no);
if(ret){
rtl_printf("ComRTOpen error [ret=%x]¥n", ret);
return -1;
} else {
rtl_printf("ComRTOpen success!! [PortNo=%d]¥n", g_port_no);
}
return 0;
- 21 -
Interface Corporation
TUT-0043
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
}
/* 終了関数(モジュールが取り外される時、呼ばれる関数) */
void cleanup_module(void)
{
int
ret;
rtl_printf("cleanup_module called¥n");
}
/* シリアルポートのクローズ */
ret = ComRTClose(g_port_no);
if(ret){
rtl_printf("ComRTClose error [PortNo=%d ret=%x]¥n", g_port_no, ret);
}
次に、List3-2に示すプログラムを入力し、ファイル名を「makefile」として保存してください。
これは、上記プログラムをコンパイルするメイクファイルです。
List 3-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
コンパイルすると、RTLinuxモジュールsample1.oが作成されます。insmodコマンドで、RTLinuxモ
ジュールを組み込みます。
# make
# ls
makefile sample1.c sample1.o
# insmod sample1.o
組み込む前に、リスト中のrtl_printf関数の出力内容が画面で確認できるよう、X Windowで使用さ
れている方は、コンソールをもう一つ立ち上げ、次のコマンドを入力してください。
# tail –f /var/log/messages
コンソール画面で作業されている方は、次のように打ち込んでください。
# tail –f /var/log/messages &
これにより、rtl_printf関数が出力する内容を確認できます。
★/var/log/messages
syslogやcron等で実行されたサービスのログ等の情報は、「/var/log/」に保存されます。
通常、ログは「/var/log/messages」に保存されることが多いです。
RTLinuxでは、rtl_printf関数を使って、ここに出力し、デバッグプリントができるようになっていま
す。(そのままコンソール画面に出力されるようには、なっていません。)
上の用例では、tailコマンドを使って、このログ出力を常に表示状態にしています。
コンソール画面の例で用いた&(アンパサンド)コマンドはジョブコマンドの一種で、tailコマンドを
バックグランドで実行させています。
コンソール画面では、X Windowのように幾つもコンソールを起動することができないので、このよ
うにします。
Interface Corporation
- 22 -
TUT-0043
sample1.oを組み込むと、システム内の各シリアルポートの情報が列挙表示されます。
(以下は例です。お客様の環境で実行した際、表示される内容が異なる場合があります)
# insmod sample1.o
init_module called
----- Serial Port Information ----PortNo:0
VendorID:1147h
DeviceID:4141
SubsystemID:0001h
RevisionID:0
BoardID:0
ChannelNumber:1
BaseAddress:b800h
IRQ No:7
----- Serial Port Information ----PortNo:1
VendorID:1147h
DeviceID:4141
SubsystemID:0001h
RevisionID:0
BoardID:0
ChannelNumber:2
BaseAddress:b400h
IRQ No:7
ComRTOpen success!! [PortNo=0]
次に、組み込んだRTLinuxモジュールを取り外します。
コンソールに以下を入力し、Enterキーを押します。
# rmmod sample1
すると、コンソール画面は、以下のメッセージが表示されます。
# rmmod sample1
cleanup_module called
RTLinuxモジュールが取り外されたことが分かります。
何度かinsmodコマンドによるモジュール組み込みとrmmodコマンドによるモジュール取り外しを
繰り返してみてください。
その都度、メッセージが表示されることが分かります。
- 23 -
Interface Corporation
TUT-0043
3.3 シリアルポートの情報を列挙するプログラムの解説
それでは、先程のプログラムの解説を行います。
まず、このプログラムの動作概要を示します。
RTLinux モジュール
sample1.o
組み込み(insmod)
取り外し(rmmod)
init_module 関数
cleanup_module 関数
RTLinux
作成したRTLinuxモジュールをinsmodコマンドでRTLinuxに組み込む時、init_module関数が呼ばれ
ます。init_module関数ではComRTGetPortInformation関数を呼び出し、システム内に存在する全て
のシリアルポートの情報を列挙し、最初に見つけたシリアルポートに対してオープン処理を行っ
ています。
また、rmmodコマンドで削除する時、cleanup_module関数が呼ばれます。cleanup_module関数では
シリアルポートのクローズ処理をしています。
(18~40行目:ComRTGetPortInformation関数による情報の列挙)
ここでは、ComRTGetPortInformation関数を用いて、コンピュータ内に存在する全ての弊社調歩同
期シリアル通信製品の情報を列挙しています。
この関数は、第1引数でポート番号を指定して呼び出すと、第2引数のCOMRT_PORTINFO構造体
にシリアルポートのI/Oモジュール情報を返します。
得られる情報は、以下の通りです。
メンバ変数名
内 容
VendorID
ベンダIDが返ります。1147hが返ります。
DeviceID
デバイスIDが返ります。
SubsystemIDと組み合わせることで、I/Oモジュールの型式を特定すること
ができます。(組み合わせについては、Helpを参照してください)
SubsystemID
サブシステムIDが返ります。
RevisionID
リビジョンIDが返ります。
BoardID
I/Oモジュール上のRSW1の値が返ります。
同一型式のI/Oモジュールを、システム内で特定する時、このRSW1を変
えておくことで、どのI/Oモジュールにシリアルポートが割り当てられて
いるのか、判断することができます。
ChannelNumber
チャンネル番号が返ります。
I/Oモジュール上の各シリアルポートに対して、チャンネル順番に割り振
られます。
BaseAddress
このシリアルポートに対応する通信コントローラが使用するI/Oポートの
先頭アドレスが返ります。
IrqNumber
このシリアルポートに対応する通信コントローラが使用する割り込み番
号が返ります。
Interface Corporation
- 24 -
TUT-0043
GPG-4141では、シリアルポートのポート番号の最大値は、COMRT_MAX_PORTS(=256)です。つ
まり、256のシリアルポートを同時に扱うことが可能です。
このforループ処理では、全てのポート番号に対して、デバイスが割り当てられているかチェック
を行い、デバイスが割り当てられているポート番号に対して、シリアルポートの情報を表示して
います。
38行目では、シリアルポートが最初に見つかった時、見つかったポート番号をg_port_no変数に記
録しています。これは、以降の処理で使うために行っています。
(43行目:ComRTOpen関数)
ComRTOpen関数はシリアルポートのオープン処理を行っています。
この関数でオープンを行うと、送受信等の関数が使用できるようになります。
★ComRTGetPortInformation 関数の特殊性
ComRTGetPortInformation 関数は、少々特殊な関数です。
GPG-4141 に用意されているほとんどの関数は、ComRTOpen 関数で、シリアルポートをオープンしない
限り呼び出すことはできません。オープンしないまま、呼び出すと全てエラーとなります。
しかし、ComRTGetPortInformation 関数だけは特殊で、オープン処理を行っていなくても呼び出すことが
できます。
これは、シリアルポートをオープンする時、システム内の特定のポートを明示的にオープンできるよう
にするために用意されているからです。
この関数を併用することで、例えば、RSW1 が 2 に設定された PCI-4141 のチャンネル番号 2 のシリアル
ポートを、指定してオープンさせる等といったことが可能になります。
こうすることで、構築したシステムを他所の環境に移築した時や、移築した時システム内の I/O モジュー
ルの順番を替えてしまった時でも、目的のシリアルポートをオープンさせることが可能になります。
次章のサンプルでは、実際に特定の I/O モジュールからシリアルポートをオープンさせていますので、
参考にしてください。
(62行目:ComRTClose関数)
ComRTClose関数は、シリアルポートをクローズさせる関数です。
オープンしたシリアルポートは、使用後は必ずクローズするようにしてください。
★ComRTClose 関数を呼ばないと、どうなるか?
ComRTClose 関数を呼び出さないと、シリアルポートはオープンしたままの状態になります。
オープン状態なので、ComRTOpen 関数を呼び出した場合、エラーが返ります。
このような場合、対処方法としては、GPG-4141 ドライバモジュール(rcp4141/rcp4161)を一旦取り外す必
要があります。
オープンしたら必ずクローズしてください。
- 25 -
Interface Corporation
TUT-0043
第4章 より高度な処理を行おう
先程のプログラムは、RTLinuxモジュールの組み込みと取り外しの時にしか動作しないものでした。
実際のプログラミングでは、誰かから(大抵は上位アプリケーション)指令を受け、その指令に従っ
て何らかのアクションを起こすのが普通です。
この章では、Linuxプログラムから、RTLinuxモジュールを制御するプログラムを作成します。
4.1 周期的なデータの送受信
ここでは、周期的にデータを送信し、これを別のシリアルポートで受け取り、Linuxプロセスでの
データを送るという処理を行います。
ここでは、以下の製品を使用します。
PCI-4141
1枚:調歩同期通信I/Oモジュール
RS-232Cリバースケーブル
1本:9pin D-subコネクタ←→9pin D-subコネクタ接続ケーブル
下図に、接続構成を示します。
RS-232C リバースケーブル
CH1
PCI-4141
RSW1:0
CH2
I/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに調歩同期シリアル通
信製品を実装します。
PCI-4141の2つのチャンネルを、RS-232C リバースケーブルで接続します。
お手持ちの調歩同期通信I/Oモジュールで、どのように接続すれば良いかについては、ハードウェ
アマニュアルの『外部接続』を参照してください。
以下の4つのファイルを作成します。
ファイル名
備 考
sample2.h
LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル
module2.c
RTLinuxモジュールのソースコード
sample2.c
Linuxプロセスのソースコード
makefile
上記ソースコードをコンパイルするためのmakefile
Interface Corporation
- 26 -
TUT-0043
List4-1は、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名
を「sample2.h」として保存してください。
List4-1 sample2.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
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
sample2.h 共通定義ヘッダファイル
Copyright 2002 Interface Corporation. All rights reserved.
*/
#if !defined(___SAMPLE2_H)
#define
___SAMPLE2_H
#include "pcicomrt.h"
/* Constants --------------------------------------------------------------- */
#define FIFO_COMMAND
1
/* Linuxプロセスから指令を受け取るRT-FIFO */
#define FIFO_THRU_CMD
2
/* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */
#define FIFO_RESULT
3
/* RTLinux内で受信したデータをLinuxプロセスに送るRT-FIFO */
#define DEVICE_ID
#define SUB_SYSTEM_ID
#define RSW_NO
#define SEND_CH
#define RECV_CH
4141
0x0001
0
1
2
/*
/*
/*
/*
/*
I/Oモジュールを特定する一意のID値(PCI-4141を表す) */
I/Oモジュールを特定する一意のID値(PCI-4141を表す) */
同一型式のI/Oモジュールを区別するRSW1設定値 */
送信用に指定するチャンネル番号 */
受信用に指定するチャンネル番号 */
#define BUFF_SIZE
1000
/* Linuxプロセスへ結果を送るRT-FIFOのサイズ */
/* Command ID -------------------------------------------------------------- */
/* コマンドID群(RTLinuxスレッドへの指示用) */
enum CMD_IDS {
ID_START,
/* 周期的な送信のスタート指示 */
ID_STOP
/* 周期的な送信のストップ指示 */
};
/* コマンド指示用の構造体 */
struct CMD_STRUCT {
enum CMD_IDS
id;
/* コマンドID */
/* 各コマンドに対する設定パラメータ */
long
smp_period_ms;
/* ID_START時使用:周期の設定(ms単位) */
};
#endif
★ ワンポイント
お使いの調歩同期通信製品が PCI-4141 でない場合、sample2.h の 16,17 行目を使用している I/O モジュー
ルに合わせて修正してください。
型式と ID 値の対応は、Help の COMRT_PORTINFO 構造体の説明を参照してください。
以下に、CTP-4142 を使用する場合の例を示します。
#define
DEVICE_ID 4142 ← 4141 を 4142 に変更。
#define
SUB_SYSTEM_ID
0x0101
← 0x0001 を 0x0101 に変更。
- 27 -
Interface Corporation
TUT-0043
List4-2は、RTLinuxモジュールのソースファイルです。ファイル名を「module2.c」として保存し
てください。
List4-2 module2.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
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
/*
*/
module2.c RTLinuxモジュールのソースコード
Copyright 2002 Interface Corporation. All rights reserved.
#include
#include
#include
#include
<rtl.h>
<rtl_sched.h>
<rtl_fifo.h>
"sample2.h"
pthread_t my_task_info;
int
g_send_port_no = -1;
int
g_recv_port_no = -1;
/* 送信用のシリアルポート番号 */
/* 受信用のシリアルポート番号 */
/* 指定したデバイスID等の情報に合致するポート番号を検索する */
int search_rcp4141port(unsigned long DeviceID, unsigned long SubsystemID,
unsigned long BoardID, unsigned long ChannelNumber)
{
int
port_no;
COMRT_PORTINFO port_info;
}
/* 最大ポート番号まで、条件に合致するポート番号を検索する */
for(port_no = 0; port_no < COMRT_MAX_PORTS; port_no++) {
if(ComRTGetPortInformation(port_no, &port_info) == 0){
if( port_info.DeviceID == DeviceID &&
port_info.SubsystemID == SubsystemID &&
port_info.BoardID == BoardID &&
port_info.ChannelNumber == ChannelNumber) {
return port_no; /* 見つかった:ポート番号を返す */
}
}
}
return -1;
/* 見つからなかった:-1を返す */
/* 受信時にコールバックされる関数 */
void my_recv_callback(unsigned long event_factor, unsigned long user_data)
{
int
recv_len;
char
recv_buff[50];
/* 受信用のバッファ */
rtl_printf("my_recv_callback called event_factor=%lx user_data=%ld¥n", event_factor, user_data);
do{
/* 目的のイベント(受信トリガサイズに達した)か? */
if((event_factor & COMRT_EVENT_RXTRIGGER) == 0){
rtl_printf("my_recv_callback: disappointed event factor¥n");
break;
}
/* データの受信 */
recv_len = ComRTRead(g_recv_port_no, recv_buff, sizeof(recv_buff) - 1);
if(recv_len < 0){
rtl_printf("my_recv_callback: ComRTRead error [recv_len=%x]¥n", recv_len);
break;
} else {
recv_buff[recv_len] = '¥0';
rtl_printf("my_recv_callback: recv data='%s'¥n", recv_buff);
}
}
/* 受信したデータを、RT-FIFO経由でLinuxプロセスに送る */
rtf_put(FIFO_RESULT, recv_buff, recv_len);
}while(0);
/* 周期的な送信を行うRTLinuxスレッド */
void* my_task(void* arg)
Interface Corporation
- 28 -
TUT-0043
69
70
71
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{
int
ret;
struct CMD_STRUCT cmd;
struct timespec
t;
char
send_buff[50];
/* 送信用のバッファ */
rtl_printf("my_task called arg=%d¥n", arg);
/* RTLinuxスレッドが組み込み中、動作する永久ループ */
while(1){
/* 自スレッドを、次の周期までスリープさせる */
pthread_wait_np();
/* RT-FIFOからの指示があれば取り込み */
ret = rtf_get(FIFO_THRU_CMD, &cmd, sizeof(cmd));
if(ret == sizeof(cmd)){
rtl_printf("my_task: get command id=%d¥n", cmd.id);
}
switch(cmd.id){
case ID_START:
/* 周期的な送信のスタート */
rtl_printf("my_task: send cycle is start!!¥n");
pthread_make_periodic_np(pthread_self(), gethrtime(),
cmd.smp_period_ms * 1000 * 1000);
break;
case ID_STOP:
/* 周期的な送信のストップ */
rtl_printf("my_task: send cycle is stop!!¥n");
pthread_suspend_np(pthread_self());
break;
default:
rtl_printf("unknown id!!¥n"); break;
}
/* 文字列の送信 */
t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME));
sprintf(send_buff, "now clock=%08ld", t.tv_sec);
ret = ComRTWrite(g_send_port_no, send_buff, strlen(send_buff));
if(ret){
rtl_printf("my_task: ComRTWrite error [ret=%x]¥n", ret);
}
rtl_printf("my_task: send data='%s'¥n", send_buff);
}
}
return 0;
/* Linuxプロセスからの指令を受け取るハンドラ */
int my_handler(unsigned int fifo)
{
int
ret;
struct CMD_STRUCT cmd;
rtl_printf("my_handler called fifo=%d¥n", fifo);
}
/* Linuxプロセスの指示に従って、RTLinuxスレッド等の制御を行う */
while((ret = rtf_get(FIFO_COMMAND, &cmd, sizeof(cmd))) == sizeof(cmd)){
rtf_put(FIFO_THRU_CMD, &cmd, sizeof(cmd));
rtl_printf("my_handler: get command id=%d¥n", cmd.id);
pthread_wakeup_np(my_task_info);
}
if(ret != 0){
rtl_printf("my_handler: error!!(%d)¥n", ret);
return -EINVAL;
}
return 0;
/* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */
int init_module(void)
{
int
ret;
COMRT_CONFIG conf;
rtl_printf("init_module called¥n");
EXPORT_NO_SYMBOLS;
/* Linuxプロセスからの指示を受け取るハンドラとRT-FIFOを生成する */
- 29 -
Interface Corporation
TUT-0043
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
rtf_destroy(FIFO_COMMAND);
rtf_create(FIFO_COMMAND, sizeof(struct CMD_STRUCT));
rtf_create_handler(FIFO_COMMAND, my_handler);
/* ハンドラとRTLinuxスレッドの間のRT-FIFOを生成する */
rtf_destroy(FIFO_THRU_CMD);
rtf_create(FIFO_THRU_CMD, sizeof(struct CMD_STRUCT));
/* コールバックとLinuxプロセスの間のRT-FIFOを生成する */
rtf_destroy(FIFO_RESULT);
rtf_create(FIFO_RESULT, sizeof(char) * BUFF_SIZE);
/* 送信用シリアルポートのオープン */
g_send_port_no = search_rcp4141port(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, SEND_CH);
if(g_send_port_no < 0){
rtl_printf("Fail find send channel device.¥n");
return -1;
}
ret = ComRTOpen(g_send_port_no);
if(ret){
rtl_printf("ComRTOpen error [ret=%x]¥n", ret);
return –2;
} else {
rtl_printf("ComRTOpen success!! [port no=%d]¥n", g_send_port_no);
}
/* 受信用シリアルポートのオープン */
g_recv_port_no = search_rcp4141port(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, RECV_CH);
if(g_recv_port_no < 0){
rtl_printf("Fail find recv channel device.¥n");
return –3;
}
ret = ComRTOpen(g_recv_port_no);
if(ret){
rtl_printf("ComRTOpen error [ret=%x]¥n", ret);
return –4;
} else {
rtl_printf("ComRTOpen success!! [port no=%d]¥n", g_recv_port_no);
}
/* シリアルポートの通信パラメータのデフォルト値の取得 */
ret = ComRTGetConfig(g_send_port_no, &conf);
if(ret){
rtl_printf("ComRTGetConfig error [ret=%x]¥n", ret);
return –5;
}
/* 送信用通信パラメータの変更 */
conf.DuplexMode
= COMRT_FULL_DUPLEX;
conf.BaudRate
= 9600;
conf.Parity
= COMRT_PARITY_NONE;
conf.StopBits
= COMRT_ONE_STOPBIT;
conf.WordLength
= 8;
/* 送信用シリアルポートへの通信パラメータの設定
ret = ComRTSetConfig(g_send_port_no, &conf);
if(ret){
rtl_printf("ComRTSetConfig error [ret=%x]¥n", ret);
return –6;
}
/*
/*
/*
/*
/*
*/
全二重に設定 */
通信速度を9600bpsに設定 */
パリティビットなし */
ストップビットは1ビット */
データ長は8ビット */
/* 受信用通信パラメータの変更(差分のみ追加) */
conf.RxEventTrigger = 18;
/* 18バイト受信時に受信トリガイベント発生 */
conf.CallbackProc
= my_recv_callback;
/* 受信用シリアルポートのコールバックを登録 */
conf.UserData
= g_recv_port_no;
/* コールバックの引数に、ポート番号を指定 */
/* 受信用シリアルポートへの通信パラメータの設定 */
ret = ComRTSetConfig(g_recv_port_no, &conf);
if(ret){
rtl_printf("ComRTSetConfig error [ret=%x]¥n", ret);
return –7;
}
/* 受信用シリアルポートに対し、コールバックが行われる条件を設定 */
ret = ComRTSetEventMask(g_recv_port_no, COMRT_EVENT_RXTRIGGER);
if(ret){
rtl_printf("ComRTSetEventMask error [ret=%x]¥n", ret);
return –8;
}
Interface Corporation
- 30 -
TUT-0043
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
}
/* RTLinuxスレッドを作成、起動する */
return pthread_create(&my_task_info, NULL, (void*)my_task, 0);
/* 終了関数(モジュールが取り外される時、呼ばれる関数) */
void cleanup_module(void)
{
int
ret;
rtl_printf("cleanup_module called¥n");
/* 送信用シリアルポートをクローズする */
ret = ComRTClose(g_send_port_no);
if(ret){
rtl_printf("ComRTClose error [ret=%d]¥n", ret);
}
/* 受信用シリアルポートをクローズする */
ret = ComRTClose(g_recv_port_no);
if(ret){
rtl_printf("ComRTClose error [ret=%d]¥n", ret);
}
/* RT-FIFOを閉じる */
rtf_destroy(FIFO_COMMAND);
rtf_destroy(FIFO_THRU_CMD);
rtf_destroy(FIFO_RESULT);
}
/* RTLinuxスレッドを終了させる */
pthread_cancel(my_task_info);
pthread_join(my_task_info, NULL);
List4-3は、Linuxプロセスのソースファイルです。ファイル名を「sample2.c」として保存してくだ
さい。
List4-3 sample2.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
/*
*/
sample2.c Linuxプロセスのソースコード
Copyright 2002 Interface Corporation. All rights reserved.
#include
#include
#include
#include
#include
#include
#include
#include
<stdio.h>
<fcntl.h>
<unistd.h>
<math.h>
<sys/time.h>
<sys/ioctl.h>
<rtl_fifo.h>
"sample2.h"
/* Linuxプロセスのメインルーチン */
int main(void)
{
int
fd_result, fd_cmd;
fd_set
rfds;
struct timeval tv;
struct CMD_STRUCT cmd;
char
rt_fifo_name[80];
time_t
start_time;
char
recv_buff[80];
int
recv_len;
/* RTLinuxモジュールに指令を送るRT-FIFOのオープン */
sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND);
if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){
fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);
return -1;
}
/* RTLinuxモジュールからの結果を受け取るRT-FIFOのオープン */
sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT);
if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){
- 31 -
Interface Corporation
TUT-0043
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
72
73
74
75
76
77
78
79
80
81
82
}
fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);
return –2;
/* 周期的な送信の開始指示 */
cmd.id
= ID_START;
cmd.smp_period_ms = 500;
/* 500ms周期の送信設定 */
if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){
fprintf(stderr, "Failled to send the start command.¥n");
return –3;
}
/* 5秒間、受信監視を行う */
start_time = time(NULL);
while(fabs(difftime(time(NULL), start_time)) < 5.0){
FD_ZERO(&rfds);
FD_SET(fd_result, &rfds);
tv.tv_sec = 30; /* select関数のタイムアウト値の設定:30秒 */
tv.tv_usec = 0;
}
/* 受信データの受け取り */
if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){
if(FD_ISSET(fd_result, &rfds)){ /* fd_resultに対してRT-FIFOの書き込みがあった */
recv_len = read(fd_result, recv_buff, sizeof(recv_buff) - 1);
if(recv_len >= 0){
recv_buff[recv_len] = '¥0';
printf("recv data='%s'¥n", recv_buff);
}
}
}
/* 周期的な送信の停止指示 */
cmd.id
= ID_STOP;
cmd.smp_period_ms = 0;
if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){
fprintf(stderr, "Failled to send the stop command.¥n");
return –4;
}
printf("fd_cmd:%d¥n", close(fd_cmd));
printf("fd_result:%d¥n", close(fd_result));
}
printf("The Linux proccess is successfully completed.¥n");
return 0;
List4-4は、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として
保存してください。
List4-4 makefile
1
2
3
4
5
6
7
8
include /usr/include/rtlinux/rtl.mk
all: module2.o sample2
sample2: sample2.c
$(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o sample2 sample2.c
module2.o:module2.c
$(CC) $(INCLUDE) $(CFLAGS) -o module2.o -c module2.c
コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。
# make
← コンパイルします
# ls
← コンパイルしたファイルを一覧表示します
makefile sample2 module2.c module2.o sample2.c sample2.h
# insmod module2.o ← RTLinux モジュールを組み込んでいます
次に、Linuxプロセスを実行します。
# ./sample2
Interface Corporation
← Linux プロセスを実行します
- 32 -
TUT-0043
実行画面を以下に示します。
(画面左上のウィンドウがLinuxプロセスを実行しているコンソール。画面右下のウィンドウはRTLinux
モジュールのログメッセージを表示させているコンソールです)
サンプルの実行画面例
sample2を実行させると、「recv data=’now clock=xxxxxxxx’」と表示が繰り返し出力され、暫くし
てプログラムが終了します。
- 33 -
Interface Corporation
TUT-0043
4.2 周期的なデータの送受信の解説
それでは、先程のプログラムの解説を行います。
プログラムの大まかな動きを、下図に示します。
Linux プロセス
チャンネル 1
チャンネル 2
Linux プロセス
スタート指令
データ送信
“now clock=xxxxxxxx”
XXms 周期
データ送付
データ受信
データ送信
“now clock=xxxxxxxx”
データ送付
データ受信
データ送信
ストップ指令
“now clock=xxxxxxxx”
データ送付
データ受信
my_task 関数が処理します
my_recv_callback 関数が
処理します
sample2の動作概要
Linuxプロセスからスタート指示があると、チャンネル1のシリアルポートから特定のデータがチ
ャンネル2に対して、周期的に送信されます。
チャンネル2のシリアルポートは、受け取ったデータを、RT-FIFOを介してLinuxプロセスに送りま
す。
チャンネル1の送信処理は、RTLinuxスレッド(my_task)が行っています。
チャンネル2の受信処理は、調歩同期通信のドライバモジュールから呼ばれるコールバック関数
(my_recv_callback)が行っています。
Linuxプロセスの仕事は、通信処理を行うRTLinuxモジュールに対する周期処理のスタート指令,ス
トップ指令,チャンネル2が受信したデータを、RT-FIFO経由で受け取ることです。
Interface Corporation
- 34 -
TUT-0043
次に、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。
main
ユーザ空間
Linux プロセス(sample2)
RTLinux モジュール(module2.o)
FIFO_COMMAND
カーネル空間
指令
my_handler
破棄
生成
FIFO_THRU_CMD
init_module
cleanup_module
指令の転送
生成
my_task
破棄
FIFO_RESULT
コールバック生成
受信イベント
受信データ
my_recv_callback
LinuxプロセスとRTLinuxモジュールの相関関係
LinuxプロセスからRTLinuxモジュールに対する指示は、RT-FIFOを経由して、一旦ハンドラ
(my_handler)に送られ、そこから別のRT-FIFOを介してRTLinuxスレッド(my_task)に送られます。
my_taskでは、周期的なデータの送信処理が行われますが、送られたデータは、調歩同期通信ドラ
イバモジュールが呼び出すコールバック関数(my_recv_callback)にて受け取られます。
my_recv_callbackで受け取ったデータは、RT-FIFOを経由して、Linuxプロセスに対して送られます。
図中のinit_moduleとcleanup_moduleから伸びている矢印は、これらの関数からハンドラ
(my_handler)とRTLinuxスレッド(my_task)が生成,破棄されていることを表しています。
init_moduleでは、RTLinuxスレッドおよびRT-FIFOの生成の他、調歩同期通信ドライバモジュール
のオープン処理,通信パラメータの初期化,コールバック関数(my_recv_callback)の登録が行われま
す。
cleanup_moduleでは、RTLinuxスレッドおよびRT-FIFOの破棄の他、調歩同期通信ドライバモジュー
ルのクローズ処理が行われます。
- 35 -
Interface Corporation
TUT-0043
4.2.1 調歩同期通信ドライバモジュールの役割
調歩同期通信ドライバモジュールは内部で様々な仕事を行います。
ここでは、ドライバモジュールの構造について、簡単に紹介します。
プログラムコード
コールバック関数
関数呼び出し
コールバック呼び出し
ドライバモジュール
内部バッファ
送信管理処理
受信管理処理
シリアル通信
コントローラ
調歩同期通信ボード
ドライバモジュールの構造
調歩同期通信ドライバモジュールは、調歩同期通信I/Oモジュール上のシリアル通信コントローラ
の制御を行います。
ドライバは、データの送受信管理を行いますが、処理を円滑に行うため、内部にバッファを持っ
ています。(デフォルトでは約4KBが内部バッファに確保されます)
プログラムからデータの送信が指示された時、内部バッファに一旦格納された後、ドライバがシ
リアル通信コントローラを制御して、データを送信します。
データの受信は、ドライバがシリアル通信コントローラのデータ受信を検知し、データを取り出
した後、内部バッファに一旦蓄積しています。プログラムは、この蓄積したデータを取り出すよ
うになっています。
このような構造になっているため、プログラマは通信コントローラを直接制御した際に発生する、
面倒なデータの管理処理を行わなくて済むようになっています。
通信コントローラ内部で発生した様々な事象の変化を、即プログラムが受け取って処理できるよ
う、ドライバモジュールはコールバック機構を提供しています。
プログラマは、コールバック関数と、コールバックさせたいイベント内容を予め登録しておくこ
とで、ドライバモジュール内部で発生した事象の変化を、検知することができます。
実際、module2.cでは、指定件数のデータが受信されたらコールバック関数が呼び出されるようプ
ログラミングされています。
コールバック関数では、ドライバからデータを取り出して然るべき処理を行っています。
Interface Corporation
- 36 -
TUT-0043
★内部バッファの構造
内部バッファは、1 つのシリアルポートに対して、送信用バッファ,受信用バッファが、それぞれ 1 つず
つ用意されます。
内部バッファは、キュー構造になっており、送信指示された時や未送信のデータが内部バッファにあっ
た時に、データは内部バッファの後尾に格納されます。
内部バッファはドライバモジュールが組み込まれる時、固定長で確保されます。
従って、あまりに大きいデータを送信しようとしたり、受信したデータを取り出さず溜め込み続けると、
データが溢れ出してしまいます。
実際には送信バッファが一杯になると、送信用の関数を呼び出した際、エラーが返ります。
受信バッファの場合、受信されたデータから破棄されます。
受信バッファが溢れないよう、受信データが溜まったら然るべきタイミングで抜き取るよう、注意して
プログラミングしてください。
4.2.2 共通定義ファイルの役割
共通定義ファイル(sample2.h)は、LinuxプロセスとRTLinuxモジュールが、共通で使用する定数等
を抜き出したものです。
共通定義ファイルでは、以下の設定を行っています。
行番号
内 容
#define宣言>
12∼22行目
RT-FIFOの番号の定義,各関数で使用する定数値の指定,バッファサイズの指定。
enum宣言>
26~29行目
LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値を指
定。
struct宣言>
32∼37行目
LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造を指
定。
ここで重要なのがLinuxプロセスからRTLinuxモジュールに対して指令を出すために使用されるコ
マンドの構造体(CMD_STRUCT)です。
Linuxプロセスでは、この構造体に値をセットしてRTLinuxモジュールのハンドラに渡します。ハ
ンドラでは、この構造体ごと受け取って、指示された内容に従って処理を行います。
Linux プロセス
struct CMD_STRUCT {
enum CMD_IDS
id;
long
smp_period_ms;
RTLinux モジュール
LinuxプロセスからRTLinuxモジュールのハンドラへのコマンドの流れ
- 37 -
Interface Corporation
TUT-0043
コマンドの構造体は、2つのメンバ変数から構成されています。RTLinuxモジュールに、どんな作
業をして欲しいか指示を出すID値(idメンバ変数)と、ID値を補足する情報(smp_period_msメンバ変
数)です。
作業を指示するID値は、26∼29行の列挙体定数 ID_STARTとID_STOPで定義されています。以下
に、LinuxプロセスからRTLinuxモジュールに指示する際の取り決めを、簡単にまとめます。
id変数
内 容
ID_START
smp_period_ms で指 定し た時間間隔 で、RTLinux モジュール内の
RTLinuxスレッド(my_task)をスタートする。
ID_STOP
RTLinuxスレッド(my_task)をストップさせる。
この構造体は、後の説明にも出てきますので注意して読み進めてください。
4.2.3 RTLinuxモジュールの動き
ここでは、RTLinuxモジュール(module2.o)の動きに注目して見てみます。
RTLinuxモジュールでは、周期的な送受信処理を実現するために、init_module関数内で、幾つか
リソースを生成しています。それを下表に示します。
項 目
内 容
RT-FIFO(FIFO_COMMAND) Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハ
ンドラmy_handlerに渡されます。
RT-FIFO(FIFO_THRU_CMD) ハンドラにて、Linuxプロセスから受け取った情報を、周期送信処理
を実現するRTLinuxスレッド(my_task)に渡すためのRT-FIFOです。
RT-FIFO(FIFO_RESULT)
コールバック関数(my_recv_callback)にて受け取ったデータを、Linux
プロセスに返すためのRT-FIFOです。
Linuxプロセスからの指示を受け取るための処理の入り口です。
ハンドラ(my_handler)
RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る
処理に回されます。
周期送信処理を実現するRTLinuxスレッドです。
RTLinuxスレッド(my_task)
Linuxプロセスから送られる指示は、最終的にここに送られ、周期送
信処理を実現します。
Interface Corporation
- 38 -
TUT-0043
次に、生成された各リソースの相互関係と処理の流れを下図に示します。
Linux プロセス
FFO_COMMAND
コマンド指示
ハンドラ(my_handler)
FIFO_THRU_CMD
FIFO_RESULT
RTLinux スレッド(my_task)
ID_START
受信データ
ID_STOP
周期送信
ComRTWrite 関数
←周期呼び出し
チャンネル 1 からチャンネル 2 に
データの送信
コールバック関数(my_recv_callback)
調歩同期通信
ドライバモジュール
受信イベント発生
データ受信
ComRTRead 関数
RTLinuxモジュール内の処理の流れ
RTLinuxモジュール内で中心となるのは、周期送信処理を実現するRTLinuxスレッド(my_task)と、
受信処理を行うコールバック関数(my_recv_callback)です。
RTLinuxスレッドは、Linuxプロセスからの指令により、スタート(ID_START),ストップ(ID_STOP)
を行います。スタート後の実行中、スレッドは周期ごとにデータの送信を行います。
コールバック関数は、調歩同期通信ドライバモジュール内で、送信されたデータが受信された時
や、溜まったデータが一定数に達する時に呼ばれます。ここでは、溜まったデータを抜き取り、
LinuxプロセスへRT-FIFOを経由して送ります。
(145∼155行目:RT-FIFOおよびハンドラの生成)
init_module関数の最初の段階では、RTLinuxモジュールおよびLinuxプロセスで使用するRT-FIFO
および、Linuxプロセスからの指示を受け取るハンドラを生成しています。
(158∼169行目:送信用シリアルポートのオープン)
158行目のserarch_rcp4141port関数は、指定するデバイスID,サブシステムID,RSW1番号,チャンネル
番号に合致するデバイスを検索し、該当するデバイスに関連付けられているポート番号を返しま
す。
163行目のComRTOpen関数は、返されたポート番号を基にオープンを行っています。
この処理は、構築したシステムを別の場所に移築した際、ポート番号の割り振りが変化しても、
常に目的のシリアルポートをオープンさせるための工夫です。
(172∼183行目:受信用シリアルポートのオープン)
先のコードは、送信用シリアルポートのオープンを行いましたが、こちらでは受信用のシリアル
ポートをオープンしています。
- 39 -
Interface Corporation
TUT-0043
(186∼214行目:シリアルポートの通信パラメータの設定)
ここでは、送信用シリアルポートと受信用シリアルポートに対して、通信用パラメータの設定を
行っています。
まず、186行目のComRTGetConfig関数で通信パラメータのデフォルト値を取り出し、通信パラ
メータを幾つか修正した後、199行目のComRTSetConfig関数で送信用シリアルポートの通信パラ
メータを、210行目のComRTSetConfig関数で受信用シリアルポートの通信パラメータの設定を行
っています。
受信用シリアルポートでは、送信用シリアルポートの設定に比べ、後の処理でコールバック関数
を使用するために、コールバック関数の登録と、コールバック関数が呼び出される受信トリガイ
ベントの設定を行っています。
(216行目:コールバック関数の条件設定)
216行目のComRTSetEventMask関数は、先のComRTSetConfig関数で登録した受信用シリアルポー
トのコールバック関数に対して、どのような条件でコールバック関数を呼び出させるか設定して
います。
ここでは、受信データサイズが受信トリガサイズに達した時に呼ばれるよう、
COMRT_EVENT_RXTRIGGER(=1)を設定しています。
(223行目:pthread_create関数)
pthread_create関数では、周期送信処理を実行するRTLinuxスレッド(my_task)を生成しています。
(122∼130行目:ハンドラの処理)
ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinux
スレッド(my_task)に渡すことにあります。
この処理は、ほとんど定型的なものです。
Linux プロセス側
rtf_get
RT-FIFO
my_handler
ハンドラ
rtf_put
RTLinux スレッド側
RT-FIFO
LinuxプロセスからRTLinuxスレッドへのデータの流れ
(78∼109行目:RTLinuxスレッドの処理)
RTLinuxスレッド(my_task)の処理の中心は、この78∼109行のwhileループです。
ここで、Linuxプロセスから与えられた指示によって、周期実行の開始と停止を行い(87∼98行の
処理)、周期実行ごとに102∼103行目のsprintfで生成したデータを、104行目のComRTWrite関数で
送信しています。
Interface Corporation
- 40 -
TUT-0043
周期実行の開始と停止は、先に述べたCMD_IDS列挙体の定数値により決定されます。
ID_START smp_period_msメンバ変数の値をms単位の実行周期として、
pthread_make_periodic_np関数を呼び出し、自身の実行周期の間隔を指定している。
ID_STOP
pthread_suspend_np関数を呼び出し、自身のスレッドをスリープ状態にしている。
周期実行の間隔は、smp_period_msの値により決定されます。
例えばここで100の値が指定されると、100msごとに送信処理が行われます。
(38∼65行目:コールバック関数の処理)
RTLinuxスレッドのComRTWrite関数でチャンネル1より送信されたデータは、チャンネル2で受信
され、ドライバモジュールがデータを内部バッファに溜め込みます。
そして、データの量が指定バイト数に達した時(206行目のRxEventTriggerメンバ変数の値)、調歩同
期通信ドライバモジュールはコールバック関数(my_recv_callback)を呼び出します。
47行目のif文は、コールバック関数が呼ばれる際に渡された第1引数(event_factor)の値をチェック
しています。この引数は、コールバック関数が呼ばれた理由がセットされているので、ここでは、
処理する目的に合致しているか確認しています。
53行目のComRTRead関数は、内部バッファに溜まった受信データを取り出す処理を行っています。
この関数を呼び出すと、取り出した受信データのバイト数が返ります。
呼び出しに失敗したら負の値が返ります。
呼び出しに成功すると、58行目に移ります。ここで取り出した受信データの最後にヌル文字(‘¥0’)
をセットしています。これは、取り出した受信データを、文字列として扱えるようにするために
行っています。
ComRTRead関数自体は、受信データをバイナリデータとして扱うため、文字列の終端記号(ヌル文
字)をバッファの最後尾に書き込むことは行いません。そのため、このような処理を行っています。
63行目のrtf_put関数は、取り出した受信データを、RT-FIFO経由でLinuxプロセスに送っています。
- 41 -
Interface Corporation
TUT-0043
4.2.4 Linuxプロセスの動き
ここでは、Linuxプロセス(sample2)の動きに注目して見てみます。
まず、LinuxプロセスとRTLinuxモジュールとの関係を、下図に示します。
コマンド指令
RTLinux
RT-FIFO(FIFO_COMMAND)
モジュール
main
受信データ取得
RT-FIFO(FIFO_RESULT)
LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係
Linuxプロセスは、RT-FIFOを2つほどオープンし、それぞれコマンド指令と、RTLinuxモジュール
からの受信データの取得に使用しています。
(29∼39行目:RT-FIFOのオープン処理)
ここでは、open関数を使用し、RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープン
しています。
(42∼47行目:周期的な送信の開始)
ここでは、RTLinuxモジュールに対して、周期的な送信を開始させるため、CMD_STRUCT構造体
に、周期送信開始を意味するID_START列挙定数と周期間隔を指定し、write関数を使ってRT-FIFO
経由で指示を送っています。
RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。
(50∼67行目:受信データの取得)
ここでは、RTLinuxモジュール内で実行される周期的な送信データを受け取った受信データを、
select関数とread関数を使って取得しています。
受信データの取得はtime関数を用い、約5秒間行っています。
(70∼75行目:周期的な送信の停止)
ここでは、RTLinuxモジュールに対して周期的な送信を停止させるため、CMD_STRUCT構造体に
周期送信停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で指示を送
っています。
RTLinuxモジュールはこの指示を受け取った後、実行を停止します。
Interface Corporation
- 42 -
TUT-0043
4.3 マルチメータからのデータの取り込み
先程は、周期的なデータの送信と受信を行いました。ここでは、計測器と接続して制御を行って
見ます。
! 注意
ここで使う調歩同期通信I/Oモジュールは、接続相手であるAgilent34401AがRS-232C通信イ
ンタフェースを採用しているため、RS-232Cを通信インタフェースに持つI/Oモジュールでない
と動かせません。予めご了承ください。
ここでは、以下の製品を使用します。
PCI-4141
RS-232Cリバースケーブル
Agilent34401A
1枚:調歩同期通信I/Oモジュール
1本:9ピンD-subコネクタ←→9ピンD-subコネクタ接続ケーブル
1台:マルチメータ アジレント・テクノロジー社製
下図に、接続構成を示します。
CH1
PCI-4141
RSW1:0
Agilent34401A
RS-232C リバースケーブル
I/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに調歩同期シリアル通
信製品を実装します。
PCI-4141のチャンネル1とAgilent34401Aの背面のRS-232Cコネクタを、RS-232C リバースケーブル
で接続します。
以下の4つのファイルを作成します。
ファイル名
備 考
sample3.h
LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル
module3.c
RTLinuxモジュールのソースコード
sample3.c
Linuxプロセスのソースコード
makefile
上記ソースコードをコンパイルするためのmakefile
- 43 -
Interface Corporation
TUT-0043
List4-5は、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名
を「sample3.h」として保存してください。
List4-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
27
28
29
30
31
32
33
34
35
36
37
38
/*
sample3.h 共通定義ヘッダファイル
Copyright 2002 Interface Corporation. All rights reserved.
*/
#if
!defined(___SAMPLE2_H)
#define
___SAMPLE2_H
#include
"pcicomrt.h"
/* Constants --------------------------------------------------------------- */
#defineFIFO_COMMAND
1 /* Linuxプロセスから指令を受け取るRT-FIFO */
#defineFIFO_THRU_CMD
2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */
#defineFIFO_RESULT
3 /* RTLinux内で受信したデータをLinuxプロセスに送るRT-FIFO */
#defineDEVICE_ID
#defineSUB_SYSTEM_ID
#defineRSW_NO
#defineSEND_RECV_CH
4141
/* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */
0x0001 /* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */
0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */
1 /* 送受信用に指定するチャンネル番号 */
#defineBUFF_SIZE
1000
/* Linuxプロセスへ結果を送るRT-FIFOのサイズ */
/* Command ID -------------------------------------------------------------- */
/* コマンドID群(RTLinuxスレッドへの指示用) */
enum CMD_IDS {
ID_START,
/* 周期的な送信のスタート指示 */
ID_STOP
/* 周期的な送信のストップ指示 */
};
/* コマンド指示用の構造体 */
struct CMD_STRUCT {
enum CMD_IDS
id;
};
/* コマンドID */
/* 各コマンドに対する設定パラメータ */
long
smp_period_ms;
/* ID_START時使用:周期の設定(ms単位) */
#endif
Interface Corporation
- 44 -
TUT-0043
List4-6は、RTLinuxモジュールのソースファイルです。ファイル名を「module3.c」として保存し
てください。
List4-6 module3.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
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
/*
*/
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;
int
g_port_no = -1;
/* 送受信用のシリアルポート番号 */
/* 指定したデバイスID等の情報に合致するポート番号を検索する */
int search_rcp4141port(unsigned long DeviceID, unsigned long SubsystemID,
unsigned long BoardID, unsigned long ChannelNumber)
{
int
port_no;
COMRT_PORTINFO port_info;
}
/* 最大ポート番号まで、条件に合致するポート番号を検索する */
for(port_no = 0; port_no < COMRT_MAX_PORTS; port_no++) {
if(ComRTGetPortInformation(port_no, &port_info) == 0){
if( port_info.DeviceID == DeviceID &&
port_info.SubsystemID == SubsystemID &&
port_info.BoardID == BoardID &&
port_info.ChannelNumber == ChannelNumber) {
return port_no;
/* 見つかった:ポート番号を返す */
}
}
}
return -1;
/* 見つからなかった:-1を返す */
/* Agilent34401Aに対して、送信処理を行う関数 */
int send_hp34401a(int port_no, char* msg)
{
int
ret;
rtl_printf("send_hp34401a port_no=%d msg=%s¥n", port_no, msg);
}
ret = ComRTWrite(port_no, msg, strlen(msg));
/* データの送信 */
if(ret){
rtl_printf("send_hp34401a: ComRTWrite error [ret=%x]¥n", ret);
}
return ret;
/* Agilent34401Aから受信処理を行う関数 */
int recv_hp34401a(int port_no, char* buff, int buff_size)
{
int
recv_len;
rtl_printf("recv_hp34401a port_no=%d buff=%p buff_size=%d¥n", port_no, buff, buff_size);
}
recv_len = ComRTRead(port_no, buff, buff_size); /* データの受信 */
if(recv_len < 0){
rtl_printf("recv_hp34401a: ComRTRead error [recv_len=%x]¥n", recv_len);
}
return recv_len;
/* 受信時にコールバックされる関数 */
void my_recv_callback(unsigned long event_factor, unsigned long user_data)
{
int
recv_len;
- 45 -
Interface Corporation
TUT-0043
70
71
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
char
recv_buff[50];
rtl_printf("my_recv_callback called event_factor=%lx user_data=%ld¥n", event_factor, user_data);
do{
/* 目的のイベント(受信トリガサイズに達した)か? */
if((event_factor & COMRT_EVENT_RXTRIGGER) == 0){
rtl_printf("my_recv_callback: disappointed event factor¥n");
break;
}
/* データの受信 */
recv_len = recv_hp34401a(g_port_no, recv_buff, sizeof(recv_buff) - 1);
if(recv_len < 0){
rtl_printf("my_recv_callback: recv_hp34401a error [recv_len=%d]¥n", recv_len);
break;
} else {
recv_buff[recv_len] = '¥0';
rtl_printf("my_recv_callback: recv data=%s", recv_buff);
}
/* 受信したデータを、RT-FIFO経由でLinuxプロセスに送る */
rtf_put(FIFO_RESULT, recv_buff, recv_len);
}
/* RTLinuxスレッドを起床させる */
pthread_wakeup_np(my_task_info);
}while(0);
/* 周期的な送信を行うRTLinuxスレッド */
void* my_task(void* arg)
{
int
ret;
struct CMD_STRUCT cmd;
struct timespec
t;
rtl_printf("my_task called arg=%d¥n", arg);
/* Agilent34401Aを初期化させる */
send_hp34401a(g_port_no, "*RST¥r¥n");
/* RTLinuxスレッドが組み込み中、動作する永久ループ */
while(1){
/* 自スレッドを、次の周期までスリープさせる */
pthread_wait_np();
/* RT-FIFOからの指示があれば取り込み */
ret = rtf_get(FIFO_THRU_CMD, &cmd, sizeof(cmd));
if(ret == sizeof(cmd)){
rtl_printf("my_task: get command id=%d¥n", cmd.id);
switch(cmd.id){
case ID_START:
/* 周期的な送信のスタート */
rtl_printf("my_task: send cycle is start!!¥n");
/* Agilent34401Aをリモート状態にする */
send_hp34401a(g_port_no, "System:REMOTE¥r¥n");
pthread_make_periodic_np(pthread_self(), gethrtime(),
cmd.smp_period_ms * 1000 * 1000);
break;
case ID_STOP:
/* 周期的な送信のストップ */
rtl_printf("my_task: send cycle is stop!!¥n");
/* Agilent34401Aをリモート状態から解除する */
send_hp34401a(g_port_no, "System:LOCAL¥r¥n");
pthread_suspend_np(pthread_self());
break;
default:
rtl_printf("unknown id!!¥n"); break;
}
} else {
t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME));
rtl_printf("now clock=%ld¥n", t.tv_sec);
/* Agilent34401Aに対して、電圧の計測を要求 */
Interface Corporation
- 46 -
TUT-0043
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
send_hp34401a(g_port_no, ":Measure:Voltage:DC?¥r¥n");
}
}
}
return 0;
/* 自スレッドをサスペンドさせ、受信完了時の起床待ちに入る */
pthread_suspend_np(pthread_self());
/* Linuxプロセスからの指令を受け取るハンドラ */
int my_handler(unsigned int fifo)
{
int
ret;
struct CMD_STRUCT cmd;
rtl_printf("my_handler called fifo=%d¥n", fifo);
}
/* Linuxプロセスの指示に従って、RTLinuxスレッド等の制御を行う */
while((ret = rtf_get(FIFO_COMMAND, &cmd, sizeof(cmd))) == sizeof(cmd)){
rtf_put(FIFO_THRU_CMD, &cmd, sizeof(cmd));
rtl_printf("my_handler: get command id=%d¥n", cmd.id);
pthread_wakeup_np(my_task_info);
}
if(ret != 0){
rtl_printf("my_handler: error!!(%d)¥n", ret);
return -EINVAL;
}
return 0;
/* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */
int init_module(void)
{
int
ret;
COMRT_CONFIG
conf;
rtl_printf("init_module called¥n");
EXPORT_NO_SYMBOLS;
/* Linuxプロセスからの指示を受け取るハンドラとRT-FIFOを生成する */
rtf_destroy(FIFO_COMMAND);
rtf_create(FIFO_COMMAND, sizeof(struct CMD_STRUCT));
rtf_create_handler(FIFO_COMMAND, my_handler);
/* ハンドラとRTLinuxスレッドの間のRT-FIFOを生成する */
rtf_destroy(FIFO_THRU_CMD);
rtf_create(FIFO_THRU_CMD, sizeof(struct CMD_STRUCT));
/* コールバックとLinuxプロセスの間のRT-FIFOを生成する */
rtf_destroy(FIFO_RESULT);
rtf_create(FIFO_RESULT, sizeof(char) * BUFF_SIZE);
/* シリアルポートのオープン */
g_port_no = search_rcp4141port(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, SEND_RECV_CH);
if(g_port_no < 0){
rtl_printf("Fail find send channel device.¥n");
return -1;
}
ret = ComRTOpen(g_port_no);
if(ret){
rtl_printf("ComRTOpen error [ret=%x]¥n", ret);
return –2;
} else {
rtl_printf("ComRTOpen success!! [port no=%d]¥n", g_port_no);
}
/* シリアルポートの通信パラメータのデフォルト値の取得 */
ret = ComRTGetConfig(g_port_no, &conf);
if(ret){
rtl_printf("ComRTGetConfig error [ret=%x]¥n", ret);
return –3;
}
/* 送信用通信パラメータの変更 */
conf.DuplexMode
= COMRT_FULL_DUPLEX;
- 47 -
/* 全二重に設定 */
Interface Corporation
TUT-0043
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
conf.BaudRate
= 9600;
/* 通信速度を9600bpsに設定 */
conf.Parity
= COMRT_PARITY_NONE;/* パリティビットなし */
conf.StopBits
= COMRT_TWO_STOPBITS;
/* ストップビットは2ビット */
conf.WordLength
= 8;
/* データ長は8ビット */
/* 17バイト受信時に受信トリガイベント発生 */
conf.RxEventTrigger = 17;
conf.CallbackProc
= my_recv_callback;
/* 受信用シリアルポートのコールバックを登録 */
/* コールバックの引数に、ポート番号を指定 */
conf.UserData
= g_port_no;
/* シリアルポートへの通信パラメータの設定 */
ret = ComRTSetConfig(g_port_no, &conf);
if(ret){
rtl_printf("ComRTSetConfig error [ret=%x]¥n", ret);
return –4;
}
/* シリアルポートに対し、コールバックが行われる条件を設定 */
ret = ComRTSetEventMask(g_port_no, COMRT_EVENT_RXTRIGGER);
if(ret){
rtl_printf("ComRTSetEventMask error [ret=%x]¥n", ret);
return –5;
}
/* ER,RS信号をONにする */
ComRTSetModemStatus(g_port_no, 6);
}
/* RTLinuxスレッドを作成、起動する */
return pthread_create(&my_task_info, NULL, (void*)my_task, 0);
/* 終了関数(モジュールが取り外される時、呼ばれる関数) */
void cleanup_module(void)
{
int
ret;
rtl_printf("cleanup_module called¥n");
/* 送信用シリアルポートをクローズする */
ret = ComRTClose(g_port_no);
if(ret){
rtl_printf("ComRTClose error [ret=%d]¥n", ret);
}
/* RT-FIFOを閉じる */
rtf_destroy(FIFO_COMMAND);
rtf_destroy(FIFO_THRU_CMD);
rtf_destroy(FIFO_RESULT);
}
/* RTLinuxスレッドを終了させる */
pthread_cancel(my_task_info);
pthread_join(my_task_info, NULL);
List4-7は、Linuxプロセスのソースファイルです。ファイル名を「sample3.c」として保存してくだ
さい。
List4-7 sample3.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
*/
sample3.c Linuxプロセスのソースコード
Copyright 2002 Interface Corporation. All rights reserved.
#include
#include
#include
#include
#include
#include
#include
#include
<stdio.h>
<fcntl.h>
<unistd.h>
<math.h>
<sys/time.h>
<sys/ioctl.h>
<rtl_fifo.h>
"sample3.h"
/* Linuxプロセスのメインルーチン */
int main(void)
{
int
fd_result, fd_cmd;
Interface Corporation
- 48 -
TUT-0043
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
72
73
74
75
76
77
78
79
80
81
82
fd_set
rfds;
struct timeval tv;
struct CMD_STRUCT cmd;
char
rt_fifo_name[80];
time_t
start_time;
char
recv_buff[80];
int
recv_len;
/* RTLinuxモジュールに指令を送るRT-FIFOのオープン */
sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND);
if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){
fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);
return -1;
}
/* RTLinuxモジュールからの結果を受け取るRT-FIFOのオープン */
sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT);
if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){
fprintf(stderr, "Fail to open %s¥n", rt_fifo_name);
return –2;
}
/* 周期的な送信の開始指示 */
cmd.id
= ID_START;
cmd.smp_period_ms = 500;
/* 500ms周期の送信設定 */
if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){
fprintf(stderr, "Failled to send the start command.¥n");
return –3;
}
/* 5秒間、受信監視を行う */
start_time = time(NULL);
while(fabs(difftime(time(NULL), start_time)) < 5.0){
FD_ZERO(&rfds);
FD_SET(fd_result, &rfds);
tv.tv_sec = 30; /* select関数のタイムアウト値の設定:30秒 */
tv.tv_usec = 0;
}
/* 受信データの受け取り */
if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){
if(FD_ISSET(fd_result, &rfds)){
/* fd_resultに対してRT-FIFOの書き込みがあった */
recv_len = read(fd_result, recv_buff, sizeof(recv_buff) - 1);
if(recv_len >= 0){
recv_buff[recv_len] = '¥0';
printf("recv data=%s¥n", recv_buff);
}
}
}
/* 周期的な送信の停止指示 */
cmd.id
= ID_STOP;
cmd.smp_period_ms = 0;
if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){
fprintf(stderr, "Failled to send the stop command.¥n");
return –4;
}
printf("fd_cmd:%d¥n", close(fd_cmd));
printf("fd_result:%d¥n", close(fd_result));
}
printf("The Linux proccess is successfully completed.¥n");
return 0;
- 49 -
Interface Corporation
TUT-0043
List4-8は、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として
保存してください。
List4-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) -O3 -Wall -o sample3 sample3.c
module3.o:module3.c
$(CC) $(INCLUDE) $(CFLAGS) -o module3.o -c module3.c
プ ロ グ ラ ム を 動 か す 前 に 、 Agilent34401A の マ ニ ュ ア ル を 参 照 し 、 フ ロ ン ト パ ネ ル か ら
Agilent34401Aを以下の設定に合わせてください。
項目(E:Input/Output MENU内)
INTERFACE
RS-232C
BAUD RATE
9600 BAUD
PARITY
NONE: 8BITS
LANGUAGE
SCPI
設定値
コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。
# make
# ls
makefile sample3 module3.c module3.o sample3.c sample3.h
# insmod module3.o ← RTLinux モジュールを組み込んでいます
次に、Linuxプロセスを実行します。
# ./sample3
← Linux プロセスを実行しています
実行画面を以下に示します。
(画面左上のウィンドウがLinuxプロセスを実行しているコンソール。画面右下のウィンドウは
RTLinuxモジュールのログメッセージを表示させているコンソールです)
サンプルの実行画面例
sample3を実行させると、Agilent34401Aから取得した電圧値のデータが繰り返し出力され、暫くし
てプログラムが終了します。
Interface Corporation
- 50 -
TUT-0043
4.4 マルチメータからのデータの取り込み解説
それでは、先程のプログラムの解説を行います。
プログラムの大まかな動きを、下図に示します。
Linux プロセス
Agilent34401A
チャンネル 1
データ送信
“*RST¥r¥n”
スタート指令
データ受信
データ送信
“System:REMOTE¥r¥n”
データ受信
データ送信
“:Measure:Voltage:DC?¥r¥n”
XXms 周期
データ受信
計測した電圧値のデータ
計測
データ送信
データ受信
データ送信
“:Measure:Voltage:DC?¥r¥n”
データ受信
計測した電圧値のデータ
計測
データ送信
データ受信
ストップ指令
データ送信
“System:LOCAL¥r¥n”
データ受信
sample3の動作概要
プログラム起動直後、チャンネル1のシリアルポートからAgilent34401Aに対して、Agilent34401A
を初期化する命令(” *RST¥r¥n”)が送信されます。
これは、RTLinuxスレッドの起動直後に行われます。
Linuxプロセスからスタート指示があると、まず、チャンネル1のシリアルポートからAgilent34401A
をリモート状態にする命令(” System:REMOTE¥r¥n”)が送信されます。
その後、Agilent34401Aに計測を指示する命令(“:Measure:Voltage:DC?¥r¥n”)が送信されます。
この命令は、周期的に送信されます。
Agilent34401Aでは、計測を指示する命令を受けると、現在の電圧を計測します。
チャンネル1は、Agilent34401Aが計測した電圧値を受け取るためにデータの受信を行います。
プログラムでは、データの受信を行った時、RT-FIFOを介してLinuxプロセスにデータを送ってい
ます。
- 51 -
Interface Corporation
TUT-0043
Linuxプロセスからストップ指示があると、チャンネル1からリモート状態を解除する命令
(“System:LOCAL¥r¥n”)が送信されます。
チャンネル1の送信処理は、RTLinuxスレッド(my_task)が行っています。
受信処理は、調歩同期通信のドライバモジュールから呼ばれるコールバック関数
(my_recv_callback)が行っています。
Linuxプロセスの仕事は、通信処理を行うRTLinuxモジュールに対する周期処理のスタート指令,ス
トップ指令,Agilent34401Aから受信した電圧値のデータをRT-FIFO経由で受け取ることです。
次に、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。
main
ユーザ空間
Linux プロセス(sample3)
RTLinux モジュール(module3.o)
FIFO_COMMAND
カーネル空間
指令
my_handler
破棄
生成
FIFO_THRU_CMD
init_module
cleanup_module
指令の転送
生成
my_task
破棄
FIFO_RESULT
コールバック生成
受信イベント
受信データ
my_recv_callback
LinuxプロセスとRTLinuxモジュールの相関関係
実は、各々の生成関係は、『34ページ 4.2 周期的なデータの送受信の解説』と全く同じです。
Linuxプロセスからの指示は、RT-FIFOを経由して、my_handler→my_taskの順に流れていきます。
受信結果をmy_recv_callbackからRT-FIFOを経由してLinuxプロセスに返すのも同じです。
Interface Corporation
- 52 -
TUT-0043
4.4.1 sample2/module2との違い
先のサンプルと比較すると分かりますが、双方のコードは、非常に似ています。
共通定義ファイル(sample2.hとsample3.h),Linuxプロセスのコード(sample2.cとsample3.c)は、コメン
ト文等一部が異なるだけで、全く同じと言っても差し支えないでしょう。
また、RTLinuxモジュールのコード(module2.cとmodule3.c)も、内容を吟味すると、非常に構造が
似ていることがわかります。
sample2/module2は2チャンネル間の通信、sample3/module3は計測器の制御で、処理が異なると思
われますが、基本的な部分で類似点が多いため、このように似ています。
4.4.2 RTLinuxモジュールの動き
ここでは、RTLinuxモジュール(module3.o)の動きに注目して見てみます。
RTLinuxモジュールでは、周期的な送受信処理を実現するために、init_module関数内で、幾つかリ
ソースを生成しています。それを下表に示します。
項 目
内 容
RT-FIFO(FIFO_COMMAND)
Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハ
ンドラmy_handlerに渡されます。
RT-FIFO(FIFO_THRU_CMD)
ハンドラにて、Linuxプロセスから受け取った情報を、周期送信処理
を実現するRTLinuxスレッド(my_task)に渡すためのRT-FIFOです。
RT-FIFO(FIFO_RESULT)
コールバック関数(my_recv_callback)にて受け取ったデータを、Linux
プロセスに返すためのRT-FIFOです。
ハンドラ(my_handler)
Linuxプロセスからの指示を受け取るための処理の入り口です。
RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然
る処理に回されます。
RTLinuxスレッド(my_task)
周期送信処理を実現するRTLinuxスレッドです。
Linuxプロセスから送られる指示は、最終的にここに送られ、周期送
信処理を実現します。
- 53 -
Interface Corporation
TUT-0043
次に、生成された各リソースの相互関係と処理の流れを下図に示します。
Linux プロセス
FFO_COMMAND
コマンド指示
ハンドラ(my_handler)
FIFO_THRU_CMD
FIFO_RESULT
RTLinux スレッド(my_task)
ID_START
受信データ
ID_STOP
周期送信
ComRTWrite 関数
←周期呼び出し
HP34401A に命令を送信
コールバック関数(my_recv_callback)
調歩同期通信
ドライバモジュール
受信イベント発生
データ受信
ComRTRead 関数
RTLinuxモジュール内の処理の流れ
基本的な流れは、先のsample2/module2と変わりません。
送受信している処理の中身が、計測器とのやり取りに置き換わっただけです。
(177∼248行目:初期化の処理)
RT-FIFOとハンドラの生成部分は変わりがありません。
違いは、オープンしているシリアルポートが2つから1になり(200∼211行目)、通信用パラメータが
少し変化しています(221∼228行目)。
この変化は、接続相手であるAgilent34401Aの通信設定に合わせたものです。
後は、コールバック関数の登録とイベントの値,スレッドの生成まで同じです。
唯一異なる点は、244行目のComRTSetModemStatus関数で、ER信号をONにしていることです。
Agilent34401Aとの通信では、ER信号をONにしないと通信が行えないので、このようにしていま
す。
(156∼174行目:ハンドラの処理)
ハンドラの処理内容は、先のサンプルと全く同じです。
(100∼153行目:RTLinuxスレッドの処理)
RTLinuxスレッドの処理は、基本的には先のサンプルと同じですが、送信内容と、受信用のコール
バック関数の連携方法が少々異なります。
送信内容の意味については、Agilent34401Aのマニュアル中のコマンド説明と見比べながら読み進
めることをお奨めします。
Interface Corporation
- 54 -
TUT-0043
まず、RTLinuxスレッド起動直後、109行目で"*RST¥r¥n"という文字列を、Agilent34401Aに送信し、
Agilent34401Aを初期化させています。
次に、Linuxプロセスからスタート指示が入ると、122∼130行目の処理が行われます。
ここでは、Agilent34401Aに対して"System:REMOTE¥r¥n"を送信し、リモート状態に設定するのと
(126行目)、RTLinuxスレッド自身の周期実行時間の設定(128行目)を行っています。
スタートが指示されると、周期的にスレッドが呼び出されます。Linuxプロセスから指示が無い場
合、142∼149行目の処理が実行されます。
ここでは、Agilent34401Aに対して":Measure:Voltage:DC?¥r¥n"を送信し、Agilent34401Aが電圧の計
測を行うよう指示しています。
次のpthread_suspend_np関数は、自スレッドを一旦サスペンド状態にしています。
このサスペンド処理の意味については、受信用コールバック関数の最後の方、95行目の
pthread_wakeup_np関数と比較して読まれると良いです。
つまり、ここで一旦サスペンド状態にした後、内部ではAgilent34401Aからのデータを受信し、受
信用のコールバック関数が呼ばれます。
ここで、受信データの取り出し処理が行われた後、pthread_wakeup_np関数で、サスペンド状態に
されたRTLinuxスレッドを再び起床させているのです。
RTLinux スレッド
受信用コールバック
pthread_suspend_np 関数
Agilent34401A
":Measure:Voltage:DC?¥r¥n"
サスペンド
計測
計測した電圧値のデータ
pthread_make_periodic_np
関数の設定時間
pthread_wakeup_np 関数
起床
pthread_suspend_np 関数
":Measure:Voltage:DC?¥r¥n"
サスペンド
計測
計測した電圧値のデータ
pthread_wakeup_np 関数
起床
RTLinuxスレッドとコールバックとAgilent34401Aの処理関係
- 55 -
Interface Corporation
TUT-0043
(67∼97行目:コールバック関数の処理)
受信用のコールバック関数の処理は、Agilent34401Aから受け取った電圧値のデータを取り出し、
RT-FIFO経由でLinuxプロセスに送ることにあります。
その後、先に説明したように、スリープ状態のRTLinuxスレッドを95行目のpthread_wakeup_np関
数で起床させています。
(37∼63行目:送信と受信のサブルーチン)
37∼48行目のsend_hp34401a関数と、52∼63行目のrecv_hp34401a関数は、Agilent34401Aに対する送
信と受信のサブルーチンです。
内部ではそれぞれ、ComRTWrite関数とComRTRead関数を用いています。
送受信のエラー判定をまとめるために、このようにしています。
Interface Corporation
- 56 -
TUT-0043
第5章 デバッグ手法
これまでの章で、RTLinux上での調歩同期通信制御プログラミングはどのようなものかがお分かり
頂けたと思います。この後、プログラミングを行っていく上で、避けては通れないデバッグをサ
ポートする機能を説明します。
作成したプログラムは、調歩同期通信ドライバを使用した部分の処理と、調歩同期通信ドライバ
を使用しない部分の処理に分かれると思います。調歩同期通信ドライバを使用しない部分につい
ては、デバッグのやり方(rtl_printfの説明,gdbの使用方法等)をRTLinuxチュートリアル導入編に記載
していますので、そちらを参照してください。
ここでは、RTLinux 調歩同期通信ドライバを使用した部分の処理について、デバッグ手法を紹介
していきます。
5.1 ドライバデバッグ支援機能を使ってみる
GPG-4141のドライバには、デバッグ情報を出力するデバッグ支援機能がついています。ドライバ
組み込み時、rcp4141_debuglevelパラメータにデバッグレベルを指定することでドライバデバッグ
情報が出力されます。
デバッグレベルは以下の5段階があります。
rcp4141_debuglevelパラメータはrcp4141使用時に指定します。rcp4161使用時はrcp4161_debuglevel
パラメータを使用してください。
デバッグレベル
機 能
0
デバッグ情報を出力しません
1
関数呼び出しトレース
2
エラー情報
4
I/Oモジュールリソース情報
16
制御信号情報
ドライバ組み込み時にオプションを指定しない場合は、デバッグレベルは0となります。
デバッグ支援機能を使うと、システムの負荷が高くなってしまうため、デバッグ時以外は、この
機能を使用しないようにしてください。
★デバッグ情報を複数出力する
デバッグレベルの値の算術和を取った値を指定することで、複数のデバッグレベルを使用できます。
例)関数呼び出しトレースとエラー情報を出力する場合(‘=’の前後にスペースは要りません)
# modprobe rcp4141 rcp4141_debuglevel=3 ← rcp4141 使用時
# modprobe rcp4161 rcp4161_debuglevel=3 ← rcp4161 使用時
- 57 -
Interface Corporation
TUT-0043
5.1.1 関数呼び出しトレース
この関数呼び出しトレースを使用すると、処理の実行状況や関数呼び出し時の引数の値を容易に
知ることができます。では実際にデバッグ支援機能を使用して、さきほど作成したサンプルプロ
グラムを動かしてみます。
関数呼び出しトレースを指定して、ドライバを組み込みます。
(‘=’の前後にスペースは必要ありません)
# modprobe rcp4141 rcp4141_debuglevel=1
次にシステム内のI/Oモジュール情報の列挙,初期化,終了処理を行うモジュール(「List 3-1
sample1.c」で作成したsample1.o)を組み込んでみます。
# insmod sample1.o
現段階では、ComRTGetPortInformation関数とComRTOpen関数が呼び出されているはずです。それ
では、ログを確認します。
#less /var/log/messages
…
May 21 11:11:47 localhost
May 21 11:11:47 localhost
(0, [0xc4bcdee4])
May 21 11:11:47 localhost
----May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
May 21 11:11:47 localhost
(1, [0xc4bcdee4])
May 21 11:11:47 localhost
----…
May 21 11:11:47 localhost
(5, [0xc4bcdee4])
May 21 11:11:47 localhost
(6, [0xc4bcdee4])
May 21 11:11:47 localhost
(7, [0xc4bcdee4])
…
(END)
kernel: init_module called
kernel: rcp4141:ComRTGetPortInformation
kernel: ----- Serial Port Information
kernel:
kernel:
kernel:
kernel:
kernel:
kernel:
kernel:
kernel:
kernel:
kernel:
PortNo:0
VendorID:1147h
DeviceID:4141
SubsystemID:0001h
RevisionID:0
BoardID:0
ChannelNumber:1
BaseAddress:b800h
IRQ No:7
rcp4141:ComRTGetPortInformation
kernel: ----- Serial Port Information
kernel: rcp4141:ComRTGetPortInformation
kernel: rcp4141:ComRTGetPortInformation
kernel: rcp4141:ComRTGetPortInformation
ログにもComRTGetPortInformation関数,ComRTOpen関数の順番に呼び出されていることが分かり
ます。ログ中の[ ]で表されている部分は、引数がポインタの場合の変数のアドレスを示していま
す。
次に組み込んだsample1.oを取り外してみます。
#rmmod sample1
Interface Corporation
- 58 -
TUT-0043
ログを見てみます。ComRTClose関数が呼び出されていることが分かります。
#less /var/log/messages
…
May 21 11:31:33 localhost kernel: cleanup_module called
May 21 11:31:33 localhost kernel: rcp4141:ComRTClose(0)
(END)
以上のように、関数が呼ばれた順番にログが残されています。
5.1.2 エラー情報
エラー情報を出力するように設定しておくと、関数のエラーコードよりも詳細なエラー情報を出
力します。
では、エラー情報出力を指定してドライバを組み込みます。
# modprobe rcp4141 rcp4141_debuglevel=2
「List5-1 sample1.c」を以下のように修正してください。
List 5-1 sample1.c修正
12
51
52
53
追加>
COMRT_CONFIG
cfg;
ComRTGetConfig(g_port_no, &cfg);
cfg.WordLength = 9;
ComRTSetConfig(g_port_no, &cfg);
コンパイルしてモジュールを組み込んでください。
# make
# insmod sample1.o
sample1.o: init_module: 許可されていない操作です
Hint: insmod errors can be caused by incorrect module parameters, including
invalid IO or IRQ parame
ters
エラーが出てドライバモジュールを組み込むことができません。
それでは、ログを見ます。
# less /var/log/messages
…
Jun 18 19:38:57 localhost kernel: rcp4141:ttyST0:
ComRTConfig:WordLength parameter error
最終行のメッセージの内容から、引数パラメータの値が不正であることがわかります。
- 59 -
Interface Corporation
TUT-0043
5.1.3 I/Oモジュールリソース情報
I/Oモジュールのリソースが正常かどうかを見ることにより、ソフトウェアが原因かハードウェア
が原因かを知ることができます。では、I/Oモジュールリソース情報を出力させます。
# modprobe rcp4141 rcp4141_debuglevel=4
I/Oモジュールリソース情報は、ドライバを組み込んだ時点で出力されます。
ではログを見ます。
#less /var/log/messages
Jun
18
18:22:33
localhost
kernel:
rcp4141:ttyST0:DeviceID=0x102d,
SubsystemID=0x1, RevisionID=0x1
Jun 18 18:22:33 localhost kernel: rcp4141:I/O address=0xb800, Irq=7
Jun
18
18:22:33
localhost
kernel:
rcp4141:ttyST1:DeviceID=0x102d,
SubsystemID=0x1, RevisionID=0x1
Jun 18 18:22:33 localhost kernel: rcp4141:I/O address=0xb400, Irq=7
Jun 18 18:22:33 localhost kernel: PCI-4141 support clocks
Jun 18 18:22:33 localhost kernel: 1.8432MHz 7.3728MHz 14.7456MHz 4.9152MHz
4.096MHz 8.0MHz
拡張スロットに実装されているrcp4141が対応しているPCI I/Oモジュールのリソースが表示され
ます。
項 目
DeviceID
SubsystemID
RevisionID
I/O address
Irq
support clocks
内 容
デバイスID
サブシステムID
リビジョンID
I/Oポートアドレス
割り込み番号
サポートする基準クロック
この値が異常の場合(I/Oポートアドレスや割り込み番号が0と表示された場合)は、ハードウェアに
問題が発生していることも考えられます。
Interface Corporation
- 60 -
TUT-0043
5.1.4 制御信号情報
I/Oモジュールの制御信号の状態を確認することができます。
では、制御信号の状態を確認してみましょう。
# modprobe rcp4141 rcp4141_debuglevel=16
sample1.oは、制御信号を制御していないので、Agilent34401Aとの通信制御を行うモジュール「List
4-6 module3.c」で作成したmodule3.oを組み込みます。
このモジュールは、ComRTSetModemStatus関数でER,RS信号を制御しています。
#insmod sample3.o
May 21 13:14:30 localhost
May 21 13:14:30 localhost
May 21 13:14:30 localhost
May 21 13:14:30 localhost
kernel:
kernel:
kernel:
kernel:
init_module called
ComRTOpen success!! [port no=0]
RS:^
ER:^
ログには「RS:^」と「ER:^」が出力されており、RS信号とER信号が変化したことが記録されてい
ます。
記号の意味を以下に示します。
記 号
意 味
^
ON
v
OFF
- 61 -
Interface Corporation
TUT-0043
第6章 リファレンス
この章では、GPG-4141の関数,構造体,および戻り値の一覧を掲載しています。より詳しい情報は、
Helpを参照してください。
6.1 関数一覧
No.
1
2
区 分
初期化終了
3
4
5
6
7
8
9
10
11
12
13
14
15
16
関数名
ComRTOpen
ComRTClose
ComRTSetup
ComRTGetPortInformation
ハード
ウェア
通信設定
ComRTSetConfig
ComRTGetConfig
ComRTWrite
ComRTRead
ComRTSetModemStatus
ComRTGetModemStatus
ComRTErrorStatus
ComRTSendBreak
ComRTFlush
ComRTEnableTransmitter
ComRTSetEventMask
ComRTGetEventMask
送受信
制御信号
その他
イベント
機 能
ポートのオープンを行います。
ポートのクローズを行い、ポートアクセスのた
めに使用されていた各種リソースの解放を行
い、以後シリアルポートへのアクセスを禁止し
ます。
ポートのオープン/クローズと通信設定を行い
ます。
指定したポートのハードウェア情報を取得し
ます。
ポートの通信設定を行います。
ポートの通信設定を取得します。
データを送信します。
受信データを取得します。
制御信号の出力状態を変更します。
制御信号の状態を取得します。
通信エラー情報,通信統計情報を取得します。
ブレーク信号を送信します。
送受信バッファをクリアします。
データラインの切り替えを行います。
イベントマスクを設定します。
イベントマスクを取得します。
6.2 戻り値一覧
エラー識別子
なし
-ENODEV
値
0
-19
-EINVAL
-22
-ENOSPC
-28
-ENOSYS
-38
Interface Corporation
意 味
対処方法
正常終了
ポートが見つかりません。
指定したポートは存在しないか、
オープン
されていません。
設定に間違いがあります。 設定の内容に間違いが無いか、
再度ご確認ください。
送信バッファに空きがあり 送信バッファに空きが生じるまで、
呼び出
ません。
しを待機ください。
現在のモードで、使用でき このAPIを使用できないモードで、APIを
ないAPIを呼び出そうとし 使用しようとしています。
モードを切り替
ました。
えてください。
- 62 -
TUT-0043
技術資料紹介
弊社では下記の技術資料を提供しております。
詳しくは、弊社Web site(www.interface.co.jp)、または弊社窓口までお問い合わせください。
カタログ
PRM-0061
PRM-0062
PRM-0063
CPZカタログ(日本語版)
PCIカタログ(日本語版)
CSIカタログ(日本語版)
チュートリアル
TUT-0058
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
チュートリアル CPZ拡張ユニット 入門編
チュートリアル XP Embedded OS構築編
チュートリアル 画像入力I/Oモジュール
CANチュートリアル
モーションコントロールチュートリアル
RTLinuxによるモーションコントローラI/Oモジュール制御プログラミング チュートリアル(GPG-7400用)
RTLinuxによるメモリンクI/Oモジュール制御プログラミング チュートリアル
RTLinuxによるメモリ共有インタフェースI/Oモジュール制御プログラミング チュートリアル
RTLinuxによる調歩同期シリアル通信I/Oモジュール制御プログラミング チュートリアル
RTLinuxによるGP-IBI/Oモジュール制御プログラミング チュートリアル
RTLinuxによるDAI/Oモジュール制御プログラミング チュートリアル
RTLinuxによるADI/Oモジュール制御プログラミング チュートリアル
RTLinuxによるDIOI/Oモジュール制御プログラミング チュートリアル
RTLinuxによるHDLCI/Oモジュール制御プログラミング チュートリアル
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/CompactPCII/Oモジュールを制御する方法
ActiveXコントロールによるシステム組み込み技術
CompactPCIへの置き換え+システム構築/移行ガイド
MS-DOSからPCI/CompactPCII/Oモジュールを制御する方法
- 63 -
Interface Corporation
TUT-0043
参考文献
著 者
森 友一郎,薬師 輝久,馬場 秀忠
題 名
RTLinuxリアルタイム処理プログラミング
ハンドブック(株式会社秀和システム:2000年)
! 警告
本ドキュメントの一部または全てを弊社の許可なく、複写,複製,転載,電子化することを禁じま
す。
Interface Corporation
- 64 -
TUT-0043
2007年 1月 Ver. 1.5 発行
発行所
〒732-0828
広島県広島市南区京橋町10-21
TEL 082-262-7777
FAX 082-262-5066
定価 ¥2,000
本書の内容の一部または全部を、無断で転載することを禁止します。
本書の内容は、将来予告なく変更することがありますので、予めご了承ください。
© 2002, 2007 Interface Corporation. All rights reserved.
サポート体制
本製品についてのお問い合わせは、お客様相談センタで承ります。弊社Web siteのオンライ
ンQA(「サポート」→「お客様相談センタ」をクリック)、E-mailまたはフリーダイヤルをご利用く
ださい。
お問い合わせ先
<お客様相談センタ>
0120-447213
FAX
0120-458257
TEL
(祝日および弊社休業日を除く月~金 AM9:00~PM5:00迄)
E-mail [email protected]
TUT-0043 Ver. 1.5 Vol. 1/1
www.interface.co.jp
RTLinuxによる調歩同期シリアル通信ボード制御プログラミング チュートリアル
TUT-0043 Ver. 1.5
www.interface.co.jp