チュートリアルenomoto/kgrsr/hardware/data/tut...tut-0048 - 1 - interface corporation...

104
www.interface.co.jp チュートリアル RTLinuxによるカウンタI/Oモジュール 制御プログラミング

Upload: others

Post on 22-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

www.interface.co.jp

チュートリアル

RTLinuxによるカウンタI/Oモジュール

制御プログラミング

Page 2: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

www.interface.co.jp

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

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

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

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

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

さい。

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

Page 3: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 1 - Interface Corporation

改訂履歴

Ver. 年 月 改 訂 内 容 1.3 2005年7月 ●対応型式追加

●用語統一 ●『エンコーダカウンタドライバ(GPG-6204)』関数一覧更新 ●技術資料一覧更新

1.2 2004年12月 ●対象型式追加 ●技術資料一覧更新 ●誤記修正

1.1 2003年10月 ●GPG-6201の内容を追加 ●誤記修正

1.0 2002年9月 新規作成

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

Page 4: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 2 -

目 次

第 1章 概要 6

1.1 パルスジェネレータI/Oモジュールの概要 ............................................................................... 6 1.2 パルスカウンタI/Oモジュールの概要 ....................................................................................... 7 1.3 ユニバーサルカウンタI/Oモジュールの概要 ........................................................................... 9 1.4 3モードパルスカウンタI/Oモジュールの概要 ...................................................................... 11

第 2章 カウンタI/Oモジュール on RTLinux 14

2.1 RTLinuxによるカウンタI/Oモジュール制御 .......................................................................... 14 2.2 カウンタI/Oモジュール制御概略 ............................................................................................. 16 2.3 リアルタイムカーネルの組み込み .......................................................................................... 17

第 3章 パルスジェネレータI/Oモジュールの制御 18

3.1 パルスジェネレータドライバの組み込み .............................................................................. 18 3.2 パルス出力I/Oモジュールの制御 ............................................................................................. 20 3.3 パルス出力I/Oモジュールの制御の解説 ................................................................................. 28

3.3.1 サンプルプログラムの動き ............................................................................................ 28 3.3.2 共通定義ファイルの役割と、LinuxプロセスとRTLinuxモジュールとの連携....... 29 3.3.3 RTLinuxモジュールの動き ............................................................................................. 30 3.3.4 Linuxプロセスの動き ...................................................................................................... 32

第 4章 パルスカウンタI/Oモジュールの制御 33

4.1 パルスカウンタドライバの組み込み ...................................................................................... 33 4.2 パルスカウンタI/Oモジュールの制御 ..................................................................................... 34 4.3 パルスカウンタI/Oモジュールの制御の解 ............................................................................. 42

4.3.1 プログラムの動き ............................................................................................................ 42 4.3.2 共通定義ファイルの役割 ................................................................................................ 43 4.3.3 RTLinuxモジュールの動き ............................................................................................. 44 4.3.4 Linuxプロセスの動き ...................................................................................................... 47

第 5章 ユニバーサルカウンタI/Oモジュールの制御 48

5.1 ユニバーサルカウンタドライバの組み込み .......................................................................... 48 5.2 ユニバーサルカウンタI/Oモジュールの制御 ......................................................................... 50 5.3 ユニバーサルカウンタI/Oモジュールの制御の解 ................................................................. 57

5.3.1 プログラムの動き ............................................................................................................ 57 5.3.2 共通定義ファイルの役割 ................................................................................................ 58 5.3.3 RTLinuxモジュールの動き ............................................................................................. 59 5.3.4 Linuxプロセスの動き ...................................................................................................... 62

第 6章 3モードパルスカウンタI/Oモジュールの制御 63

6.1 3モードパルスカウンタドライバの組み込み ....................................................................... 63 6.2 3モードパルスカウンタI/Oモジュールの制御 ...................................................................... 65

Page 5: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 3 - Interface Corporation

6.3 3モードパルスカウンタI/Oモジュールの制御の解説.......................................................... 74

6.3.1 プログラムの動き ............................................................................................................ 74 6.3.2 共通定義ファイルの役割 ................................................................................................ 75 6.3.3 RTLinuxモジュールの動き ............................................................................................. 77 6.3.4 Linuxプロセスの動き ...................................................................................................... 80

第 7章 デバッグ手法 81

7.1 ドライバデバッグ支援機能を使ってみる .............................................................................. 81 7.1.1 関数呼び出しトレース .................................................................................................... 82 7.1.2 I/Oモジュールリソース情報 .......................................................................................... 83

第 8章 リファレンス 85

8.1 パルスジェネレータドライバ(GPG-6105) .............................................................................. 85 8.1.1 関数一覧 ............................................................................................................................ 85 8.1.2 戻り値一覧 ........................................................................................................................ 86

8.2 パルスカウンタドライバ(GPG-6106) ...................................................................................... 87 8.2.1 関数一覧 ............................................................................................................................ 87 8.2.2 戻り値一覧 ........................................................................................................................ 88

8.3 3モードパルスカウンタドライバ(GPG-6201) ....................................................................... 89 8.3.1 関数一覧 ............................................................................................................................ 89 8.3.2 戻り値一覧 ........................................................................................................................ 90

8.4 ユニバーサルカウンタドライバ(GPG-6202) .......................................................................... 92 8.4.1 関数一覧 ............................................................................................................................ 92 8.4.2 戻り値一覧 ........................................................................................................................ 93

8.5 3モードパルスカウンタドライバ(GPG-6204) ....................................................................... 95 8.5.1 関数一覧 ............................................................................................................................ 95 8.5.2 戻り値一覧 ........................................................................................................................ 96

技術資料紹介 98

Page 6: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 4 -

はじめに

平素は格別のご高配を賜り、厚くお礼申し上げます。本冊子はRTLinux/Free上で弊社PCI,CompactPCIおよびCardBus 3モードパルス/パルスカウンタ/ユニバーサルカウンタ/パルスジェネレータI/Oモジュール(以後カウンタI/Oモジュールと略します)を制御したい方を対象に、カウンタI/Oモジュールの概要,ソフトウェアのインストール方法,プログラミング方法を記載しています。 RTLinux上での弊社カウンタI/Oモジュール制御を使ったプログラミングにお役に立てれば幸いです。 本書では、以下記載がない限り、「RTLinux」は「RTLinux/Free」のことを指します。 なお本冊子はRTLinuxバージョン3.1を対象に作成されています。RTLinuxのバージョンが異なる場合、動作保証はいたしかねますので予めご了承ください。

●ご意見・ご要望 弊社へのご意見,ご要望がございましたら、下記までお問い合わせください。

www.interface.co.jp E-mail:[email protected]

●本冊子で扱うソフトウェア 本冊子で扱うソフトウェア製品を以下に列挙します。

ソフトウェア製品名 型式 パルスジェネレータI/Oモジュール Linux/RT対応ドライバソフトウェア GPG-6105 パルスカウンタI/Oモジュール Linux/RT対応ドライバソフトウェア GPG-6106 3モードパルスカウンタI/Oモジュール Linux/RT対応ドライバソフトウェア GPG-6201 ユニバーサルカウンタI/Oモジュール Linux/RT対応ドライバソフトウェア GPG-6202 3モードパルスカウンタI/Oモジュール Linux/RT対応ドライバソフトウェア GPG-6204

●ソフトウェアの入手方法について カウンタI/OモジュールのLinux/RTLinux対応ドライバソフトウェア(GPG-6105,6106,6201,6202,6204)をお求めの際は、弊社お客様相談センタまでお問い合わせください。

●カウンタI/OモジュールのLinux/RTLinux対応ドライバソフトウェア

(GPG-6105,6106,6201,6202,6204)のドキュメント構成について

Page 7: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 5 - Interface Corporation

各ドキュメントに掲載している内容は下記のとおりです。 ドキュメント 内容

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

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

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

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

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

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

PCI-320412 PCI-360116 PCI-6106 PCI-6202

PCI-320416 PCI-360216 PCI-6201 PCI-6204

PCI-360112 PCI-6105 PCI-6201E PCI-6205C

対象型式 (CPZ)

CPZ-320412 CPZ-360116

CPZ-320416 CPZ-6204

CPZ-360112 CPZ-6205

対象型式 (CTP)

CTP-320412 CTP-360116 CTP-6202

CTP-320416 CTP-6106 CTP-6204

CTP-360112 CTP-6201 CTP-6205

対象型式 (CSI)

CSI-320412 CSI-360116

CSI-320416 CSI-631204

CSI-360112

対象型式 (LPC)

LPC-321116 LPC-321416 LPC-361116 LPC-361416

LPC-321216 LPC-340216 LPC-361216 LPC-631204

LPC-321316 LPC-340416 LPC-361316 LPC-632104

対象型式 (PEX)

PEX-321116 PEX-321416 PEX-361116 PEX-361416

PEX-321216 PEX-340216 PEX-361216 PEX-631204

PEX-321316 PEX-340416 PEX-361316 PEX-632104

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

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

Page 8: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 6 -

第1章 概要

本章では、パルス/エンコード信号の入出力を行うカウンタI/Oモジュール(3モードパルスカウンタ/パルスカウンタ/ユニバーサルカウンタ/パルスジェネレータI/Oモジュール)の概要を説明します。

1.1 パルスジェネレータI/Oモジュールの概要

パルスジェネレータI/Oモジュールは、指定された周波数とデューティ比に従って、矩形状のパルスを連続的に発生するI/Oモジュールです。 パルス出力を実現するため、内部にPLL周波数シンセサイザを内蔵しています。 パルスジェネレータI/Oモジュールは、パルス出力の開始と停止、出力周波数の設定とデューティ比の切り替えが行えるようになっています。

パルスジェネレータボード

PLL周波数シンセサイザ

パルス出力開始パルス出力停止

周波数変更 デューティ比変更

パルス出力

パルス出力の仕組み

アナログ出力I/Oモジュールやデジタル出力I/Oモジュールとの大きな違いは、パルス出力に特化したハードウェアで実現しているため、出力されるパルスの精度が非常に高いということです。 なお、PLL周波数シンセサイザは、チャンネルごとに搭載されています。このため、チャンネルごとにパルス出力の周波数やデューティ比を変更することができます。

Page 9: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 7 - Interface Corporation

1.2 パルスカウンタI/Oモジュールの概要

パルスカウンタI/Oモジュールは、パルス信号のパルス数を計測する専用のI/Oモジュールです。 入力信号の立ち下りエッジあるいは立ち上がりエッジをカウントします。

入力信号

カウント カウント カウント

立ち下りエッジでカウントする例

基本機能はこれだけですが、本製品にはパルスカウントを制御するモードがいくつか用意されて

います。 モード 説明

ゲート付きカウントモード

外部ゲート信号の状態により、カウントの有効/無効を制御します。

ストップステータス

ゲート信号(GATE)

カウントクロック(CLK)

カウンタ

カウンタステータス

スタートステータス

カウント割込み

カウンタステータスリード

割り込みステータスリード

1 20 3 4 5 6 7 8

このモードでは、外部ゲート信号がLowレベルの時にパルス信号のカウントが行われます。 Highレベルの時に、パルス信号が入力されてもカウントされません。

スタートストップカウントモード

外部ゲート(スタート)信号と、外部ストップ信号の入力により、カウントの開始と停止を制御します。

ストップステータス

スタート信号(GATE)

カウントクロック(CLK)

カウンタ

カウンタステータス

スタートステータス

カウント割込み

ストップ信号(STOP)

カウンタステータスリード

割り込みステータスリード

1 20 3 4 5 6 7 8

このモードでは、外部ゲート(スタート)信号の立ち下りエッジでカウントの開始、外部ストップ信号の立ち下りでカウントが停止します。

Page 10: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 8 -

モード 説明

トグルカウントモード

外部ゲート信号の入力により、カウントの開始と停止が切り替わります。

1 20 3 4 5 6 7 8

ストップステータス

ゲート信号(GATE)

カウントクロック(CLK)

カウンタ

カウンタステータス

スタートステータス

カウント割込み

カウンタステータスリード

割り込みステータスリード このモードでは、外部ゲート信号の最初の立ち下がりエッジでカウントが開始、次の立ち下がりエッジでカウントの停止、更に次の立ち下がりエッジでカウントの開始といった動作を行います。

フリーカウントモード

PcntEnable関数の呼び出しにより、カウントの開始と停止を制御します。

1 20 3 4 5 6 7

イネーブルステータス

カウントクロック

カウンタ

カウンタステータス

8 9

このモードでは、外部信号を使用しません。

また、パルスカウンタI/Oモジュールは、通常外部クロック信号のパルスをカウントしますが、I/Oモジュール内部の基準クロック回路の出力信号をカウントさせることもできます。 基準クロック回路は、0.1μs~1sの間で設定可能です。

Page 11: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 9 - Interface Corporation

1.3 ユニバーサルカウンタI/Oモジュールの概要

ユニバーサルカウンタI/Oモジュールは、パルス信号のパルス数の計測の他、パルス信号の周期測定,Highパルス幅の測定,平均周波数の測定を行える多機能I/Oモジュールです。

<パルスカウントモード>

入力信号

カウント カウント カウント

<周期測定モード>

パルスの周期時間を測定

<平均周波数測定モード>

平均周波数を測定

<Highパルス幅測定モード>

Highパルス幅の時間を測定 その他、ユニバーサルカウンタI/Oモジュールには、計測に必要な幾つかの機能が搭載されています。

項目 説明 基準クロック パルスカウントモード以外のモードでは、この基準クロックが使用

されます。 基準クロックは、測定対象を計測するための基準を設定します。 走者の走る速度を測るために使用されるストップウオッチのような役割を果たします。

パルスカウントモード 外部入力信号のパルス数をカウントします。 この機能は『7ページ 1.2 パルスカウンタI/Oモジュールの概要』のパルスカウントI/Oモジュールの機能と同じものです。 このモードでは、単にパルス数をカウントするため、基準クロックの設定値は無効です。 それとは別に、入力信号の立ち下りエッジでカウントするか、立ち上がりエッジでカウントするか、設定できるようになっています。

周期測定モード 外部入力信号のパルス期間(入力信号の立ち上がりから次の立ち上がりまで。なお、入力極性を立ち下がりに変えることも可能です)に、基準クロックにて設定されたクロックが、何カウントできるかカウントすることで、周期を求めるモードです。 このモードでは、設定する基準クロックの値は、小さい値を与える方が得られる精度が高くなります。 例えば、入力信号の周期幅が100msの時、基準クロックを10msに設定すると得られるカウンタ値は10ですが(2桁の分解能)、基準クロックを1msにすると得られるカウンタ値は100になり(3桁の分解能)、精度が上がります。

Page 12: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 10 -

項目 説明

Highパルス幅測定モード 外部入力信号のHighパルスの間に、基準クロックにて設定されたクロックが、何カウントできるかカウントすることで、Highパルス幅を求めるモードです。 なお、本I/Oモジュールでは入力極性を反転させることができるので、Lowパルス幅を求めることもできます。 このモードでは、周期測定モードと同様、設定する基準クロックの値は、小さい値を与える方が得られる精度が高くなります。 とはいえ、無闇やたらに小さな基準クロック値を与えるのは禁物です。小さな基準クロック値は確かに精度を高めますが、カウンタのビット数が24ビットと有限であることに注意してください。 低周波数の入力信号に対して、高分解能の基準クロックを与えると、カウンタがオーバーフローする可能性が生じます。求める精度に応じて、基準クロックの値を設定してください。

平均周波数測定モード 基準クロックにて設定された時間の間に入力されたパルス数をカウントし、その平均値から平均周波数を求めるモードです。 このモードでは、設定する基準クロックの値は、入力周波数に対して大きい値を与える必要があります。 例えば、入力周波数が100Hzの時、周期幅は1÷100= 0.01sで、10msです。 基準クロックは、この10msより大きい値を与える必要があります。でないと、基準クロック区間内にパルスを計測できず、カウンタの値は常に0が返ってしまいます。 なお、設定する基準クロックの値は、平均周波数を求めるのにかかる時間です。大きな値を設定すると、それだけ計測に時間がかかることに留意してください。

分周器 本I/Oモジュールには、入力周波数を分周して、計数回路に入力する分周器が付いています。 この分周器の機能を使用する際は、設定値により精度が低下する場合があることに留意してください。 例えば、入力周波数が10kHz(= 10,000Hz)でなく、10,005Hzだったとします。この入力信号を1/100の設定の分周器を通ると、10005÷100= 100.05Hz≒約100Hzとなってしまいます。 通常は、1/1分周として計測を行うのがお奨めです。

0Hz検出 本I/Oモジュールには、指定された時間の間に入力に変化が無い時、これを検知する機能が搭載されています。 この機能を使用することで、外部入力信号に入力が無い状態を判断することができます。

Page 13: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 11 - Interface Corporation

1.4 3モードパルスカウンタI/Oモジュールの概要

3モードパルスカウンタI/Oモジュールは、ロータリ・エンコーダと呼ばれる軸の回転数をパルス信号に変換するセンサの出力信号をカウントし、軸の回転量を計測するI/Oモジュールです。主に、NC機械,ロボット,自動搬送機等のモータコントロールにおいて、その移動量をコンピュータで計測/解析するために使われます。

3モードパルス カウンタ

I/Oモジュール

ロータリ・エンコーダ

項目 説明 ロータリ・エンコーダの内部構造

下図にロータリ・エンコーダの内部機構を示します。

投光素子(LED)

B相スリット

A相スリット

Z相スリット

フォトトランジスタ

回転軸

固定スリット(B)

回転スリット(A)

A相B相Z相

投光素子

固定スリット(B)

回転スリット(A)

フォトトランジスタ

アンプ

回転軸

投光素子(LED)と受光素子(フォトトランジスタ)の間に2枚のスリット円盤A,Bが置いてあり、回転スリット(A)が回転することにより、投光素子の光が透過,遮断されます。 この光を受光素子で検出することで回転したか否か判断するわけです。出力信号を複数相にするため、固定スリット(B)は複数に分かれています。A相,B相,Z相の3つのスリットに分かれているものが一般的です。

Page 14: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 12 -

項目 説明

ロータリ・エンコーダの出力波形

下図に各端子(A相,B相,Z相)における波形の例を示します。

原点

1ピッチ

A相

B相

Z相

位相差90°

原点

A相

B相

時計回り:CW【Clockwise】

原点

A相

B 相

反時計回り:CCW【Counterclockwise】

Z相は3モードパルス1回転につき1パルス出力されます。 出力信号A,Bの位相差は常に90°です、これにより軸の回転方向により、出力される波形にずれが生じます。 時計回り(CW:【Clockwise】)の場合、A信号の立ち上がり時にB信号は必ず「Low」になっているため回転方向検出信号は「Low」になります。 反時計回り(CCW:【Counterclockwise】)の場合、A信号の立ち上がり時にB信号は「High」になっているため、回転方向検出信号は「High」になります。このようにして回転方向の判別を行うことができます。3モードパルスI/Oモジュールではカウント値の加算・減算が行われます。また、A,B信号の周波数は3モードパルスの回転速度と比例しています。したがって、これを一定時間間隔でカウントすれば回転速度を、検出することができます。

インクリメンタル型とアブソリュート型

ロータリ・エンコーダは、出力パルスの形式により、インクリメンタル型とアブソリュート型の2つに分類されます。弊社3モードパルスカウンタI/Oモジュールは、インクリメンタル型に対応しています。 (アブソリュート型を使用される場合、弊社デジタル入力I/Oモジュールを使用ください) アブソリュート型では回転の有無にかかわらず、回転角に応じた絶対位置の信号がパラレルに出力されます。 一方、インクリメンタル型では回転している間のみ、回転角度に応じたパルスが出力されます。

Page 15: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 13 - Interface Corporation

項目 説明

分解能 ロータリ・エンコーダを使用し計測制御を行う場合、その位置精度を示す値として分解能が用いられます。 ロータリ・エンコーダにおいて分解能とは、軸が1回転する際に出力されるパルス数を示しています。

逓倍(テイバイ) 逓倍とは、カウンタのカウントアップ(ダウン)のタイミングを表します。1逓倍はB相の入力が「Low」の時A相の入力の変化によりカウント値が変化します。2逓倍はA相の入力が変化した時カウント値が変化します。4逓倍はA相またはB相の入力が変化した時カウント値が変化します。 このため、1逓倍カウントでカウント値を1変化させると、4逓倍カウントでは、カウント値は4変化することになります。 従って、4逓倍カウントは1逓倍カウントの4倍の分解能をもっており、細かな位置指定が可能となります。

A

B

○ × × ×

○ ○ ○ ○

○ × ○ ×

←1逓倍→

A

B

× ○

○ ○

×

× ○←2逓倍→

←4逓倍→

アップカウント ダウンカウント

×

×

○:カウントする×:カウントしない

Page 16: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 14 -

第2章 カウンタI/Oモジュール on RTLinux

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

ます。

2.1 RTLinuxによるカウンタI/Oモジュール制御

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

<パルスジェネレータI/Oモジュールの場合>

パルスジェネレータ I/Oモジュール

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

Linux アプリケーション

パルス出力

入力機器

RTLinuxモジュール

RTLinuxスレッド

リアルタイム FIFO

<パルスカウンタI/Oモジュールの場合>

パルスカウンタ I/Oモジュール

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

Linuxアプリケーション

パルス入力

出力機器

RTLinuxモジュール

RTLinuxスレッド

リアルタイム FIFO

<ユニバーサルカウンタI/Oモジュールの場合>

ユニバーサル カウンタ

I/Oモジュール

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

Linux アプリケーション

パルス入力

出力機器

RTLinuxモジュール

RTLinuxスレッド

リアルタイム FIFO

<3モードパルスカウンタI/Oモジュールの場合>

3モードパルス カウンタ

I/Oモジュール

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

Linux アプリケーション

出力機器

RTLinuxモジュール

RTLinuxスレッド

エンコーダ入力

リアルタイム FIFO

RTLinux上でのカウンタI/Oモジュール制御構成

Page 17: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 15 - Interface Corporation

RTLinuxモジュール リアルタイム処理を行うモジュール本体です。お客様はRTLinux対応ドライバソフトウェアを使って、カウンタI/Oモジュールを制御するために、このモジュールを作成する必要があります。 RTLinuxスレッド 実際にリアルタイム処理を行う際、RTLinuxモジュール下で動作するRTLinuxスレッドを作成します。このRTLinuxスレッドは通常のLinuxのプロセスよりも優先して実行されます。 RT-FIFO リアルタイムFIFOとも呼ばれます。RTLinuxスレッドとLinuxアプリケーション、またはRTLinuxスレッド同士のデータの受け渡しを行うために使用されます。

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

Page 18: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 16 -

2.2 カウンタI/Oモジュール制御概略

カウンタI/Oモジュールの制御は、下記の制御シーケンス(順番)で行います。

I/Oモジュール初期化

各種処理

終了処理 (3)

(2)

(1)

カウンタI/Oモジュールの制御シーケンス

(1)I/Oモジュールの初期化 カウンタI/Oモジュールへの操作を行うため、まず、I/Oモジュールを利用可能な状態にします。 この処理がI/Oモジュールの初期化です。I/Oモジュールの初期化を行うと、プログラムはI/Oモジュールへのアクセスが可能となります。本処理が行われないとI/Oモジュールへのアクセスは行えません。

(2)各種処理 カウンタI/Oモジュールを使って、制御を行います。

(3)終了処理

I/Oモジュールの使用終了を行うための手続きです。プログラム終了時に行います。

Page 19: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 17 - Interface Corporation

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

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 2 7184 0 [rtl_sched rtl_fifo rtl_posixio

rtl_time] ↑rtl、rtl_time等のリアルタイムカーネルが組み込まれています。 リアルタイムカーネルは正常に組み込まれています。

リアルタイムカーネルを組み込んだ後に、ドライバモジュールを組み込むことにより、カウンタ

I/Oモジュールのリアルタイム制御が行えるようになります。

Page 20: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 18 -

第3章 パルスジェネレータI/Oモジュールの制御

ここでは、パルスジェネレータI/Oモジュールの制御プログラムを作成します。

3.1 パルスジェネレータドライバの組み込み

パルスジェネレータI/Oモジュールを制御するために、パルスジェネレータドライバモジュールを組み込む必要があります。 RTLinuxをインストールし、リアルタイムカーネルを組み込んだ後、「パルスジェネレータI/Oモジュール Linux/RTドライバソフトウェア(GPG-6105)」をインストールします。 以下のモジュールファイルがインストールされます。 ファイル名 内容 rcp6105.o パルスジェネレータI/Oモジュール制御のドライバモジュール本体です。

実際にI/Oモジュールを制御するためのモジュールです。このドライバモジュール内の関数をRTLinuxモジュールから呼び出すことにより、パルスジェネレータI/Oモジュールを制御することができます。

dpg0100.o 弊社RTLinuxドライバ群の共用モジュールです。

★テストドライバについて 上記ファイル以外に、GPG-6105をインストールすると、rcp6105t.oというファイルがインストールされます。こ

れは、I/Oモジュールがなくてもテストが行えるようにするためのテストドライバです。(仮想的なパルスジェネ

レータI/Oモジュールのドライバとして動作します) rcp6105.oの代わりに組み込むことで、I/Oモジュールを実装しなくても、各関数を実行することができます。

詳しい説明はヘルプを参照してください。

ドライバモジュールの組み込みは、inspulse.shスクリプトで簡単に行えます。 # cd /usr/src/interface/gpg6105/i386/rtl/drivers # sh inspulse.sh

モジュールが組み込まれているかどうかlsmodコマンドを使って確認します。 # lsmod Module Size Used by rcp6105 30560 0 (unused) dpg0100 6272 0 [rcp6105] rtl_sched 43200 0 [rcp6105 dpg0100] rtl_fifo 10016 0 (unused) rtl_posixio 7216 0 [rtl_fifo] rtl_time 10064 0 [rcp6105 rtl_sched rtl_posixio] rtl 27184 0 [rcp6105 dpg0102 rtl_sched rtl_fifo rtl_ posixio rtl_time] mbuf 6048 0 (unused)

dpg0100、rcp6105が組み込まれていることが分かります。 以上で、パルスジェネレータI/Oモジュールのリアルタイム制御を行うプログラミングまでの準備が整いました。

Page 21: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 19 - Interface Corporation

なお、ドライバモジュールの取り外しは、rmpulse.shスクリプトで行います。 #cd /usr/src/interface/gpg6105/i386/rtl/drivers #sh rmpulse.sh

以上で準備は終わりです。次からいよいよプログラミングを行っていきます。

★スクリプトを使わずに組み込むには? ドライバモジュールの組み込みは、スクリプトを使用する方が簡単なのでお奨めですが、直接ドライバモジュ

ールを組み込むことも可能です。 以下にinsmodコマンドを使った場合の組み込み例を示します。 insmodコマンドを使って、ドライバモジュールを組み込む場合> # insmod dpg0100 # insmod rcp6105 rmmodコマンドを使って、ドライバモジュールを取り外す場合> # rmmod rcp6105 #rmmod dpg0100

Page 22: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 20 -

3.2 パルス出力I/Oモジュールの制御

ここでは、パルスジェネレータI/OモジュールのCN1から周波数とデューティ比を変化させながらパルスを出力します。 そして、パルス出力の様子を、デジタルオシロスコープで確認します。

プログラム実行時に使用する製品

PCI-6105 1枚:パルスジェネレータI/Oモジュール TDS224 1台:デジタルオシロスコープ

ソニーテクトロニクス社製 BNCケーブル 1本

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

PCI-6105CN1

デジタルオシロスコープ(TDS224)

BNCケーブル

RSW1

パルスジェネレータI/Oモジュール(PCI-6105)のI/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに実装します。 パルスジェネレータI/OモジュールのCN1にBNCケーブルを接続し、デジタルオシロスコープに接続します。 以下の4つのファイルを作成します。 ファイル名 備考 pulse.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル pulse.c Linuxプロセスのソースコード pulse_mod.c RTLinuxモジュールのソースコード makefile 上記ソースコードをコンパイルするためのmakefile

Page 23: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 21 - Interface Corporation

下記Listは、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名を「pulse.h」として保存してください。

★プログラム中のコメントについて サンプルプログラムには、理解し易いよう、日本語コメントを用いています。 しかし、プログラム中に日本語を用いてコンパイルすると、正常にコンパイルできない場合があります。 その時は、日本語コメントを削除してコンパイルしてください。

pulse.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 40

/* パルス出力の制御サンプルプログラム 共通定義ヘッダファイル(pulse.h) Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___PULSE_H) #define ___PULSE_H #include "fbipulse.h" /* Constants ------------------------------------------------------------------ */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define DEVICE_ID 6105 /* I/Oモジュールを特定する一意のID値(PCI-6105を表す) */ #define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-6105を表す) */ #define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define CH_NO 1 /* パルス出力するチャンネル番号 */ /* Command ID ----------------------------------------------------------------- */ /* コマンドID群(RTLinuxスレッドへの指示用) */ enum CMD_IDS { ID_START, /* パルス出力のスタート指示 */ ID_STOP, /* パルス出力のストップ指示 */ ID_SET_CONFIG /* 周波数やデューティ比等の設定 */ }; /* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ /* 各コマンドに対する設定パラメータ */ long smp_period_ms; /* ID_START時使用:監視周期の設定(ms単位) */ int freq_base; /* ID_SET_CONFIG時使用:基本周波数の設定 */ int freq_mag; /* ID_SET_CONFIG時使用:周波数倍率の設定 */ int duty; /* ID_SET_CONFIG時使用:デューティ比の設定 */ }; #endif

Page 24: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 22 -

下記Listは、RTLinuxモジュールのソースファイルです。ファイル名を「pulse_mod.c」として保存してください。

pulse_mod.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

/* パルス出力の制御サンプルプログラム RTLinuxモジュールのソースコード(pulse_mod.c) Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "pulse.h" pthread_t my_task_info; int g_device_no = -1; /* パルスジェネレータI/Oモジュールのデバイス番号 */ /* 状態監視および制御を行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd; struct timespec t; 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: pulse out is start!!¥n"); ret = PulseGenerate(g_device_no, CH_NO); /* パルス出力の発生 */ if(ret){ rtl_printf("PulseGenerate error [ret=%x]¥n", ret); } pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* パルス出力のストップ */ rtl_printf("my_task: pulse out is stop!!¥n"); ret = PulseStop(g_device_no, CH_NO); /* パルス出力の停止 */ if(ret){ rtl_printf("PulseStop error [ret=%x]¥n", ret); } pthread_suspend_np(pthread_self()); break; case ID_SET_CONFIG: /* 周波数やデューティ比の設定 */ rtl_printf("my_task: pulse configuration!!(%d, %d, %d)¥n", cmd.freq_base, cmd.freq_mag, cmd.duty); /* 基本周波数と周波数倍率の設定 */ ret = PulseSetFreq(g_device_no, CH_NO, cmd.freq_base, cmd.freq_mag); if(ret){ rtl_printf("PulseSetFreq error [ret=%x]¥n", ret); } /* デューティ比の設定 */ ret = PulseSetDuty(g_device_no, CH_NO, cmd.duty); if(ret){

Page 25: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 23 - Interface Corporation

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

rtl_printf("PulseSetDuty error [ret=%x]¥n", ret); } break; default: rtl_printf("unknown id!!¥n"); break; } } /* 経過時間を表示する */ t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME)); rtl_printf("now clock=%ld¥n", t.tv_sec); } 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; 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)); /* パルスジェネレータI/Oモジュールのオープン */ ret = PulseOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no, ULSE_FLAG_NORMAL); if(ret){ rtl_printf("PulseOpenEx error [ret=%x]¥n", ret); return -1; } else { rtl_printf("PulseOpenEx success!! [device no=%d]¥n", g_device_no); } /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了関数(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret; rtl_printf("cleanup_module called¥n"); /* パルスジェネレータI/Oモジュールをクローズする */ ret = PulseClose(g_device_no);

Page 26: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 24 -

146 147 148 149 150 151 152 153 154 155 156 157

if(ret){ rtl_printf("PulseClose error [ret=%d]¥n", ret); } /* RT-FIFOを閉じる */ rtf_destroy(FIFO_COMMAND); rtf_destroy(FIFO_THRU_CMD); /* RTLinuxスレッドを終了させる */ pthread_cancel(my_task_info); pthread_join(my_task_info, NULL); }

下記Listは、Linuxプロセスのソースファイルです。ファイル名を「pulse.c」として保存してください。

pulse.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

/* パルス出力の制御サンプルプログラム Linuxプロセスのソースコード(pulse.c) 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 "pulse.h" /* キー入力待ちを行う関数マクロ */ #define HIT_ANY_KEY() do{ char dummy[20]; printf("--- Press the Enter key ---¥n"); fgets(dummy, sizeof(dummy), stdin); }while(0) /* Linuxプロセスのメインルーチン */ int main(void) { int fd_cmd; struct CMD_STRUCT cmd; char rt_fifo_name[80]; /* RTLinuxモジュールに指令を送るRT-FIFOのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND); if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -1; } printf("パルス出力の開始¥n"); cmd.id = ID_START; cmd.smp_period_ms = 500; /* 500ms周期の監視設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the start command.¥n"); return -1; } HIT_ANY_KEY(); printf("出力周波数100Hz、デューティ比20%に設定する¥n"); cmd.id = ID_SET_CONFIG; cmd.freq_base = 1000; cmd.freq_mag = PULSE_0_1; cmd.duty = 20; /* デューティ比20% */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the set config command.¥n"); return -1; } HIT_ANY_KEY(); printf("出力周波数123kHz、デューティ比80%に設定する¥n"); cmd.id = ID_SET_CONFIG; cmd.freq_base = 1230;

Page 27: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 25 - Interface Corporation

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

cmd.freq_mag = PULSE_100; cmd.duty = 80; /* デューティ比80% */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the set config command.¥n"); return -1;

} HIT_ANY_KEY(); printf("パルス出力の停止¥n"); cmd.id = ID_STOP; cmd.smp_period_ms = 0; if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the stop command.¥n"); return -1; } printf("fd_cmd:%d¥n", close(fd_cmd)); printf("The Linux process is successfully completed.¥n"); return 0; }

Page 28: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 26 -

下記Listは、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として保存してください。

makefile 1 2 3 4 5 6 7 8

include /usr/include/rtlinux/rtl.mk all: pulse_mod.o pulse pulse: pulse.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O3 -Wall -o pulse pulse.c pulse_mod.o: pulse_mod.c $(CC) $(INCLUDE) $(CFLAGS) -o pulse_mod.o -c pulse_mod.c

コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。

# make ← コンパイルします # ls ← コンパイルしたファイルを一覧表示します makefile pulse pulse.c pulse.h pulse_mod.c pulse_mod.o # insmod pulse_mod.o ← RTLinuxモジュールを組み込んでいます

次に、Linuxプロセスを実行します。

# ./pulse ← Linuxプロセスを実行します

すると、以下のようなメッセージが表示されます。

パルス出力の開始 --- Press the Enter key ---

オシロスコープの画面を監視しながら、Enterキーを押してください。

出力周波数100Hz、デューティ比20%に設定する --- Press the Enter key ---

オシロスコープで、100Hzでデューティ比20%のパルスが出力されている様子が確認できます。更にEnterキーを押します。

出力周波数123kHz、デューティ比80%に設定する --- Press the Enter key ---

Page 29: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 27 - Interface Corporation

今度は、123kHzでデューティ比80%のパルスが出力されている様子が確認できます。

オシロスコープでパルス出力を確認している様子

更にEnterキーを押すと、プログラムが終了します。

パルス出力の停止 fd_cmd:0 The Linux process is successfully completed. #

Page 30: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 28 -

3.3 パルス出力I/Oモジュールの制御の解説

それでは、先ほどのプログラムの解説をします。

3.3.1 サンプルプログラムの動き

サンプルプログラムは、以下の順番で、パルスジェネレータI/Oモジュールに対して制御を行っています。 1. パルスジェネレータI/Oモジュールに対して、パルス出力を開始させる。 2.「--- Press the Enter key ---」と表示し、Enterキー待ちをする。 3. パルス出力の周波数を100Hzに、デューティ比を20%に切り替える。 「--- Press the Enter key ---」と表示し、Enterキー待ちをする。

4. パルス出力の周波数を123kHzに、デューティ比を80%に切り替える。 5.「--- Press the Enter key ---」と表示し、Enterキー待ちをする。 6. パルスジェネレータI/Oモジュールに対して、パルス出力を停止させる。 サンプルを動かす時、Linuxプロセス(pulse)とRTLinuxモジュール(pulse_mod.o),パルスジェネレータI/Oモジュールのドライバモジュール(rcp6105.o)が連携して動作しています。 これらの関係を下図に示します。

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

パルスジェネレータのドライバモジュール(rcp6105.o)

Linuxプロセス,RTLinuxモジュール,ドライバモジュールの相関関係

パルスジェネレータI/Oモジュールの直接の制御は、ドライバモジュールが担当します。 ドライバモジュールを使ったパルス出力の制御は、RTLinuxモジュールが行っています。Linuxプロセスは、RTLinuxモジュールに対して、作業の依頼を行っています。

Page 31: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 29 - Interface Corporation

3.3.2 共通定義ファイルの役割と、LinuxプロセスとRTLinuxモジュールとの連携

共通定義ファイル(pulse.h)は、LinuxプロセスとRTLinuxモジュールのコードの内、共通で使用する定義の内容を抜き出したものです。

共通定義ファイルでは、以下の設定を行っています。 行番号 内容

13~19行目 #define宣言> RT-FIFOの番号の定義と、各関数で使用する定数値を指定。

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

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

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

Linuxプロセス

RTLinuxモジュール

struct CMD_STRUCT {

enum CMD_IDS id;

long

smp_period_ms;

int freq_base;

int freq_mag;

int duty;

};

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

コマンドの構造体は、RTLinuxモジュールが行う作業の指示を行うID値(idメンバ変数)と、ID値に補足する情報(smp_period_ms,freq_base,freq_mag,dutyメンバ変数)によって構成されます。 作業の指示を行うID値の種類は、CMD_IDS列挙体にて定義されています。

id変数 内容 ID_START パルス出力を開始させる。

また、smp_period_msで指定した時間間隔(ms)で、RTLinuxモジュール内のRTLinuxスレッド(my_task)をスタートする。

ID_STOP パルス出力を停止させる。 また、RTLinuxスレッド(my_task)をストップさせる。

ID_SET_CONFIG パルス出力の周波数とデューティ比を変更する。 freq_baseとfreq_magの組み合わせで周波数を、dutyでデューティ比を変更する。

この構造体は、後の説明にも出てきますので注意して読み進めてください。

Page 32: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 30 -

3.3.3 RTLinuxモジュールの動き

RTLinuxモジュール(pulse_mod.o)は、Linuxプロセスからの作業依頼に従って、ドライバを使ってパルス出力の制御を行います。 (107~134行目:RT-FIFO、RTLinuxスレッドの生成やドライバの初期化) RTLinuxモジュールが組み込まれる時、最初に107行から始まるinit_module関数が呼び出されます。

ここでは、RT-FIFOやRTLinuxスレッド、ハンドラ等のリソースを生成しています。 項目 内容

RT-FIFO(FIFO_COMMAND) 117行目のrtf_create関数> Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハンドラmy_handlerに渡されます。

RT-FIFO(FIFO_THRU_CMD) 122行目のrtf_create関数> ハンドラにて、Linuxプロセスから受け取った情報を、パルス出力制御を行うRTLinuxスレッド(my_task)に渡すためのRT-FIFOです。

ハンドラ(my_handler) 118行目のrtf_create_handler関数> Linuxプロセスからの指示を受け取るための処理の入り口です。RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る処理に回されます。

RTLinuxスレッド(my_task) 134行目のpthread_create関数> パルス出力制御を行うRTLinuxスレッドです。 Linuxプロセスから送られる指示は、最終的にここに送られ、パルス出力制御を行います。

また、パルスジェネレータI/Oモジュールの制御を開始するために、125行目のPulseOpenEx関数を使ってオープンしています。

以下に引数と対応を示します。 引数名 内容

ulDeviceID デバイスIDを指定します ulSubSystemIDと組み合わせて、I/Oモジュールの型式を指定します。 組み合わせについては、ヘルプを参照してください。

ulSubSystemID サブシステムIDを指定します。 ulBoardID I/Oモジュール識別用ロータリスイッチ(RSW1)の設定値を指定

します。 pnDevice 上記の組み合わせに対するデバイス番号が、呼出し後にセット

されます。 fdwFlags 排他的にオープンするか(多重にオープンできない)、共有して

オープンするか指定します。

この引数を与えて関数を呼び出すと、ドライバモジュールは、引数に適合するパルスジェネレー

タI/Oモジュールを検索し、合致したI/Oモジュールに対してデバイス番号を割り振り、第4引数に返します。 プログラマは、このデバイス番号を使って、以降のAPIの呼び出しを行います。

Page 33: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 31 - Interface Corporation

★何故、PulseOpenEx関数を使うのか? LinuxやWindowsプログラムでは、PulseOpen関数を使用しますが、RTLinuxではPulseOpenEx関数の使用

を推奨しています。 これは、プログラムで使用するパルスジェネレータI/Oモジュールを、システム内で一意のID値を使用するこ

とで、他の環境にシステムを移築しても特定するためにあります。 PulseOpen関数を使用した場合、第1引数で指定するデバイス番号は、RTLinuxシステム内で、パルスジェ

ネレータI/Oモジュールが認識された順番に割り振られます。 この場合、複数のパルスジェネレータI/Oモジュールを使用していた場合、ユニット並びにコンピュータ内のパ

ルスジェネレータI/Oモジュールの順番を変更した際、想定外のデバイス番号が割り振られてしまう恐れがあ

ります。 これを避けるため、RTLinuxプログラムでは、PulseOpenEx関数を使い、パルスジェネレータI/Oモジュールを

特定してデバイス番号を得る仕組みを推奨しています。

(94~102行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

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

(26~81行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この26~81行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、パルス出力の開始と停止、周波数とデューティ比の変更を行い(35~75行の処理)、周期呼び出し毎に、経過時間をログに出力しています (79~80行目)。

処理の決定は、CMD_IDS列挙体の定数値により決定されます。 列挙定数値 内容

ID_START 39行目のPulseGenerate関数で、パルス出力を開始します。 また、 smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し(44行目)、自身の実行周期の間隔を指定しています。

ID_STOP 50行目のPulseStop関数で、パルス出力を停止します。 また、pthread_suspend_np関数を呼び出し(55行目)、自身のスレッドをスリープ状態にしています。

ID_SET_CONFIG freq_baseメンバ変数とfreq_magメンバ変数の組み合わせで、62行目のPulseSetFreq関数で周波数を変更します。 dutyメンバ変数の値で、68行目のPulseSetDuty関数でデューティ比を変更します。

ID_STARTでパルス出力を行うと、RTLinuxスレッドは周期的に実行を行います。 サンプルでは、79~80行目で経過時間をログ出力しています。

Page 34: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 32 -

3.3.4 Linuxプロセスの動き

Linuxプロセス(pulse)は、パルス出力の制御をRTLinuxモジュールに対して依頼します。

main RT-FIFO(FIFO_COMMAND)コマンド指令 RTLinux

モジュール

LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係

(28~32行目:RT-FIFOのオープン処理) ここでは、open関数を使用し、RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープンしています。 (34~40行目:パルス出力の開始) ここでは、RTLinuxモジュールに対して、パルス出力を開始させるため、CMD_STRUCT構造体に、パルス出力開始を意味するID_START列挙定数と、周期間隔を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (44~52行目:周波数とデューティ比の変更) ここでは、RTLinuxモジュールに対して、パルス出力の周波数を100Hzに、デューティ比を20%に変更させるため、CMD_STRUCT構造体に周波数とデューティ比の変更を意味するID_SET_CONFIG列挙定数と各パラメータを指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (56~64行目:周波数とデューティ比の変更2) 先ほどと同じで、パルス出力の周波数を123kHz、デューティ比を80%に変更させる指示をRT-FIFO経由で送っています。 (68~74行目:パルス出力の停止) ここでは、RTLinuxモジュールに対して、パルス出力を停止させるため、CMD_STRUCT構造体に、パルス出力停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

Page 35: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 33 - Interface Corporation

第4章 パルスカウンタI/Oモジュールの制御

ここでは、パルスカウンタI/Oモジュールの制御プログラムを作成します。

4.1 パルスカウンタドライバの組み込み

パルスカウンタI/Oモジュールを制御するために、パルスカウンタドライバモジュールを組み込む必要があります。 RTLinuxをインストールし、リアルタイムカーネルを組み込んだ後、「パルスカウンタI/Oモジュール Linux/RTドライバソフトウェア(GPG-6106)」をインストールします。 以下のモジュールファイルがインストールされます。 ファイル名 内容 rcp6106.o パルスカウンタI/Oモジュール制御のドライバモジュール本体です。

実際にI/Oモジュールを制御するためのモジュールです。このドライバモジュール内の関数をRTLinuxモジュールから呼び出すことにより、パルスカウンタI/Oモジュールを制御することができます。

dpg0100.o 弊社RTLinuxドライバ群の共用モジュールです。 dpg0102.o 弊社RTLinuxドライバ群の共用モジュールです。

★テストドライバ(rcp6106t.o)について 上記ファイル以外に、GPG-6106をインストールすると、rcp6106t.oというファイルがインストールされます。こ

れは、I/Oモジュールがなくてもテストが行えるようにするためのテストドライバです。(仮想的なパルスカウン

タI/Oモジュールのドライバとして動作します) rcp6106.oの代わりに組み込むことで、I/Oモジュールを実装しなくても、各関数を実行することができます。

詳しい説明はヘルプを参照してください。 ドライバモジュールの組み込みは、inspcnt.shスクリプトで簡単に行えます。 # cd /usr/src/interface/gpg6106/i386/rtl/drivers # sh inspcnt.sh

モジュールが組み込まれているかどうかlsmodコマンドを使って確認します。 # lsmod Module Size Used by rcp6106 29472 0 dpg0102 790352 0 [rcp6106] dpg0100 6272 0 [rcp6106] rtl_sched 43200 0 [rcp6106 dpg0100] rtl_fifo 10016 0 rtl_posixio 7216 0 [rtl_fifo] rtl_time 10064 0 [rcp6106 rtl_sched rtl_posixio] rtl 27184 0 [rcp6106 dpg0102 dpg0100 rtl_sched rtl_fifo rtl_posixio rtl_time] mbuf 6048 0 (unused)

Page 36: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 34 -

dpg0100、dpg0102、rcp6106が組み込まれていることが分かります。 以上で、パルスカウンタI/Oモジュールのリアルタイム制御を行うプログラミングまでの準備が整いました。 なお、ドライバモジュールの取り外しは、rmpcnt.shスクリプトで行います。 # cd /usr/src/interface/gpg6106/i386/rtl/drivers # sh rmpcnt.sh

以上で準備は終わりです。次からいよいよプログラミングを行っていきます。 ★スクリプトを使わずに組み込むには? ドライバモジュールの組み込みは、スクリプトを使用する方が簡単なのでお奨めですが、直接ドライバモジュ

ールを組み込むことも可能です。 以下にinsmodコマンドを使った場合の組み込み例を示します。 insmodコマンドを使って、ドライバモジュールを組み込む場合> # insmod dpg0100 # insmod dpg0102 # insmod rcp6106 rmmodコマンドを使って、ドライバモジュールを取り外す場合> # rmmod rcp6106 # rmmod dpg0102 # rmmod dpg0100

4.2 パルスカウンタI/Oモジュールの制御

ここでは、パルスカウンタI/OモジュールのCH1に入力されたパルス数をカウントします。

プログラム実行時に使用する製品 PCI-6106 1枚:パルスカウンタI/Oモジュール ファンクションジェネレータ 1台:岩崎通信機社製 SG-4101 TRM-2201 1台:96点裸線接続端子台(DINレール) CAB-6601 1本:96ピンハーフピッチ接続ケーブル BNCケーブル 1本

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

PCI-6106CN1ファンクションジェネレータ

BNCケーブル

RSW110

TRM-2201

CAB-6601

Page 37: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 35 - Interface Corporation

パルスカウンタI/Oモジュール(PCI-6106)のI/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに実装します。 ファンクションジェネレータの出力を、TRM-2201を介してCN1のCH1に結線します。結線例を以下に示します。

ファンクションジェネレータ側 PCI-6106 CN1側 +側 TCLK1 -側 GND

お手持ちのパルスカウンタI/Oモジュールで、どのように接続すれば良いかについては、ハードウェアマニュアルの『外部接続』を参照してください。 以下の4つのファイルを作成します。 ファイル名 備考

pcnt.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル pcnt.c Linuxプロセスのソースコード pcnt_mod.c RTLinuxモジュールのソースコード makefile 上記ソースコードをコンパイルするためのmakefile

Page 38: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 36 -

下記Listは、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名を「pcnt.h」として保存してください。

pcnt.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

/* パルスカウンタI/Oモジュールによる制御サンプルプログラム 共通定義ヘッダファイル(pcnt.h) Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___PCNT_COMMON_H) #define ___PCNT_COMMON_H #include "fbipcnt.h" /* Constants --------------------------------------------------------------- */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define FIFO_RESULT 3 /* Linuxプロセスへ結果を送るRT-FIFO */ #define DEVICE_ID 6106 /* I/Oモジュールを特定する一意のID値(PCI-6106を表す) */ #define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-6106を表す) */ #define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define CH_NO 1 /* カウント入力するチャンネル番号 */ #define BUFF_SIZE 10 /* ユーザプロセスへ結果を送る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 39: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 37 - Interface Corporation

下記Listは、RTLinuxモジュールのソースファイルです。ファイル名を「pcnt_mod.c」として保存してください。

pcnt_mod.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

/* パルスカウンタI/Oモジュールによる制御サンプルプログラム RTLinuxモジュールのソースコード(pcnt_mod.c) Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "pcnt.h" pthread_t my_task_info; int g_device_no = -1; /* パルスカウンタI/Oモジュールのデバイス番号 */ /* 定周期カウントを行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd; struct timespec t; unsigned short count; 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: count start¥n"); /* カウンタのクリア */ ret = PcntClear(g_device_no, CH_NO); if(ret){ rtl_printf("PcntClear error [ret=%x]¥n", ret); } /* カウンタの動作開始 */ ret = PcntEnable(g_device_no, CH_NO, 1); if(ret){ rtl_printf("PcntEnable error [ret=%x]¥n", ret); } /* 定周期設定 */ pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* 定周期カウントのストップ */ rtl_printf("my_task: count stop¥n"); /* カウンタの動作停止 */ ret = PcntEnable(g_device_no, CH_NO, 0); if(ret){ rtl_printf("PcntEnable error [ret=%x]¥n", ret); } /* カウンタのクリア */ ret = PcntClear(g_device_no, CH_NO); if(ret){ rtl_printf("PcntClear error [ret=%x]¥n", ret); }

Page 40: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 38 -

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

pthread_suspend_np(pthread_self()); break; default: rtl_printf("unknown id!!¥n"); break; } } else { /* カウンタ値の読み込み */ ret = PcntRead(g_device_no, CH_NO, &count); if(ret){ rtl_printf("PcntRead error [ret=%x]¥n", ret); } else { /* 読み込んだカウンタ値を、ユーザプロセスへRT-FIFOを介して返す */ rtf_put(FIFO_RESULT, &count, sizeof(count)); } } /* 経過時間を表示する */ t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME)); rtl_printf("now clock=%ld¥n", t.tv_sec); } 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; 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(unsigned short) * BUFF_SIZE); /* パルスカウンタI/Oモジュールのオープン */ ret = PcntOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no, 0); if(ret){ rtl_printf("PcntOpenEx error [ret=%x]¥n", ret); return -1; } else { rtl_printf("PcntOpenEx success!! [device no=%d]¥n", g_device_no); } /* モードの設定 */

Page 41: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 39 - 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

ret = PcntSetMode( g_device_no, CH_NO, 3, /* フリーカウントモード */ 1, /* 非絶縁TTL入力 */ 1, /* 立下りエッジでカウント */ 0); /* 外部クロックを使用 */ if(ret){ rtl_printf("PcntSetMode error [ret=%x]¥n", ret); return -2; } #if 0 /* 内部クロックの周期設定 */ ret = PcntSetBaseClock(g_device_no, CH_NO, 7 /* 1Hzの内部クロック */); if(ret){ rtl_printf("PcntSetBaseClock error [ret=%x]¥n", ret); return -3; } /* 補足説明: PcntSetBaseClockは、PcntSetModeで内部クロックを選択した際に 有効です。 内部クロックを選択すると、パルスカウンタI/Oモジュールには、ここで 設定した周期のクロックがカウンタに入力されます。 */ #endif /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了モジュール(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret; rtl_printf("cleanup_module called¥n"); /* パルスカウンタI/Oモジュールをクローズする */ ret = PcntClose(g_device_no); if(ret){ rtl_printf("PcntClose 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); }

Page 42: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 40 -

下記Listは、Linuxプロセスのソースファイルです。ファイル名を「pcnt.c」として保存してください。

pcnt.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

/* パルスカウンタI/Oモジュールによる制御サンプルプログラム Linuxプロセスのソースコード(pcnt.c) 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 "pcnt.h" /* Linuxプロセスのメインルーチン */ int main(void) { int fd_cmd, fd_result; fd_set rfds; struct timeval tv; struct CMD_STRUCT cmd; char rt_fifo_name[80]; int i; unsigned short count; /* RTLinuxモジュールに指令を送るRT-FIFOのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND); if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -1; } /* RTLinuxモジュールからの結果を受け取るFIFOチャネルのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT); if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -2; } printf("パルスカウントの開始¥n"); cmd.id = ID_START; cmd.smp_period_ms = 500; /* 500ms周期の周期設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the start command.¥n"); return -3; } /* パルスカウンタのデータ受信(10回データを受け取るかタイムアウトすると抜けます) */ for(i = 0; i < 10; i++){ FD_ZERO(&rfds); FD_SET(fd_result, &rfds); tv.tv_sec = 60; /* select関数のタイムアウト値の設定:60秒 */ tv.tv_usec = 0; /* メッセージの受け取り */ if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){ if(FD_ISSET(fd_result, &rfds)){ /* fd_resultに対してFIFOの書き込みがあった */ if(read(fd_result, &count, sizeof(count)) > 0){ printf("count = %u¥n", count); } } } } printf("パルスカウントの停止¥n"); cmd.id = ID_STOP; if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){

Page 43: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 41 - Interface Corporation

70 71 72 73 74 75 76 77 78 79

fprintf(stderr, "Failed 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 process is successfully completed.¥n"); return 0; }

下記Listは、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として保存してください。

makefile 1 2 3 4 5 6 7 8

include /usr/include/rtlinux/rtl.mk all: pcnt_mod.o pcnt pcnt: pcnt.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o pcnt pcnt.c pcnt_mod.o: pcnt_mod.c $(CC) $(INCLUDE) $(CFLAGS) -o pcnt_mod.o -c pcnt_mod.c

コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。

# make ← コンパイルします # ls ← コンパイルしたファイルを一覧表示します makefile pcnt pcnt.c pcnt.h pcnt_mod.c pcnt_mod.o # insmod pcnt_mod.o ← RTLinuxモジュールを組み込んでいます

次に、ファンクションジェネレータからパルスを出力させながら、Linuxプロセスを実行します。

# ./pcnt ← Linuxプロセスを実行します

パルスカウントの結果が表示されます。

パルスカウントの開始 count = 25 count = 50 count = 76 count = 101 count = 127 count = 152 count = 178 count = 203 count = 229 count = 254 パルスカウントの停止 fd_cmd:0 fd_result:0 The Linux process is successfully completed.

Page 44: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 42 -

4.3 パルスカウンタI/Oモジュールの制御の解

それでは、先ほどのプログラムの解説をします。

4.3.1 プログラムの動き

プログラムの大まかな動きを、下図に示します。 Linuxプロセス RTLinuxモジュール

スタート指令

ID_START

計測したカウンタ値

カウンタ値読み込み

計測したカウンタ値

カウンタ値読み込み

ストップ指令

ID_STOP

・・・

500ms周期

パルスカウンタプログラムの動作概要

1. LinuxプロセスからRTLinuxモジュールに対し、指定された周期(プログラムでは500ms周期)でカウンタ値を読み取るよう指示が出されます。

2. LinuxプロセスからRTLinuxモジュールに対し、指定された周期(プログラムでは500ms周期)でカウンタ値を読み取るよう指示が出されます。

3. RTLinuxモジュールでは周期毎に、パルスカウンタのカウンタ値を読み取り、Linuxプロセスに対してRT-FIFO経由で、データを送ります。

4. Linuxプロセスは、送られたデータを受け取り、カウンタ値を表示します。 プログラムでは、これを10回繰り返しています。

5. Linuxプロセスは、カウンタ値読み取りを停止するよう指示します。

Page 45: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 43 - Interface Corporation

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

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

パルスカウンタのドライバモジュール(rcp6106.o)

受信データ

FIFO_RESULT

パルスカウンタI/Oモジュールの直接の制御は、ドライバモジュールが担当します。 ドライバモジュールを使ったパルスカウンタの制御は、RTLinuxモジュールが行っています。Linuxプロセスは、RTLinuxモジュールに対して、作業の依頼を行っています。

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

共通定義ファイル(pcnt.h)は、LinuxプロセスとRTLinuxモジュールのコードの内、共通で使用する定義の内容を抜き出したものです。

共通定義ファイルでは、以下の設定を行っています。 行番号 内容

13~22行目 #define宣言> RT-FIFOの番号の定義と、各関数で使用する定数値を指定。

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

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

ここで重要なのは、LinuxプロセスからRTLinuxモジュールに対して指令を出すために使用される、コマンドの構造体(CMD_STRUCT)です。

Page 46: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 44 -

コマンドの構造体(CMD_STRUCT)は、RTLinuxモジュールが行う作業の指示を行うID値(idメンバ変数)の種類を、CMD_IDS列挙体で定義しています。

id変数 内容 ID_START パルスカウンタの読み取りを開始させる>

smp_period_msで指定した時間間隔(ms)で、RTLinuxモジュール内のRTLinuxスレッド(my_task)をスタートする。

ID_STOP パルスカウンタの読み取りを停止させる> RTLinuxスレッド(my_task)をストップさせる。

この構造体は、後の説明にも出てきますので注意して読み進めてください。

4.3.3 RTLinuxモジュールの動き

RTLinuxモジュール(pcnt_mod.o)は、Linuxプロセスからの作業依頼に従って、ドライバからパルスカウンタのカウンタ読み取り等の制御を行います。 (115~174行目:RT-FIFO、RTLinuxスレッドの生成やドライバの初期化) RTLinuxモジュールが組み込まれる時、最初に115行から始まるinit_module関数が呼び出されます。 ここでは、RT-FIFOやRTLinuxスレッド、ハンドラ等のリソースを生成しています。

項目 内容 RT-FIFO(FIFO_COMMAND) 125行目のrtf_create関数>

Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハンドラmy_handlerに渡されます。

RT-FIFO(FIFO_THRU_CMD) 130行目のrtf_create関数> ハンドラにて、Linuxプロセスから受け取った情報を、RTLinuxスレッド(my_task)に渡すためのRT-FIFOです。

RT-FIFO(FIFO_RESULT) 134行目のrtf_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッド(my_task)で取得したデータを、Linuxプロセスに渡すためのRT-FIFOです。

ハンドラ(my_handler) 126行目のrtf_create_handler関数> Linuxプロセスからの指示を受け取るための処理の入り口です。RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る処理に回されます。

RTLinuxスレッド (my_task)

173行目のpthread_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッドです。 Linuxプロセスから送られる指示は、最終的にここに送られ、パルスカウンタの制御を行います。

また、パルスカウンタI/Oモジュールの制御を開始するために、137行目のPcntOpenEx関数を使ってオープンしています。

Page 47: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 45 - Interface Corporation

以下に引数と対応を示します。 引数名 内容

uDeviceID デバイスIDを指定します。 uSubsystemIDと組み合わせて、I/Oモジュールの型式を指定します。 組み合わせについては、ヘルプを参照ください。

uSubsystemID サブシステムIDを指定します。 uBoardID I/Oモジュール識別用ロータリスイッチ(RSW1)の設定値を指定します。 pnDevice 上記の組み合わせに対するデバイス番号が、呼出し後にセットされま

す。 uReserved 予約された引数です(0を指定します)。

この引数を与えて関数を呼び出すと、ドライバモジュールは、引数に適合するパルスカウンタI/Oモジュールを検索し、合致したI/Oモジュールに対してデバイス番号を割り振り、第4引数に返します。 プログラマは、このデバイス番号を使って、以降のAPIの呼び出しを行います。

★何故、PcntOpen関数を使うのか? LinuxやWindowsプログラムでは、PcntOpen関数を使用しますが、RTLinuxではPcntOpenEx関数の使用を

推奨しています。 これは、プログラムで使用するパルスカウンタI/Oモジュールを、システム内で一意のID値を使用すること

で、他の環境にシステムを移築しても特定するためにあります。 PcntOpen関数を使用した場合、第1引数で指定するデバイス番号は、RTLinuxシステム内で、パルスカウン

タI/Oモジュールが認識された順番に割り振られます。 この場合、複数のパルスカウンタI/Oモジュールを使用していた場合、ユニット並びにコンピュータ内のパル

スカウンタI/Oモジュールの順番を変更した際、想定外のデバイス番号が割り振られてしまう恐れがありま

す。 これを避けるため、RTLinuxプログラムでは、PcntOpenEx関数を使い、パルスカウンタI/Oモジュールを特定

してデバイス番号を得る仕組みを推奨しています。

146行目のPcntSetMode関数では、モードの設定を行います。 このプログラムでは、カウンタ動作モードをフリーカウントモード、入力仕様を非絶縁TTL入力、外部クロックの極性を立下りエッジ、入力パルスのクロック源を外部クロックに設定しています。

★内部クロックを使用する場合 プログラムでは、外部クロックをパルスカウントの対象としています。 内部クロックをパルスカウントの対象とする場合、151行目の0を1に修正し、157行目の「#if 0」を「#if 1」とし

て157~170行目のコードを有効化させ、コンパイルしてください。 159行目のPcntSetBaseClock関数は内部クロックの周期を設定します。 プログラムでは、1Hzに設定しています。

Page 48: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 46 -

(102~106行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

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

(27~89行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この27~89行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、定周期のカウンタ読み出しと停止を行っています。

処理の決定は、CMD_IDS列挙体の定数値により決定されます。 列挙定数値 内容

ID_START 41行目のPcntClear関数で、カウンタを0クリアします。 47行目のPcntEnable関数で、パルスカウントを開始させます。 smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し(53行目)、自身の実行周期の間隔を指定しています。

ID_STOP 60行目のPcntEnable関数で、パルスカウントを停止させます。 66行目のPcntClear関数で、カウンタを0クリアします。 pthread_suspend_np関数を呼び出し(71行目)、自身のスレッドをスリープ状態にしています。

パルスカウントの開始と停止は、PcntEnable関数で行います。この関数を呼び出してパルスカウントを開始すると、パルスカウンタは現在のカウンタ値からカウントを行います。 パルスカウントの開始時0からカウントさせるため、PcntClear関数を呼び出してカウンタを0クリアしています。

★PcntEnable関数は、フリーカウントモード以外でも必要です。 プログラムでは、フリーカウントモードを使用してパルスカウントを行っています。 その他のモード、例えばゲート付きカウントモードで、この関数の呼び出しは必要でしょうか? 答えは必要です。 PcntEnable関数は、カウンタ機能の有効/無効を制御します。そのため、この関数を呼び出してカウンタ機

能を有効にしない限り、ゲート付きカウントモードに設定して、外部ゲート信号をLowレベルにしたとしても、

カウンタは動作しません。

ID_STARTでカウントを開始すると、RTLinuxスレッドは周期的に実行を行います。 周期的な実行呼び出し時は、76~83行の処理が行われます。 ここでは、77行目のPcntRead関数でカウンタ値を読み取り、カウンタ値をLinuxプロセスにRT-FIFO経由で送ります。

Page 49: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 47 - Interface Corporation

4.3.4 Linuxプロセスの動き

Linuxプロセス(pcnt)は、パルスカウンタの制御をRTLinuxモジュールに対して依頼します。

main

RT-FIFO(FIFO_RESULT)

RT-FIFO(FIFO_COMMAND)

カウンタ値取得

コマンド指令 RTLinux

モジュール

LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係

(29~40行目:RT-FIFOのオープン処理) ここでは、open関数を使用し、RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープンしています。 (43~48行目:周期的なカウント読み出しの開始) ここでは、RTLinuxモジュールに対して、周期的のカウント読み出しを開始させるため、CMD_STRUCT構造体に開始を意味するID_START列挙定数と、周期間隔を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (51~65行目:カウンタ値の取得) ここでは、RTLinuxモジュール内で実行される周期的なカウンタ読み出し処理から、受け取ったカウンタ値を、select関数とread関数を使って、取得しています。 データの取得は、10回行われます。 (68~72行目:周期的なカウント読み出しの停止) ここでは、RTLinuxモジュールに対して、周期的なカウント読み出しを停止させるため、CMD_STRUCT構造体に実行停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

Page 50: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 48 -

第5章 ユニバーサルカウンタI/Oモジュールの制御

ここでは、ユニバーサルカウンタI/Oモジュールの制御プログラムを作成します。

5.1 ユニバーサルカウンタドライバの組み込み

ユニバーサルカウンタI/Oモジュールを制御するために、ユニバーサルカウンタドライバモジュールを組み込む必要があります。 RTLinuxをインストールし、リアルタイムカーネルを組み込んだ後、「ユニバーサルカウンタI/OモジュールLinux/RTドライバソフトウェア(GPG-6202)」をインストールします。 以下のモジュールファイルがインストールされます。 ファイル名 内容 rcp6202.o ユニバーサルカウンタI/Oモジュール制御のドライバモジュール本体です。

実際にI/Oモジュールを制御するためのモジュールです。このドライバモジュール内の関数をRTLinuxモジュールから呼び出すことにより、ユニバーサルカウンタI/Oモジュールを制御することができます。

dpg0100.o 弊社RTLinuxドライバ群の共用モジュールです。 dpg0102.o 弊社RTLinuxドライバ群の共用モジュールです。

★テストドライバ(rcp6202t.o)について 上記ファイル以外に、GPG-6202をインストールすると、rcp6202t.oというファイルがインストールされます。こ

れは、I/Oモジュールがなくてもテストが行えるようにするためのテストドライバです。(仮想的なユニバーサル

カウンタI/Oモジュールのドライバとして動作します) rcp6202.oの代わりに組み込むことで、I/Oモジュールを実装しなくても、各関数を実行することができます。

詳しい説明はヘルプを参照してください。 ドライバモジュールの組み込みは、inscnt.shスクリプトで簡単に行えます。 # cd /usr/src/interface/gpg6202/i386/rtl/drivers # sh inscnt.sh

モジュールが組み込まれているかどうかlsmodコマンドを使って確認します。 # lsmod Module Size Used by rcp6202 47552 0 (unused) dpg0102 790352 0 [rcp6202] dpg0100 6272 0 [rcp6202] rtl_sched 43200 0 [rcp6202 dpg0100] rtl_fifo 10016 0 rtl_posixio 7216 0 [rtl_fifo] rtl_time 10064 0 [rcp6202 rtl_sched rtl_posixio] rtl 27184 0 [rcp6202 dpg0102 dpg0100 rtl_sched rtl_fifo rtl_posixio rtl_time] mbuf 6048 0 (unused)

Page 51: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 49 - Interface Corporation

dpg0100、dpg0102、rcp6202が組み込まれていることが分かります。 以上で、ユニバーサルカウンタI/Oモジュールのリアルタイム制御を行うプログラミングまでの準備が整いました。

なお、ドライバモジュールの取り外しは、rmcnt.shスクリプトで行います。 # cd /usr/src/interface/gpg6202/i386/rtl/drivers # sh rmcnt.sh

以上で準備は終わりです。次からいよいよプログラミングを行っていきます。 ★スクリプトを使わずに組み込むには? ドライバモジュールの組み込みは、スクリプトを使用する方が簡単なのでお奨めですが、直接ドライバモジュ

ールを組み込むことも可能です。 以下にinsmodコマンドを使った場合の組み込み例を示します。 insmodコマンドを使って、ドライバモジュールを組み込む場合> # insmod dpg0100 # insmod dpg0102 # insmod rcp6202 rmmodコマンドを使って、ドライバモジュールを取り外す場合> # rmmod rcp6202 # rmmod dpg0102 # rmmod dpg0100

Page 52: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 50 -

5.2 ユニバーサルカウンタI/Oモジュールの制御

ここでは、ユニバーサルカウンタI/OモジュールのCH1に入力されたパルス数をカウントします。

プログラム実行時に使用する製品 PCI-6202 1枚:ユニバーサルカウンタI/Oモジュール ファンクションジェネレータ 1台:岩崎通信機社製 SG-4101 TRM-2201 1台:96点裸線接続端子台(DINレール) CAB-6601 1本:96ピンハーフピッチ接続ケーブル BNCケーブル 1本

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

PCI-6202CN1ファンクションジェネレータ

BNCケーブル

RSW110

TRM-2201

CAB-6601

ユニバーサルカウンタI/Oモジュール(PCI-6202)のI/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに実装します。 ファンクションジェネレータの出力を、TRM-2201を介してCN1のCH1に結線します。結線例を以下に示します。

ファンクションジェネレータ側 PCI-6202 CN1側 +側 IN1(T) -側 GND

お手持ちのユニバーサルカウンタI/Oモジュールで、どのように接続すれば良いかについては、ハードウェアマニュアルの『外部接続』を参照してください。 以下の4つのファイルを作成します。 ファイル名 備考

cnt.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義ファイル cnt.c Linuxプロセスのソースコード cnt_mod.c RTLinuxモジュールのソースコード makefile 上記ソースコードをコンパイルするためのmakefile

Page 53: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 51 - Interface Corporation

下記Listは、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名を「cnt.h」として保存してください。

cnt.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 40 41 42 43 44 45 46 47 48 49 50

/* ユニバーサルカウンタI/Oモジュールによる制御サンプルプログラム 共通定義ヘッダファイル(cnt.h) Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___CNT_COMMON_H) #define ___CNT_COMMON_H #include "fbicnt.h" /* Constants --------------------------------------------------------------- */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define FIFO_RESULT 3 /* Linuxプロセスへ結果を送るRT-FIFO */ #define DEVICE_ID 6202 /* I/Oモジュールを特定する一意のID値(PCI-6202を表す) */ #define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-6202を表す) */ #define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define CH_NO 1 /* パルス入力するチャンネル番号 */ #define BUFF_SIZE 10 /* ユーザプロセスへ結果を送るRT-FIFOのサイズ */ /* Command ID -------------------------------------------------------------- */ /* コマンドID群(RTLinuxスレッドへの指示用) */ enum CMD_IDS { ID_SET_CONFIG, /* 読み出すカウンタ値の種類の設定 */ ID_START, /* 定周期カウントのスタート指示 */ ID_STOP /* 定周期カウントのストップ指示 */ }; /* 読み出すカウンタ値の種類 */ enum CNT_TYPE { TYPE_AVG_FREQ = 0, /* 平均周波数測定モード */ TYPE_CYCLE = 1, /* 周期測定モード */ TYPE_H_PULSE_WIDTH = 2, /* Highパルス幅測定モード */ TYPE_PULSE_COUNT = 3 /* パルスカウントモード */ }; /* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ /* 各コマンドに対する設定パラメータ */ long smp_period_ms; /* ID_START時使用:周期の設定(ms単位) */ enum CNT_TYPE type; /* ID_SET_CONFIG時使用:カウンタ値の種類設定 */ int base_clock; /* ID_SET_CONFIG時使用:基準クロック設定 */ }; #endif

Page 54: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 52 -

下記Listは、RTLinuxモジュールのソースファイルです。ファイル名を「cnt_mod.c」として保存してください。

cnt_mod.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

/* ユニバーサルカウンタI/Oモジュールによる制御サンプルプログラム RTLinuxモジュールのソースコード(cnt_mod.c) Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "cnt.h" pthread_t my_task_info; int g_device_no = -1; /* ユニバーサルカウンタI/Oモジュールのデバイス番号 */ enum CNT_TYPE g_mode_type; /* カウンタ動作モード */ /* サブルーチン:カウンタ値の読み込み */ unsigned long get_cnt_read(void) { int ret; unsigned long count; /* カウンタ値の読み込み */ ret = CntRead(g_device_no, CH_NO, &count); if(ret){ rtl_printf("CntRead error [ret=%x]¥n", ret); count = -1L; /* 読み込みに失敗したら-1を返す */ } else { rtl_printf("CntRead count=%x¥n", count); } return count; } /* 定周期カウントを行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd; struct timespec t; unsigned long count; 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_SET_CONFIG: /* 読み出すカウンタ値の種類の設定 */ rtl_printf("my_task: set config¥n"); g_mode_type = cmd.type; /* モードの設定 */ ret = CntSetMode( g_device_no, CH_NO, (int)g_mode_type, /* 動作モードの指定 */ 1, /* 立下りエッジでカウント */ 1, /* 分周率を1/1に設定 */ 1); /* 非絶縁TTL入力 */ if(ret){ rtl_printf("CntSetMode error [ret=%x]¥n", ret);

Page 55: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 53 - 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

} if(g_mode_type != TYPE_PULSE_COUNT){ /* 補足説明: パルスカウントモードの時、この関数の呼び出しは無効です。 */ /* 基準クロックの設定 */ ret = CntSetBaseClock( g_device_no, CH_NO, cmd.base_clock, /* 基準クロックの設定 */ 0); /* 0Hz検出時間:無効に設定 */ if(ret){ rtl_printf("CntSetBaseClock error [ret=%x]¥n", ret); } } else { /* 補足説明: パルスカウントモード時のみ、この関数の呼び出しは有効です。 */ /* カウンタ方向の設定 */ ret = CntSetCounterDirection( g_device_no, CH_NO, 0); /* UP方向 */ if(ret){ rtl_printf("CntSetCounterDirection error [ret=%x]¥n", ret); } } break; case ID_START: /* 定周期カウントのスタート */ rtl_printf("my_task: count start¥n"); if(g_mode_type == TYPE_PULSE_COUNT){ /* カウンタのクリア */ ret = CntClear(g_device_no, CH_NO); if(ret){ rtl_printf("CntClear error [ret=%x]¥n", ret); } } /* 定周期設定 */ pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* 定周期カウントのストップ */ rtl_printf("my_task: count stop¥n"); pthread_suspend_np(pthread_self()); break; default: rtl_printf("unknown id!!¥n"); break; } } else { count = get_cnt_read(); /* カウンタ値読み出しのルーチン呼び出し */ rtf_put(FIFO_RESULT, &count, sizeof(count)); } /* 経過時間を表示する */ t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME)); rtl_printf("now clock=%ld¥n", t.tv_sec); } 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));

Page 56: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 54 -

144 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

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; 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(unsigned long) * BUFF_SIZE); /* ユニバーサルカウンタI/Oモジュールのオープン */ ret = CntOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no, CNT_FLAG_NORMAL); if(ret){ rtl_printf("CntOpenEx error [ret=%x]¥n", ret); return -1; } else { rtl_printf("CntOpenEx success!! [device no=%d]¥n", g_device_no); } /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了モジュール(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret; rtl_printf("cleanup_module called¥n"); /* ユニバーサルカウンタI/Oモジュールをクローズする */ ret = CntClose(g_device_no); if(ret){ rtl_printf("CntClose 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); }

Page 57: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 55 - Interface Corporation

下記Listは、Linuxプロセスのソースファイルです。ファイル名を「cnt.c」として保存してください。

cnt.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

/* ユニバーサルカウンタI/Oモジュールによる制御サンプルプログラム Linuxプロセスのソースコード(cnt.c) 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 "cnt.h" /* Linuxプロセスのメインルーチン */ int main(void) { int fd_cmd, fd_result; fd_set rfds; struct timeval tv; struct CMD_STRUCT cmd; char rt_fifo_name[80]; int i; long count; /* RTLinuxモジュールに指令を送るRT-FIFOのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND); if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -1; } /* RTLinuxモジュールからの結果を受け取るFIFOチャネルのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT); if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -2; } /* 読み出すカウンタ値の種類を設定 */ cmd.id = ID_SET_CONFIG; cmd.type = TYPE_PULSE_COUNT; /* パルスカウントモードに設定 */ cmd.base_clock = 6; /* 基準クロック:1msに設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the config command.¥n"); return -3; } printf("カウントの開始¥n"); cmd.id = ID_START; cmd.smp_period_ms = 500; /* 500ms周期の周期設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the start command.¥n"); return -4; } /* パルスカウンタのデータ受信(10回データを受け取るかタイムアウトすると抜けます) */ for(i = 0; i < 10; i++){ FD_ZERO(&rfds); FD_SET(fd_result, &rfds); tv.tv_sec = 60; /* select関数のタイムアウト値の設定:60秒 */ tv.tv_usec = 0; /* メッセージの受け取り */ if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){ if(FD_ISSET(fd_result, &rfds)){ /* fd_resultに対してFIFOの書き込みがあった */

Page 58: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 56 -

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

if(read(fd_result, &count, sizeof(count)) > 0){ printf("count = %ld (read %s)¥n", count, (count < 0) ? "fail" : "success"); } } } } printf("カウントの停止¥n"); cmd.id = ID_STOP; if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the stop command.¥n"); return -5; } printf("fd_cmd:%d¥n", close(fd_cmd)); printf("fd_result:%d¥n", close(fd_result)); printf("The Linux process is successfully completed.¥n"); return 0; }

下記Listは、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として保存してください。

makefile 1 2 3 4 5 6 7 8

include /usr/include/rtlinux/rtl.mk all: cnt_mod.o cnt cnt: cnt.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o cnt cnt.c cnt_mod.o: cnt_mod.c $(CC) $(INCLUDE) $(CFLAGS) -o cnt_mod.o -c cnt_mod.c

コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。

# make ← コンパイルします # ls ← コンパイルしたファイルを一覧表示します cnt cnt.c cnt.h cnt_mod.c cnt_mod.o makefile # insmod cnt_mod.o ← RTLinuxモジュールを組み込んでいます

次に、ファンクションジェネレータからパルスを出力させながら、Linuxプロセスを実行します。

# ./cnt ← Linuxプロセスを実行します

パルスカウントの結果が表示されます。

カウントの開始 count = 26 (read success) count = 51 (read success) count = 77 (read success) count = 102 (read success) count = 128 (read success) count = 154 (read success) count = 179 (read success) count = 205 (read success) count = 230 (read success) count = 256 (read success) カウントの停止 fd_cmd:0 fd_result:0 The Linux process is successfully completed.

Page 59: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 57 - Interface Corporation

5.3 ユニバーサルカウンタI/Oモジュールの制御の解

それでは、先ほどのプログラムの解説をします。

5.3.1 プログラムの動き

プログラムの大まかな動きを、下図に示します。

Linuxプロセス RTLinuxモジュール

モード等の指定

ID_SET_CONFIG

スタート指令

ID_START

計測したカウンタ値

カウンタ値読み込み

計測したカウンタ値

カウンタ値読み込み

ストップ指令

ID_STOP

・・・

500ms周期

ユニバーサルカウンタプログラムの動作概要

1. Linuxプロセスから、ユニバーサルカウンタI/Oモジュールに対するモード設定と、基準クロックの値がセットされます。

2. LinuxプロセスからRTLinuxモジュールに対し、指定された周期(プログラムでは500ms周期)でカウンタ値を読み取るよう指示が出されます。

3. RTLinuxモジュールでは周期ごとに、ユニバーサルカウンタのカウンタ値を読み取り、Linuxプロセスに対してRT-FIFO経由で、データを送ります。

4. Linuxプロセスは、送られたデータを受け取り、カウンタ値を表示します。 プログラムでは、これを10回繰り返しています。

5. Linuxプロセスは、カウンタ値読み取りを停止するよう指示します。

Page 60: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 58 -

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

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

ユニバーサルカウンタのドライバモジュール(rcp6202.o)

受信データ

FIFO_RESULT

ユニバーサルカウンタI/Oモジュールの直接の制御は、ドライバモジュールが担当します。 ドライバモジュールを使ったユニバーサルカウンタの制御は、RTLinuxモジュールが行っています。Linuxプロセスは、RTLinuxモジュールに対して、作業の依頼を行っています。

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

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

行番号 内容 13~22行目 #define宣言>

RT-FIFOの番号の定義と、各関数で使用する定数値を指定。 26~38行目 enum宣言>

LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値と、ユニバーサルカウンタに対するモードの種類を指定。

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

ここで重要なのは、LinuxプロセスからRTLinuxモジュールに対して指令を出すために使用される、コマンドの構造体(CMD_STRUCT)です。

Page 61: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 59 - Interface Corporation

コマンドの構造体(CMD_STRUCT)は、RTLinuxモジュールが行う作業の指示を行うID値(idメンバ変数)の種類を、CMD_IDS列挙体で定義しています。

id変数 内容 ID_SET_CONFIG ユニバーサルカウンタ読み取り時のモードを指定する>

typeの値で、ユニバーサルカウンタ読み取り時のモードを指定する。 base_clockの値で、基準クロックの値を指定する。

ID_START ユニバーサルカウンタの読み取りを開始させる> smp_period_msで指定した時間間隔(ms)で、RTLinuxモジュール内のRTLinuxスレッド(my_task)をスタートする。

ID_STOP ユニバーサルカウンタの読み取りを停止させる> RTLinuxスレッド(my_task)をストップさせる。

この構造体は、後の説明にも出てきますので注意して読み進めてください。

5.3.3 RTLinuxモジュールの動き

RTLinuxモジュール(cnt_mod.o)は、Linuxプロセスからの作業依頼に従って、ドライバからユニバーサルカウンタのカウンタ読み取り等の制御を行います。 (155~187行目:RT-FIFO、RTLinuxスレッドの生成やドライバの初期化) RTLinuxモジュールが組み込まれる時、最初に155行から始まるinit_module関数が呼び出されます。

ここでは、RT-FIFOやRTLinuxスレッド、ハンドラ等のリソースを生成しています。 項目 内容

RT-FIFO(FIFO_COMMAND) 165目のrtf_create関数> Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハンドラmy_handlerに渡されます。

RT-FIFO(FIFO_THRU_CMD) 170行目のrtf_create関数> ハンドラにて、Linuxプロセスから受け取った情報を、RTLinuxスレッド(my_task)に渡すためのRT-FIFOです。

RT-FIFO(FIFO_RESULT) 174行目のrtf_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッド(my_task)で取得したデータを、Linuxプロセスに渡すためのRT-FIFOです。

ハンドラ(my_handler) 166行目のrtf_create_handler関数> Linuxプロセスからの指示を受け取るための処理の入り口です。RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る処理に回されます。

RTLinuxスレッド (my_task)

186行目のpthread_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッドです。 Linuxプロセスから送られる指示は、最終的にここに送られ、ユニバーサルカウンタの制御を行います。

Page 62: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 60 -

また、ユニバーサルカウンタI/Oモジュールの制御を開始するために、177行目のCntOpenEx関数を使ってオープンしています。 以下に引数と対応を示します。

引数名 内容 uDeviceID デバイスIDを指定します

uSubsystemIDと組み合わせて、I/Oモジュールの型式を指定します。 組み合わせについては、ヘルプを参照してください。

uSubsystemID サブシステムIDを指定します。 uBoardID I/Oモジュール識別用ロータリスイッチ(RSW1)の設定値を指定します。 pnDevice 上記の組み合わせに対するデバイス番号が、呼出し後にセットされます。 fdwFlags 排他的にオープンするか(多重にオープンできない)、共有してオープンする

か指定します。

この引数を与えて関数を呼び出すと、ドライバモジュールは、引数に適合するユニバーサルカウ

ンタI/Oモジュールを検索し、合致したI/Oモジュールに対してデバイス番号を割り振り、第4引数に返します。プログラマは、このデバイス番号を使って、以降のAPIの呼び出しを行います。

★何故、CntOpenEx関数を使うのか? LinuxやWindowsプログラムでは、CntOpen関数を使用しますが、RTLinuxではCntOpenEx関数の使用を推

奨しています。 これは、プログラムで使用するユニバーサルカウンタI/Oモジュールを、システム内で一意のID値を使用する

ことで、他の環境にシステムを移築しても特定するためにあります。 CntOpen関数を使用した場合、第1引数で指定するデバイス番号は、RTLinuxシステム内で、ユニバーサル

カウンタI/Oモジュールが認識された順番に割り振られます。 この場合、複数のユニバーサルカウンタI/Oモジュールを使用していた場合、ユニット並びにコンピュータ内

のユニバーサルカウンタI/Oモジュールの順番を変更した際、想定外のデバイス番号が割り振られてしまう

恐れがあります。 これを避けるため、RTLinuxプログラムでは、CntOpenEx関数を使い、ユニバーサルカウンタI/Oモジュール

を特定してデバイス番号を得る仕組みを推奨しています。

(142~146行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

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

Page 63: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 61 - Interface Corporation

(45~129行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この45~129行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、定周期のカウンタ読み出しと停止を行っています。 処理の決定は、CMD_IDS列挙体の定数値により決定されます。

列挙定数値 内容 ID_SET_CONFIG 61行目のCntSetMode関数でカウンタ動作モード(typeメンバ変数にて指定)

と入力極性(立下りエッジに固定)、分周率(1分周に固定)、入力仕様(非絶縁TTL入力に固定)の設定を行います。 typeメンバ変数にてパルスカウントモードに指定された場合、90行目のCntSetCounterDirection関数でカウンタ方向をUP方向に設定します。 パルスカウントモード以外に指定された場合、77行目のCntSetBaseClock関数で基準クロック(base_clockメンバ変数にて指定)と0Hz検出時間(無効に固定)の設定を行います。

ID_START カウンタ動作モードがパルスカウントモードに指定されている場合、104行目のCntClear関数で、カウンタを0クリアします。 次に、smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し(111行目)、自身の実行周期の間隔を指定しています。

ID_STOP pthread_suspend_np関数を呼び出し(117行目)、自身のスレッドをスリープ状態にしています。

カウンタ動作がパルスカウントモードか、そうでないかによって、呼び出す関数が変化している

ことに注意してください。 ID_STARTでカウントを開始すると、RTLinuxスレッドは周期的に実行を行います。 周期的な実行呼び出し時は、122~123行の処理が行われます。 ここでは、122行目のサブルーチンget_cnt_readでカウンタ値を読み取り、カウンタ値をLinuxプロセスにRT-FIFO経由で送ります。 get_cnt_readの処理は18~32行目にあります。ここでは、CntRead関数でカウンタ値の読み取りを行い、値を返却します。もし、読み取りに失敗すると-1を返します。

★カウンタ値の読み取りの失敗 ユニバーサルカウンタでは、カウンタ値の読み取りに失敗する場合があります。 例えば、周期測定モードの時、周期測定が終わる前にカウンタ値を読み取ろうとすると失敗します。これ

は、周期測定が完了していないのに値を読もうとしているからで、周期測定が完了した後ならば、正常に

値を取得できます。 これを回避するには、CntGetStatus関数でカウンタ値がラッチされたのを確認するか、カウンタラッチ時に発

生させることができる割り込みを使用して、カウンタ値を読み取ります。

Page 64: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 62 -

5.3.4 Linuxプロセスの動き

Linuxプロセス(cnt)は、ユニバーサルカウンタの制御をRTLinuxモジュールに対して依頼します。

main

RT-FIFO(FIFO_RESULT)

RT-FIFO(FIFO_COMMAND)

カウンタ値取得

コマンド指令 RTLinux

モジュール

LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係

(29~40行目:RT-FIFOのオープン処理) ここでは、open関数を使用し、RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープンしています。 (43~49行目:モードの設定) ここでは、RTLinuxモジュールに対して、動作モードと基準クロックの値を設定させるため、CMD_STRUCT構造体に設定を意味するID_SET_CONFIG列挙定数と、動作モードと基準クロック値をセットし、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (52~57行目:周期的なカウント読み出しの開始) ここでは、RTLinuxモジュールに対して、周期的のカウント読み出しを開始させるため、CMD_STRUCT構造体に開始を意味するID_START列挙定数と周期間隔を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (60~74行目:カウンタ値の取得) ここでは、RTLinuxモジュール内で実行される周期的なカウンタ読み出し処理から受け取ったカウンタ値を、select関数とread関数を使って取得しています。 データの取得は、10回行われます。 (77~81行目:周期的なカウント読み出しの停止) ここでは、RTLinuxモジュールに対して、周期的なカウント読み出しを停止させるため、CMD_STRUCT構造体に実行停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

Page 65: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 63 - Interface Corporation

第6章 3モードパルスカウンタI/Oモジュールの制御

ここでは、3モードパルスカウンタI/Oモジュールの制御プログラムを作成します。

6.1 3モードパルスカウンタドライバの組み込み

3モードパルスカウンタI/Oモジュールを制御するために、3モードパルスカウンタドライバモジュールを組み込む必要があります。 RTLinuxをインストールし、リアルタイムカーネルを組み込んだ後、「3モードパルスカウンタI/OモジュールLinux/RTドライバソフトウェア(GPG-6204/GPG-6201)」をインストールします。 以下のモジュールファイルがインストールされます。

ファイル名 内容

rcp6204.o (rcp6201.o)

3モードパルスカウンタI/Oモジュール制御のドライバモジュール本体です。 実際にI/Oモジュールを制御するためのモジュールです。このドライバモジュール内の関数をRTLinuxモジュールから呼び出すことにより、3モードパルスカウンタI/Oモジュールを制御することができます。

dpg0100.o 弊社RTLinuxドライバ群の共用モジュールです。 dpg0102.o 弊社RTLinuxドライバ群の共用モジュールです。

★テストドライバ(rcp6204t.o/ rcp6201t.o)について 上記ファイル以外に、GPG-6204(GPG-6201)をインストールすると、rcp6204t.o(rcp6201t.o)というファイルが

インストールされます。これは、I/Oモジュールがなくてもテストが行えるようにするためのテストドライバです。

(仮想的な3モードパルスカウンタI/Oモジュールのドライバとして動作します) rcp6204.o(rcp6201t.o)の代わりに組み込むことで、I/Oモジュールを実装しなくても、各関数を実行すること

ができます。詳しい説明はヘルプを参照してください。 ドライバモジュールの組み込みは、inspenc.shスクリプトで簡単に行えます。 # cd /usr/src/interface/gpg6204/i386/rtl/drivers # sh inspenc.sh

モジュールが組み込まれているかどうかlsmodコマンドを使って確認します。 # lsmod Module Size Used by rcp6204 94064 0 dpg0102 790352 0 (unused) dpg0100 6272 0 [rcp6204] rtl_sched 43200 0 [rcp6204 dpg0100] rtl_fifo 10016 0 rtl_posixio 7216 0 [rtl_fifo] rtl_time 10064 0 [rcp6204 rtl_sched rtl_posixio] rtl 27184 0 [rcp6204 dpg0102 dpg0100 rtl_sched rtl_fifo rtl_posixio rtl_time] mbuf 6048 0 (unused)

dpg0100,dpg0102,rcp6204が組み込まれていることが分かります。 以上で、3モードパルスカウンタI/Oモジュールのリアルタイム制御を行うプログラミングまでの準備が整いました。

Page 66: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 64 -

なお、ドライバモジュールの取り外しは、rmpenc.shスクリプトで行います。 # cd /usr/src/interface/gpg6204/i386/rtl/drivers # sh rmpenc.sh

以上で準備は終わりです。次からいよいよプログラミングを行っていきます。

★スクリプトを使わずに組み込むには? ドライバモジュールの組み込みは、スクリプトを使用する方が簡単なのでお奨めですが、直接ドライバモジュ

ールを組み込むことも可能です。 以下にinsmodコマンドを使った場合の組み込み例を示します。 insmodコマンドを使って、ドライバモジュールを組み込む場合> # insmod dpg0100 # insmod dpg0102 # insmod rcp6204 rmmodコマンドを使って、ドライバモジュールを取り外す場合> # rmmod rcp6204 # rmmod dpg0102 # rmmod dpg0100

Page 67: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 65 - Interface Corporation

6.2 3モードパルスカウンタI/Oモジュールの制御

ここでは、ロータリエンコーダを接続し、ロータリエンコーダのカウント数を計測します。

プログラム実行時に使用する製品 PCI-6204 1枚:3モードパルスカウンタI/Oモジュール ロータリエンコーダ 1個:オムロン社製 E6A2-CWZ3 外部電源 1個

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

PCI-6204CN1ロータリエンコーダ

RSW1

+ -外部電源

3モードパルスカウンタI/Oモジュール(PCI-6204)のI/Oモジュール識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに実装します。 使用するロータリエンコーダをCN1のCH1に結線します。結線例を以下に示します。 ロータリエンコーダ側 PCI-6204 CN1側 外部電源側

茶 51:1A+ 53:1B+ 55:1Z+

+5V

黒 52:1A-(L) 白 54:1B-(L) 橙 56:1Z-(L) 青 GND

お手持ちのロータリエンコーダI/Oモジュールで、どのように接続すれば良いかについては、ハードウェアマニュアルの『個別仕様』を参照してください。

以下の4つのファイルを作成します。 ファイル名 備考

penc.h LinuxプロセスとRTLinuxモジュールの双方で共有する定義 ファイル

penc.c Linuxプロセスのソースコード penc_mod.c RTLinuxモジュールのソースコード makefile 上記ソースコードをコンパイルするためのmakefile

Page 68: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 66 -

下記Listは、LinuxプロセスとRTLinuxモジュール間で、共通で使う定義ファイルです。ファイル名を「penc.h」として保存してください。

penc.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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

/* 3モードパルスカウンタI/Oモジュールによる制御サンプルプログラム 共通定義ヘッダファイル(penc.h) Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___PENC_COMMON_H) #define ___PENC_COMMON_H #include "fbipenc.h" /* Constants --------------------------------------------------------------- */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define FIFO_RESULT 3 /* Linuxプロセスへ結果を送るRT-FIFO */ #define DEVICE_ID 6204 /* I/Oモジュールを特定する一意のID値(PCI-6204を表す) */#define SUB_SYSTEM_ID 0x0001 /* I/Oモジュールを特定する一意のID値(PCI-6204を表す) */ #define RSW_NO 0 /* 同一型式のI/Oモジュールを区別するRSW1設定値 */ #define CH_NO 1 /* エンコーダから入力するチャンネル番号 */ #define BUFF_SIZE 10 /* ユーザプロセスへ結果を送るRT-FIFOのサイズ */ /* Command ID -------------------------------------------------------------- */ /* コマンドID群(RTLinuxスレッドへの指示用) */ enum CMD_IDS { ID_SET_CONFIG, /* 読み出すカウンタ値の種類の設定 */ ID_START, /* 定周期カウントのスタート指示 */ ID_STOP /* 定周期カウントのストップ指示 */ }; /* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ /* 各コマンドに対する設定パラメータ */ long smp_period_ms; /* ID_START時使用:周期の設定(ms単位) */ unsigned long base_count; /* ID_START時使用:スタート時のカウンタ値 */ int mode; /* ID_SET_CONFIG時使用:モード設定 */ unsigned long comp_count; /* ID_SET_CONFIG時使用:比較カウンター値 */ }; /* ステータスの種類 */ enum STAT_TYPE { STAT_COUNT, /* カウンタデータ */ STAT_COMPARATOR, /* 比較カウンタ一致検出 */ STAT_CARRY_BORROW /* キャリー・ボロー検出 */ }; /* ステータス用の構造体 */ struct STAT_STRUCT { enum STAT_TYPE type; /* ステータスの種類 */ unsigned long count; /* カウンタ値データ */ }; #endif

Page 69: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 67 - Interface Corporation

下記Listは、RTLinuxモジュールのソースファイルです。ファイル名を「penc_mod.c」として保存してください。

penc_mod.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

/* 3モードパルスカウンタI/Oモジュールによる制御サンプルプログラム RTLinuxモジュールのソースコード(penc_mod.c) Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include "penc.h" pthread_t my_task_info; int g_device_no = -1; /* 3モードパルスカウンタI/Oモジュールのデバイス番号 */ #define STAT_CHK_CBF (1 << 8) /* ステータスチェック用:キャリー・ボロービット */ #define STAT_CHK_EQF (1 << 11) /* ステータスチェック用:一致検出ビット */ #define STAT_CHK_ALL (STAT_CHK_CBF | STAT_CHK_EQF) /* サブルーチン:カウンタ値の読み込み */ int get_cnt_read(unsigned long* ret_count) { int ret; unsigned long count; /* カウンタ値の読み込み */ ret = PencGetCounter(g_device_no, CH_NO, &count); if(ret){ rtl_printf("PencGetCounter error [ret=%x]¥n", ret); } else { rtl_printf("CntRead count=%x¥n", count); *ret_count = count; } return ret; } /* サブルーチン:ステータス変化時の処理(ステータスの変化をRT-FIFO経由で送る) */ void sub_stat_proc(int status) { struct STAT_STRUCT rt_stat; unsigned long count; if(status & STAT_CHK_ALL){ /* 現在のカウンタ値の読み込み */ if(get_cnt_read(&count)) return; if(status & STAT_CHK_CBF){ /* キャリー・ボロー発生検出 */ rt_stat.type = STAT_CARRY_BORROW; } else if(status & STAT_CHK_EQF){ /* カウンタ一致検出 */ rt_stat.type = STAT_COMPARATOR; } /* 補足説明: カウンタ一致検出には、EQビットとEQFビットがありますが、 ここではステータスリードまで値を保持する、EQFビットを 用いています。 なお、QBFビットもステータスリードまで値が保持されます。 */ rt_stat.count = count; /* ステータス値を、ユーザプロセスへRT-FIFOを介して返す */ rtf_put(FIFO_RESULT, &rt_stat, sizeof(rt_stat)); } } /* 定周期カウントを行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd;

Page 70: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 68 -

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

struct timespec t; int status; struct STAT_STRUCT rt_stat; unsigned long count; 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_SET_CONFIG: /* 読み出すカウンタ値の種類の設定 */ rtl_printf("my_task: set config¥n"); /* モードの設定 */ ret = PencSetMode( g_device_no, CH_NO, cmd.mode, /* 動作モードの指定 */ 0, /* UP方向のカウント */ 1, /* 比較一致検出を行う */ 0); /* ソフトウェアラッチを行う */ if(ret){ rtl_printf("PencSetMode error [ret=%x]¥n", ret); } /* 比較カウンタのセット */ ret = PencSetComparator( g_device_no, CH_NO, cmd.comp_count); /* 比較カウンタ値 */ if(ret){ rtl_printf("PencSetComparator error [ret=%x]¥n", ret); } break; case ID_START: /* 定周期カウントのスタート */ rtl_printf("my_task: count start¥n"); ret = PencSetCounter( g_device_no, CH_NO, cmd.base_count); /* ベースカウンタ値 */ if(ret){ rtl_printf("PencSetCounter error [ret=%x]¥n", ret); } /* 定周期設定 */ pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* 定周期カウントのストップ */ rtl_printf("my_task: count stop¥n"); pthread_suspend_np(pthread_self()); break; default: rtl_printf("unknown id!!¥n"); break; } } else { /* ステータス読み込み */ ret = PencGetStatus(g_device_no, CH_NO, &status); if(ret){ rtl_printf("PencGetStatus error [ret=%x]¥n", ret); } else { if(status & STAT_CHK_ALL){ /* ステータス変化時の処理ルーチン呼び出し */ sub_stat_proc(status); } else { /* カウンタ値の読み出し */ if(get_cnt_read(&count) == PENC_ERROR_SUCCESS){ rt_stat.type = STAT_COUNT; rt_stat.count = count;

Page 71: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 69 - Interface Corporation

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

/* ステータス値を、ユーザプロセスへRT-FIFOを介して返す */ rtf_put(FIFO_RESULT, &rt_stat, sizeof(rt_stat)); } } } } /* 経過時間を表示する */ t = timespec_from_ns(clock_gethrtime(CLOCK_REALTIME)); rtl_printf("now clock=%ld¥n", t.tv_sec); } 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; 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(struct STAT_STRUCT) * BUFF_SIZE); /* 3モードパルスカウンタI/Oモジュールのオープン */ ret = PencOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no, 0); if(ret){ rtl_printf("PencOpenEx error [ret=%x]¥n", ret); return -1; } else { rtl_printf("PencOpenEx success!! [device no=%d]¥n", g_device_no); } /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了モジュール(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret;

Page 72: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 70 -

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

rtl_printf("cleanup_module called¥n"); /* 3モードパルスカウンタI/Oモジュールをクローズする */ ret = PencClose(g_device_no); if(ret){ rtl_printf("PencClose 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); }

Page 73: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 71 - Interface Corporation

下記Listは、Linuxプロセスのソースファイルです。ファイル名を「penc.c」として保存してください。

penc.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

/* 3モードパルスカウンタI/Oモジュールによる制御サンプルプログラム Linuxプロセスのソースコード(penc.c) 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 "penc.h" /* ステータスの状態を文字列化 */ const char* get_stat_type(enum STAT_TYPE type) { switch(type){ case STAT_COUNT: return "count"; case STAT_COMPARATOR: return "comparator output"; case STAT_CARRY_BORROW: return "carry/borrow"; default: return "unknown"; } } /* Linuxプロセスのメインルーチン */ int main(void) { int fd_cmd, fd_result; fd_set rfds; struct timeval tv; struct CMD_STRUCT cmd; char rt_fifo_name[80]; int i; struct STAT_STRUCT stat; /* RTLinuxモジュールに指令を送るRT-FIFOのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_COMMAND); if((fd_cmd = open(rt_fifo_name, O_WRONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -1; } /* RTLinuxモジュールからの結果を受け取るFIFOチャネルのオープン */ sprintf(rt_fifo_name, "/dev/rtf%d", FIFO_RESULT); if((fd_result = open(rt_fifo_name, O_RDONLY)) < 0){ fprintf(stderr, "Failed to open %s¥n", rt_fifo_name); return -2; } /* 読み出すカウンタ値の種類を設定 */ cmd.id = ID_SET_CONFIG; cmd.mode = 4; /* 位相差パルスカウントモード、標準、非同期クリア */ cmd.comp_count = 1000; /* 比較カウンター:1000に設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the config command.¥n"); return -3; } printf("カウントの開始¥n"); cmd.id = ID_START; cmd.smp_period_ms = 100; /* 100ms周期の周期設定 */ cmd.base_count = 0; /* スタート時のカウンター:0に設定 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Fai led to send the start command.¥n"); return -4; }

Page 74: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 72 -

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

/* 3モードパルスカウンタのデータ受信(100回データを受け取るかタイムアウトすると抜けます) */ for(i = 0; i < 100; i++){ FD_ZERO(&rfds); FD_SET(fd_result, &rfds); tv.tv_sec = 60; /* select関数のタイムアウト値の設定:60秒 */ tv.tv_usec = 0; /* データの受け取り */ if(select(FD_SETSIZE, &rfds, NULL, NULL, &tv) > 0){ if(FD_ISSET(fd_result, &rfds)){ /* fd_resultに対してFIFOの書き込みがあった */ if(read(fd_result, &stat, sizeof(stat)) > 0){ printf("i=%d count=%ld [%s]¥n", i, stat.count, get_stat_type(stat.type)); } } } } printf("カウントの停止¥n"); cmd.id = ID_STOP; if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the stop command.¥n"); return -5; } printf("fd_cmd:%d¥n", close(fd_cmd)); printf("fd_result:%d¥n", close(fd_result)); printf("The Linux process is successfully completed.¥n"); return 0; }

Page 75: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 73 - Interface Corporation

下記Listは、上記ファイルをコンパイルするメイクファイルです。ファイル名を「makefile」として保存してください。

makefile

1 2 3 4 5 6 7 8

include /usr/include/rtlinux/rtl.mk all: penc_mod.o penc penc: penc.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o penc penc.c penc_mod.o: penc_mod.c $(CC) $(INCLUDE) $(CFLAGS) -o penc_mod.o -c penc_mod.c

コンパイルし、insmodコマンドでRTLinuxモジュールを組み込みます。

# make ← コンパイルします # ls ← コンパイルしたファイルを一覧表示します makefile penc penc.c penc.h penc_mod.c penc_mod.o # insmod penc_mod.o ← RTLinuxモジュールを組み込んでいます

次に、Linuxプロセスを実行します。

# ./penc ← Linuxプロセスを実行します ロータリエンコーダを回転させてください。 回転に合わせて、表示されるカウンタ値が変化するのが読み取れます。 i=70 count=1264 [count] i=71 count=1282 [count] i=72 count=1276 [count] i=73 count=1248 [count] i=74 count=1176 [count] i=75 count=1054 [count] i=76 count=981 [comparator output] i=77 count=880 [count] i=78 count=757 [count] i=79 count=647 [count] i=80 count=564 [count] i=81 count=488 [count] i=82 count=425 [count] i=83 count=372 [count] i=84 count=299 [count] i=85 count=236 [count] i=86 count=169 [count] i=87 count=54 [count] i=88 count=-41 [carry/borrow] i=89 count=-100 [count] i=90 count=-173 [count]

Page 76: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 74 -

6.3 3モードパルスカウンタI/Oモジュールの制御の解説

それでは、先ほどのプログラムの解説をします。

6.3.1 プログラムの動き

プログラムの大まかな動きを、下図に示します。 Linuxプロセス RTLinuxモジュール

モード等の指定

ID_SET_CONFIG

スタート指令

ID_START

計測したカウンタ値

カウンタ値読み込み

計測したカウンタ値

カウンタ値読み込み

ストップ指令

ID_STOP

・・・

100ms周期

モードパルスカウンタプログラムの動作概要

1. Linuxプロセスから、3モードパルスカウンタI/Oモジュールに対するモード設定と、比較カウンタの値がセットされます。

2. LinuxプロセスからRTLinuxモジュールに対し、指定された周期(プログラムでは100ms周期)でカウンタ値を読み取るよう指示が出されます。

3. RTLinuxモジュールでは周期ごとに、ロータリエンコーダのカウンタ値を読み取り、Linuxプロセスに対してRT-FIFO経由で、データを送ります。 この時、カウンタ値が0を越えたか(キャリー・ボロー検出)、1で設定した比較カウンタの値と一致したか(比較カウンタ一致検出)どうか、ステータスのチェックが行われ、ステータス情報としてLinuxプロセスに送られます。

4. Linuxプロセスは、送られたデータを受け取り、カウンタ値を表示します。 プログラムでは、これを100回繰り返しています。

5. Linuxプロセスは、カウンタ値読み取りを停止するよう指示します。

Page 77: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 75 - Interface Corporation

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

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

エンコーダカウンタのドライバモジュール(rcp6204.o)

受信データ

FIFO_RESULT

3モードパルスカウンタI/Oモジュールの直接の制御は、ドライバモジュールが担当します。 ドライバモジュールを使った3モードパルスカウンタの制御は、RTLinuxモジュールが行っています。Linuxプロセスは、RTLinuxモジュールに対して、作業の依頼を行っています。

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

共通定義ファイル(penc.h)は、LinuxプロセスとRTLinuxモジュールのコードの内、共通で使用する定義の内容を抜き出したものです。

共通定義ファイルでは、以下の設定を行っています。 行番号 内容

13~22行目 #define宣言> RT-FIFOの番号の定義と、各関数で使用する定数値を指定。

26~30行目 44~48行目

enum宣言> LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドのID値と、Linuxプロセスにカウンタ値を返す際のステータス値を指定。

33~41行目 51~54行目

struct宣言> LinuxプロセスからRTLinuxモジュールに対して指令を出す際のコマンドの構造と、Linuxプロセスにカウンタ値を返すデータ構造を指定。

ここで重要なのは、LinuxプロセスからRTLinuxモジュールに対して指令を出すために使用される、コマンドの構造体(CMD_STRUCT)と、RTLinuxモジュールからLinuxプロセスに対して取得したカウンタ値を送るために使用される、データの構造体(STAT_STRUCT)です。

Page 78: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 76 -

コマンドの構造体(CMD_STRUCT)は、RTLinuxモジュールが行う作業の指示を行うID値(idメンバ変数)の種類を、CMD_IDS列挙体で定義しています。

id変数 内容 ID_SET_CONFIG 3モードパルスカウンタ読み取り時のモードを指定する>

modeの値で、3モードパルスカウンタ読み取り時のモードを指定する。 comp_countの値で、比較カウンターの値をセットする。

ID_START 3モードパルスカウンタの読み取りを開始させる> 読み取り開始時の初期カウンタ値(base_count)を指定する。 smp_period_msで指定した時間間隔(ms)で、RTLinuxモジュール内のRTLinuxスレッド(my_task)をスタートする。

ID_STOP 3モードパルスカウンタの読み取りを停止させる> RTLinuxスレッド(my_task)をストップさせる。

データの構造体(STAT_STRUCT)は、カウンタ読み取り時に検出されたステータスの情報(typeメンバ変数)を、STAT_TYPE列挙体で定義しています。 countメンバ変数は、カウンタの値が格納されます。

type変数 内容 STAT_COUNT 特になし。 STAT_COMPARATOR 比較カウンタ一致が検出されました。

前回のカウンタ読み取りから今回のカウンタ読み取りの間に、比較カウンタで設定したカウンタ値と3モードパルスカウンタの値が一致しました。

STAT_CARRY_BORROW キャリー・ボローが検出されました。 前回のカウンタ読み取りから今回のカウンタ読み取りの間に、3モードパルスカウンタの値がカウンタ値0と一致しました。

この構造体は、後の説明にも出てきますので注意して読み進めてください。

Page 79: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 77 - Interface Corporation

6.3.3 RTLinuxモジュールの動き

RTLinuxモジュール(penc_mod.o)は、Linuxプロセスからの作業依頼に従って、ドライバからロータリエンコーダのカウンタ読み取り等の制御を行います。 (182~214行目:RT-FIFO,RTLinuxスレッドの生成やドライバの初期化) RTLinuxモジュールが組み込まれる時、最初に182行から始まるinit_module関数が呼び出されます。 ここでは、RT-FIFOやRTLinuxスレッド、ハンドラ等のリソースを生成しています。

項目 内容 RT-FIFO(FIFO_COMMAND) 192行目のrtf_create関数>

Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハンドラmy_handlerに渡されます。

RT-FIFO(FIFO_THRU_CMD) 197行目のrtf_create関数> ハンドラにて、Linuxプロセスから受け取った情報を、RTLinuxスレッド(my_task)に渡すためのRT-FIFOです。

RT-FIFO(FIFO_RESULT) 201行目のrtf_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッド(my_task)で取得したデータを、Linuxプロセスに渡すためのRT-FIFOです。

ハンドラ(my_handler) 193行目のrtf_create_handler関数> Linuxプロセスからの指示を受け取るための処理の入り口です。RT-FIFO経由で送られた情報は、一旦このハンドラが受け取り、然る処理に回されます。

RTLinuxスレッド(my_task) 213行目のpthread_create関数> 周期的なカウンタ読み取りを行うRTLinuxスレッドです。 Linuxプロセスから送られる指示は、最終的にここに送られ、 3モードパルスカウンタの制御を行います。

また、3モードパルスカウンタI/Oモジュールの制御を開始するために、204行目のPencOpenEx関数を使ってオープンしています。 以下に引数と対応を示します。

引数名 内容 uDeviceID デバイスIDを指定します

uSubsystemIDと組み合わせて、I/Oモジュールの型式を指定します。 組み合わせについては、ヘルプを参照ください。

uSubsystemID サブシステムIDを指定します。 uBoardID I/Oモジュール識別用ロータリスイッチ(RSW1)の設定値を指定

します。 pnDevice 上記の組み合わせに対するデバイス番号が、呼出し後にセット

されます。 uReserved 予約された引数です(0を指定します)。

この引数を与えて関数を呼び出すと、ドライバモジュールは、引数に適合する3モードパルスカウンタI/Oモジュールを検索し、合致したI/Oモジュールに対してデバイス番号を割り振り、第4引数に返します。プログラマは、このデバイス番号を使って、以降のAPIの呼び出しを行います。

Page 80: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 78 -

★何故、PencOpen関数を使うのか? LinuxやWindowsプログラムでは、PencOpen関数を使用しますが、RTLinuxではPencOpenEx関数の使用を

推奨しています。 これは、プログラムで使用する3モードパルスカウンタI/Oモジュールを、システム内で一意のID値を使用する

ことで、他の環境にシステムを移築しても特定するためにあります。 PencOpen関数を使用した場合、第1引数で指定するデバイス番号は、RTLinuxシステム内で、3モードパル

スカウンタI/Oモジュールが認識された順番に割り振られます。 この場合、複数の3モードパルスカウンタI/Oモジュールを使用していた場合、ユニット並びにコンピュータ内

の3モードパルスカウンタI/Oモジュールの順番を変更した際、想定外のデバイス番号が割り振られてしまう

恐れがあります。 これを避けるため、RTLinuxプログラムでは、PencOpenEx関数を使い、3モードパルスカウンタI/Oモジュー

ルを特定してデバイス番号を得る仕組みを推奨しています。

(169~173行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

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

(78~156行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この78~156行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、3モードパルスカウンタのモード設定および比較カウンタの設定、定周期のカウンタ読み出しと停止を行っています。

処理の決定は、CMD_IDS列挙体の定数値により決定されます。 列挙定数値 内容

ID_SET_CONFIG 92行目のPencSetMode関数で動作モード(modeメンバ変数にて指定)とカウンタ方向(UP方向に固定)、一致検出機能(機能有効に固定)、ラッチ条件(ソフトウェアラッチに固定)の設定を行います。 103行目のPencSetComparator関数で、比較カウンタ(comp_countメンバ変数にて指定)の設定を行います。

ID_START 113行目のPencSetCounter関数で、カウンタの初期値(base_countメンバ変数にて指定)を設定します。 smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し(121行目)、自身の実行周期の間隔を指定しています。

ID_STOP pthread_suspend_np関数を呼び出し(127行目)、自身のスレッドをスリープ状態にしています。

Page 81: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 79 - Interface Corporation

ID_STARTでカウントを開始すると、RTLinuxスレッドは周期的に実行を行います。 周期的な実行呼び出し時は、132~150行の処理が行われます。 ここでは、133行目のPencGetStatus関数で、キャリー・ボローの発生および、比較カウンタの一致が検出されたかステータスのチェックを行います。 変化が検出されると、サブルーチンsub_stat_proc(38~63行目)が呼ばれ、検出されたステータスに応じてSTAT_STRUCT構造体にPencGetCounter関数で読み出したカウンタ値とステータスをセットし、LinuxプロセスにRT-FIFO経由で送ります。 変化が検出されない場合も、STAT_STRUCT構造体にカウンタ値とステータスをセットし、LinuxプロセスにRT-FIFO経由で送ります。

★PencGetStatus関数のステータス値について PencGetStatus関数を呼び出して得られるステータス値は、キャリー・ボローの検出と、比較カウンタ一致の

検出の他、多くの情報が含まれています。 本プログラムでは、この内キャリー・ボローの検出にQBFビットを、比較カウンタ一致の検出にEQFビットを

使用しています。 比較カウンタ一致の検出にEQビットでなくEQFビットを使用しているのは、EQビットが比較カウンタと現在

のカウンタ値が一致している間のみ’1’が立つのに対して、EQFビットは一致したらステータスが読まれるま

で’1’が立ちつづけるため、確実に検出が可能なためです。 なお、QBFビットも一度キャリー・ボローが検出されると、ステータスが読まれるまで’1’が保持されます。

Page 82: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 80 -

6.3.4 Linuxプロセスの動き

Linuxプロセス(penc)は、3モードパルスカウンタの制御をRTLinuxモジュールに対して依頼します。

main

RT-FIFO(FIFO_RESULT)

RT-FIFO(FIFO_COMMAND)

カウンタ値取得

コマンド指令 RTLinux

モジュール

LinuxプロセスとRTLinuxモジュールとのRT-FIFOの関係

(40~51行目:RT-FIFOのオープン処理) ここでは、open関数を使用し、RTLinuxモジュールとデータのやり取りを行うRT-FIFOをオープンしています。 (54~60行目:モードの設定) ここでは、RTLinuxモジュールに対して、動作モードと比較カウンタの値を設定させるため、CMD_STRUCT構造体に、設定を意味するID_SET_CONFIG列挙定数と、動作モードと比較カウンタ値をセットし、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (63~69行目:周期的なカウント読み出しの開始) ここでは、RTLinuxモジュールに対して、周期的のカウント読み出しを開始させるため、CMD_STRUCT構造体に開始を意味するID_START列挙定数と、周期間隔とカウンタ初期値を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュール側では、この指示をハンドラで受けて処理を行います。 (72~87行目:カウンタ値の取得) ここでは、RTLinuxモジュール内で実行される周期的なカウンタ読み出し処理から、受け取ったカウンタ値を、select関数とread関数を使って、取得しています。 データの取得は、100回行われます。 (90~94行目:周期的なカウント読み出しの停止) ここでは、RTLinuxモジュールに対して、周期的なカウント読み出しを停止させるため、CMD_STRUCT構造体に実行停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFO経由で指示を送っています。 RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

Page 83: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 81 - Interface Corporation

第7章 デバッグ手法

これまでの章で、RTLinux上でのカウンタI/Oモジュールの制御プログラミングはどのようなものかがお分かりいただけたと思います。この後、プログラミングを行っていく上で、避けては通れ

ないデバッグをサポートする機能を説明します。 作成したプログラムは、ドライバソフトウェアを使用した部分の処理と、ドライバソフトウェア

を使用しない部分の処理に分かれると思います。ドライバソフトウェアを使用しない部分につい

ては、デバッグのやり方(rtl_printfの説明,gdbの使用方法等)をRTLinuxチュートリアル導入編に記載していますので、そちらを参照してください。 ここでは、RTLinuxドライバソフトウェアを使用した部分の処理について、デバッグ手法を紹介していきます。

7.1 ドライバデバッグ支援機能を使ってみる

カウンタI/Oモジュールのドライバには、デバッグ情報を出力するデバッグ支援機能がついています。ドライバ組み込み時、下記に示す引数パラメータにデバッグレベルを指定することでドライ

バデバッグ情報が出力されます。

ドライバデバッグ情報のパラメータ名 型式 ドライバデバッグ時のパラメータ名

GPG-6105 rcp6105_debuglevel GPG-6106 rcp6106_debuglevel GPG-6201 rcp6201_debuglevel GPG-6202 rcp6202_debuglevel GPG-6204 rcp6204_debuglevel

デバッグレベルは以下の各段階があります。

ドライバのデバッグレベル 型式 デバッグレベル 機能

0 デバッグ情報を出力しません

1 関数呼び出しトレース

GPG-6105 GPG-6106 GPG-6201 GPG-6202 GPG-6204 4 I/Oモジュールリソース情報

ドライバ組み込み時にオプションを指定しない場合は、デバッグレベルは0となります。 デバッグ支援機能を使うと、システムの負荷が高くなってしまうため、デバッグ時以外は、この

機能を使用しないようにしてください。

★デバック情報を複数出力する。 デバッグレベルの値の算術和を取った値を指定することで、複数のデバッグレベルを使用できます。 例)GPG-6105使用時、関数呼び出しトレースとI/Oモジュールリソース情報を出力する場合 (‘=’の前後にスペースは要りません) # modprobe rcp6105 rcp6105_debuglevel=5

Page 84: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 82 -

7.1.1 関数呼び出しトレース

この関数呼び出しトレースを使用すると、処理の実行状況や、関数呼び出し時の引数の値を容易

に知ることができます。実際にデバッグ支援機能を使用して、さきほど作成したサンプルプログ

ラムを動かしてみます。 (例として、『20ページ 3.2 パルス出力I/Oモジュールの制御』で作成したサンプルを使用します。) 関数呼び出しトレースを指定して、ドライバを組み込みます。 (‘=’の前後にスペースは要りません) # modprobe rcp6105 rcp6105_debuglevel=1

次にシステム内のI/Oモジュール情報の列挙、初期化、終了処理を行うモジュール(pulse_mod.o)を組み込んでみます。 # insmod pulse_mod.o

現段階では、PulseOpenEx関数が呼び出されているはずです。 それでは、ログを確認してみましょう。 #less /var/log/messages … Jun 5 11:15:44 localhost kernel: init_module called Jun 5 11:15:44 localhost kernel: rcp6105:PulseOpenEx(0x17d9, 0x1, 0x0, [0xc6adb6f8], 0x0) Jun 5 11:15:44 localhost kernel: PulseOpenEx success!! [device no=1] … (END)

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

ログを見てみます。PulseClose関数が呼び出されていることが分かります。 #less /var/log/messages … Jun 5 11:17:36 localhost kernel: cleanup_module called Jun 5 11:17:36 localhost kernel: rcp6105:PulseClose(1) (END)

以上のように、関数が呼ばれた順番にログが残されています。

Page 85: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 83 - Interface Corporation

7.1.2 I/Oモジュールリソース情報

I/Oモジュールのリソースが正常かどうかを見ることにより、ソフトウェアが原因かハードウェアが原因かを知ることができます。 では、I/Oモジュールリソース情報を出力するようにしてみましょう。 #insmod rcp6105.o rcp6105_debuglevel=4

I/Oモジュールリソース情報は、ドライバを組み込んだ時点で出力されます。 ではログを見てみましょう。 #less /var/log/messages Jun 5 11:31:00 localhost kernel: rcp6105:install device : Jun 5 11:31:00 localhost kernel: rcp6105: Device1 : DeviceID=6105, SubSystemID=1, RevisionID=1, RSW1=0 Jun 5 11:31:00 localhost kernel: rcp6105: I/O address1=d000, I/O address2=ffff, Memory address=ffffffff, irq=0

拡張スロットに実装されているrcp6105が対応しているPCII/Oモジュールのリソースが表示されます。

リソース情報の項目

型式 項目 内容 Device デバイス番号 DeviceID デバイスID SubSystemID サブシステムID RevisionID リビジョンID RSW1 I/Oモジュール識別用ロータリスイッチ

(RSW1) I/O address1 I/Oポートアドレス I/O address2 I/Oポートアドレス Memory address メモリアドレス

GPG-6105

irq 割り込み番号

Page 86: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 84 -

型式 項目 内容

DeviceNo デバイス番号 DeviceID デバイスID SubSystemID サブシステムID RevisionID リビジョンID RSW1 I/Oモジュール識別用ロータリスイッチ

(RSW1) I/O address0 I/Oポートアドレス I/O address1 I/Oポートアドレス

GPG-6106

irq 割り込み番号 Device デバイス番号 DeviceID デバイスID SubSystemID サブシステムID RevisionID リビジョンID RSW1 I/Oモジュール識別用ロータリスイッチ

(RSW1) I/O address1 I/Oポートアドレス I/O address2 I/Oポートアドレス Memory address メモリアドレス

GPG-6201

irq 割り込み番号 DeviceNo デバイス番号 DeviceID デバイスID SubSystemID サブシステムID RevisionID リビジョンID RSW1 I/Oモジュール識別用ロータリスイッチ

(RSW1) I/O address0 I/Oポートアドレス I/O address1 I/Oポートアドレス Memory address メモリアドレス

GPG-6202

irq 割り込み番号 Device デバイス番号 DeviceID デバイスID SubSystemID サブシステムID RevisionID リビジョンID RSW1 I/Oモジュール識別用ロータリスイッチ

(RSW1) I/O address1 I/Oポートアドレス I/O address2 I/Oポートアドレス Memory address メモリアドレス

GPG-6204

irq 割り込み番号

この値が異常の場合(0が表示された等の場合)は、ハードウェアに問題が発生していることも考えられます。

Page 87: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 85 - Interface Corporation

第8章 リファレンス

この章では、各製品の関数および戻り値の一覧を掲載しています。より詳しい情報は、ヘルプを

参照してください。

8.1 パルスジェネレータドライバ(GPG-6105)

8.1.1 関数一覧

No. 関数名 機能 1 PulseOpen パルスジェネレータI/Oモジュールのオープンを行います。 2 PulseOpenEx パルスジェネレータI/Oモジュールのオープンを行います。

(デバイスID,サブシステムID,I/OモジュールIDを指定してオープンします。)

3 PulseClose パルスジェネレータI/Oモジュールのクローズを行います。 4 PulseSetFreq 出力周波数を設定します。 5 PulseGetFreq 現在の出力周波数を取得します。 6 PulseSetDuty デューティ比を設定します。 7 PulseGetDuty デューティ比を取得します。 8 PulseGenerate パルスを発生させます。 9 PulseGenerateEx 複数チャンネルのパルスを発生させます。 10 PulseStop パルスを停止します。 11 PulseStopEx 複数チャンネルのパルスを停止します。 12 PulseGetResource パルスジェネレータI/Oモジュールのリソースを取得します。

Page 88: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 86 -

8.1.2 戻り値一覧

エラー識別子 値 意味 対処方法 PULSE_ERROR_SUCCESS 0 正常終了 - PULSE_ERROR_NOT_DEVICE C0000001h ドライバが呼び出

せません。 指定されたデバイスが見つかりませんでした。指定しているデバイス名が存在するかどうかを確認してください。

PULSE_ERROR_NOT_OPEN C0000002h ドライバが OPENできません。

デバイスのオープン時に何らかのエラーが発生しました。(ドライバ内部作業領域の確保に失敗した等。)

PULSE_ERROR_INVALID_DEVICE_NUMBER

C0000003h デバイス番号が正しくありません。

不正なデバイス番号で呼び出しを行おうとしました。デバイス番号設定プログラムで設定したデバイス番号を使用してください。

PULSE_ERROR_ALREADY_OPEN C0000004h 既に OPENされているデバイスをOPENしようとしました。

既に OPENされているデバイスです。

PULSE_ERROR_NOT_SUPPORTED C0000009h I/Oモジュールがサポートしていない関数です。

I/Oモジュールがサポートしていない機能のため制御できません。

PULSE_ERROR_INVALID_CHANNEL C0001001h 不正なチャンネル番号を指定しました。

チャンネル番号の値の範囲が指定範囲外です。

PULSE_ERROR_INVALID_RANGE C0001002h 不正な基本周波数を指定しました。

周波数レンジの値の範囲が指定範囲外です。

PULSE_ERROR_INVALID_MAG C0001003h 不正な周波数倍率を指定しました。

周波数倍率の値の範囲が指定範囲外です。

PULSE_ERROR_INVALID_DUTY C0001004h 不正なデューティ比を指定しました。

デューティ比の値の範囲が指定範囲外です。

PULSE_ERROR_NULL_POINTER C0001008h NULLポインタを指定しました。

引数に NULLポインタが指定されました。

PULSE_ERROR_PARAMETER C0001009h 引数パラメータの値が不正です。

引数の値の範囲が指定範囲外です。

Page 89: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 87 - Interface Corporation

8.2 パルスカウンタドライバ(GPG-6106)

8.2.1 関数一覧

No. 関数名 機能 1 PcntOpen パルスカウンタI/Oモジュールのオープンを行い、以後のI/Oモジュール

へのアクセスを行えるようにします。(デバイス番号でのオープン) 2 PcntOpenEx パルスカウンタI/Oモジュールのオープンを行い、以後のI/Oモジュール

へのアクセスを行えるようにします。(デバイスID,サブシステムID,RSW1設定値でのオープン)

3 PcntClose パルスカウンタI/Oモジュールのクローズを行い、I/Oモジュールアクセスのために使用されていた各種リソースの解放を行い、以後のI/Oモジュールへのアクセスを禁止します。

4 PcntSetMode パルスカウンタの動作モードを設定します。 設定項目には、モード,入力仕様,入力極性,クロック切り換えがあります。

5 PcntGetMode パルスカウンタの動作モードを取得します。 6 PcntEnable パルスカウンタのイネーブル/ディセーブルを切り替えます。 7 PcntSetBaseClock 内部基準クロックを設定します。 8 PcntGetBaseClock 内部基準クロックを取得します。 9 PcntRead カウンタ値を読み込みます。 10 PcntReadEx 複数チャンネルのカウンタ値を読み込みます。 11 PcntClear カウンタをクリアします。 12 PcntClearEx 複数チャンネルのカウンタをクリアします。 13 PcntSetEventMask コールバックイベントのマスクを設定します。 14 PcntGetEventMask コールバックイベントのマスクを取得します。 15 PcntSetEvent コールバックイベントを登録します。 16 PcntKillEvent コールバックイベントを削除します。 17 PcntSetTimerConfig インターバルタイマの設定を行います。 18 PcntGetTimerConfig インターバルタイマの設定情報を取得します。 19 PcntGetTimerCount インターバルタイマのカウント値を取得します。 20 PcntGetStatus 現在のカウンタステータスを取得します。 21 PcntInputDI パルスカウントI/Oモジュールの汎用入力値を取得します。 22 PcntOutputDO パルスカウントI/Oモジュールで汎用出力を行います。 23 lpEventProc PcntSetEvent関数にて登録し、割り込みイベントが発生した時にコールさ

れるコールバック関数です。

Page 90: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 88 -

8.2.2 戻り値一覧

エラー識別子 値 意味 対処方法 PCNT_ERROR_SUCCESS 0 正常終了 - PCNT_ERROR_NOT_DEVICE C0000001h ドライバが呼び出せませ

ん。 指定されたデバイスが見つかりませんでした。指定しているデバイス番号が存在するかどうかを確認してください。

PCNT_ERROR_NOT_OPEN C0000002h ドライバが OPENできません。

デバイスのオープン時に何らかのエラーが発生しました。(ドライバ内部作業領域の確保に失敗した等。)

PCNT_ERROR_INVALID_DEVICE_ NUMBER

C0000003h デバイス番号が正しくありません。

不正なデバイス番号で呼び出しを行おうとしました。デバイス番号設定プログラムで設定したデバイス番号を使用してください。

PCNT_ERROR_ALREADY_OPEN C0000004h 既に OPENされているデバイスを OPENしようとしました。

既に OPENされているデバイスです。

PCNT_ERROR_NOT_SUPPORTED C0000009h I/Oモジュールがサポートしていない関数です。

I/Oモジュールがサポートしていない機能のため制御できません。

PCNT_ERROR_INITIALIZE_IRQ C0001000h 割り込みの初期化に失敗しました

システムエラーです。

PCNT_ERROR_INVALID_CHANNEL C0001001h 不正なチャンネル番号を指定しました。

チャンネル番号は1~4を指定してください。(PcntReadEx関数および PcntClearEx関数の時は、1~15を指定してください)

PCNT_ERROR_INVALID_MODE C0001002h 不正なモードを指定しました。

モードは0~3を指定してください

PCNT_ERROR_INVALID_CONFIG C0001003h 不正な入力仕様を指定しました

入力仕様は、0か1を指定してください。

PCNT_ERROR_INVALID_LINE C0001004h 不正な入力極性を指定しました。

入力極性は、0か1を指定してください。

PCNT_ERROR_INVALID_CLOCK C0001005h 不正なクロック切り替え値を指定しました。

クロック切り替え値は、0か1を指定してください。

PCNT_ERROR_INVALID_ENABLE C0001006h 不正なカウンタ切り替え値を指定しました。

カウンタ切り替え値は、0か1を指定してください。

PCNT_ERROR_INVALID_BASECLOCK C0001007h 不正な基準クロックを指定しました。

基準クロックは、0~7を指定してください。

PCNT_ERROR_INVALID_MASK C0001008h 不正なイベントマスクを指定しました。

イベントマスクは、0~7を指定してください。

PCNT_ERROR_INVALID_ITIMER C0001009h 不正なインターバルタイマ設定値を指定しました。

正しいインターバルタイマ設定値を指定してください。

PCNT_ERROR_INVALID_OUTPUT C000100Ah 不正なタイムアウト値を指定しました。

正しいタイムアウト値を指定してください。

PCNT_ERROR_ALREADY_REGISTRATION

C000100Bh イベントはすでに登録済みです。 -

PCNT_ERROR_ALREADY_DELETE C000100Ch イベントはすでに削除されています。 -

PCNT_ERROR_NULL_POINTER C0001011h NULLポインタが渡されました。

システムに障害が発生している可能性がございます。どのような状況でエラーが発生したかをご連絡ください。

PCNT_ERROR_PARAMETER C0001012h 引数パラメータの値が不正です。

API関数に指定する値が不正もしくは範囲外です。

PCNT_ERROR_DRVCAL C0001013h ドライバがコールできません。

ドライバファイルが組み込まれていない場合等に発生します。ドライバの組み込みを行ってください。

Page 91: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 89 - Interface Corporation

8.3 3モードパルスカウンタドライバ(GPG-6201)

8.3.1 関数一覧

No. 関数名 機能 1 EncOpen 3モードパルスカウンタI/Oモジュールのオープンを行います。2 EncOpenEx 3モードパルスカウンタI/Oモジュールのオープンを行います。

(デバイスID,サブシステムID,RSW1設定値でのオープン) 3 EncClose 3モードパルスカウンタI/Oモジュールのクローズを行います。4 EncSetSystemMode 3モードパルスカウンタI/Oモジュールのシステムモードを切

り替えます。システムモードは、0か1の2種類となります。 5 EncSetMode 3モードパルスカウンタI/Oモジュールの動作モード,カウンタ

方向,イベント発生方法の設定を行います。 6 EncGetMode 3モードパルスカウンタI/Oモジュールの現在の設定状態を取

得します。 7 EncEnableCount 複数チャンネルのカウンタ動作を許可/禁止します。 8 EncSetCounter カウンタ値を設定します。 9 EncGetCounter カウンタ値を取得します。 10 EncSetCounterEx 複数のチャンネルにカウンタ値を設定します。 11 EncGetCounterEx 複数チャンネルのカウンタ値を取得します。 12 EncSetComparator 比較カウンタ値を設定します。 13 EncGetComparator 比較カウンタ値を取得します。 14 EncSetZMode 3モードパルスカウンタI/OモジュールのZ相クリア条件,Z相入

力論理を設定します。 15 EncGetZMode 3モードパルスカウンタI/OモジュールのZ相クリア条件,Z相入

力論理を取得します。 16 EncSetFilter 3モードパルスカウンタI/Oモジュールのフィルタのカットオ

フ周波数を設定します。 17 EncGetFilter 3モードパルスカウンタI/Oモジュールのフィルタのカットオ

フ周波数を取得します。 18 EncSetEventMask イベントマスクを設定します。 19 EncGetEventMask イベントマスク設定を取得します。 20 EncSetEvent コールバック関数を登録します。 21 EncKillEvent 登録されたコールバック関数を削除します。 22 EncSetTimerConfig インターバルタイマの設定を行います。 23 EncGetTimerConfig インターバルタイマの設定情報を取得します。 24 EncGetTimerCount インターバルタイマのカウント値を取得します。 25 EncGetStatus カウンタのステータスを取得します。 26 EncReset 3モードパルスカウンタI/Oモジュールをリセットします。 27 lpEventProc

(イベントコールバック関数) EncSetEvent関数にて登録し、割り込みイベントが発生した時にコールされるコールバックルーチンです。

Page 92: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 90 -

8.3.2 戻り値一覧

エラー識別子 値 意味 対処方法 ENC_ERROR_SUCCESS 0 正常終了 - ENC_ERROR_NOT_ DEVICE

C0000001h ドライバが呼び出せません。

指定されたデバイスが見つかりませんでした。指定しているデバイス番号が存在するかどうかを確認してください。

ENC_ERROR_NOT_ OPEN

C0000002h ドライバがOPENできません。

デバイスのオープン時に何らかのエラーが発生しました。(ドライバ内部作業領域の確保に失敗した等。)

ENC_ERROR_INVALID_DEVICE_NUMBER

C0000003h デバイス番号が正しくありません。

不正なデバイス番号で呼び出しを行おうとしました。デバイス番号設定プログラムで設定したデバイス番号を使用してください。

ENC_ERROR_ALREADY_OPEN

C0000004h 既にOPENされているデバイスを OPENしようとしました。

既に OPENされているデバイスです。

ENC_ERROR_NOT_ SUPPORTED

C0000009h I/Oモジュールがサポートしていない関数です。

I/Oモジュールがサポートしていない機能のため制御できません。

ENC_ERROR_INITIALIZE_IRQ

C0001000h 割り込みの初期化に失敗しました。

システムエラーです。

ENC_ERROR_INVALID_ CHANNEL

C0001001h 不正なチャンネル番号を指定しました。

I/Oモジュールが対応するデバイス番号を指定してください。

ENC_ERROR_INVALID_ MODE

C0001002h 不正なモードを指定しました。

モードはEncSetMode関数のビット割付範囲の値を指定してください。

ENC_ERROR_INVALID_ DIRECT

C0001003h 不正なカウンタ方向を指定しました。

カウンタ方向は、0か1を指定してください。

ENC_ERROR_INVALID_ COUNTER

C0001004h 不正なカウンタプリセット値を指定しました。

カウンタプリセット値は、24ビット値を指定してください。

ENC_ERROR_INVALID_ COMPARATOR

C0001005h 不正な比較カウンタ値を指定しました。

比較カウンタ値は、24ビット値を指定してください。

ENC_ERROR_INVALID_ZMODE

C0001006h 不正なZ相論理設定値を指定しました。

Z相論理設定値は、EncSetZMode関数のビット割付範囲の値を指定してください。

ENC_ERROR_INVALID_ FILTER

C0001007h 不正なフィルタ設定値を指定しました。

フィルタ設定値は、EncSetFilter関数のビット割付範囲の値を指定してください。

ENC_ERROR_INVALID_ MASK

C0001008h 不正なイベントマスクを指定しました。

正しいイベントマスク値を指定してください。

ENC_ERROR_INVALID_ ITIMER

C0001009h 不正なインターバルタイマ設定値を指定しました。

正しいインターバルタイマ設定値を指定してください。

ENC_ERROR_ALREADY_ REGISTRATION

C000100Ah イベントはすでに登録済みです。

イベントは1つしか登録できません。 登録済みのイベントを削除してから、新しいイベントを登録しなおしてください。

Page 93: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 91 - Interface Corporation

エラー識別子 値 意味 対処方法 ENC_ERROR_ALREADY_DELETE

C000100Bh イベントはすでに削除されています。

ENC_ERROR_MEMORY_NOTALLOCATED

C000100Ch 作業用メモリの確保に失敗しました。

利用可能なメモリが足りなくなっています。不要なアプリケーション等を終了させ、利用可能なメモリを増やすようにしてください。

ENC_ERROR_DRVCAL C000100Fh ドライバがコールできません。

ドライバファイルがインストールされていない場合等に発生します。ドライバのインストールを行ってください。

ENC_ERROR_NULL_ POINTER

C0001010h NULLポインタが渡されました。

システムに障害が発生している可能性がございます。どのような状況でエラーが発生したかをご連絡ください。

ENC_ERROR_PARAMETER C0001011h 引数パラメータの値が不正です

API関数に指定する値が不正もしくは範囲外です。

Page 94: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 92 -

8.4 ユニバーサルカウンタドライバ(GPG-6202)

8.4.1 関数一覧

No. 関数名 機能 1 CntOpen ユニバーサルカウンタI/Oモジュールのオープンを行い、以後のI/Oモジ

ュールへのアクセスを行えるようにします。 2 CntOpenEx ユニバーサルカウンタI/Oモジュールのオープンを行い、以後のI/Oモジ

ュールへのアクセスを行えるようにします。(デバイスID,サブシステムID,RSW1設定値でのオープン)

3 CntClose ユニバーサルカウンタI/Oモジュールのクローズを行い、I/Oモジュールアクセスのために使用されていた各種リソースの解放を行い、以後のI/Oモジュールへのアクセスを禁止します。

4 CntSetMode ユニバーサルカウンタの動作モードを設定します。 設定項目には、モード,入力仕様,入力極性,分周値があります。

5 CntGetMode ユニバーサルカウンタの動作モードを取得します。 6 CntSetClockDivisor 分周値を設定します。 7 CntSetCounterDirection カウンタ方向(UP/DOWN)を設定します。 8 CntGetCounterDirection カウンタ方向(UP/DOWN)を取得します。 9 CntRead カウンタを読み込みます。 10 CntClear カウンタをクリアします。 11 CntSetBaseClock 基準クロックおよび0Hz検出時間を設定します。 12 CntGetBaseClock 基準クロックおよび0Hz検出時間を取得します。 13 CntSetEventMask コールバックイベントのマスクを設定します。 14 CntGetEventMask コールバックイベントのマスクを取得します。 15 CntSetEvent コールバックイベントを登録します。 16 CntKillEvent コールバックイベントを削除します。 17 CntSetTimerConfig インターバルタイマの設定を行います。 18 CntGetTimerConfig インターバルタイマの設定情報を取得します。 19 CntGetTimerCount インターバルタイマのカウント値を取得します。 20 CntGetStatus 現在のカウンタステータスを取得します。 21 CntClearStatus カウンタステータスをクリアします。 22 EventProc CntSetEvent関数にて登録し、割り込みイベントが発生した時にコール

されるコールバックルーチンです。

Page 95: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 93 - Interface Corporation

8.4.2 戻り値一覧

エラー識別子 値 意味 対処方法 CNT_ERROR_SUCCESS 0 正常終了 - CNT_ERROR_NOT_DEVICE C0000001h ドライバが呼び

出せません。 指定されたデバイスが見つかりませんでした。指定しているデバイスが存在するかどうかを確認してください。

CNT_ERROR_NOT_OPEN C0000002h ドライバがOPENできません。

デバイスのオープン時に何らかのエラーが発生しました。(ドライバ内部作業領域の確保に失敗した等。)

CNT_ERROR_INVALID_ DEVICE_NUMBER

C0000003h デバイス番号が正しくありません。

不正なデバイス番号で呼び出しを行おうとしました。デバイス番号設定プログラムで設定したデバイス番号を使用してください。

CNT_ERROR_ALREADY_ OPEN

C0000004h 既に OPENされているデバイスを OPENしようとしました。

既に OPENされているデバイスです。

CNT_ERROR_NOT_SUPPORTED C0000009h I/Oモジュールがサポートしていない関数です。

I/Oモジュールがサポートしていない機能のため制御できません。

CNT_ERROR_INITIALIZE_ IRQ

C0001000h 割り込みの初期化に失敗しました。

システムエラーです。

CNT_ERROR_INVALID_ CHANNEL

C0001001h 不正なチャンネル番号を指定しました。

チャンネル番号は 1~2を指定してください。

CNT_ERROR_INVALID_ MODE

C0001002h 不正なモードを指定しました。

モードは0~3を指定してください

CNT_ERROR_INVALID_LINE C0001003h 不正な入力極性を指定しました。

入力極性は、0か1を指定してください。

CNT_ERROR_INVALID_ DIVIDE

C0001004h 不正な分周値を指定しました。

正しい分周設定値を指定してください。

CNT_ERROR_INVALID_ CONFIG

C0001005h 不正な入力仕様を指定しました。

入力仕様は、0か1を指定してください。

CNT_ERROR_INVALID_ DIRECT

C0001006h 不正なカウント方向を指定しました。

カウント方向は、0か1を指定してください。

CNT_ERROR_INVALID_BASECLOCK

C0001007h 不正な基準クロックを指定しました。

基準クロックは、00h~0Fhを指定してください。

CNT_ERROR_INVALID_ZEROHZ C0001008h 不正な0Hz検出時間を指定しました。

正しい0Hz検出時間を指定してください。

CNT_ERROR_INVALID_ITIMER C000100Ah 不正なインターバルタイマ設定値を指定しました。

正しいインターバルタイマ設定値を指定してください。

Page 96: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 94 -

エラー識別子 値 意味 対処方法

CNT_ERROR_ALREADY_REGISTRATION

C000100Bh イベントはすでに登録済みです。

新しいイベントを登録する場合は、一度イベントを削除してください。

CNT_ERROR_ALREADY_DELETE C000100Ch イベントはすでに削除されています。

新しいイベントを登録し直してください。

CNT_ERROR_NULL_POINTER C0001012h NULLポインタが渡されました。

システムに障害が発生している可能性がございます。どのような状況でエラーが発生したかをご連絡ください。

CNT_ERROR_PARAMETER C0001013h 引数パラメータの値が不正です。

API関数に指定する値が不正もしくは範囲外です。

CNT_ERROR_ZEROHZ C0001014h 0Hzを検出しました。

CNT_ERROR_INVALID_COUNT C0001018h カウント値の取得に失敗しました。

カウント実行中にカウント値を取得した場合に発生します。カウントが完了した後でカウント値の取得を行ってください。

CNT_ERROR_MEMORY_NOTALLOCATED

C0001019h メモリ領域の確保に失敗しました。

ドライバの内部エラーです。どのような状況でエラーが発生したかをご連絡ください。

CNT_ERROR_MEMORY_FREE C000101Ah メモリ領域の開放に失敗しました。

ドライバの内部エラーです。どのような状況でエラーが発生したかをご連絡ください。

CNT_ERROR_DRVCAL C000101Bh ドライバがコールできません。

ドライバファイルが組み込まれていない場合等に発生します。ドライバの組み込みを行ってください。

Page 97: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 95 - Interface Corporation

8.5 3モードパルスカウンタドライバ(GPG-6204)

8.5.1 関数一覧

No. 関数名 機能 1 PencOpen 3モードパルスカウンタI/Oモジュールのオープンを行います。 2 PencOpenEx 3モードパルスカウンタI/Oモジュールのオープンを行い、以後の

I/Oモジュールへのアクセスを行えるようにします。(デバイスID,サブシステムID,RSW1設定値でのオープン)

3 PencClose 3モードパルスカウンタI/Oモジュールのクローズを行います。 4 PencSetMode 3モードパルスカウンタI/Oモジュールの動作モード,カウンタ方向,

一致検出フラグの設定,ラッチ方法の設定を行います。 5 PencGetMode 3モードパルスカウンタI/Oモジュールの現在の設定状態を取得し

ます。 6 PencSetCounter カウンタ値を設定します。 7 PencGetCounter カウンタ値を取得します。 8 PencSetCounterEx 複数のチャンネルにカウンタ値を設定します。 9 PencGetCounterEx 複数チャンネルのカウンタ値を取得します。 10 PencSetComparator 比較カウンタ値を設定します。 11 PencGetComparator 比較カウンタ値を取得します。 12 PencSetZMode Z相の極性,外部信号によるカウンタクリア・ラッチ条件を設定しま

す。 13 PencGetZMode Z相の極性,外部信号によるカウンタクリア・ラッチ条件を取得しま

す。 14 PencEnableCount 複数チャンネルのカウンタ動作を許可/禁止します。 15 PencSetEventMask イベントマスクを設定します。 16 PencGetEventMask イベントマスク設定を取得します。 17 PencSetEventEx コールバック関数を登録します。 18 PencKillEvent 登録されたコールバック関数を削除します。 19 PencSetTimerConfig インターバルタイマの設定を行います。 20 PencGetTimerConfig インターバルタイマの設定情報を取得します。 21 PencGetTimerCount インターバルタイマのカウント値を取得します。 22 PencGetStatus カウンタのステータスを取得します。 23 PencGetStatusEx 複数チャンネルのカウンタステータスとカウンタ値を取得しま

す。 24 PencReset 指定されたチャンネルのカウンタをリセットします。 25 PencSetFilter デジタルフィルタの設定を行います。 26 PencGetFilter デジタルフィルタの設定を取得します。 27 PencInputDI 汎用入力値を取得します。 28 PencOutputDO 汎用出力を行います。 29 1pEventProcEx 1pEventProcEx関数にて登録し、割り込みイベントが発生したとき

にコールバックされるコールバックルーチンです。 30 PencSetResetInMask 外部リセット入力信号端子(RSTIN)のマスクを設定します。 31 PencGetResetInMask 外部リセット入力信号端子(RSTIN)のマスク設定を取得します。 32 PencGetResetInStatus 外部リセット入力信号端子(RSTIN)の状態を取得します。

Page 98: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 96 -

8.5.2 戻り値一覧

エラー識別子 値 意味 対処方法 PENC_ERROR_SUCCESS 0 正常終了 - PENC_ERROR_NOT_DEVICE C0000001h ドライバが呼び出せま

せん。 指定されたデバイスが見つかりませんでした。指定しているデバイス番号が存在するかどうかを確認してください。

PENC_ERROR_NOT_OPEN C0000002h ドライバが OPENできません。

デバイスのオープン時に何らかのエラーが発生しました。(ドライバ内部作業領域の確保に失敗した等。)

PENC_ERROR_INVALID_ DEVICE_NUMBER

C0000003h デバイス番号が正しくありません。

不正なデバイス番号で呼び出しを行おうとしました。デバイス番号設定プログラムで設定したデバイス番号を使用してください。

PENC_ERROR_ALREADY_ OPEN

C0000004h 既に OPENされているデバイスを OPENしようとしました。

既に OPENされているデバイスです。

PENC_ERROR_NOT_SUPPORTED

C0000009h I/Oモジュールがサポートしていない関数です。

I/Oモジュールがサポートしていない機能のため制御できません。

PENC_ERROR_INITIALIZE_ IRQ

C0001000h 割り込みの初期化に失敗しました。

システムエラーです。

PENC_ERROR_INVALID_ CHANNEL

C0001001h 不正なチャンネル番号を指定しました。

I/Oモジュールが対応するデバイス番号を指定してください。

PENC_ERROR_INVALID_ MODE

C0001002h 不正なモードを指定しました。

モードはPencSetMode関数のビット割付範囲の値を指定してください。

PENC_ERROR_INVALID_ DIRECT

C0001003h 不正なカウンタ方向を指定しました。

カウンタ方向は、0か1を指定してください。

PENC_ERROR_INVALID_ EQUALS

C0001004h 不正な一致検出フラグを指定しました。

一致検出フラグは、0か1を指定してください。

PENC_ERROR_INVALID_ LATCH

C0001005h 不正なラッチ設定値を指定しました。

ラッチ設定値は、0か1を指定してください。

PENC_ERROR_INVALID_ COUNTER

C0001006h 不正なカウンタプリセット値を指定しました。

カウンタプリセット値は、32ビット値(PCI/PAZ-6205C,CTP-6205は24ビット値)を指定してください。

PENC_ERROR_INVALID_ COMPARATOR

C0001007h 不正な比較カウンタ値を指定しました。

比較カウンタ値は、32ビット値(PCI/PAZ-6205C,CTP-6205は24ビット値)を指定してください。

PENC_ERROR_INVALID_ ZMODE

C0001008h 不正なZ相論理設定値を指定しました。

Z相論理設定値は、PencSetZMode関数のビット割付範囲の値を指定してください。

PENC_ERROR_INVALID_ MASK

C0001009h 不正なイベントマスクを指定しました。

正しいイベントマスク設定値を指定してください。

PENC_ERROR_INVALID_ ITIMER

C000100Ah 不正なインターバルタイマ設定値を指定しました。

正しいインターバルタイマ設定値を指定してください。

PENC_ERROR_ALREADY_ REGISTRATION

C000100Bh イベントはすでに登録済みです。

イベントは1つしか登録できません。 登録済みのイベントを削除してから、新しいイベントを登録しなおしてください。

Page 99: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 97 - Interface Corporation

エラー識別子 値 意味 対処方法

PENC_ERROR_ALREADY_ DELETE

C000100Ch イベントはすでに削除されています。

PENC_ERROR_MEMORY_ NOTALLOCATED

C000100Dh 作業用メモリの確保に失敗しました。

利用可能なメモリが足りなくなっています。不要なアプリケーション等を終了させ、利用可能なメモリを増やすようにしてください。

PENC_ERROR_DRVCAL C0001010h イベントはすでに削除されています。

PENC_ERROR_NULL_ POINTER

C0001011h NULLポインタが渡されました。

システムに障害が発生している可能性がございます。どのような状況でエラーが発生したかをご連絡ください。

PENC_ERROR_PARAMETER C0001012h 引数パラメータの値が不正です。

API関数に指定する値が不正もしくは範囲外です。

PENC_ERROR_INVALID_FILTER

0xC0001013 不正なデジタルフィルタ設定値を指定しました。

正しいデジタルフィルタ設定値を指定してください。

PENC_ERROR_INVALID_DO

0xC0001014 不正な汎用出力設定値を指定しました。

正しい汎用出力設定値を指定してください。

PENC_ERROR_INVALID_RSTINMASK

0xC0001015 不正な外部リセットマスク設定値を指定しました。

外部リセットマスク設定は、0 か1 を指定してください。

Page 100: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

Interface Corporation - 98 -

技術資料紹介 弊社では下記の技術資料を提供しております。 詳しくは、弊社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 101: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048

- 99 - Interface Corporation

参考文献

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

(株式会社秀和システム:2000年)

警告!

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

す。

Page 102: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

TUT-0048 2006年 7月 Ver. 1.3 発行 発行所

〒732-0828 広島県広島市南区京橋町10-21 TEL 082-262-7777 FAX 082-262-5066

定価 ¥2,000

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

Page 103: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

www.interface.co.jp

サポート体制

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

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

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

TUT-0048 Ver. 1.3 Vol. 1/1

Page 104: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0048 - 1 - Interface Corporation 改訂履歴 Ver. 年 月 改 訂 内 容 1.3 2005年7月 対応型式追加 用語統一

www.interface.co.jp

チュートリアル RTLinuxによるカウンタI/Oモジュール制御プログラミング

TUT-0048 Ver. 1.3