69
www.interface.co.jp チュートリアル RTLinuxによる調歩同期シリアル通信ボード 制御プログラミング チュートリアル

チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

www.interface.co.jp

チュートリアル

RTLinuxによる調歩同期シリアル通信ボード

制御プログラミング チュートリアル

Page 2: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

www.interface.co.jp

商標/登録商標 本ドキュメントに掲載されている会社名,製品名は、それぞれ各社の商標または登録商標です。 保障の内容と制限 弊社はドキュメント内の情報の正確さに万全を期しています。万一、誤記または誤植等があった

場合、弊社は予告なく改訂する場合があります。ドキュメントまたはドキュメント内の情報に起

因するいかなる損害に対しても弊社は責任を負いません。 製品に含まれるバグ、あるいは製品の供給(納期遅延),性能、もしくは使用に起因する付帯的損害もしくは間接的損害に対して、弊社に全面的に責がある場合でも、弊社はその製品に対する改良

(正常に動作する)、代品交換までとし、金銭面での賠償の責任は一切負わないものとしますので、予めご了承ください。 ドキュメント内の図や表は説明のためであり、ユーザ個別の応用事例により変化する場合があり

ます。 著作権,知的所有権 弊社は本製品に含まれるおよび本製品に対する権利や知的所有権を保持しています。 本製品はコンピュータ ソフトウェア(プログラム),図,文章,写真等を含んでいます。 複製の禁止 弊社の許可なく、本製品(ドキュメント含む)の全て、または一部に関わらず、複製,改変等を行うことはできません。 責任の制限 弊社は、弊社または再販売者の予見の有無に関わらず、発生したいかなる特別損害,偶発的損害,間接的な損害,重大な損害について、責任を負いません。 補償の内容 本ドキュメントで使用している弊社製品の補償については、各製品のマニュアルを参照してくだ

さい。

本書の内容の一部または全部を、無断で転載することを禁止します。 本書の内容は、将来予告なく変更することがありますので、予めご了承ください。 © 2002, 2007 Interface Corporation. All rights reserved.

Page 3: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 1 - Interface Corporation

改訂履歴

Ver. 年 月 改 訂 内 容 1.5 2007年1月 ●対応型式追加。

●マルチメータ型式変更。 HP34401A→Agilent34401A ●技術資料一覧更新。

1.4 2005年 10月 ●対応型式追加。 ●誤記修正。 ●技術資料一覧更新。

1.3 2004年 9月 ●対応型式追加。 ●技術資料一覧更新。

1.2 2003年 9月 ●誤記修正。 1.1 2002年 9月 ●対応型式追加。

●誤記修正。 1.0 2002年 6月 新規作成

本チュートリアルをご使用の際は、必ず各製品型式の最新のドキュメント(ユーザーズマニュアル,Help)をあわせて参照してください。また、最新のドライバソフトウェアをご使用ください。 ユーザーズマニュアル,ドライバソフトウェアは弊社Web site(www.interface.co.jp)からダウンロードできます。(Helpはドライバソフトウェアに含まれています)

Page 4: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 2 -

目 次

第 1章 調歩同期通信の概要 7

1.1 シリアル通信 ................................................................................................................................. 7 1.2 RS-232CとRS-485.......................................................................................................................... 8 1.3 同期方式 ......................................................................................................................................... 9 1.4 調歩同期通信 ................................................................................................................................. 9 1.5 データ長 ....................................................................................................................................... 10 1.6 パリティビット ........................................................................................................................... 10 1.7 通信速度(bps)とスループット .................................................................................................. 10 1.8 その他の用語解説 ....................................................................................................................... 11 1.9 調歩同期通信を行うにあたってのアドバイス ...................................................................... 11

第 2章 調歩同期通信 on RTLinux 13

2.1 パフォーマンス ........................................................................................................................... 13 2.1.1 応答性 ................................................................................................................................ 13 2.1.2 周期性 ................................................................................................................................ 15

2.2 RTLinuxによる調歩同期通信I/Oモジュール制御 .................................................................. 16 2.3 シリアルポート制御概略........................................................................................................... 17

第 3章 シリアルポート制御の第一歩 18

3.1 RTLinux調歩同期通信ドライバの組み込み............................................................................ 19 3.2 シリアルポートの情報を列挙する .......................................................................................... 21 3.3 シリアルポートの情報を列挙するプログラムの解説 .......................................................... 24

第 4章 より高度な処理を行おう 26

4.1 周期的なデータの送受信........................................................................................................... 26 4.2 周期的なデータの送受信の解説............................................................................................... 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章 デバッグ手法 57

5.1 ドライバデバッグ支援機能を使ってみる .............................................................................. 57 5.1.1 関数呼び出しトレース .................................................................................................... 58 5.1.2 エラー情報 ........................................................................................................................ 59 5.1.3 I/Oモジュールリソース情報 .......................................................................................... 60 5.1.4 制御信号情報 .................................................................................................................... 61

Page 5: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 3 - Interface Corporation

第 6章 リファレンス 62

6.1 関数一覧 ....................................................................................................................................... 62 6.2 戻り値一覧 ................................................................................................................................... 62

技術資料紹介 63

Page 6: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 4 -

はじめに

平素は格別のご高配を賜り、厚くお礼申し上げます。本冊子は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登録が必要になります。

Page 7: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 5 - Interface Corporation

●調歩同期 I/OモジュールのLinux/RTLinux対応ドライバソフトウェア(GPG-4141)のドキュメント構成について 各ドキュメントに掲載している内容は下記のとおりです。 ドキュメント 内 容

Readme 製品のインストール方法や、アンインストール方法,ファイル構成の他、製品に関する最新情報を掲載しています。 このドキュメントを最初に確認してください。

Help ドライバソフトウェアの仕様,関数の個別説明、および使用方法等の説明を掲載しています。プログラム作成時に確認してください。

チュートリアル 本ドキュメントです。初めてRTLinux上で調歩同期 I/Oモジュールを制御する時や、調歩同期 I/Oモジュールを使用したシステム構築時の参考として確認してください。 本ドキュメントの他、RTLinuxの導入編のチュートリアルを合わせて参照してください。 RTLinuxのインストールや、基本的なプログラミング等が記載されています。

また、本ドキュメントは、予めRTLinuxのインストール、および使用されるソフトウェア(GPG-4141)のインストールを済ませた方を対象に記述しています。

●本書での表記について コマンドの実行例において、行頭に「%」がつく場合は一般ユーザでの実行、「#」がつく場合はrootでの実行を意味します。「%」や「#」は実際に入力する文字ではありませんのでご注意ください。

Page 8: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 6 -

対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI)

PCI-4141 PCI-4142 PCI-4144 PCI-4147 PCI-4150 PCI-4646 PCI-466104 PCI-466104PA PCI-466120P PCI-466140P

PCI-4141P PCI-4142P PCI-4145 PCI-4148C PCI-4155 PCI-466102 PCI-466104A PCI-466108 PCI-466140 PCI-466140PA

PCI-4141PE PCI-4142PE PCI-4146 PCI-4149C PCI-4161 PCI-466102P PCI-466104P PCI-466120 PCI-466140A PCI-466180

対象型式 (CPZ)

CPZ-4141 CPZ-4142P CPZ-4146 CPZ-4149 CPZ-466104 CPZ-466104PA CPZ-466120P CPZ-466140P

CPZ-4141P CPZ-4144 CPZ-4147 CPZ-466102 CPZ-466104A CPZ-466108 CPZ-466140 CPZ-466140PA

CPZ-4142 CPZ-4145 CPZ-4148 CPZ-466102P CPZ-466104P CPZ-466120 CPZ-466140A CPZ-466180

対象型式 (CTP)

CTP-4141 CTP-4142P CTP-4146 CTP-4149

CTP-4141P CTP-4144 CTP-4147 CTP-466102

CTP-4142 CTP-4145 CTP-4148 CTP-466120

対象型式 (CSI)

CSI-466120 CSI-466402

CSI-466202 CSI-466302

対象型式 (PEX)

PEX-466102 PEX-466140

PEX-466104 PEX-466120

対象型式 (LPC)

LPC-466102 LPC-466140

LPC-466104 LPC-466120

対象ユーザ 制御用電子機器および、コンピュータ等に関して基本的な知識を有している方。

※ 本冊子は上記の弊社製品型式のみに対応しています。 製品の詳細は弊社Web siteを参照してください。

Page 9: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 7 - Interface Corporation

第1章 調歩同期通信の概要

本章では、コンピュータや計測器等の装置との間で、データをやり取りする方法の1つである調歩同期通信について概要を説明します。 この調歩同期通信とは、「シリアル通信」と呼ばれる通信方式で、データをやり取りするために

用いる同期方式の一種です。 コンピュータで、アナログモデムやISDNのTA(ターミナルアダプタ)を使って通信を行う場合、「シリアルポート」と呼ばれるインタフェースの口に、「シリアルケーブル」と呼ばれるケーブ

ルを挿して、機器と繋ぐと思います。 こうして通信を行う時、コンピュータと通信機器の間では、データのやり取りが行われています。

このやり取りは、実は「調歩同期通信」と呼ばれる方式でデータのやり取りが行われています。 弊社では、この調歩同期通信が行えるインタフェース製品を提供しております。 このインタフェース製品を使用することで、お客様は、複数の機器とデータのやり取りが行える

ようになります。

1.1 シリアル通信

シリアル通信とは、1本の線を使ってデータをやり取りする通信方式です。対語として、パラレル通信があり、これは複数の線を使ってデータをやり取りする通信方式です。 コンピュータに接続する機器は、シリアル通信かパラレル通信と呼ばれる通信方式で、データを

やり取りします。

シリアル通信は、1本の線でデータを送る方式。

パラレル通信は、複数の線でデータを 送る方式。

シリアル通信とパラレル通信の違い

Page 10: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 8 -

一般に、シリアル通信方式を採用した通信インタフェースは、他の通信インタフェースに比べ、

ケーブル敷設等のコストが安価であることが多いです。逆に、パラレル通信方式を採用した通信

インタフェースは、高価であることが多いですが、一度に複数のデータを送ることが可能なため、

大量のデータを高速に送るのに向いていると言われています。 しかし最近では、高速なシリアル通信方式が開発され、このようなことは 一概には言えなくなってきました。 シリアル通信方式の代表的なものとしては、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

ドライバレシーバ間でのデータ転送

この接続では複数のドライバが動作するとバス上でデータが衝突しますので、送信を行うときの

みドライバをデータラインに接続し、送信を行わないときはデータラインから切り離す必要があ

ります。

Page 11: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 9 - Interface Corporation

1.3 同期方式

ある機器から別の機器にデータを送る時、2つの機器はタイミングを合わせて、データの受け渡しを行う必要があります。 タイミングを合わせないと、受け手はどの時点が受け取るべきデータなのか判断することができ

ません。このタイミングを合わせることを「同期を取る」と言います。 同期の方法は千差万別です。RS-232CやRS-485の通信インタフェースで使用される同期方法は、大きく分けて、調歩同期,キャラクタ同期,フラグ同期が挙げられます。 調歩同期は、1キャラクタのデータを送るごとに、データの先頭にスタートビット、末尾にストップビットと呼ばれる制御ビットを挿入して同期を取る方式です。 受け手側では、この特定のビットを検出することで、1キャラクタの受信データの始まりと終わりを認識します。 キャラクタ同期は、ブロックと呼ばれる複数キャラクタの集まりの先頭に、特定のコードを付加

して同期を取る方式です。 フラグ同期は、フラグと呼ばれる特定のビット列で、フレームと呼ばれるデータ列を挟んで同期

を取る方式です。 本書では、この内、調歩同期を使用する通信制御について解説します。

1.4 調歩同期通信

調歩同期は、通信の効率という面から見ると、キャラクタごとにスタートビット,ストップビットを挿入しなくてはならないため、通信効率は、他の同期方式に比べて良くありません。 ただしデータに同期したクロックを送信する必要がなく、装置が簡略化できるため、現在のコン

ピュータ通信で広く普及している通信方式です。

start 0 1 2 3 4 5 6 7 parity stopHL

スタートビット

パリティビット

ストップビット

データビット

調歩同期通信のデータ構成

データがやりとりされていないとき(アイドル時)、データを送る信号線は、High状態 即ち”1”になっているため、最初のデータが”1”の場合には、アイドル時との区別がつきません。 そこで、データの送信開始を受信装置に知らせるために、まずLow状態 即ち”0”を1ビット送信します。この最初に送信する”0”がスタートビットです。 スタートビットに続いて送信するビット列をデータビットと呼びます。 送信側は、まずスタートビットを送り、次に1データを最下位ビット(LSB)から送信します。 最後のデータビットを送り終わるとデータラインを再び“1”(High状態)に戻し、次のデータが連続している場合は、一定時間待ってから次のスタートビットを送信します。 この最後に送信する”1”がストップビットです。ストップビットの長さは、1 / 1.5 / 2ビットの中から選択できます(通信コントローラによっては選択できない長さもあります)。

Page 12: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 10 -

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しか得られません。

Page 13: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 11 - Interface Corporation

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用のものがほとんどです。 コンピュータとモデムを接続する場合は、ほとんどの場合、ストレートタイプのケーブルを使用します。 機器同士を直接接続する場合は、リバース(クロス)タイプのケーブルを使用します。 ただし、購入前に結線図をよく確認して、使用目的と合致するケーブルを選択してください。

Page 14: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 12 -

項 目 内 容

送受信バッファメモリとは、何のためにあるのか?

シリアル通信でよく問題となるのが、データの受け取り側が、今あるデータを取り出す前に、次のデータが送られる状況が発生することです。 これは、ベルトコンベアに載せられて送られてくる物品を、捌くのが追いつかなくなる状況に似ています。これを俗に「取りこぼしが発生した」と言います。 取りこぼしが発生する状況としては、幾つか原因が考えられます。代表的な例としては、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

Page 15: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 13 - Interface Corporation

第2章 調歩同期通信 on RTLinux

RTLinuxは、Linux上でリアルタイム処理を可能にするOSです。そのRTLinux上で調歩同期通信I/Oモジュールを動かすことにより、リアルタイム性が要求されるシステムを構築することが可能に

なります。

2.1 パフォーマンス

実際にどの程度のリアルタイム性が保証されているかを測定した結果を見てみます。通常のLinux上での結果と比較しています。

2.1.1 応答性

データを受信してから、コールバック関数内ですぐにデータ送信関数を呼び出した場合、データ

受信完了から、実際にデータが送信されるまでの時間を測定しました。 RTLinux,Linuxともに、1000回応答時間を測定しています。

データ受信 コールバック関数

受信完了

コールバック関数呼び出し

データ送信開始

この時間を測定

データ送信

応答性を測定した時間

Page 16: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 14 -

応答時間の分布

件 数 データ区間 (μs) RTLinux Linux 44 0 0 45 10 0 46 254 0 47 529 0 48 186 0 49 18 0 50 3 0

51~999 0 92 1000~1999 0 96 2000~2999 0 102 3000~3999 0 102 4000~4999 0 97 5000~5999 0 103 6000~6999 0 99 7000~7999 0 100 8000~8999 0 99

9000~ 0 110

RTLinuxでは、平均応答時間,最大応答時間,最小応答時間の全てにおいてLinuxよりも優れた結果が出ています。 特に注目されるのが、最大応答時間です。負荷が入った場合、Linuxでは、10msにまで応答時間のぶれが発生しているのに対し、RTLinuxでは、50μsまでしかぶれが発生していません。 最悪値の保証が、RTLinuxとLinuxでは相当の差があるわけです。

応答時間のトータル結果

測定環境 トータル結果

RTLinux Linux

平均(μs) 47.0 5089.0 最大(μs) 50.0 10070.0 最小(μs) 45.0 80.0 標準偏差(μs) 0.8 2883.5

0

100

200

300

400

500

600

0

324

648

972

1296

1620

1944

2268

2592

2916

3240

3564

3888

4212

4536

4860

5184

5508

5832

6156

6480

6804

7128

7452

7776

8100

8424

8748

9072

9396

9720

1004

RTLinux

Linux

Linuxの応答時間はぶれが大きい。

0

100

200

300

400

500

600

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

0

100

200

300

400

500

600

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

拡 大

RTLinuxの応答時間はぶれが少ない。

データ区間(μs)

データ区間(μs) 件数

件数

RTLinuxとLinuxの応答時間の比較

Page 17: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 15 - Interface Corporation

2.1.2 周期性

次に、指定した周期でデータ送信を繰り返し行い、その周期のぶれや限界値を測定しました。 こちらも各周期で1000回ずつ測定を行っています。

ネットワーク負荷なし RTLinux Linux 測定環境

指定周期

平均 (μs)

最大 (μs)

最小 (μs)

標準偏差(μs)

平均 (μs)

最大 (μs)

最小 (μs)

標準偏差(μs)

10000 10001.1 10005.0 9997.0 1.2 10001.3 10061.0 9943.0 5.2 1000 1000.1 1004.0 996.0 1.2 10001.3 10071.0 9935.0 4.5

ネットワーク負荷あり RTLinux Linux 測定環境

指定周期

平均 (μs)

最大 (μs)

最小 (μs)

標準偏差(μs)

平均 (μs)

最大 (μs)

最小 (μs)

標準偏差(μs)

10000 10001.1 10007.0 9995.0 1.4 10001.2 10939.0 9051.0 56.6 1000 1000.1 1005.0 996.0 1.2 10001.2 11081.0 8938.0 50.6

Linuxでは1ms周期を実行しても10ms以下の周期実行は行えておらず、最大値と最小値のぶれも大きくなっていますが、RTLinuxでは最大値と最小値のぶれも小さくなっています。 またネットワーク負荷をかけたとき、Linuxではデータばらつきが10倍に増えましたが、RTLinuxではほとんど増えていません。 違いを分かりやすくするために、10ms(ネットワーク負荷あり)での周期実行の違いを図に示しました(縦軸は、件数、横軸は測定時間を示しています)。 LinuxよりもRTLinuxのほうが、ぶれが小さいことが分かります。

件数

データ区間(μs) RTLinuxとLinuxの周期性測定結果

Page 18: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 16 -

2.2 RTLinuxによる調歩同期通信I/Oモジュール制御

RTLinux上で弊社 調歩同期通信I/Oモジュールを制御するには、お客様の作成するRTLinux モジュールからRTLinux対応 調歩同期通信ドライバソフトウェアの関数を呼び出すことで行います。通常、RTLinuxモジュールではRTLinuxスレッドを生成し、ここから関数を呼び出して処理を行います。 また、RTLinuxモジュールとLinuxアプリケーションがデータのやりとりを行う場合は、RT-FIFOを使用します。 制御構成を簡単に示すと、下図のようになります。

シリアル通信I/Oモジュール

RTLinux対応 ドライバモジュール (rcp4141.o)

Linuxアプリケーション

データ送信

データ受信

リアルタイムFIFO

通信機器

RTLinuxモジュール

RTLinuxスレッド

RTLinux上での調歩同期通信I/Oモジュール制御構成

●RTLinuxモジュール

リアルタイム処理を行うモジュール本体です。お客様はRTLinux対応 調歩同期通信ドライバソフト

ウェアを使って、シリアルポートを制御するために、このモジュールを作成する必要があります。

●RTLinuxスレッド

実際にリアルタイム処理を行う際、RTLinuxモジュール下で動作するRTLinuxスレッドを作成します。

このRTLinuxスレッドは通常のLinuxのプロセスよりも優先して実行されます。

●RT-FIFO

リアルタイムFIFOとも呼ばれます。RTLinuxスレッドとLinuxアプリケーション、またはRTLinuxス

レッド同士のデータの受け渡しを行うために使用されます。

★RT-FIFO RT-FIFOはデバイスとして扱われており、/dev/rtf0等という名前で存在しています。

Page 19: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 17 - Interface Corporation

2.3 シリアルポート制御概略

調歩同期通信I/Oモジュールでは、制御はシリアルポート単位に行います。 シリアルポートの制御は、下記の制御シーケンス(順番)で行います。

シリアルポート初期化

各種処理

終了処理(3)

(2)

(1)

シリアルポートの制御シーケンス

①シリアルポートの初期化 シリアルポートへの操作を行うため、まず、シリアルポートを利用可能な状態にします。この処理

がシリアルポートの初期化です。I/Oモジュールの初期化を行うと、プログラムはシリアルポートへ

のアクセスが可能となります。本処理が行われないとシリアルポートへのアクセスは行えません。

②各種処理

シリアルポートから、データの送信および受信を行います。

③終了処理

シリアルポートの使用終了を行うための手続きです。プログラム終了時に行います。

Page 20: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 18 -

第3章 シリアルポート制御の第一歩

ここでは、実際に弊社 調歩同期通信I/Oモジュールを用いて、シリアルポートの制御プログラムを作成します。 この章では例として、以下の製品を使用しています。

PCI-4141 1枚:調歩同期通信I/Oモジュール

下図に、設定例を示します。

PCI-4141

RSW1:0

I/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに調歩同期シリアル通信製品を実装します。 (この章では、ケーブル等を接続して通信を行いません) I/Oモジュールをシステムに組み込んでから、動かすまでの流れは下記のようになります。 各項目に従って、RTLinux上でのシリアルポート制御プログラミングを行います。

RTLinuxリアルタイムカーネルの組み込み

RTLinux 調歩同期通信ドライバ組み込み

プログラミング

コンパイル

実行

RTLinux上でのシリアルポート制御までの流れ

Page 21: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 19 - Interface Corporation

3.1 RTLinux調歩同期通信ドライバの組み込み

RTLinuxの調歩同期通信ドライバを組み込む前に、RTLinux導入編のチュートリアルを参照し、RTLinuxのインストールとRTLinuxモジュールを動かすために必要なリアルタイムカーネルのインストールを行ってください。

参照箇所: RTLinuxのインストール 第1章 RTLinuxの導入 リアルタイムカーネルの組み込み 第2章 RTLinuxのインストール

リアルタイムカーネルの組み込み例:

% su ← リアルタイムカーネルを組み込むため、 スーパーユーザになります。 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等のリアルタイムカーネルが組み込まれています。 リアルタイムカーネルは正常に組み込まれています。

リアルタイムカーネルを組み込んだ後に、調歩同期通信ドライバモジュールを組み込むことによ

り、シリアルポートのリアルタイム制御が行えるようになります。 シリアルポートを実際に制御するには、ドライバモジュールを事前に組み込む必要があります。 組み込み方法は、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が組み込まれていることが分かります。

Page 22: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 20 -

/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

Page 23: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 21 - Interface Corporation

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 <rtl.h> #include "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;

Page 24: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 22 -

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のように幾つもコンソールを起動することができないので、このようにします。

Page 25: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 23 - Interface Corporation

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コマンドによるモジュール取り外しを繰り返してみてください。 その都度、メッセージが表示されることが分かります。

Page 26: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 24 -

3.3 シリアルポートの情報を列挙するプログラムの解説

それでは、先程のプログラムの解説を行います。 まず、このプログラムの動作概要を示します。

sample1.o

RTLinuxモジュール

RTLinux

組み込み(insmod) 取り外し(rmmod)

init_module関数 cleanup_module関数

作成した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 このシリアルポートに対応する通信コントローラが使用する割り込み番号が返ります。

Page 27: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 25 - Interface Corporation

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)を一旦取り外す必要があります。 オープンしたら必ずクローズしてください。

Page 28: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 26 -

第4章 より高度な処理を行おう

先程のプログラムは、RTLinuxモジュールの組み込みと取り外しの時にしか動作しないものでした。 実際のプログラミングでは、誰かから(大抵は上位アプリケーション)指令を受け、その指令に従って何らかのアクションを起こすのが普通です。 この章では、Linuxプログラムから、RTLinuxモジュールを制御するプログラムを作成します。

4.1 周期的なデータの送受信

ここでは、周期的にデータを送信し、これを別のシリアルポートで受け取り、Linuxプロセスでのデータを送るという処理を行います。 ここでは、以下の製品を使用します。

PCI-4141 1枚:調歩同期通信I/Oモジュール RS-232Cリバースケーブル 1本:9pin D-subコネクタ←→9pin D-subコネクタ接続ケーブル

下図に、接続構成を示します。

PCI-4141

RSW1:0

RS-232C リバースケーブル

CH1

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

Page 29: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 27 - Interface Corporation

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 4141 /* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */#define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */#define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define SEND_CH 1 /* 送信用に指定するチャンネル番号 */ #define RECV_CH 2 /* 受信用に指定するチャンネル番号 */ #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に変更。

Page 30: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 28 -

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 <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "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)

Page 31: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 29 - Interface Corporation

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を生成する */

Page 32: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 30 -

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; /* 通信速度を9600bpsに設定 */ conf.Parity = COMRT_PARITY_NONE; /* パリティビットなし */ conf.StopBits = COMRT_ONE_STOPBIT; /* ストップビットは1ビット */ conf.WordLength = 8; /* データ長は8ビット */ /* 送信用シリアルポートへの通信パラメータの設定 */ ret = ComRTSetConfig(g_send_port_no, &conf); if(ret){ rtl_printf("ComRTSetConfig error [ret=%x]¥n", ret); return –6; } /* 受信用通信パラメータの変更(差分のみ追加) */ 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; }

Page 33: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 31 - Interface Corporation

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 <stdio.h> #include <fcntl.h> #include <unistd.h> #include <math.h> #include <sys/time.h> #include <sys/ioctl.h> #include <rtl_fifo.h> #include "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){

Page 34: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 32 -

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 ← Linuxプロセスを実行します

Page 35: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 33 - Interface Corporation

実行画面を以下に示します。 (画面左上のウィンドウがLinuxプロセスを実行しているコンソール。画面右下のウィンドウはRTLinux

モジュールのログメッセージを表示させているコンソールです)

サンプルの実行画面例

sample2を実行させると、「recv data=’now clock=xxxxxxxx’」と表示が繰り返し出力され、暫くしてプログラムが終了します。

Page 36: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 34 -

4.2 周期的なデータの送受信の解説

それでは、先程のプログラムの解説を行います。 プログラムの大まかな動きを、下図に示します。

Linuxプロセス チャンネル 1 チャンネル 2

スタート指令

ストップ指令

データ送信

データ受信

“now clock=xxxxxxxx”

データ送信

データ受信

“now clock=xxxxxxxx”

データ送信

データ受信

“now clock=xxxxxxxx”

XXms周期

my_task関数が処理します

Linuxプロセス

データ送付

データ送付

データ送付

my_recv_callback関数が

処理します

sample2の動作概要

Linuxプロセスからスタート指示があると、チャンネル1のシリアルポートから特定のデータがチャンネル2に対して、周期的に送信されます。 チャンネル2のシリアルポートは、受け取ったデータを、RT-FIFOを介してLinuxプロセスに送ります。 チャンネル1の送信処理は、RTLinuxスレッド(my_task)が行っています。 チャンネル2の受信処理は、調歩同期通信のドライバモジュールから呼ばれるコールバック関数(my_recv_callback)が行っています。 Linuxプロセスの仕事は、通信処理を行うRTLinuxモジュールに対する周期処理のスタート指令,ストップ指令,チャンネル2が受信したデータを、RT-FIFO経由で受け取ることです。

Page 37: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 35 - Interface Corporation

次に、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

受信データ

破棄

破棄

カーネル空間

ユーザ空間Linuxプロセス(sample2)

RTLinuxモジュール(module2.o)FIFO_COMMAND

FIFO_THRU_CMD

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の破棄の他、調歩同期通信ドライバモジュールのクローズ処理が行われます。

Page 38: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 36 -

4.2.1 調歩同期通信ドライバモジュールの役割

調歩同期通信ドライバモジュールは内部で様々な仕事を行います。 ここでは、ドライバモジュールの構造について、簡単に紹介します。

調歩同期通信ボード

内部バッファ

シリアル通信

コントローラ

送信管理処理 受信管理処理

プログラムコード

関数呼び出し コールバック呼び出し

コールバック関数

ドライバモジュール

ドライバモジュールの構造

調歩同期通信ドライバモジュールは、調歩同期通信I/Oモジュール上のシリアル通信コントローラの制御を行います。 ドライバは、データの送受信管理を行いますが、処理を円滑に行うため、内部にバッファを持っ

ています。(デフォルトでは約4KBが内部バッファに確保されます) プログラムからデータの送信が指示された時、内部バッファに一旦格納された後、ドライバがシ

リアル通信コントローラを制御して、データを送信します。 データの受信は、ドライバがシリアル通信コントローラのデータ受信を検知し、データを取り出

した後、内部バッファに一旦蓄積しています。プログラムは、この蓄積したデータを取り出すよ

うになっています。 このような構造になっているため、プログラマは通信コントローラを直接制御した際に発生する、

面倒なデータの管理処理を行わなくて済むようになっています。 通信コントローラ内部で発生した様々な事象の変化を、即プログラムが受け取って処理できるよ

う、ドライバモジュールはコールバック機構を提供しています。 プログラマは、コールバック関数と、コールバックさせたいイベント内容を予め登録しておくこ

とで、ドライバモジュール内部で発生した事象の変化を、検知することができます。 実際、module2.cでは、指定件数のデータが受信されたらコールバック関数が呼び出されるようプログラミングされています。 コールバック関数では、ドライバからデータを取り出して然るべき処理を行っています。

Page 39: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 37 - Interface Corporation

★内部バッファの構造 内部バッファは、1 つのシリアルポートに対して、送信用バッファ,受信用バッファが、それぞれ 1 つずつ用意されます。 内部バッファは、キュー構造になっており、送信指示された時や未送信のデータが内部バッファにあった時に、データは内部バッファの後尾に格納されます。 内部バッファはドライバモジュールが組み込まれる時、固定長で確保されます。 従って、あまりに大きいデータを送信しようとしたり、受信したデータを取り出さず溜め込み続けると、データが溢れ出してしまいます。 実際には送信バッファが一杯になると、送信用の関数を呼び出した際、エラーが返ります。 受信バッファの場合、受信されたデータから破棄されます。 受信バッファが溢れないよう、受信データが溜まったら然るべきタイミングで抜き取るよう、注意してプログラミングしてください。

4.2.2 共通定義ファイルの役割

共通定義ファイル(sample2.h)は、LinuxプロセスとRTLinuxモジュールが、共通で使用する定数等を抜き出したものです。 共通定義ファイルでは、以下の設定を行っています。 行番号 内 容

12~22行目 #define宣言> RT-FIFOの番号の定義,各関数で使用する定数値の指定,バッファサイズの指定。

26~29行目 enum宣言> LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値を指定。

32~37行目 struct宣言> LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造を指定。

ここで重要なのがLinuxプロセスからRTLinuxモジュールに対して指令を出すために使用されるコマンドの構造体(CMD_STRUCT)です。 Linuxプロセスでは、この構造体に値をセットしてRTLinuxモジュールのハンドラに渡します。ハンドラでは、この構造体ごと受け取って、指示された内容に従って処理を行います。

Linuxプロセス

RTLinuxモジュール

struct CMD_STRUCT {

enum CMD_IDS id;

long

smp_period_ms;

LinuxプロセスからRTLinuxモジュールのハンドラへのコマンドの流れ

Page 40: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 38 -

コマンドの構造体は、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です。 ハンドラ(my_handler) Linuxプロセスからの指示を受け取るための処理の入り口です。

RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る処理に回されます。

RTLinuxスレッド(my_task) 周期送信処理を実現するRTLinuxスレッドです。 Linuxプロセスから送られる指示は、最終的にここに送られ、周期送信処理を実現します。

Page 41: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 39 - Interface Corporation

次に、生成された各リソースの相互関係と処理の流れを下図に示します。

ハンドラ(my_handler)

RTLinuxスレッド(my_task)

FFO_COMMAND

FIFO_THRU_CMD

Linuxプロセス

調歩同期通信 ドライバモジュール

ID_START ID_STOP

周期送信 ComRTWrite関数

コールバック関数(my_recv_callback)

データ受信 受信イベント発生

ComRTRead関数

FIFO_RESULT

コマンド指示

受信データ

チャンネル 1からチャンネル 2に

データの送信

←周期呼び出し

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行目:受信用シリアルポートのオープン) 先のコードは、送信用シリアルポートのオープンを行いましたが、こちらでは受信用のシリアル

ポートをオープンしています。

Page 42: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 40 -

(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)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

rtf_get rtf_putLinuxプロセス側 RTLinuxスレッド側

LinuxプロセスからRTLinuxスレッドへのデータの流れ

(78~109行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この78~109行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、周期実行の開始と停止を行い(87~98行の処理)、周期実行ごとに102~103行目のsprintfで生成したデータを、104行目のComRTWrite関数で送信しています。

Page 43: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 41 - Interface Corporation

周期実行の開始と停止は、先に述べた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プロセスに送っています。

Page 44: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 42 -

4.2.4 Linuxプロセスの動き

ここでは、Linuxプロセス(sample2)の動きに注目して見てみます。 まず、LinuxプロセスとRTLinuxモジュールとの関係を、下図に示します。

main

RT-FIFO(FIFO_RESULT)

RT-FIFO(FIFO_COMMAND)

受信データ取得

コマンド指令 RTLinux

モジュール

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モジュールはこの指示を受け取った後、実行を停止します。

Page 45: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 43 - Interface Corporation

4.3 マルチメータからのデータの取り込み

先程は、周期的なデータの送信と受信を行いました。ここでは、計測器と接続して制御を行って

見ます。

注意!

ここで使う調歩同期通信I/Oモジュールは、接続相手であるAgilent34401AがRS-232C通信イ

ンタフェースを採用しているため、RS-232Cを通信インタフェースに持つI/Oモジュールでない

と動かせません。予めご了承ください。 ここでは、以下の製品を使用します。

PCI-4141 1枚:調歩同期通信I/Oモジュール RS-232Cリバースケーブル 1本:9ピンD-subコネクタ←→9ピンD-subコネクタ接続ケーブル Agilent34401A 1台:マルチメータ アジレント・テクノロジー社製

下図に、接続構成を示します。

PCI-4141

Agilent34401A

RSW1:0

RS-232C リバースケーブル

CH1

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

Page 46: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 44 -

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 --------------------------------------------------------------- */ #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 4141 /* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */ #define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-4141を表す) */ #define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define SEND_RECV_CH 1 /* 送受信用に指定するチャンネル番号 */ #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

Page 47: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 45 - Interface Corporation

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 <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "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;

Page 48: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 46 -

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に対して、電圧の計測を要求 */

Page 49: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 47 - Interface Corporation

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"); /* 自スレッドをサスペンドさせ、受信完了時の起床待ちに入る */ pthread_suspend_np(pthread_self()); } } 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を生成する */ 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; /* 全二重に設定 */

Page 50: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 48 -

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ビット */ conf.RxEventTrigger = 17; /* 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 <stdio.h> #include <fcntl.h> #include <unistd.h> #include <math.h> #include <sys/time.h> #include <sys/ioctl.h> #include <rtl_fifo.h> #include "sample3.h" /* Linuxプロセスのメインルーチン */ int main(void) { int fd_result, fd_cmd;

Page 51: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 49 - Interface Corporation

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; }

Page 52: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 50 -

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から取得した電圧値のデータが繰り返し出力され、暫くしてプログラムが終了します。

Page 53: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 51 - Interface Corporation

4.4 マルチメータからのデータの取り込み解説

それでは、先程のプログラムの解説を行います。 プログラムの大まかな動きを、下図に示します。

Linuxプロセス チャンネル 1

スタート指令

ストップ指令

データ送信

データ受信

“*RST¥r¥n”

XXms周期

Agilent34401A

データ送信

データ受信

“System:REMOTE¥r¥n”

データ送信

データ受信

“:Measure:Voltage:DC?¥r¥n”

データ送信

データ受信

計測した電圧値のデータ

計測

データ送信

データ受信

“: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プロセスにデータを送っています。

Page 54: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 52 -

Linuxプロセスからストップ指示があると、チャンネル1からリモート状態を解除する命令(“System:LOCAL¥r¥n”)が送信されます。

チャンネル1の送信処理は、RTLinuxスレッド(my_task)が行っています。 受信処理は、調歩同期通信のドライバモジュールから呼ばれるコールバック関数

(my_recv_callback)が行っています。 Linuxプロセスの仕事は、通信処理を行うRTLinuxモジュールに対する周期処理のスタート指令,ストップ指令,Agilent34401Aから受信した電圧値のデータをRT-FIFO経由で受け取ることです。 次に、LinuxプロセスとRTLinuxモジュールの関係を、下図に示します。

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

受信データ

破棄

破棄

カーネル空間

ユーザ空間Linuxプロセス(sample3)

RTLinuxモジュール(module3.o)FIFO_COMMAND

FIFO_THRU_CMD

FIFO_RESULT

my_recv_callback

受信イベントコールバック生成

LinuxプロセスとRTLinuxモジュールの相関関係

実は、各々の生成関係は、『34ページ 4.2 周期的なデータの送受信の解説』と全く同じです。 Linuxプロセスからの指示は、RT-FIFOを経由して、my_handler→my_taskの順に流れていきます。受信結果をmy_recv_callbackからRT-FIFOを経由してLinuxプロセスに返すのも同じです。

Page 55: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 53 - Interface Corporation

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プロセスから送られる指示は、最終的にここに送られ、周期送信処理を実現します。

Page 56: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 54 -

次に、生成された各リソースの相互関係と処理の流れを下図に示します。

ハンドラ(my_handler)

RTLinuxスレッド(my_task)

FFO_COMMAND

FIFO_THRU_CMD

Linuxプロセス

調歩同期通信

ドライバモジュール

ID_START ID_STOP

←周期呼び出し周期送信 ComRTWrite関数

コールバック関数(my_recv_callback)

データ受信受信イベント発生

ComRTRead関数

FIFO_RESULT

コマンド指示

受信データ

HP34401Aに命令を送信

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のマニュアル中のコマンド説明と見比べながら読み進めることをお奨めします。

Page 57: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 55 - Interface Corporation

まず、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スレッド 受信用コールバック Agilent34401A

計測 サスペンド

起床

":Measure:Voltage:DC?¥r¥n"

計測した電圧値のデータ

pthread_suspend_np関数

pthread_wakeup_np関数

計測 サスペンド

起床

":Measure:Voltage:DC?¥r¥n"

計測した電圧値のデータ

pthread_suspend_np関数

pthread_wakeup_np関数

pthread_make_periodic_np

関数の設定時間

RTLinuxスレッドとコールバックとAgilent34401Aの処理関係

Page 58: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 56 -

(67~97行目:コールバック関数の処理) 受信用のコールバック関数の処理は、Agilent34401Aから受け取った電圧値のデータを取り出し、RT-FIFO経由でLinuxプロセスに送ることにあります。 その後、先に説明したように、スリープ状態のRTLinuxスレッドを95行目のpthread_wakeup_np関数で起床させています。 (37~63行目:送信と受信のサブルーチン) 37~48行目のsend_hp34401a関数と、52~63行目のrecv_hp34401a関数は、Agilent34401Aに対する送信と受信のサブルーチンです。 内部ではそれぞれ、ComRTWrite関数とComRTRead関数を用いています。 送受信のエラー判定をまとめるために、このようにしています。

Page 59: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 57 - Interface Corporation

第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使用時

Page 60: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 58 -

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 kernel: init_module called May 21 11:11:47 localhost kernel: rcp4141:ComRTGetPortInformation (0, [0xc4bcdee4]) May 21 11:11:47 localhost kernel: ----- Serial Port Information ----- May 21 11:11:47 localhost kernel: PortNo:0 May 21 11:11:47 localhost kernel: VendorID:1147h May 21 11:11:47 localhost kernel: DeviceID:4141 May 21 11:11:47 localhost kernel: SubsystemID:0001h May 21 11:11:47 localhost kernel: RevisionID:0 May 21 11:11:47 localhost kernel: BoardID:0 May 21 11:11:47 localhost kernel: ChannelNumber:1 May 21 11:11:47 localhost kernel: BaseAddress:b800h May 21 11:11:47 localhost kernel: IRQ No:7 May 21 11:11:47 localhost kernel: rcp4141:ComRTGetPortInformation (1, [0xc4bcdee4]) May 21 11:11:47 localhost kernel: ----- Serial Port Information ----- … May 21 11:11:47 localhost kernel: rcp4141:ComRTGetPortInformation (5, [0xc4bcdee4]) May 21 11:11:47 localhost kernel: rcp4141:ComRTGetPortInformation (6, [0xc4bcdee4]) May 21 11:11:47 localhost kernel: rcp4141:ComRTGetPortInformation (7, [0xc4bcdee4]) … (END)

ログにもComRTGetPortInformation関数,ComRTOpen関数の順番に呼び出されていることが分かります。ログ中の[ ]で表されている部分は、引数がポインタの場合の変数のアドレスを示しています。 次に組み込んだsample1.oを取り外してみます。 #rmmod sample1

Page 61: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 59 - Interface Corporation

ログを見てみます。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

最終行のメッセージの内容から、引数パラメータの値が不正であることがわかります。

Page 62: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 60 -

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 デバイスID SubsystemID サブシステムID RevisionID リビジョンID I/O address I/Oポートアドレス Irq 割り込み番号 support clocks サポートする基準クロック

この値が異常の場合(I/Oポートアドレスや割り込み番号が0と表示された場合)は、ハードウェアに問題が発生していることも考えられます。

Page 63: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 61 - Interface Corporation

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 kernel: init_module called May 21 13:14:30 localhost kernel: ComRTOpen success!! [port no=0] May 21 13:14:30 localhost kernel: RS:^ May 21 13:14:30 localhost kernel: ER:^

ログには「RS:^」と「ER:^」が出力されており、RS信号とER信号が変化したことが記録されています。 記号の意味を以下に示します。

記 号 意 味 ^ ON v OFF

Page 64: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 62 -

第6章 リファレンス

この章では、GPG-4141の関数,構造体,および戻り値の一覧を掲載しています。より詳しい情報は、Helpを参照してください。

6.1 関数一覧 No. 区 分 関数名 機 能 1 ComRTOpen ポートのオープンを行います。 2 ComRTClose ポートのクローズを行い、ポートアクセスのた

めに使用されていた各種リソースの解放を行い、以後シリアルポートへのアクセスを禁止します。

3

初期化終了

ComRTSetup ポートのオープン/クローズと通信設定を行います。

4 ハード ウェア

ComRTGetPortInformation 指定したポートのハードウェア情報を取得します。

5 ComRTSetConfig ポートの通信設定を行います。 6

通信設定 ComRTGetConfig ポートの通信設定を取得します。

7 ComRTWrite データを送信します。 8

送受信 ComRTRead 受信データを取得します。

9 ComRTSetModemStatus 制御信号の出力状態を変更します。 10 ComRTGetModemStatus 制御信号の状態を取得します。 11 ComRTErrorStatus 通信エラー情報,通信統計情報を取得します。12 ComRTSendBreak ブレーク信号を送信します。 13 ComRTFlush 送受信バッファをクリアします。 14

制御信号 その他

ComRTEnableTransmitter データラインの切り替えを行います。 15 ComRTSetEventMask イベントマスクを設定します。 16

イベント ComRTGetEventMask イベントマスクを取得します。

6.2 戻り値一覧

エラー識別子 値 意 味 対処方法 なし 0 正常終了 -ENODEV -19 ポートが見つかりません。 指定したポートは存在しないか、オープン

されていません。 -EINVAL -22 設定に間違いがあります。 設定の内容に間違いが無いか、

再度ご確認ください。 -ENOSPC -28 送信バッファに空きがあり

ません。 送信バッファに空きが生じるまで、呼び出しを待機ください。

-ENOSYS -38 現在のモードで、使用できないAPIを呼び出そうとしました。

このAPIを使用できないモードで、APIを使用しようとしています。モードを切り替えてください。

Page 65: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

- 63 - Interface Corporation

技術資料紹介 弊社では下記の技術資料を提供しております。 詳しくは、弊社Web site(www.interface.co.jp)、または弊社窓口までお問い合わせください。 カタログ

PRM-0061 CPZカタログ(日本語版) PRM-0062 PCIカタログ(日本語版) PRM-0063 CSIカタログ(日本語版)

チュートリアル TUT-0058 チュートリアル CPZ拡張ユニット 入門編 TUT-0056 チュートリアル XP Embedded OS構築編 TUT-0055 チュートリアル 画像入力I/Oモジュール TUT-0054 CANチュートリアル TUT-0053 モーションコントロールチュートリアル TUT-0050 RTLinuxによるモーションコントローラI/Oモジュール制御プログラミング チュートリアル(GPG-7400用) TUT-0048 RTLinuxによるメモリンクI/Oモジュール制御プログラミング チュートリアル TUT-0044 RTLinuxによるメモリ共有インタフェースI/Oモジュール制御プログラミング チュートリアル TUT-0043 RTLinuxによる調歩同期シリアル通信I/Oモジュール制御プログラミング チュートリアル TUT-0041 RTLinuxによるGP-IBI/Oモジュール制御プログラミング チュートリアル TUT-0040 RTLinuxによるDAI/Oモジュール制御プログラミング チュートリアル TUT-0039 RTLinuxによるADI/Oモジュール制御プログラミング チュートリアル TUT-0038 RTLinuxによるDIOI/Oモジュール制御プログラミング チュートリアル TUT-0037 RTLinuxによるHDLCI/Oモジュール制御プログラミング チュートリアル TUT-0036 RTLinuxによるPCI/CompactPCI/CardBus制御入門書(導入編) TUT-0034 Visual C++によるPPI入門書 TUT-0033 Visual Basicによるメモリ共有インタフェース入門書 TUT-0032 Visual C++によるメモリ共有インタフェース入門書 TUT-0031 Visual Basicによるメモリンク入門書 TUT-0030 Visual C++によるメモリンク入門書 TUT-0029 Visual BasicによるHDLC入門書 TUT-0028 Visual C++によるHDLC入門書 TUT-0027 Visual BasicによるGP-IB入門書 TUT-0026 Visual C++によるGP-IB入門書 TUT-0025 Visual BasicによるDIO入門書 TUT-0024 Visual C++によるDIO入門書 TUT-0023 Visual BasicによるDA入門書 TUT-0022 Visual C++によるDA入門書 TUT-0021 Visual BasicによるAD入門書 TUT-0020 Visual C++によるAD入門書 TUT-0019 Visual Basicによるモーションコントローラ入門書 TUT-0018 Visual C++によるモーションコントローラ入門書 TUT-0017 メモリンクを使用した負荷分散システム事例チュートリアル TUT-0016 Visual BasicによるPPI入門書 TUT-0015 モーションコントロールチュートリアル TUT-0014 Microsoft Visual Studio .NET移行ガイド TUT-0008 拡張ユニット チュートリアル(問題解決編) TUT-0007 拡張ユニットチュートリアル(入門編) TUT-0006 C(98)/ISA製品からPCI/CompactPCI製品への移行チュートリアル(DOS編) TUT-0005 DOSによるLAP-B入門書 TUT-0004 DOSによるAD入門書 TUT-0003 LinuxによるPCI/CompactPCI/CardBus制御 入門書 TUT-0002 PCI-ISAバスブリッジチュートリアル TUT-0001 PCI-Cバスブリッジチュートリアル

技術情報資料 初めてのCANインタフェース Linux, リアルタイムLinux移植(SH-4)経験談及び当社の今後の取り組みについて LinuxからPCI/CompactPCII/Oモジュールを制御する方法 ActiveXコントロールによるシステム組み込み技術 CompactPCIへの置き換え+システム構築/移行ガイド MS-DOSからPCI/CompactPCII/Oモジュールを制御する方法

Page 66: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

TUT-0043

Interface Corporation - 64 -

参考文献

著 者 題 名 森 友一郎,薬師 輝久,馬場 秀忠 RTLinuxリアルタイム処理プログラミング

ハンドブック(株式会社秀和システム:2000年)

警告!

本ドキュメントの一部または全てを弊社の許可なく、複写,複製,転載,電子化することを禁じま

す。

Page 67: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

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.

Page 68: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

www.interface.co.jp

サポート体制

本製品についてのお問い合わせは、お客様相談センタで承ります。弊社Web siteのオンライ

ンQA(「サポート」→「お客様相談センタ」をクリック)、E-mailまたはフリーダイヤルをご利用く

ださい。 お問い合わせ先 <お客様相談センタ> TEL 0120-447213 FAX 0120-458257 (祝日および弊社休業日を除く月~金 AM9:00~PM5:00迄) E-mail [email protected]

TUT-0043 Ver. 1.5 Vol. 1/1

Page 69: チュートリアル - InterfaceTUT-0043 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式 (PCI) PCI-4141 PCI-4142

www.interface.co.jp

RTLinuxによる調歩同期シリアル通信ボード制御プログラミング チュートリアル TUT-0043 Ver. 1.5