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

74
www.interface.co.jp チュートリアル RTLinuxによるDAボード 制御プログラミング チュートリアル

Upload: others

Post on 23-Sep-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

www.interface.co.jp

チュートリアル

RTLinuxによるDAボード

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

Page 2: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

www.interface.co.jp

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

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

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

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

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

さい。

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

Page 3: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 1 - Interface Corporation

改訂履歴

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

●誤記修正。 ●技術資料一覧更新。 ●フォーマット変更。

1.4 2005年6月 ●技術資料一覧更新。 ●誤記修正。

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

1.2 2003年 10月 ●関数追加,誤記修正。 1.1 2002年 11月 ●対応型式追加,修正。 1.0 2002年 8月 新規作成

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

Page 4: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 2 -

目 次

第 1章 アナログ出力概要 7

1.1 D/Aコンバータ .............................................................................................................................. 7 1.2 アナログ出力 ................................................................................................................................. 8 1.3 分解能と精度 ................................................................................................................................. 8 1.4 バイポーラとユニポーラ............................................................................................................. 9 1.5 セトリング時間とアナログ出力更新レート .......................................................................... 10 1.6 データ転送方式 ........................................................................................................................... 11

第 2章 DA(Digital to Analog) on RTLinux 12

2.1 パフォーマンス ........................................................................................................................... 12 2.1.1 周期性 ................................................................................................................................ 12 2.1.2 負荷をかけた際の違い .................................................................................................... 13

2.2 RTLinuxによるDA制御 .............................................................................................................. 15 2.3 DA製品制御概略 ......................................................................................................................... 16

第 3章 DA製品制御の第一歩 17

3.1 RTLinux DAドライバの組み込み ............................................................................................. 18 3.2 CardBus ID設定ユーティリティについて ............................................................................... 20 3.3 1件のDA出力を行う .................................................................................................................. 22 3.4 1件のDA出力プログラムの解説 .............................................................................................. 24

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

4.1 DaOutputDAExを使ったアナログ出力更新 ............................................................................ 27 4.2 DaOutputDAExを使ったアナログ出力更新の解説 ................................................................ 36

4.2.1 共通定義ファイルの役割 ................................................................................................ 39 4.2.2 RTLinuxモジュールの動き ............................................................................................. 40 4.2.3 Linuxプロセスの動き ...................................................................................................... 43

4.3 DaStartSamplingを使ったアナログ出力更新........................................................................... 45 4.4 DaStartSamplingを使ったアナログ出力更新の解説............................................................... 54

4.4.1 先のサンプルとの違い .................................................................................................... 55 4.4.2 DAドライバモジュールの構造 ...................................................................................... 55 4.4.3 RTLinuxモジュールの動き ............................................................................................. 56

4.5 DaOutputDAExとDaStartSamplingのどちらを使うべきか .................................................... 60

第 5章 デバッグ手法 61

5.1 ドライバデバッグ支援機能を使ってみる .............................................................................. 61 5.1.1 関数呼び出しトレース .................................................................................................... 62 5.1.2 エラー情報 ........................................................................................................................ 63 5.1.3 製品リソース情報 ............................................................................................................ 63 5.1.4 アナログ出力データ情報 ................................................................................................ 64

Page 5: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 3 - Interface Corporation

第 6章 リファレンス 65

6.1 関数一覧 ....................................................................................................................................... 65 6.2 戻り値一覧 ................................................................................................................................... 66

技術資料紹介 68

Page 6: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 4 -

はじめに

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

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

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

●本冊子で扱うソフトウェア 本冊子で扱うソフトウェア製品は下記の通りです。

ソフトウェア製品名 型 式 アナログ出力ボード Linux/RT対応ドライバソフトウェア GPG-3300

●ソフトウェアの入手方法について ソフトウェアは弊社Web siteよりダウンロード(無料)できます。 CD-ROM等、媒体による提供は有償となります。価格に送料,消費税は含まれません。 ※ ダウンロードするためには、ユーザID登録が必要になります。

Page 7: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 5 - Interface Corporation

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

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

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

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

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

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

Page 8: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 6 -

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

PCI-3174 PCI-3305 PCI-3329 PCI-3337 PCI-3341A PCI-3345A PCI-3521 PCI-3525 PCI-360216

PCI-3175 PCI-3310 PCI-3335 PCI-3338 PCI-3342A PCI-3346A PCI-3522A PCI-360112

PCI-3176 PCI-3325 PCI-3336 PCI-3340 PCI-3343A PCI-3347 PCI-3523A PCI-360116

対象型式 (CPZ)

CPZ-3174 CPZ-3325 CPZ-3340A CPZ-3340D CPZ-3346 CPZ-3349 CPZ-3521 CPZ-360112

CPZ-3175 CPZ-3329 CPZ-3340B CPZ-3342 CPZ-3347 CPZ-3350 CPZ-3522 CPZ-360116

CPZ-3182 CPZ-3338 CPZ-3340C CPZ-3343 CPZ-3348 CPZ-3351 CPZ-3523 CPZ-360810

対象型式 (CTP)

CTP-3174 CTP-3325 CTP-3340A CTP-3340D CTP-3346 CTP-3349 CTP-3521 CTP-360112

CTP-3175 CTP-3329 CTP-3340B CTP-3342 CTP-3347 CTP-3350 CTP-3522 CTP-360116

CTP-3182 CTP-3338 CTP-3340C CTP-3343 CTP-3348 CTP-3351 CTP-3523

対象型式 (CSI)

CSI-340212 CSI-360116

CSI-340312 CSI-360112

対象型式 (PEX)

PEX-340216 PEX-361216

PEX-340416 PEX-361316

PEX-361116 PEX-361416

対象型式 (LPC)

LPC-340216 LPC-361216

LPC-340416 LPC-361316

LPC-361116 LPC-361416

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

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

Page 9: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 7 - Interface Corporation

第1章 アナログ出力概要

これまでに、アナログ(analog)という言葉を一度は耳にしたことがあると思います。 ではアナログとは何でしょう。しばしばデジタルという言葉と対比し使われますが、デジタルが

「1つ2つと区切って数えられる」のに対し、アナログとは「連続した量で、1つ2つと区切って数えられない」ものを言います。 デジタル時計とアナログ時計を例にあげてみます。

デジタル時計では、「1:53」と単純に読み取ればよいわけですが、アナログ時計で仮に小数点以下を読み取っていくとしたらどうでしょう。「1:53」,「1:53.1」,「1:53.124」,「1:53.1245……..」と、きりがありませんね。

1.1 D/Aコンバータ

D/Aコンバータとは、Digital to Analog Converterの略で、デジタル・アナログ変換器と訳されます。デジタル・アナログ変換器とはデジタル値をアナログ量に変換してくれる装置のことです。 本冊子で紹介するDA製品もD/Aコンバータが搭載された、インタフェース製品です。 コンピュータはデジタル信号で動いています。一方、私たちが普段、目や耳にすることのできる

「光」や「音」の情報は全てアナログ信号です。 ところで、今のコンピュータはCDの再生ができたり、音声の再生が行えたりと、このアナログ信号である「音」の出力が行えます。 これは、コンピュータ内部のデジタルな情報がD/Aコンバータによってアナログ情報に変換され、スピーカーより出力されているからです。

Page 10: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 8 -

1.2 アナログ出力

DA製品は、アナログ信号を出力することができるインタフェース製品です。 DA製品からは、電圧または電流の固定値または時間とともに連続的に変化させた、電気信号が出力されます。

電圧[V]

時間 → 0

0 .5

1

1 .5

2

2 .5

3

3 .5

4

4 .5

5

グラフは横軸が時間、 縦軸が電圧を表しています。

1.3 分解能と精度

D/Aコンバータは、デジタルデータを比例する電圧値に変換して出力します。 ここで、2ビットのデジタル値を0~5Vの範囲の電圧に変換するとします。 2ビットで表現できる値は、「00」,「01」,「10」,「11」の4つです。従って、デジタル量をアナログ量に変換するには、これら4つのデジタル値を、0~5Vの電圧値のどれかに割り当てなければなりません。つまり、0~5Vまでの範囲を4で割った値(=1.25V)が、デジタル量1つに対する電圧の幅に対応します。

00 01 10 11

0V

1.25V

2.5V

3.75V

5V

1.25V

電圧

デジタル値

Page 11: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 9 - Interface Corporation

この区別できる電圧の範囲、言い換えれば最小単位の1ビットに対するアナログ量を分解能といい、LSB(Least Significant Bit)として表現されます。一般的には分解能nビットといった具合に表現されています。出力電圧が0~5Vで分解能12ビットの時は、

5 ÷ 4096 ≒ 0.00122(V)

が、1LSBとなります。

★レンジの上限値 デジタル値の最大値に相当する電圧は、レンジの上限になりません。 例えば、12ビット分解能, ±5Vレンジの時は 4095が最大値となり、それに相当する電圧は、 10÷4096×4095-5≒4.9975Vとなります。

★量子化誤差 高分解能の D/Aコンバータを使えば、より高精度の DA変換が可能です。 出力電圧が 0~+5Vの時、12ビット分解能と 16ビット分解能では、以下の違いが生じます。 12ビット分解能:5÷4096 ≒0.00122V(1.22mV) 16ビット分解能:5÷65536≒0.00007629V(76μV) ただ、高分解能の D/Aコンバータは、比例して高価なので、使用用途に要求される精度に合わせて選択する必要があります。

1.4 バイポーラとユニポーラ

アナログ出力は、出力電圧域の違いにより「ユニポーラ(unipolar)」と「バイポーラ(bipolar)」とに区別することができます。ポーラとは「極」を意味し、それぞれ「単極性」,「双極性」と訳されます。 出力電位差(最大出力電圧-最小出力電圧)が5Vの場合、ユニポーラでは最小出力電圧0Vから最大出力電圧+5Vの出力を行います。一方、バイポーラでは0Vを中心に最小出力電圧-2.5Vから最大出力電圧+2.5Vの出力を行います。

0

0.5

1

1.5

2

2.5

3

3.5

4

4.5

5

-2.5

-2

-1.5

-1

-0.5

0

0.5

1

1.5

2

2.5

ユニポーラ バイポーラ

電圧[V]電圧[V]

時間→

時間→

Page 12: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 10 -

1.5 セトリング時間とアナログ出力更新レート

D/Aコンバータを用いて、デジタル信号をアナログ信号に変換する時、アナログ出力が規定の精度に収まるまでの時間をセトリング時間と呼びます。

目標の電圧値→

出力電圧

一般に、目標値±1/2LSB に収まる

までの時間がセトリング時間。

セトリング時間

多くのD/Aコンバータでは、出力のフルスケール変化から出力電圧が±1/2LSBに収まるまでの時間を、

セトリング時間として定義しています。

カタログやマニュアルの仕様等に記載されている5μsや0.2μs等の値は、デジタル値を与えられ、D/Aコ

ンバータが目標の電圧/電流にまでアナログ信号を変化させるまでの時間を指します。

これとは別の速度指標として、「アナログ出力更新レート」という用語があります。

アナログ出力更新レートとは、1秒間に何回アナログ出力するかを示します。単位はHzで表されます。

例えば、アナログ出力更新レート500Hzとは、1秒間に500回 周期的にアナログ出力させることを意味

します。

お客様がデバイスドライバに対して指示する速度指標は、通常こちらが使われます。

Page 13: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 11 - Interface Corporation

1.6 データ転送方式

D/Aコンバータにデータを渡す方法には、下記に示す方法があります。

方 式 内 容 I/O方式 CPUは、I/Oポートを経由してD/Aコンバータにデータを渡します。

D/A

コンバータデータCPU

データセット

アナログ出力させるために、都度I/Oポートにアクセスしなければなりません。従って、高速にアナログ出力を繰り返す用途には向いていません。システム構成は比較的簡素なため、一般に安価です。

FIFO方式 CPUは、I/Oポートを経由して、一旦製品内のFIFOと呼ばれるバッファ領域に、 データを格納します。

D/A コンバータ

データ

CPU データセット

データ

データ

FIFOバッファ

D/AコンバータとFIFOメモリは直結されており、アナログ出力されるデータが高速に読み込まれます。このため、高速かつ連続的なアナログ出力を行うのに向いています。ただし、システム構成は複雑になるため、I/O方式に比べて高価になります。

メモリ方式 CPUは、製品内のメモリ領域にD/Aコンバータに渡すデータを書き込み、指令を与えると、製品がメモリからデータを読み取って、自分でD/Aコンバータにデータを渡します。

D/A

コンバータ

データ

CPU

データ

データ

メモリ

コンピュータのメモリ空間

データ セット

D/Aコンバータとメモリは直結されており、アナログ出力されるデータが高速に読み込まれます。データのセットとD/Aコンバータのアナログ出力は同期する必要が無いので、非常に高速かつ連続的なアナログ出力を行うのに向いています。ただし、システム構成は複雑になるため、高価になります。

Page 14: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 12 -

第2章 DA(Digital to Analog) on RTLinux

RTLinuxは、Linux上でリアルタイム処理を可能にするOSです。そのRTLinux上でDA製品を動かすことにより、リアルタイム性が要求されるシステムを構築することが可能になります。

2.1 パフォーマンス

RTLinuxとLinuxで、周期性と負荷をかけた際の違いを比較します。

2.1.1 周期性

指定した周期でアナログ出力を繰り返し行い、その周期性のぶれや限界値を測定しました。 各周期で1000回ずつ測定を行っています。

RTLinux周期測定結果

周期 平均(ms) MAX(ms) MIN(ms) 標準偏差(μs) 100ms 100.009 100.012 100.007 0.8130ms 29.999 30.025 29.987 1.5620ms 19.999 20.007 19.994 0.9610ms 9.999 10.003 9.997 1.011ms 0.999 1.005 0.997 0.77

100μs 0.996 0.102 0.098 0.7050μs 0.049 0.055 0.048 0.7220μs 0.019 0.022 0.018 0.71

Linux周期測定結果

周期 平均(ms) MAX(ms) MIN(ms) 標準偏差(μs) 100ms 110.010 110.062 109.977 4.6930ms 40.000 40.020 39.500 16.0220ms 30.003 30.050 29.521 16.4210ms 20.001 20.539 19.935 23.561ms

100μs 50μs 20μs

Linuxで周期実行を行った場合には、20ms以下に設定して周期を設定することができず、20ms以下の値に設定して実行を行った場合には全て20ms周期で実行されてしまいます。また20ms以上に周期を設定して実行した場合でも、設定した周期+10ms程度のずれが発生しています。また、周期のばらつきもRTLinuxに比べると大きくなっていることが分かります。

RTLinuxで周期実行を行った場合には、20μsまで設定した周期で正確に周期実行が行われており、標準偏差の値も非常に小さい範囲にまとまっていることが分かります。

Page 15: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 13 - Interface Corporation

2.1.2 負荷をかけた際の違い

次に、アナログ出力更新レート10kHzで実行し、負荷をかけた場合と無負荷の場合で出力周期にどの程度影響が発生するかを測定しました。 各条件で1000回ずつ測定を行っています。

アナログ出力更新 測定結果

10kHz 平均(μs) MAX(μs) MIN(μs) 中央値(μs) 最頻値(μs) 標準偏差(μs) Linux無負荷 100.65 111 100 100 100 1.39Linux負荷 200.72 429 29 211 88 93.13

RTLinux無負荷 100.41 108 91 100 100 0.69RTLinux負荷 100.43 105 94 100 100 0.96

0

100

200

300

400

500

600

頻度

20

40

60

80

100

120

140

160

180

200

220

240

260

280

300

320

340

周期(μs)

10kHz 無負荷

Linux 10kHz 無負荷 RTLinux 10kHz 無負荷

Page 16: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 14 -

0

100

200

300

400

500

600頻

20

40

60

80

100

120

140

160

180

200

220

240

260

280

300

320

340

周期(μs)

10kHz 負荷

Linux 10kHz 負荷 RTLinux 10kHz 負荷

Linux・RTLinux共に無負荷時には、出力更新のばらつきは同程度で、ほぼ設定通りの周期で出力が実行されていることが分かります。 次に負荷として、AD製品(PCI-3133)を使用してサンプリング周期70kHzでADサンプリングを実行した状態で、アナログ出力更新のばらつきを測定しました。 負荷をかけた状態でアナログ出力更新を実行した場合、Linuxでは大きくばらつきが出ており、明らかに正常に出力更新が行えなくなっていることが分かります。 RTLinuxでは、ADサンプリングがLinux上のタスクとして動いているため、より優先度の高いDA側のサンプリング処理がほとんど影響を受けていないことが分かります。

Page 17: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 15 - Interface Corporation

2.2 RTLinuxによるDA制御

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

DA製品

RTLinux対応 ドライバモジュール

(rcp3300.o)

RTLinuxモジュール Linux アプリケーション

信号出力

RT-FIFO

入力機器

RTLinuxスレッド

●RTLinuxモジュール

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

ウェアを使ってDA製品を制御するために、このモジュールを作成する必要があります。 ●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-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 16 -

2.3 DA製品制御概略

DA製品の制御は、下記の制御シーケンス(順番)で行います。

I/Oモジュール初期化

各種処理

終了処理 (3)

(2)

(1)

(1)製品の初期化

DA製品への操作を行うため、まず、製品を利用可能な状態にします。 この処理が製品の初期化です。製品の初期化を行うと、プログラムは製品へのアクセスが可能

となります。本処理が行われないと製品へのアクセスは行えません。 (2)各種処理

DA製品を使って、アナログ出力を行います。 (3)終了処理 製品の使用終了を行うための手続きです。プログラム終了時に行います。

Page 19: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 17 - Interface Corporation

第3章 DA製品制御の第一歩

ここでは、実際に弊社DA製品を用いて、DA製品の制御プログラムを作成します。 この章では例として、以下の製品を使用しています。

PCI-3329 1枚:DA変換製品 ECO-8520 1本:36ピンハーフピッチケーブル TNS-3601 1台:垂直36ピンネジ変換端子台 TDS224 1台:デジタルオシロスコープ(ソニーテクトロニクス社製)

下図に、接続構成を示します。 これは、DA製品のチャンネル1とチャンネル2の出力を、デジタルオシロスコープに接続する例です。

PCI-3329

ECO-8520

TNS-3601

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

BNCケーブル

RSW1

DA製品(PCI-3329)の製品識別用ロータリスイッチ(RSW1)を0に設定し、コンピュータに実装します。

DA製品を、接続ケーブル(ECO-8520)を介して端子台(TNS-3601)に接続します。そこから、BNCケーブ

ルを介して、デジタルオシロスコープに接続します。

お手持ちのDA製品で、どのように接続すれば良いかについては、ハードウェアマニュアルの『外部接

続』を参照してください。

Page 20: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 18 -

製品をシステムに組み込んでから、動かすまでの流れは下記のようになります。 各項目に従って、RTLinux上でのDA製品制御プログラミングを行っていきましょう。

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

RTLinux DAドライバ組み込み

プログラミング

コンパイル

実行

3.1 RTLinux DAドライバの組み込み

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

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

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

% su ← リアルタイムカーネルを組み込むため、 スーパーユーザになります。 Password: ----- ← rootのパスワードを入力します。 # cd /usr/src/rtlinux/rtlinux-3.1 # sh scripts/insrtl ← リアルタイムカーネルの組み込みスクリプトを実行します。 # lsmod ← リアルタイムカーネルの組み込みを確認します。 Module Size Used by rtl_sched 43104 0 (unused) rtl_fifo 9968 0 (unused) rtl_posixio 7184 0 [rtl_fifo] rtl_time 10000 0 [rtl_sched rtl_posixio] rtl 27184 0 [rtl_sched rtl_fifo rtl_posixio

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

リアルタイムカーネルを組み込んだ後に、DAドライバモジュールを組み込むことにより、DA製品のリアルタイム制御が行えるようになります。

Page 21: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 19 - Interface Corporation

DA製品を制御するドライバモジュールは、dpg0100.o,dpg0102.o,rcp3300.oの3ファイルより構成されています。実際に制御するには、全てを事前に組み込む必要があります。 ファイル名 内 容 rcp3300.o DA製品制御のドライバモジュール本体です。

実際に製品を制御するためのモジュールです。このドライバモジュール内の関数をRTLinuxモジュールから呼び出すことにより、DA製品を制御することができます。

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

★テストドライバ(rcp3300t.o)について 上記ファイル以外に、GPG-3300をインストールすると、rcp3300t.oというファイルが付属します。これは、製品がなくてもテストが行えるようにするためのテストドライバです。(仮想的な DA製品のドライバとして動作します) rcp3300.oの代わりに組み込むことで、製品を実装しなくても、各関数を実行することができます。詳しい説明は Helpを参照してください。

以降の説明のディレクトリは、カーネルバージョンが2.4.4、インストールディレクトリをデフォルトに指定した場合です。 ドライバモジュールの組み込みは、insda.shスクリプトで簡単に行えます。 # cd /usr/src/interface/gpg3300/i386/rtl/drivers # sh insda.sh

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

dpg0100,dpg0102,rcp3300が組み込まれていることが分かります。 以上で、DA製品のリアルタイム制御を行うプログラミングまでの準備が整いました。

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

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

Page 22: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 20 -

★スクリプトを使わずに組み込むには? ドライバモジュールの組み込みは、スクリプトを使用する方が簡単なのでお奨めですが、直接ドライバ モジュールを組み込むことも可能です。 以下に insmodコマンドを使った場合の組み込み例を示します。 insmodコマンドを使って、ドライバモジュールを組み込む場合> # insmod dpg0100 # insmod dpg0102 # insmod rcp3300 rmmodコマンドを使って、ドライバモジュールを取り外す場合> # rmmod rcp3300 # rmmod dpg0102 # rmmod dpg0100

3.2 CardBus ID設定ユーティリティについて

CardBusID設定ユーティリティは、複数枚の同一型式CardBus製品を使用するためのものです。 CardBus製品ごとに異なるID番号を設定します。

【操作方法】 デバイス番号設定ユーティリティのメニューで「5」を選択するか、または下記のコマンドを実行します。 #dpg0101 -c

すると、CardBusID設定ユーティリティが起動し、現在挿入されている弊社CardBus製品の情報が表示されます。 ********************************************************** CardBus Setup Utility ---------------------------------------------------------- Version : 1.20-06 ---------------------------------------------------------- Copyright 2004 Interface Corporation. All right reserved. **********************************************************

========================================================== Ref. ID | Bus | Dev | Func | Model | RSW1 ---------------------------------------------------------- 1 | 3 | 0 | 0 | CBI-3133A | 2 ========================================================== ******************* Command ******************** 1. Change the board id number. 2. Run the device number setup utility. 99. Exit the proguram. ************************************************ Enter the command number:

Page 23: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 21 - Interface Corporation

項 目 内 容

Ref. ID CardBus製品のインデックス番号です。 メニュでCardBus製品の選択を行う際に指定します。

Bus CardBus製品が挿入されているバス番号を示します。 Dev CardBus製品が挿入されているデバイス番号を示します。 Func CardBus製品が挿入されているファンクション番号を示します。 Model CardBus製品の型式を示します RSW1 設定されているID番号を示します。

ID番号を変更したい場合は、メニューから「1」を選択し、変更を行いたいCardBus製品のインデックス番号を入力します。 Enter Ref. ID:

次に、CardBus製品ID番号を入力しEnterキーを押します。 CardBus製品ID番号は0~15の値を入力してください。 Enter the board id number (0-15). If you want to cancel this operation, enter -1. :

「99」を選択することでユーティリティを終了します。 ※ 変更したID番号をシステムに認識させるには、ドライバの再起動を行うか、システムを再起動してください。

※ 設定したID番号がわかるように、番号を記したシールをCardBus製品に貼ることをおすすめします。

Page 24: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 22 -

3.3 1件のDA出力を行う

ここでは、DaOutputDA関数を使って、1件のDA出力を行うプログラムを作成します。 エディタを起動し、下記Listに示すプログラムを入力して、ファイル名を「sample1.c」として保存してください。

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

sample1.c

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#include <rtl.h> #include "fbida.h" #define CH_NUM 2 /* 1件のDA出力で使用する総チャンネル数 */ #define DEVICE_ID 3329 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define SUB_SYSTEM_ID 0x0001 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define RSW_NO 0 /* 同一型式の製品を区別するRSW1設定値 */ int g_device_no = -1; /* DA製品のデバイス番号 */ /* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */ int init_module(void) { int i, ret; DASMPLCHREQ smp_ch_req[CH_NUM]; /* 1件のDA出力を行う際の情報を設定する構造体の宣言 */ unsigned short da_data[CH_NUM]; /* 1件のDA出力で出力するデータ配列の宣言 */ rtl_printf("init_module called¥n"); EXPORT_NO_SYMBOLS; /* DA製品のオープン */ ret = DaOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no); if(ret){ rtl_printf("DaOpenEx error [ret=%x]¥n", ret); return -1; } else { rtl_printf("DaOpenEx success!! [DeviceNo=%d]¥n", g_device_no); } /* 1件のDA出力 */ for(i = 0; i < CH_NUM; i++){ smp_ch_req[i].ulChNo = 1 + i; /* チャンネルを指定(1,2を順に指定しています) */ smp_ch_req[i].ulRange = DA_0_5V; /* レンジ:0~+5Vを指定 */ } for(i = 0; i < CH_NUM; i++) da_data[i] = 0xfff; /* 配列の初期化 */ ret = DaOutputDA( g_device_no, CH_NUM, /* 1件のDA出力時に使用する、総チャンネル数 */ smp_ch_req, /* 各チャンネルの情報設定 */ da_data); /* 出力するデータ配列のポインタを指定 */ if(ret){ DaClose(g_device_no); rtl_printf("DaOutputDA error [DeviceNo=%d ret=%x]¥n", g_device_no, ret); return -2; } return 0; } /* 終了関数(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret;

Page 25: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 23 - Interface Corporation

54 55 56 57 58 59 60 61 62

rtl_printf("cleanup_module called¥n"); /* DA製品のクローズ */ ret = DaClose(g_device_no); if(ret){ rtl_printf("DaClose error [DeviceNo=%d ret=%x]¥n", g_device_no, ret); } }

次に、下記に示すプログラムを入力し、ファイル名を「makefile」として保存してください。 これは、上記プログラムをコンパイルするメイクファイルです。

makefile

1 2 3 4 5

include /usr/include/rtlinux/rtl.mk all: sample1.o sample1.o:sample1.c $(CC) $(INCLUDE) $(CFLAGS) -o sample1.o -c sample1.c

コンパイルすると、RTLinuxモジュールsample1.oが作成されます。insmodコマンドで、RTLinuxモジュールを組み込みます。 # make # ls makefile sample1.c sample1.o # insmod sample1.o

組み込む前に、リスト中のrtl_printf関数の出力内容が画面で確認できるよう、X Windowで使用されている方は、コンソールをもう一つ立ち上げ、次のコマンドを入力してください。 # tail –f /var/log/messages

コンソール画面で作業されている方は、次のように打ち込んでください。 # tail –f /var/log/messages &

これにより、rtl_printf関数が出力する内容を確認できます。 ★/var/log/messages syslogや cron等で実行されたサービスのログ等の情報は、「/var/log/」に保存されます。通常、ログは「/var/log/messages」に保存されます。 RTLinux では、rtl_printf 関数を使って、ここに出力し、デバッグプリントができるようになっています。(そのままコンソール画面に出力されるようには、なっていません) 上の用例では、tailコマンドを使って、このログ出力を常に表示状態にしています。 コンソール画面の例で用いた&(アンパサンド)コマンドはジョブコマンドの一種で、tailコマンドをバックグランドで実行させています。 コンソール画面では、X Window のように幾つもコンソールを起動することができないので、このようにします。

sample1.oを組み込むと、コンソールに以下のメッセージが出力され、チャンネル1から5Vの電圧が、アナログ出力されます。 その様子は、オシロスコープ等により、観察できます。 # insmod sample1.o init_module called

Page 26: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 24 -

次に、組み込んだRTLinuxモジュールを取り外しましょう。 コンソールに以下を入力し、Enterキーを押します。 # rmmod sample1

すると、コンソール画面は、以下のメッセージが表示され、チャンネル1の電圧が0Vに変化します。 # rmmod sample1 cleanup_module called

RTLinuxモジュールが取り外されたことが判ります。 何度かinsmodコマンドによるモジュール組み込みとrmmodコマンドによるモジュール取り外しを繰り返してみてください。 その都度、メッセージが表示され、同時にチャンネル1の電圧が変化することがわかります。

3.4 1件のDA出力プログラムの解説

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

sample1.o

RTLinuxモジュール

RTLinux

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

init_module関数 cleanup_module関数

作成したRTLinuxモジュールをinsmodコマンドでRTLinuxに組み込む時、init_module関数が呼ばれます。init_module関数ではDA製品のオープン処理と、1件のDA出力を行っています。 また、rmmodコマンドで取り外す時、cleanup_module関数が呼ばれます。cleanup_module関数ではDA製品のクローズ処理をしています。 製品の制御では、オープン処理を行わないと何の制御もできません。ファイルに読み書きする時、

open関数を使ってオープンしないと、何もできないのと同じことです。 そして、製品の制御を終える時、必ずクローズ処理を行う必要があります。 サンプルでも、この形式に則って処理を行っています。 以降では細かく動きを見ていきますが、この基本事項を守っていることに注意して読み進めてく

ださい。

Page 27: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 25 - Interface Corporation

(23行目:DaOpenEx関数) DA製品を制御する前段階として、DA製品をオープンするDaOpenEx関数を呼び出しています。以下に引数と対応を示します。

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

wSubSystemIDと組み合わせて、製品の型式を指定します。 組み合わせについては、Helpを参照ください。

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

この引数を与えて関数を呼び出すと、ドライバモジュールは、引数に適合するDA製品を検索し、合致した製品に対してデバイス番号を割り振り、第4引数に返します。 プログラマは、このデバイス番号を使って、以降のAPIの呼び出しを行います。 ★何故、DaOpenEx関数を使うのか? LinuxやWindowsプログラムでは、DaOpen関数を使用しますが、RTLinuxでは DaOpenEx関数の使用を推奨しています。 これは、プログラムで使用する DA製品を、システム内で一意の ID値を使用することで、他の環境にシステムを移築しても特定するためにあります。 DaOpen関数を使用した場合、第 1引数で指定するデバイス番号は、RTLinuxシステム内で、DA製品が認識された順番に割り振られます。 この場合、複数の DA 製品を使用していた場合、ユニット並びにコンピュータ内の DA 製品の順番を変更した際、想定外のデバイス番号が割り振られてしまう恐れがあります。 これを避けるため、RTLinuxプログラムでは、DaOpenEx関数を使い、DA製品を特定してデバイス番号を得る仕組みを推奨しています。

(37行目:DaOutputDA関数) ここでは、DaOutputDA関数を用い、1件のDA出力を行っています。 1件のDA出力では、1チャンネルから複数チャンネルのDA出力が可能です。 第1引数で、DaOpenEx関数で得たデバイス番号を、第2引数でDA出力するチャンネル数、第3引数で各チャンネルの詳細設定、第4引数で出力するデータの配列のポインタを渡します。この引数を与えて関数を呼び出すと、ドライバモジュールは、受け取った引数に従って1件のDA出力を、指定されたチャンネル数分行います。

Page 28: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 26 -

第4引数ではDA出力するデータの配列のポインタを渡す必要があります。 配列の大きさは、以下の式で求めることができます。 配列の大きさ = DA出力に必要なデータサイズ × チャンネル数(第2引数の値) DA出力に必要なデータサイズは、DA製品の分解能で求めることができます。 分解能 データサイズ

8ビット 1バイト 12ビット 2バイト 16ビット 2バイト 24ビット 4バイト

後述しますが、DaOutputDA関数と同カテゴリ関数の、DaSetOutputDAEx関数および、DaOutputDAEx関数の組を使用した場合、DA出力データはバイナリ値だけでなく、電圧値/電流値の形式で設定することが可能です。 この時、DA出力に必要なデータサイズは、分解能に依らず、全て8バイト(double型のサイズ)となります。

サンプルでは、2チャンネルのDA出力を行っていますが、例えば4チャンネルのDA出力を行う場合、

必要な配列の大きさは、2(バイト)×4(チャンネル数)=8バイトとなります。

配列に格納されるDA出力データの順は、第3引数のチャンネル指定順に設定します。

サンプルでは、1、2チャンネルの順にチャンネルを指定しているので、配列のデータも、1、2チャン

ネルの順に格納します。

もし、2、1チャンネルの順にチャンネルを指定すると、配列のデータも2、1チャンネルの順に格納し

ます。

(57行目:DaClose関数)

DA製品の制御を終了するためには、DaClose関数を用います。

オープンしたDA製品は、使用後は必ずクローズしてください。 ★DaClose関数を呼ばないと、どうなるか? DaClose関数を呼び出さないと、DA製品はオープンしたままの状態になります。 オープン状態なので、DaOpen関数を呼び出した場合、エラーが返ります。 こういう事態に陥った場合、対処方法としては、GPG-3300ドライバモジュール(rcp3300)を、一旦取り外す必要があります。 オープンしたら必ずクローズしてください。

Page 29: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 27 - Interface Corporation

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

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

4.1 DaOutputDAExを使ったアナログ出力更新

先程では、DaOutputDA関数を使って、1件のDA出力を行いました。 ここでは、同じく1件のDA出力を行うDaOutputDAEx関数を使い、スレッドを周期的に動作させて、アナログ出力更新を実現します。

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

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

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

sample2.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

/* sample2.h 共通定義ヘッダファイル Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___SAMPLE2_H) #define ___SAMPLE2_H #include "fbida.h" /* Constants --------------------------------------------------------------- */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define DEVICE_ID 3329 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define SUB_SYSTEM_ID 0x0001 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define RSW_NO 0 /* 同一型式の製品を区別するRSW1設定値 */ #define CH_NUM 2 /* 1件のDA出力の総チャンネル数 */ #define SMP_NUM 100 /* アナログ出力更新の件数 */ /* DAデータ配列にアクセスする関数マクロ */ #define DA_PTR(ptr, num, ch) ((ptr) + (CH_NUM * (num)) + (ch)) typedef unsigned short DA_TYPE; /* DAデータの型 */ #define MAX_DATA 0xfffU /* DAデータの最大値 */ #define MIN_DATA 0x000U /* DAデータの最小値 */ #define MID_DATA ((MAX_DATA + MIN_DATA) / 2)/* DAデータの中間値 */ #define PI (3.1415926) /* パイの値 */ /* Command ID -------------------------------------------------------------- */ /* コマンドID群(周期アナログ出力更新用スレッドへの指示用) */ enum CMD_IDS { ID_START, /* アナログ出力更新のスタート指示 */ ID_STOP, /* アナログ出力更新のストップ指示 */

Page 30: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 28 -

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

ID_CLEAR_DATA, /* アナログ出力更新データのクリア */ ID_SET_DATA /* アナログ出力更新データのセット */ }; /* アナログ出力更新用データID群(使用するデータの指定用) */ enum DATA_KIND_IDS { ID_SIN_WAVE_DATA, /* サイン波データ */ ID_TRIANGLE_WAVE_DATA, /* 三角波データ */ ID_TEETH_SAW_WAVE_DATA, /* のこぎり波データ */ ID_RECTANGLE_WAVE_DATA /* 矩形波データ */ }; /* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ /* 各コマンドに対する設定パラメータ */ union { long smp_period_ms; /* ID_START時使用:周期の設定(ms単位) */ enum DATA_KIND_IDS data_kind; /* ID_SET_DATA時使用:データの設定 */ } opt; }; #endif

★ワンポイント お使いの DA製品が PCI-3329でない場合、sample2.hの 15,16行目を使用している製品に合わせて修正してください。 型式と ID値の対応は、Helpの説明を参照してください。 以下に、CTP-3342を使用する場合の例を示します。 #define DEVICE_ID 3342 ← 3329を 3342に変更。 #define SUB_SYSTEM_ID 0x0101 ← 0x0001を 0x0101に変更。

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

module2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

/* module2.c RTLinuxモジュールのソースコード Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include <math.h> #include "sample2.h" pthread_t my_task_info; int g_device_no = -1; /* DA製品のデバイス番号 */ DA_TYPE da_data[CH_NUM * SMP_NUM]; /* DA出力を行うバッファ */ DA_TYPE da_sin_wave_data[CH_NUM * SMP_NUM]; /* 参照用:サイン波データ */ DA_TYPE da_triangle_wave_data[CH_NUM * SMP_NUM]; /* 参照用:三角波データ */ DA_TYPE da_teeth_saw_wave_data[CH_NUM * SMP_NUM]; /* 参照用:のこぎり波データ */ DA_TYPE da_rectangle_wave_data[CH_NUM * SMP_NUM]; /* 参照用:矩形波データ */ /* アナログ出力更新を行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd; DA_TYPE* p_src_data = NULL; DA_TYPE* p_da_data = NULL; /* 1件のDA出力時に用いるデータのポインタ */ long da_buff_idx = 0; /* アナログ出力更新バッファに対するインデックス */ long smp_count = 0; /* アナログ出力更新の総件数 */ rtl_printf("my_task called arg=%d¥n", arg); /* RTLinuxスレッドが組み込み中、動作する永久ループ */

Page 31: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 29 - Interface Corporation

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 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

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: start output!!¥n"); pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.opt.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* アナログ出力更新のストップ */ rtl_printf("my_task: stop output!!¥n"); pthread_suspend_np(pthread_self()); break; case ID_CLEAR_DATA: /* アナログ出力更新用データのクリア */ rtl_printf("my_task: clear output data!!¥n"); memset(da_data, 0, sizeof(da_data)); break; case ID_SET_DATA: /* アナログ出力更新用データのセット */ rtl_printf("my_task: set output data!!¥n"); switch(cmd.opt.data_kind){ case ID_SIN_WAVE_DATA: p_src_data = da_sin_wave_data; break; case ID_TRIANGLE_WAVE_DATA: p_src_data = da_triangle_wave_data; break; case ID_TEETH_SAW_WAVE_DATA: p_src_data = da_teeth_saw_wave_data; break; case ID_RECTANGLE_WAVE_DATA: p_src_data = da_rectangle_wave_data; break; default: rtl_printf("unknown data_kind!!¥n"); break; } memcpy(da_data, p_src_data, sizeof(da_data)); break; default: rtl_printf("unknown id!!¥n"); break; } } /* 1件のDA出力を行うデータのポインタを求める */ p_da_data = DA_PTR(da_data, da_buff_idx, 0); /* 1件のDA出力を行う */ ret = DaOutputDAEx(g_device_no, p_da_data); if(ret){ rtl_printf("DaOutputDAEx error [ret=%d]¥n", ret); } /* アナログ出力更新のインデックスおよび件数の更新 */ da_buff_idx++; if(SMP_NUM <= da_buff_idx) da_buff_idx = 0; smp_count++; rtl_printf("my_task: smp_count:%ld da_buff_idx:%ld¥n", smp_count, da_buff_idx); } 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; }

Page 32: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 30 -

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

/* アナログ出力更新用データ生成の下請け関数 */ void make_sampling_data(DA_TYPE* dst_data, enum DATA_KIND_IDS id, int max_num) { int ch, num; rtl_printf("make_sampling data called dst_data=%p id=%d max_num=%d¥n", dst_data, id, max_num); switch(id){ case ID_SIN_WAVE_DATA: /* サイン波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ *DA_PTR(dst_data, num, ch) = MID_DATA * sin(num * 2 * PI / max_num) + MID_DATA; } } break; case ID_TRIANGLE_WAVE_DATA: /* 三角波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ if(num <= (max_num / 2)){ *DA_PTR(dst_data, num, ch) = (num * MAX_DATA / (max_num / 2)); } else { *DA_PTR(dst_data, num, ch) = MAX_DATA - (num * MAX_DATA / (max_num / 2)); } } } break; case ID_TEETH_SAW_WAVE_DATA: /* のこぎり波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ *DA_PTR(dst_data, num, ch) = (num * MAX_DATA / max_num); } } break; case ID_RECTANGLE_WAVE_DATA: /* 矩形波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ if(num <= (max_num / 2)){ *DA_PTR(dst_data, num, ch) = MAX_DATA; } else { *DA_PTR(dst_data, num, ch) = MIN_DATA; } } } break; default: rtl_printf("unknown id!!¥n"); break; } } /* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */ int init_module(void) { int i, ret; DASMPLCHREQ smp_ch_req[CH_NUM];/* 1件のDA出力を行う際の情報を設定する構造体の宣言 */ 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)); /* DA製品のオープン */ ret = DaOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no); if(ret){ rtl_printf("DaOpenEx error [ret=%x]¥n", ret); return -1;

Page 33: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 31 - Interface Corporation

186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

} else { rtl_printf("DaOpenEx success!! [DeviceNo=%d]¥n", g_device_no); } /* 1件のDA出力の初期設定 */ for(i = 0; i < CH_NUM; i++){ smp_ch_req[i].ulChNo= 1 + i; /* チャンネルを指定(1,2を順に指定しています) */ smp_ch_req[i].ulRange = DA_0_5V; /* レンジ:0~+5Vを指定 */ } ret = DaSetOutputDAEx( g_device_no, CH_NUM, /* 1件のDA出力時の、総チャンネル数 */ smp_ch_req, /* 各チャンネルの情報設定 */ CONV_BIN); /* データをバイナリ値で取得 */ if(ret){ DaClose(g_device_no); rtl_printf ("DaSetOutputDAEx error [ret=%x]¥n", ret); return -2; } /* 参照用データの作成 */ make_sampling_data(da_sin_wave_data, ID_SIN_WAVE_DATA, SMP_NUM); make_sampling_data(da_triangle_wave_data, ID_TRIANGLE_WAVE_DATA, SMP_NUM); make_sampling_data(da_teeth_saw_wave_data, ID_TEETH_SAW_WAVE_DATA, SMP_NUM); make_sampling_data(da_rectangle_wave_data, ID_RECTANGLE_WAVE_DATA, SMP_NUM); /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了関数(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret; rtl_printf("cleanup_module called¥n"); /* DA製品をクローズする */ ret = DaClose(g_device_no); if(ret){ rtl_printf("DaClose 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プロセスのソースファイルです。ファイル名を「sample2.c」として保存してください。

sample2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

/* sample2.c Linuxプロセスのソースコード Copyright 2002 Interface Corporation. All rights reserved. */ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <sys/ioctl.h> #include <rtl_fifo.h> #include "sample2.h" /* set output data時の、選択メニュー */ enum DATA_KIND_IDS select_wave_type(void) { int cmd_data_no;

Page 34: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 32 -

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

while(1){ printf( "¥n ----- select a wave type -----" "¥n 1: sine wave" "¥n 2: triangle wave" "¥n 3: sawteeth wave" "¥n 4: rectangle wave" "¥n -------------------------------" "¥n enter a wave type number:"); cmd_data_no = 0; if(scanf("%d", &cmd_data_no) <= 0){ getchar(); continue; /* 読み取れない入力を読み捨てる */ } switch(cmd_data_no){ case 1: return ID_SIN_WAVE_DATA; case 2: return ID_TRIANGLE_WAVE_DATA; case 3: return ID_TEETH_SAW_WAVE_DATA; case 4: return ID_RECTANGLE_WAVE_DATA; default: printf("invalid command!!¥n"); continue; } } } /* Linuxプロセスのメインルーチン */ int main(void) { int cmd_no; int fd_cmd; struct CMD_STRUCT cmd; char rt_fifo_name[80]; /* RTLinuxモジュールに指令を送る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モジュールに対する指示(99を入力すると、ループを抜けます) */ while(1){ printf( "¥n ===== select a command number =====" "¥n 1: start output" "¥n 2: stop output" "¥n 3: clear output data" "¥n 4: set output data" "¥n --------------------------------" "¥n 99: exit program" "¥n =================================" "¥n enter a command number:"); cmd_no = 0; if(scanf("%d", &cmd_no) <= 0){ getchar(); continue; /* 読み取れない入力を読み捨てる */ } if(cmd_no == 99) break; /* 選択メニューから抜ける */ switch(cmd_no){ /* 選択メニューの処理 */ case 1: /* start output */ cmd.id = ID_START; cmd.opt.smp_period_ms = 10; /* 10ms周期のアナログ出力更新設定 */ break; case 2: /* stop output */ cmd.id = ID_STOP; break; case 3: /* clear output data */ cmd.id = ID_CLEAR_DATA; break; case 4: /* set output data */ cmd.id = ID_SET_DATA; cmd.opt.data_kind = select_wave_type(); /* セットする波形データの選択 */ break; default: printf("invalid command!!¥n"); continue; }

Page 35: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 33 - Interface Corporation

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

/* 入力された命令の実行 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the command.¥n"); return -1; } } /* アナログ出力更新のストップ指示(確実にアナログ出力更新を止める) */ cmd.id = ID_STOP; 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; }

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

makefile 1 2 3 4 5 6 7 8 9 10 11

include /usr/include/rtlinux/rtl.mk all: module2.o sample2 sample2: sample2.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o sample2 sample2.c temp.o: module2.c $(CC) $(INCLUDE) $(CFLAGS) -o temp.o -c module2.c module2.o: temp.o $(LD) -r -o module2.o temp.o /usr/lib/libm.a

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

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

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

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

実行すると、選択メニューが表示されます。 ここでは、アナログ出力更新のスタート,ストップ,データのクリアとセットが選択できます。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:4

4を入力してEnterキーを押します。

Page 36: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 34 -

すると、次のメニューが表示されます。 ここでは、セットするデータの波形タイプを選択します。 ----- select a wave type ----- 1: sine wave 2: triangle wave 3: sawteeth wave 4: rectangle wave ------------------------------- enter a wave type number:1

ここでは1を入力してEnterキーを押してください。 再び、最初の選択メニューが表示されます。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:1

ここでは1を入力してEnterキーを押してください。 すると、アナログ出力更新が始まります。下図は、アナログ出力更新している様子をオシロスコー

プを使って確認している画面例です。

sample2を終了するには、選択メニューが表示されている状態で、99を入力してEnterキーを押します。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:99

Page 37: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 35 - Interface Corporation

各メニューの項目の動きについて、下表に示します。 項目名 内 容

1: start output アナログ出力更新を開始します。 この項目を選択する前に、必ず1回「4: set output data」で出力するデータをセットしてください。

2: stop output アナログ出力更新を停止します。 3: clear output data アナログ出力更新するデータの内容をクリアします。

「4: set output data」でデータを2回以上セットする時、一旦クリアして、セットしてください。

4: set output data アナログ出力更新するデータの内容をセットします。 セットするデータの種類を、下表にて選択可能です。

「4: set output data」を選択すると、下表のメニューが表示されます。 ここでは、セットするデータの種類が設定可能です。

項目名 内 容 1: sine wave サイン波のデータをセットします。 2: triangle wave 三角波のデータをセットします。 3: sawteeth wave のこぎり波のデータをセットします。 4: rectangle wave 矩形波のデータをセットします。

Page 38: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 36 -

4.2 DaOutputDAExを使ったアナログ出力更新の解説

それでは、先程のプログラムの解説を行います。 DaOutputDAEx関数を使って、周期的なアナログ出力更新を行う基本的なアルゴリズムは、定周期で起動するRTLinuxスレッドを使い、RTLinuxスレッド呼び出しごとに、1件のDA出力を行うDaOutputDAEx関数を実行し、アナログ出力更新を実現しています。

RTLinuxスレッド

DaOutputDAEx関数呼び出し

DaOutputDAEx関数呼び出し

DaOutputDAEx関数呼び出し

XX時間周期

Page 39: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 37 - Interface Corporation

DaOutputDAEx関数を実行する際、アナログ出力するデータ値は、別途確保した配列に対して、RTLinux

スレッド呼び出しごとに配列のインデックスをインクリメントしながら出力を行っています。

データ データ データ データ データ データ データ

インデックス

RTLinuxの呼び出し

DaOutputDAEx関数によるアナログ出力

データ データ データ データ データ データ データ

インデックス

RTLinuxの呼び出し

DaOutputDAEx関数によるアナログ出力

データ データ データ データ データ データ データ

インデックス

RTLinuxの呼び出し

DaOutputDAEx関数によるアナログ出力

配列には、アナログ出力の値が格納されています。このデータに時系列で順次変化する値を格納

することで、下図のようなサイン波のアナログ出力更新を実現しています。 配列に格納するデータは、プログラム次第で、どのような波形も実現可能です。

サンプルでは、サイン波,三角波,のこぎり波,矩形波の4パターンを用意しています。

データ データ

Linuxプロセス

RTLinuxモジュール

データのセット アナログ出力更新の開始 アナログ出力更新の停止

アナログ出力更新

チャンネル 1

アナログ更新出力する

データの内容をセット

サンプルでは、RTLinuxモジュールに対して、以下の機能を実装しています。

項 目 内 容 データのセット アナログ出力更新を行うデータ配列に対して、指定された波形データをセッ

トします。 波形データの種類は、サイン波,三角波,のこぎり波,矩形波の4種類です。

データのクリア アナログ出力更新を行うデータ配列を、初期化(全て0で埋める)します。 アナログ出力更新のスタート

指定された周期でアナログ出力更新を実行するRTLinuxスレッドをスタートさせます。

アナログ出力更新のストップ

アナログ出力更新を実行しているRTLinuxスレッドをストップします。

Page 40: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 38 -

下図では、Linuxプロセスが、RTLinuxモジュールに対してデータのセットからアナログ出力更新をス

タートさせ、ストップするまでの処理の流れを図示しています。

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

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

LinuxプロセスからRTLinuxモジュールに対する指示は、RT-FIFOを経由して、一旦ハンドラ(my_handler)

に送られ、そこから別のRT-FIFOを介してRTLinuxスレッド(my_task)に送られます。

my_taskでは、以下に示す主要な処理が集約されています。

・ 周期的にDaOutputDAEx関数を呼び出し、アナログ出力更新を行う。

・ 周期的なDaOutputDAEx関数の呼び出しを停止させる。

・ DaOutputDAEx関数で出力するデータ配列の内容をセットする。

・ DaOutputDAEx関数で出力するデータ配列の内容をクリアする。

init_moduleでは、RTLinuxスレッドおよびRT-FIFOの生成の他、DA製品のオープン処理と初期化が行わ

れます。

cleanup_moduleでは、RTLinuxスレッドおよびRT-FIFOの破棄の他、DA製品のクローズ処理が行われま

す。

Page 41: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 39 - Interface Corporation

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

ここでは、共通定義ファイル(sample2.h)の役割について見ましょう。 共通定義ファイルは、RTLinuxモジュール(module2.c)とLinuxプロセス(sample2.c)が、共通で使用する定数等を抜き出したものです。 各ファイルの関係を下図に示します。

sample2.h

共通定義

sample2.c

Linux

プロセス

module2.c

RTLinux

モジュール

参照参照

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

行番号 内 容 12~28行目 #define宣言、typedef定義>

関数マクロ,RT-FIFOの番号の定義,各関数で使用する定数値の指定,関数マクロ,バッファサイズの指定。

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

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

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

Linuxプロセス

RTLinuxモジュール

struct CMD_STRUCT {

enum CMD_IDS id;

union {

long

smp_period_ms;

enum DATA_KIND_IDS data_kind;

Page 42: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 40 -

コマンドの構造体は、3つのメンバ変数で構成されています。RTLinuxモジュールに、どんな作業をして欲しいか指示を出すID値(idメンバ変数)と、ID値を補足する情報(smp_period_msメンバ変数とdata_kindメンバ変数)です。 作業を指示するID値は、32~37行の列挙体ID_START,ID_STOP,ID_CLEAR_DATA,ID_SET_DATAで定義されています。 この構造体は、後の説明にも出てきますので注意して読み進めてください。

4.2.2 RTLinuxモジュールの動き

ここでは、RTLinuxモジュール(module2.o)の動きに注目して見てみましょう。 RTLinuxモジュールでは、周期サンプリングを実現するために、init_module関数内で、幾つか リソースを生成しています。それを下表に示します。

項 目 内 容 RT-FIFO(FIFO_COMMAND) Linuxプロセスからの指示を受けるためのRT-FIFOです。指示

は、ハンドラmy_handlerに渡されます。 RT-FIFO(FIFO_THRU_CMD) ハンドラにて、Linuxプロセスから受け取った情報を、アナロ

グ出力更新等の処理を実現するRTLinuxスレッド(my_task)に渡すためのRT-FIFOです。

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

RTLinuxスレッド(my_task) アナログ出力更新等の処理を実現するRTLinuxスレッドです。Linuxプロセスから送られる指示は、最終的にここに送られ、アナログ出力更新を実現します。

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

ハンドラ(my_handler)

RTLinuxスレッド(my_task)

FFO_COMMAND

FIFO_THRU_CMD

Linuxプロセス

ID_START ID_STOP

←周期呼び出し周期実行

DaOutputDAEx関数

コマンド指示

ID_CLEAR_DA

ID_SET_DATA

配列データ

Page 43: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 41 - Interface Corporation

RTLinuxモジュール内で中心となるのは、アナログ出力更新を実現するRTLinuxスレッド(my_task)です。このスレッドは、Linuxプロセスからの指令により、スタート(ID_START)、ストップ(ID_STOP)、配列データのセット(ID_SET_DATA),配列データのクリア(ID_CLEAR_DATA)を行います。スタート後の実行中、スレッドは周期ごとに1件のDA出力を行います。出力するデータは、ID_SET_DATAにてセットされます。 LinuxプロセスからRTLinuxスレッドへの指示は、ハンドラ(my_handler)を経由して行われます。このサンプルのハンドラは、Linuxプロセスからの指示を、そのまま横流しする単純なものです。 以降では、処理順にこれらの処理を眺めてみましょう。 (173~179行目:RT-FIFOおよびハンドラの生成と初期化) 173~179行目では、RTLinuxモジュールおよびLinuxプロセスで使用するRT-FIFOおよび、Linuxプロセスからの指示を受け取るハンドラを生成しています。 次に、DA製品の制御を開始するために、182行目のDaOpenEx関数を使ってオープンしています。ここで取得するデバイス番号は、他の関数で共通して使われるため、グローバル変数g_device_noに格納されています。 (195行目:DaSetOutputDAEx関数) 『22ページ 3.3 1件のDA出力を行う』では、1件のDA出力を行うために、DaOutputDA関数を使用していました。 ここでは、設定を行うDaSetOutputDAEx関数と、DA出力のみを行うDaOutputDAEx関数のペアを使用しています。

★何故、DaSetOutputDAEx関数を使うのか? DaSetOutputDAEx関数と DaOutputDAEx関数の組み合わせは、DaOutputDA関数と、ほぼ同じ処理内容です。 これは、アナログ出力更新実行時の、1 件の DA 出力の処理負荷を少しでも減らすために用意されています。 つまり、DaSetOutputDAEx関数で、1件の DA出力の処理を行う際に必要な前処理を行い、DaOutputDAEx関数の呼び出しでは、DA出力の処理のみを行うようデザインされています。

(205~208行目:アナログ出力更新用データの初期化) 205~208行目の、make_sampling_data関数は、アナログ出力更新用データの初期化を行うサブルーチンを、順次呼び出しています。 サブルーチン本体は、112~160行目にあります。処理内容を以下に示します。

項 目 内 容 サイン波データ サイン波データを作成します。

データは、da_sin_wave_data配列に格納されます。 三角波データ 三角波データを作成します。

データは、da_triangle_wave_data配列に格納されます。 のこぎり波データ のこぎり波データを作成します。

データは、da_teeth_saw_wave_data配列に格納されます。 矩形波データ 矩形波データを作成します。

データは、da_rectangle_wave_data配列に格納されます。

Page 44: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 42 -

(211行目:pthread_create関数) pthread_create関数では、アナログ出力更新等の処理を実行する、RTLinuxスレッド(my_task)を生成しています。 (99~107行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

(34~86行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この34~86行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、データのセット,クリア,アナログ出力更新の開始と停止を行い(43~69行の処理)、配列からデータを取り出して(73行目)、周期実行ごとに1件のDA出力を行っています(76行目のDaOutputDAEx関数)。

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

ID_START smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し、自身の実行周期の間隔を指定しています。

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

ID_SET_DATA アナログ出力更新を行うデータ配列に対して、前ページで作成したデータ配列を、data_kindで指定された種類に従って設定します。(59~66行目)

ID_CLEAR_DATA アナログ出力更新を行うデータ配列をクリアします。

1件のDA出力を行う際に使用するデータ配列は、15行目のda_data配列変数です。 データ配列からの取り出しは、73行目のDA_PTR関数マクロから取り出したポインタにより求めています。

Page 45: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 43 - Interface Corporation

データ配列のフォーマットは、以下のようになっており、これは、DAドライバモジュールがアナログ出力更新用に定義するデータバッファのフォーマットと同一です。

CH1データ

CH2データ

CH1データ

CH2データ

CH1データ

CH2データ

CH1データ

CH2データ

CH1データ

CH2データ

1件目のデータ

2件目のデータ

3件目のデータ

4件目のデータ

5件目のデータ

データ配列の先頭

DA_PTR関数マクロは、sample2.hの22行目で定義しています。これは、以下の引数を与えることで、

データ配列に対する参照(ポインタ)を求められます。 第1引数 データ配列の先頭ポインタ。 第2引数 データ配列にアクセスする件数の指定。 第3引数 データ配列にアクセスするチャンネル番号の指定。

こうすることで、同じようなコードを記述する無駄を省いています。 周期実行の間隔は、smp_period_msの値により決定されます。 例えばここで5の値が指定されると、10msごとに1件のDA出力が行われます。これは周波数に換算すると、1(sec) ÷ 10(ms) = 100Hzです。

4.2.3 Linuxプロセスの動き

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

main コマンド指令 RTLinux

モジュール

RT-FIFO(FIFO_COMMAND)

Linuxプロセスは、RT-FIFOをオープンし、コマンド指令に使用しています。

Page 46: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 44 -

以降では、処理順に、これらの処理を眺めてみましょう。 (54~58行目:RT-FIFOのオープン処理) ここでは、open関数を使用し、RTLinuxモジュールに指令を送るRT-FIFOをオープンしています。 (61~102行目:選択メニューと呼び出し処理) ここでは、RTLinuxモジュールに対する指示内容を選択するメニューの表示と(62~70行目)、選択項目に従ってRT-FIFO経由でRTLinuxモジュールに指示(77~101行目)しています。 4番の「set output data」を選択すると、select_wave_type関数(16~43行目)が呼ばれます。ここでは、データ配列にセットする波形の選択を行っています。 (105~109行目:アナログ出力更新の停止) ここでは、RTLinuxモジュールに対して、アナログ出力更新を停止させるため、CMD_STRUCT構造体に、サンプリング停止を意味するID_STOP列挙定数を指定し、write関数を使ってRT-FIFOで指示を送っています。 RTLinuxモジュールは、この指示を受け取った後、実行を停止します。

Page 47: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 45 - Interface Corporation

4.3 DaStartSamplingを使ったアナログ出力更新

先程、DaOutputDAEx関数を使って、アナログ出力更新を実現しました。 実は、同じサンプリングだけを行うなら、DaStartSampling関数を使う方が、簡単に処理を実現できます。 ここでは、DaStartSampling関数を使い、永続的なサンプリングを実現します。

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

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

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

sample3.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

/* sample3.h 共通定義ヘッダファイル Copyright 2002 Interface Corporation. All rights reserved. */ #if !defined(___SAMPLE3_H) #define ___SAMPLE3_H #include "fbida.h" /* Constants --------------------------------------------------------------- */ #define FIFO_COMMAND 1 /* Linuxプロセスから指令を受け取るRT-FIFO */ #define FIFO_THRU_CMD 2 /* ハンドラからRTLinuxスレッドへ指令を受け渡しするRT-FIFO */ #define DEVICE_ID 3329 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define SUB_SYSTEM_ID 0x0001 /* 製品を特定する一意のID値(PCI-3329を表す) */ #define RSW_NO 0 /* 同一型式の製品を区別するRSW1設定値 */ #define CH_NUM 2 /* 1件のDA出力の総チャンネル数 */ #define SMP_NUM 100 /* DA出力のサンプリング件数 */ #define BUFF_SIZE 1000 /* ドライバが使用する内部バッファの大きさ */ /* DAデータ配列にアクセスする関数マクロ */ #define DA_PTR(ptr, num, ch) ((ptr) + (CH_NUM * (num)) + (ch)) typedef unsigned short DA_TYPE; /* DAデータの型 */ #define MAX_DATA 0xfffU /* DAデータの最大値 */ #define MIN_DATA 0x000U /* DAデータの最小値 */ #define MID_DATA ((MAX_DATA + MIN_DATA) / 2) /* DAデータの中間値 */ #define PI (3.1415926) /* パイの値 */ /* Command ID -------------------------------------------------------------- */ /* コマンドID群(周期制御&監視用スレッドへの指示用) */ enum CMD_IDS { ID_START, /* アナログ出力更新のスタート指示 */ ID_STOP, /* アナログ出力更新のストップ指示 */ ID_CLEAR_DATA, /* アナログ出力更新データのクリア */ ID_SET_DATA /* アナログ出力更新データのセット */ }; /* アナログ出力更新用データID群(使用するデータの指定用) */ enum DATA_KIND_IDS { ID_SIN_WAVE_DATA, /* サイン波データ */ ID_TRIANGLE_WAVE_DATA, /* 三角波データ */ ID_TEETH_SAW_WAVE_DATA, /* のこぎり波データ */ ID_RECTANGLE_WAVE_DATA /* 矩形波データ */ };

Page 48: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 46 -

48 49 50 51 52 53 54 55 56 57 58 59

/* コマンド指示用の構造体 */ struct CMD_STRUCT { enum CMD_IDS id; /* コマンドID */ /* 各コマンドに対する設定パラメータ */ union { long smp_period_ms; /* ID_START時使用:周期監視の設定(ms単位) */ enum DATA_KIND_IDS data_kind; /* ID_SET_DATA時使用:データの設定 */ } opt; }; #endif

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

module3.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

/* module3.c RTLinuxモジュールのソースコード Copyright 2002 Interface Corporation. All rights reserved. */ #include <rtl.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include <math.h> #include "sample3.h" pthread_t my_task_info; int g_device_no = -1; /* DA製品のデバイス番号 */ DA_TYPE inner_da_buff[CH_NUM * BUFF_SIZE]; /* ドライバ内部が使用するバッファ */ DA_TYPE da_data[CH_NUM * SMP_NUM]; /* アナログ出力更新を行うバッファ */ DA_TYPE da_sin_wave_data[CH_NUM * SMP_NUM]; /* 参照用:サイン波データ */ DA_TYPE da_triangle_wave_data[CH_NUM * SMP_NUM]; /* 参照用:三角波データ */ DA_TYPE da_teeth_saw_wave_data[CH_NUM * SMP_NUM];/* 参照用:のこぎり波データ */ DA_TYPE da_rectangle_wave_data[CH_NUM * SMP_NUM];/* 参照用:矩形波データ */ /* アナログ出力更新時のイベント発生時に呼ばれるコールバック関数 */ void my_smp_callback(int user_arg) { rtl_printf("my_smp_callback called user_arg=%d¥n", user_arg); } /* 状態監視および制御を行うRTLinuxスレッド */ void* my_task(void* arg) { int ret; struct CMD_STRUCT cmd; DA_TYPE* p_src_data = NULL; unsigned long smp_stat, smp_count, avail_count, avail_repeat; 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: start output!!¥n"); /* アナログ出力更新の開始 */ ret = DaStartSampling(g_device_no, FLAG_ASYNC); if(ret){ rtl_printf("DaStartSampling error [ret=%x]¥n", ret); }

Page 49: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 47 - Interface Corporation

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 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

pthread_make_periodic_np(pthread_self(), gethrtime(), cmd.opt.smp_period_ms * 1000 * 1000); break; case ID_STOP: /* アナログ出力更新のストップ */ rtl_printf("my_task: stop output!!¥n"); /* アナログ出力更新の停止 */ ret = DaStopSampling(g_device_no); if(ret){ rtl_printf("DaStopSampling error [ret=%x]¥n", ret); } pthread_suspend_np(pthread_self()); break; case ID_CLEAR_DATA: /* アナログ出力更新用データのクリア */ rtl_printf("my_task: clear output data!!¥n"); /* バッファのクリア */ ret = DaClearSamplingData(g_device_no); if(ret){ rtl_printf("DaClearSamplingData error [ret=%x]¥n", ret); } break; case ID_SET_DATA: /* アナログ出力更新用データのセット */ rtl_printf("my_task: set output data!!¥n"); switch(cmd.opt.data_kind){ case ID_SIN_WAVE_DATA: p_src_data = da_sin_wave_data; break; case ID_TRIANGLE_WAVE_DATA: p_src_data = da_triangle_wave_data; break; case ID_TEETH_SAW_WAVE_DATA: p_src_data = da_teeth_saw_wave_data; break; case ID_RECTANGLE_WAVE_DATA: p_src_data = da_rectangle_wave_data; break; default: rtl_printf("unknown data_kind!!¥n"); break; } /* バッファのセット */ ret = DaSetSamplingData(g_device_no, p_src_data, SMP_NUM); if(ret){ rtl_printf("DaSetSamplingData error [ret=%x]¥n", ret); } break; default: rtl_printf("unknown id!!¥n"); break; } } /* アナログ出力更新の状態を取得する */ ret = DaGetStatus(g_device_no, &smp_stat, &smp_count, &avail_count, &avail_repeat); if(ret){ rtl_printf("DaGetStatus error [ret=%d]¥n", ret); } rtl_printf("my_task: smp_stat:%ld smp_count:%ld avail_count:%ld avail_repeat:%ld¥n", smp_stat, smp_count, avail_count, avail_repeat); } 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; }

Page 50: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 48 -

133 134 135 136 137 138 139 140 141 142 143 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

/* アナログ出力更新用データ生成の下請け関数 */ void make_sampling_data(DA_TYPE* dst_data, enum DATA_KIND_IDS id, int max_num) { int ch, num; rtl_printf("make_sampling data called dst_data=%p id=%d max_num=%d¥n", dst_data, id, max_num); switch(id){ case ID_SIN_WAVE_DATA: /* サイン波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ *DA_PTR(dst_data, num, ch) = MID_DATA * sin(num * 2 * PI / max_num) + MID_DATA; } } break; case ID_TRIANGLE_WAVE_DATA: /* 三角波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ if(num <= (max_num / 2)){ *DA_PTR(dst_data, num, ch) = (num * MAX_DATA / (max_num / 2)); } else { *DA_PTR(dst_data, num, ch) = MAX_DATA - (num * MAX_DATA / (max_num / 2)); } } } break; case ID_TEETH_SAW_WAVE_DATA: /* のこぎり波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ *DA_PTR(dst_data, num, ch) = (num * MAX_DATA / max_num); } } break; case ID_RECTANGLE_WAVE_DATA: /* 矩形波データの作成 */ for(num = 0; num < max_num; num++){ for(ch = 0; ch < CH_NUM; ch++){ if(num <= (max_num / 2)){ *DA_PTR(dst_data, num, ch) = MAX_DATA; } else { *DA_PTR(dst_data, num, ch) = MIN_DATA; } } } break; default: rtl_printf("unknown id!!¥n"); break; } } /* 初期化関数(モジュールが組み込まれた時、呼ばれる関数) */ int init_module(void) { int i, ret; DASMPLREQ smp_req; /* アナログ出力更新の条件設定を行う構造体 */ 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)); /* DA製品のオープン */ ret = DaOpenEx(DEVICE_ID, SUB_SYSTEM_ID, RSW_NO, &g_device_no); if(ret){ rtl_printf("DaOpenEx error [ret=%x]¥n", ret); return -1; } else {

Page 51: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 49 - Interface Corporation

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

rtl_printf("DaOpenEx success!! [DeviceNo=%d]¥n", g_device_no); } /* イベント検出時のコールバック関数の登録 */ ret = DaSetBoardConfig(g_device_no, BUFF_SIZE, NULL, my_smp_callback, 0); if(ret){ DaClose(g_device_no); rtl_printf ("DaSetBoardConfig error [ret=%x]¥n", ret); return -2; } /* ドライバが使用する内部バッファ領域を指定する */ ret = DaSetBoardConfigEx(g_device_no, BUFF_SIZE, 0, inner_da_buff); if(ret){ DaClose(g_device_no); rtl_printf ("DaSetBoardConfigEx error [ret=%x]¥n", ret); return -3; } /* デフォルトのアナログ出力更新の条件設定を読み取る */ ret = DaGetSamplingConfig(g_device_no, &smp_req); if(ret){ DaClose(g_device_no); rtl_printf ("DaGetSamplingConfig error [ret=%d]¥n", ret); return -4; } /* アナログ出力更新の条件設定を変更 */ smp_req.ulChCount = CH_NUM;/* 1件のDA出力時の総チャンネル数の指定 */ smp_req.fSmplFreq = 100.0; /* アナログ出力更新の周波数の設定 */ smp_req.ulSmplRepeat = 0; /* アナログ出力更新の繰り返し回数を指定無しに設定 */ for(i = 0; i < CH_NUM; i++){ smp_req.SmplChReq[i].ulChNo = 1 + i; /* チャンネルを指定(1,2を順に指定しています) */ smp_req.SmplChReq[i].ulRange = DA_0_5V; /* レンジ:0~+5Vを指定 */ } /* 書き換えたアナログ出力更新の条件設定を設定する */ ret = DaSetSamplingConfig(g_device_no, &smp_req); if(ret){ DaClose(g_device_no); rtl_printf ("DaSetSamplingConfig error [ret=%d]¥n", ret); return -5; } /* 参照用データの作成 */ make_sampling_data(da_sin_wave_data, ID_SIN_WAVE_DATA, SMP_NUM); make_sampling_data(da_triangle_wave_data, ID_TRIANGLE_WAVE_DATA, SMP_NUM); make_sampling_data(da_teeth_saw_wave_data, ID_TEETH_SAW_WAVE_DATA, SMP_NUM); make_sampling_data(da_rectangle_wave_data, ID_RECTANGLE_WAVE_DATA, SMP_NUM); /* RTLinuxスレッドを作成、起動する */ return pthread_create(&my_task_info, NULL, (void*)my_task, 0); } /* 終了関数(モジュールが取り外される時、呼ばれる関数) */ void cleanup_module(void) { int ret; rtl_printf("cleanup_module called¥n"); /* DA製品をクローズする */ ret = DaClose(g_device_no); if(ret){ rtl_printf("DaClose 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); }

Page 52: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 50 -

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

sample3.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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

/* sample3.c Linuxプロセスのソースコード Copyright 2002 Interface Corporation. All rights reserved. */ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <sys/ioctl.h> #include <rtl_fifo.h> #include "sample3.h" /* set output data時の、選択メニュー */ enum DATA_KIND_IDS select_wave_type(void) { int cmd_data_no; while(1){ printf( "¥n ----- select a wave type -----" "¥n 1: sine wave" "¥n 2: triangle wave" "¥n 3: sawteeth wave" "¥n 4: rectangle wave" "¥n -------------------------------" "¥n enter a wave type number:"); cmd_data_no = 0; if(scanf("%d", &cmd_data_no) <= 0){ getchar(); continue; /* 読み取れない入力を読み捨てる */ } switch(cmd_data_no){ case 1: return ID_SIN_WAVE_DATA; case 2: return ID_TRIANGLE_WAVE_DATA; case 3: return ID_TEETH_SAW_WAVE_DATA; case 4: return ID_RECTANGLE_WAVE_DATA; default: printf("invalid command!!¥n"); continue; } } } /* Linuxプロセスのメインルーチン */ int main(void) { int cmd_no; int fd_cmd; struct CMD_STRUCT cmd; char rt_fifo_name[80]; /* RTLinuxモジュールに指令を送る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モジュールに対する指示(99を入力すると、ループを抜けます) */ while(1){ printf( "¥n ===== select a command number =====" "¥n 1: start output" "¥n 2: stop output" "¥n 3: clear output data" "¥n 4: set output data" "¥n --------------------------------" "¥n 99: exit program" "¥n ================================="

Page 53: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

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

"¥n enter a command number:"); cmd_no = 0; if(scanf("%d", &cmd_no) <= 0){ getchar(); continue; /* 読み取れない入力を読み捨てる */ } if(cmd_no == 99) break; /* 選択メニューから抜ける */ switch(cmd_no){ /* 選択メニューの処理 */ case 1: /* start output */ cmd.id = ID_START; cmd.opt.smp_period_ms = 100; /* 100ms周期の監視設定 */ break; case 2: /* stop output */ cmd.id = ID_STOP; break; case 3: /* clear output data */ cmd.id = ID_CLEAR_DATA; break; case 4: /* set output data */ cmd.id = ID_SET_DATA; cmd.opt.data_kind = select_wave_type(); /* セットする波形データの選択 */ break; default: printf("invalid command!!¥n"); continue; } /* 入力された命令の実行 */ if(write(fd_cmd, &cmd, sizeof(cmd)) < 0){ fprintf(stderr, "Failed to send the command.¥n"); return -1; } } /* アナログ出力更新のストップ指示(確実に止める) */ cmd.id = ID_STOP; 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; }

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

makefile 1 2 3 4 5 6 7 8 9 10 11

include /usr/include/rtlinux/rtl.mk all: module3.o sample3 sample3: sample3.c $(CC) $(INCLUDE) $(USER_CFLAGS) -O2 -Wall -o sample3 sample3.c temp.o: module3.c $(CC) $(INCLUDE) $(CFLAGS) -o temp.o -c module3.c module3.o: temp.o $(LD) -r -o module3.o temp.o /usr/lib/libm.a

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

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

Page 54: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 52 -

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

# ./sample3 ← Linuxプロセスを実行しています 実行すると、選択メニューが表示されます。 選択メニューと処理は、先の『27ページ 4.1 DaOutputDAExを使ったアナログ出力更新』と同じです。アナログ出力更新のスタート,ストップ,データのクリアとセットが選択できます。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:4

4を入力してEnterキーを押します。 すると、次のメニューが表示されます。 ここでは、セットするデータの波形タイプを選択します。 ----- select a wave type ----- 1: sine wave 2: triangle wave 3: sawteeth wave 4: rectangle wave ------------------------------- enter a wave type number:1

ここでは1を入力してEnterキーを押してください。 再び、最初の選択メニューが表示されます。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:1

ここでは1を入力してEnterキーを押してください。

Page 55: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 53 - Interface Corporation

すると、アナログ出力更新が始まります。下図は、アナログ出力更新している様子を、オシロス

コープを使って確認している画面例です。

sample3を終了するには、選択メニューが表示されている状態で、99を入力してEnterキーを押します。 ===== select a command number ===== 1: start output 2: stop output 3: clear output data 4: set output data -------------------------------- 99: exit program ================================= enter a command number:99

各メニューの項目の動きについて、下表に示します。 項目名 内 容

1: start output アナログ出力更新を開始します。この項目を選択する前に、必ず1回「4: set output data」で出力するデータをセットしてください。

2: stop output アナログ出力更新を停止します。 3: clear output data アナログ出力更新するデータの内容をクリアします。

「4: set output data」でデータを2回以上セットする時、一旦クリアして、セットしてください。

4: set output data アナログ出力更新するデータの内容をセットします。 セットするデータの種類を、下表にて選択可能です。

「4: set output data」を選択すると、下表のメニューが表示されます。 ここでは、セットするデータの種類が設定可能です。

項目名 内 容 1: sine wave サイン波のデータをセットします。 2: triangle wave 三角波のデータをセットします。 3: sawteeth wave のこぎり波のデータをセットします。 4: rectangle wave 矩形波のデータをセットします。

Page 56: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 54 -

4.4 DaStartSamplingを使ったアナログ出力更新の解説

それでは、先程のプログラムの解説を行います。

DaStartSampling関数を使って、アナログ出力更新を行う処理の流れは、先のDaOutputDAExを使った

『36ページ 4.2 DaOutputDAExを使ったアナログ出力更新の解説』と比較すると良いです。

Linuxプロセスから見た、RTLinuxモジュールに対する処理の指示は、先のサンプルと同じです。

データ データ

Linuxプロセス

RTLinuxモジュール

データのセット アナログ出力更新の開始 アナログ出力更新の停止

アナログ出力更新

チャンネル 1

アナログ更新出力する

データの内容をセット

先のサンプルは、アナログ出力更新の開始を指示した時、アナログ出力を行っていたのは、RTLinux

スレッド内のDaOutputDAEx関数でした。

しかし、DaStartSampling関数では、アナログ出力の処理は、DAドライバモジュールが担当します。プ

ログラマは、DaStartSampling関数を呼び出すだけです。

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

main

init_module cleanup_module

my_task

my_handler

生成

生成

指令

指令の転送

破棄

破棄

カーネル空間

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

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

FIFO_THRU_CMD

my_smp_callback

コールバックコールバック生成

各々の生成関係は、『36ページ 4.2 DaOutputDAExを使ったアナログ出力更新の解説』とほぼ同じです。

相違点は、init_module関数から、DAドライバモジュール用のコールバック関数(my_smp_callback)が新

たに生成されている所だけです。

Page 57: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 55 - Interface Corporation

Linuxプロセスからの指示は、RT-FIFOを経由して、my_handler→my_taskの順に流れていきます。my_task

内の処理も、実際に呼び出すコードは異なりますが、処理される内容は、ほぼ同じです。

・DaStartSampling関数を呼び出し、アナログ出力更新を行う。 ・DaStopSampling関数を呼び出し、アナログ出力更新を停止させる。 ・DaStartSampling関数で出力するデータ配列の内容をセットする。 ・DaStartSampling関数で出力するデータ配列の内容をクリアする。

4.4.1 先のサンプルとの違い

先のサンプルと比較するとわかりますが、双方のコードは、非常に似通っています。 共通定義ファイル(sample2.hとsample3.h),Linuxプロセスのコード(sample2.cとsample3.c)は、コメント文等一部が異なるだけで、全く同じと言っても差し支えないでしょう。 また、RTLinuxモジュールのコード(module2.cとmodule3.c)は、実際の処理コードは異なる部分がありますが、基本的な構造が似通っていることがわかります。

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

サンプルでは、あまり見えていませんが、DAドライバモジュールは、内部で様々な仕事を行います。ここでは、アナログ出力更新を行う際のDAドライバモジュールの構造について、簡単に紹介します。 DaStartSampling関数等の、アナログ出力更新をDAドライバモジュールが行う場合、アナログ出力更新を行うために必要な内部データバッファ領域を、ユーザから提供します。(DaSetBoardConfigEx関数にて行います) ドライバモジュールは、得られたバッファ領域を使って、アナログ出力更新を行います。

DAドライバモジュール

内部データバッファ

アナログ出力更新

ロジック

データ取得

アナログ出力更新

内部データバッファの領域は、

ユーザが与える。

Page 58: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 56 -

DaSetSamplingData関数でデータをセットされると、内部データバッファの未使用領域にデータが追加

されます。例えば、1000件分の内部データバッファを確保しておき、最初に100件のデータをセット後、

次に200件のデータをセットしようとした時、内部データバッファは、合計300件のデータを内部にセ

ットした状態になります。

内部データバッファ

1000件分

最初にセットしたデータ

100件分2番目にセットしたデータ

200件分

300件分

アナログ出力更新は、セットされたデータ部分に対してのみ行われます。

従って、上図の例では、300件分のデータが、アナログ出力更新の対象となります。

データのセットを繰り返すと、内部データバッファが一杯になってしまいます。

DaClearSamplingData関数を使うと、内部データバッファ内の全てのデータを消去することができます。

4.4.3 RTLinuxモジュールの動き

ここでは、RTLinuxモジュール(module3.o)の動きに注目して見てみましょう。 RTLinuxモジュールでは、サンプリングを実現するために、init_module関数内で、幾つかリソースを生成しています。それを下表に示します。

項 目 内 容 RT-FIFO(FIFO_COMMAND) Linuxプロセスからの指示を受けるためのRT-FIFOです。指示は、ハ

ンドラmy_handlerに渡されます。 RT-FIFO(FIFO_THRU_CMD) ハンドラにて、Linuxプロセスから受け取った情報を、RTLinuxスレ

ッド(my_task)に渡すためのRT-FIFOです。 ハンドラ(my_handler) Linuxプロセスからの指示を受け取るための処理の入り口です。

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

RTLinuxスレッド(my_task) DAドライバモジュールに対して、アナログ出力更新のスタート, ストップ,データのセット,クリアを指示するRTLinuxスレッドです。

コールバック関数 (my_smp_callback)

DAドライバモジュールにてアナログ出力更新中に、何らかのイベント事象を検出すると呼び出されるコールバック関数です。

Page 59: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 57 - Interface Corporation

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

ハンドラ(my_handler)

RTLinuxスレッド(my_task)

FFO_COMMAND

FIFO_THRU_CMD

Linuxプロセス

ID_START ID_STOP

←周期呼び出し周期実行

DaGetStatus関数

コマンド指示

ID_CLEAR_DA

ID_SET_DATA

DAドライバモジュール

アナログ出力更新

『40ページ 4.2.2 RTLinuxモジュールの動き』の図と比較してみてください。

先のサンプルでは、アナログ出力更新の処理は、RTLinuxスレッド(my_task)にて行っていましたが、こ

のサンプルでは、DAドライバモジュール内で行われます。

実際のアナログ出力更新を行っているのは、DAドライバモジュールです。

このサンプルでは、トリガを指定せずにアナログ出力更新しているので、ストップ指令を送らない限

りサンプリングを続けるようになっています。

LinuxプロセスからRTLinuxスレッドへの指示は、ハンドラ(my_handler)を経由して行われます。このサ

ンプルのハンドラは、Linuxプロセスからの指示を、そのまま横流しする単純なものです。

以降では、処理順に、これらの処理を眺めてみましょう。

(195~201行目:RT-FIFOおよびハンドラの生成と初期化)

195~201行目では、RTLinuxモジュールおよびLinuxプロセスで使用するRT-FIFOおよび、Linuxプロセ

スからの指示を受け取るハンドラを生成しています。

次に、DA製品の制御を開始するために、204行目のDaOpenEx関数を使ってオープンしています。ここ

で取得するデバイス番号は、他の関数で共通して使われるため、グローバル変数g_device_noに格納さ

れています。

(213行目:コールバック関数の登録)

DaSetBoardConfig関数は、アナログ出力更新が完了したら、コールバックされる関数を登録しています。

登録すべきコールバック関数のプロトタイプ形式は、以下の通りです。 void CallbackFunc(int userArg);

Page 60: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 58 -

第4引数でコールバック関数の関数ポインタ(上の例では、CallbackFunc)を、第5引数でコールバック関数の第1引数のパラメータを渡します。 例えば、第5引数に123を渡すと、上の例ではuserArg変数に123が渡されます。 (220行目:内部データバッファの設定) DaSetBoardConfigEx関数は、ドライバが使用する内部データバッファを与えています。 第4引数で、内部データバッファのポインタ(inner_da_buff)を、第2引数でバッファのサイズ(BUFF_SIZE)を指定しています。

★DaSetBoardConfigExの引数と、内部バッファサイズの関係 DaSetBoardConfigEx関数の第 2引数は、内部データバッファのサイズを指定します。 サンプル中の、内部データバッファを確保している行と比較してみましょう。 ↓内部データバッファを確保している行。 15: DA_TYPE inner_da_buff[CH_NUM * BUFF_SIZE]; ↓DAドライバモジュールに、内部データバッファのサイズを指示している行。 220: ret = DaSetBoardConfigEx(g_device_no, BUFF_SIZE, 0, inner_da_buff); 第 2引数で指定するサイズは、データ件数にあたります。 内部データバッファの総バイト数ではありません。

(227~247行目:アナログ出力更新の条件設定) DaSetSamplingConfig関数は、アナログ出力更新の条件設定を行います。 どのチャンネルをアナログ出力するか,周波数はいくらで行うのか,リピート回数はいくらか、等の設定をここで行います。 サンプルでは、DaGetSamplingConfig関数にて、DAドライバモジュールが保持するデフォルトの条件設定パラメータを取得し、これに修正を加える形式を取っています。 デフォルトのパラメータは、DAドライバモジュールがオープン時に初期値として持っています。この値は、「その製品でアナログ出力更新できる、理想的と思われる値」がセットされています。 ここでは、デフォルト値に修正を加える形式にすることで、アナログ出力更新の条件の諸設定を

簡易にしています。 (250~253行目:アナログ出力更新用データの初期化) 250~253行目の、make_sampling_data関数は、アナログ出力更新用データの初期化を行うサブルーチンを、順次呼び出しています。 サブルーチン本体は、134~182行目にあります。処理内容を以下に示します。

項 目 内 容 サイン波データ サイン波データを作成します。

データは、da_sin_wave_data配列に格納されます。 三角波データ 三角波データを作成します。

データは、da_triangle_wave_data配列に格納されます。 のこぎり波データ のこぎり波データを作成します。

データは、da_teeth_saw_wave_data配列に格納されます。 矩形波データ 矩形波データを作成します。

データは、da_rectangle_wave_data配列に格納されます。

Page 61: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 59 - Interface Corporation

(256行目:pthread_create関数) pthread_create関数では、アナログ出力更新等の処理を実行する、RTLinuxスレッド(my_task)を生成しています。 (121~129行目:ハンドラの処理) ハンドラ(my_handler)の役目は、LinuxプロセスからRT-FIFOを経由して送られる指示を、RTLinuxスレッド(my_task)に渡すことにあります。 この処理は、ほとんど定型的なものです。

RT-FIFO RT-FIFO

my_handler

ハンドラ

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

(39~108行目:RTLinuxスレッドの処理) RTLinuxスレッド(my_task)の処理の中心は、この39~108行のwhileループです。 ここで、Linuxプロセスから与えられた指示によって、データのセットとクリア、アナログ出力更新の開始と停止を行い(48~98行の処理)、アナログ出力更新の状態をチェック(102行目のDaGetStatus関数)しています。

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

ID_START 53行目のDaStartSampling関数で、DAドライバモジュールに対して、アナログ出力更新の開始を指示しています。 その後、 smp_period_msメンバ変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し、自身の実行周期の間隔を指定しています。 これは、アナログ出力更新の状態をチェックする間隔です。

ID_STOP 65行目のDaStopSampling関数で、DAドライバモジュールに対して、アナログ出力更新の停止を指示しています。 その後、pthread_suspend_np関数を呼び出し、自身のスレッドをスリープ状態にしています。

ID_SET_DATA アナログ出力更新を行うデータ配列に対して、前ページで作成したデータ配列を、data_kindで指定された種類に従って設定します。(83~95行目) DAドライバモジュールに対して、データのセットは、92行目のDaSetSamplingData関数にて行っています。

ID_CLEAR_DATA 76行目のDaClearSamplingData関数で、DAドライバモジュールに対して、 内部データバッファのクリアを指示しています。

Page 62: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 60 -

★DaStartSampling関数の同期/非同期指定について 53行目の DaStartSampling関数では、第 2引数に FLAG_ASYNCを指定しています。 これは、アナログ出力更新を非同期に行うよう指示するものです。この引数を指定して関数を呼び出すと、処理が完了するのを待たず、すぐ関数の呼び出しから戻ります。 FLAG_SYNCを指定すると、アナログ出力更新を同期で行うよう指示することになります。 100件のアナログ出力更新を行うよう指示していた場合、この関数の呼び出しから戻った時、100件のサンプリングが終了しています。 FLAG_ASYNC を指定した場合、アナログ出力更新が終了している保証はありませんので、DaGetStatus関数やコールバック関数を用いて、アナログ出力更新が終了したことを監視する必要があります。 サンプルでは、リピート回数(236行目の ulSmplRepeatメンバ変数)を 0として、永久にアナログ出力更新を繰り返すよう指示しているので、FLAG_SYNC を指定すると、関数の呼び出しから戻らず、永遠にアナログ出力更新を続けてしまいます。 従って、ここでは FLAG_ASYNCを指定しています。

(23~26行目:コールバック関数の処理) アナログ出力更新完了時、DAドライバモジュールは、このコールバック関数を呼び出します。 サンプルでは、特に何も処理をしていません。お客様がサンプルに処理を付け加える時、アナロ

グ出力更新終了時に、何らかの終了処理を加えたい時、このコールバック関数に処理を加えると

良いでしょう。

4.5 DaOutputDAExとDaStartSamplingのどちらを使うべきか

ここまで、DaOutputDAEx関数を用い、自分で作成した周期スレッドを使ってアナログ出力更新を行う例と、DaStartSampling関数を用い、DAドライバモジュールにアナログ出力更新処理をさせる例を見てきました。 実際に、アプリケーションを構築する場合、どちらの手法を用いるのがより良いのでしょうか? これは、使用するDA製品と、構築しようとするアプリケーションの用途により変化します。以下に、弊社が望ましいと考える例を挙げます。

DaOutputDAEx関数を使った方が良い場合 DaStartSampling関数を使った方が良い場合 ・1件のDAデータ出力ごとに、処理内容を変化させたい場合。 例えば、他のAD製品やカウンタ製品の値の変化により、アナログ出力の値を変化させたい場合。 ・この使用用途に適している製品は、I/O方式の

DA製品です。

・高速度のアナログ出力更新を行いたい場合。こちらの方が、より高速にアナログ出力更新を行うことができます。 また、アナログ出力更新のスタート,ストップにトリガを用いたい場合にも有効です。

・この使用用途に適している製品は、FIFO,メモリ方式等のDA製品です。

このように、用途に応じて、DAドライバモジュールの提供する関数を使いこなしてください。

Page 63: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 61 - Interface Corporation

第5章 デバッグ手法

これまでの章で、RTLinux上でのDA制御プログラミングはどのようなものかがお分かり頂けたと思います。この後、プログラミングを行っていく上で、避けては通れないデバッグをサポートす

る機能を説明します。 作成したプログラムは、DAドライバを使用した部分の処理と、DAドライバを使用しない部分の処理に分かれると思います。DAドライバを使用しない部分については、デバッグのやり方(rtl_printfの説明,gdbの使用方法等)をRTLinuxチュートリアル導入編に記載していますので、そちらをご参照ください。 ここでは、RTLinux DAドライバを使用した部分の処理について、デバッグ手法を紹介していきます。

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

GPG-3300のドライバには、デバッグ情報を出力するデバッグ支援機能がついています。ドライバ組み込み時、rcp3300_debuglevelパラメータにデバッグレベルを指定することでドライバデバッグ情報が出力されます。 デバッグレベルは以下の5段階があります。

デバッグレベル 機 能

0 デバッグ情報を出力しません 1 関数呼び出しトレース 2 エラー情報 4 製品リソース情報 16 アナログ出力データ情報

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

機能を使用しないようにしてください。 ★デバッグ情報を複数出力する デバッグレベルの値の算術和を取った値を指定することで、複数のデバッグレベルを使用できます。 例)関数呼び出しトレースとエラー情報を出力する場合(‘=’の前後にスペースは要りません) #insmod rcp3300.o rcp3300_debuglevel=3

Page 64: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 62 -

5.1.1 関数呼び出しトレース

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

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

ログラムを動かしてみましょう。 関数呼び出しトレースを指定して、ドライバを組み込みます。 (‘=’の前後にスペースは要りません) #insmod rcp3300.o rcp3300_debuglevel=1

次に製品の初期化,1件のDA出力,終了処理を行うモジュール(「sample1.c」で作成したsample1.o)を組み込んでみます。 #insmod sample1.o

現段階では、DaOpenEx関数と、DaOutputDA関数が呼び出されているはずです。 それでは、ログを確認してみましょう。 #less /var/log/messages … May 24 12:56:41 localhost kernel: init_module called May 24 12:56:41 localhost kernel: rcp3300:DaOpenEx(0xd01, 0x1, 0x0, [0xc6cb3264]) May 24 12:56:41 localhost kernel: DaOpenEx success!! [DeviceNo=1] May 24 12:56:41 localhost kernel: rcp3300:DaOutputDa(1, 0x2, [0xc3485efc], [0xc3485ef8]) (END)

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

ログを見てみます。DaClose関数が呼び出されていることが分かります。 #less /var/log/messages … May 24 12:58:50 localhost kernel: cleanup_module called May 24 12:58:50 localhost kernel: rcp3300:DaClose(1) (END)

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

Page 65: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 63 - Interface Corporation

5.1.2 エラー情報

エラー情報を出力するように設定しておくと、関数のエラーコードよりも詳細なエラー情報を出

力します。 では、エラー情報出力を指定してドライバを組み込みます。 #insmod rcp3300.o rcp3300_debuglevel=2

「sample1.c」の33行目を以下のように修正してください。

sample1.c修正 33 33

smp_ch_req[i].ulChNo = 1 + i; ↓ smp_ch_req[i].ulChNo = 1;

コンパイルしてモジュールを組み込んでください。 #make #insmod sample1.o sample1.o: init_module: Operation not permitted

エラーが出てドライバモジュールを組み込むことができません。 それでは、ログを見てみましょう。 #less /var/log/messages Feb 25 16:30:25 localhost kernel: rcp3300:error:DaOutputDA: ulChNo parameter error

最後の行には、プログラム中で記述した部分が表示され、エラーコードより、引数パラメータの

値が不正であることがわかります。さらに、その上の行を見ると、ulChNo parameter errorという文字が残されているため、ulChNoメンバ変数のパラメータ指定が間違っていることが分かります。

5.1.3 製品リソース情報

製品のリソースが正常かどうかを見ることにより、ソフトウェアが原因かハードウェアが原因か

を知ることができます。 では、製品リソース情報を出力するようにしてみましょう。 #insmod rcp3300.o rcp3300_debuglevel=4

製品リソース情報は、ドライバを組み込んだ時点で出力されます。 ではログを見てみましょう。 #less /var/log/messages May 24 13:12:32 localhost kernel: rcp3300:install device: May 24 13:12:32 localhost kernel: rcp3300: DeviceNo.1: DeviceID=3329, SubSystemID=0x1, RevisionID=0x1, RSW1=0x0 May 24 13:12:32 localhost kernel: rcp3300: I/O address0=0xd000, I/O address1=0xffff, Memory address=0xffffffff, irq=7

Page 66: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 64 -

拡張スロットに実装されているrcp3300が対応しているPCI製品のリソースが表示されます。

項 目 内 容 DeviceNo デバイス番号 DeviceID デバイスID SubsystemID サブシステムID RevisionID リビジョンID RSW1 製品識別用ロータリスイッチ(RSW1) I/O address0 I/Oポートアドレス I/O address1 I/Oポートアドレス Memory address メモリアドレス irq 割り込み番号

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

5.1.4 アナログ出力データ情報

製品からアナログ出力を行う度に、出力しているデータの値を確認することができます。では、

アナログ出力データ情報を指定してドライバを組み込みます。 #insmod rcp3300.o rcp3300_debuglevel=16

sample1.oを組み込みます。 #insmod sample1.o

それではログを見てみましょう。 #less /var/log/messages … May 24 13:18:09 localhost kernel: init_module called May 24 13:18:09 localhost kernel: DaOpenEx success!! [DeviceNo=1] May 24 13:18:09 localhost kernel: rcp3300:DaOutputDa : DaData[0]=0xfff May 24 13:18:09 localhost kernel: rcp3300:DaOutputDa : DaData[1]=0xfff

1件のDA出力時の内容が表示されています。

Page 67: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 65 - Interface Corporation

第6章 リファレンス

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

6.1 関数一覧 No. 区 分 関数名 機 能 1 DaOpen 初期化 2 DaOpenEx 初期化(推奨) 3 DaClose 終了 4

初期化終了

DaCloseEx 終了時、現在のアナログ出力の値を保持 5 仕様取得 DaGetDeviceInfo DA製品仕様の取得 6 DaSetBoardConfig コールバック関数の設定 7

イベントコール バック DaGetBoardConfig イベントコールバックの発生要因取得

8 DaSetBoardConfigEx アナログ出力更新用内部データバッファの設定 9 DaGetBoardConfigEx アナログ出力更新用内部データバッファの情報取得 10 DaSetSamplingConfig アナログ出力更新条件の設定 11 DaGetSamplingConfig 現在のアナログ出力更新条件の取得 12 DaSetMode DA製品固有の動作モードの設定 13 DaGetMode DA製品固有の動作モードの取得 14 DaSetSamplingData アナログ出力更新用データのセット 15 DaClearSamplingData アナログ出力更新用 内部データバッファのクリア 16 DaStartSampling アナログ出力更新の開始 17 DaSyncSampling 複数枚同期アナログ出力機能を使用したアナログ出力

更新の開始 18 DaStopSampling アナログ出力更新の停止 19 DaGetStatus アナログ出力更新動作状態の取得 20 DaSetOutputMode PCI/CTP-3329,3338の同時出力機能設定 21

アナログ 出力更新

DaGetOutputMode PCI/CTP-3329,3338の同時出力機能設定の取得 22 DaOutputDA 1件のDA出力 23 DaSetOutputDAEx 1件のDA出力の設定 24

1件のDA出力

DaOutputDAEx 1件のDA出力(DaSetOutputDAExと併用) 25 DaInputDI デジタル入力端子の読み出し 26

入出力 DaOutputDO デジタル出力端子の出力

27 DaSetFifoConfig FIFO方式のアナログ出力更新設定の設定 28 DaGetFifoConfig FIFO方式のアナログ出力更新設定の取得 29 DaSetInterval インターバルタイマの設定 30 DaGetInterval インターバルタイマの設定取得 31 DaSetFunction PCI-3525のCN3の機能設定 32 DaGetFunction PCI-3525のCN3の機能設定の取得 33 fnConv DaDataConv関数で使用するコールバック関数の

ブレースホルダー 34

その他

CallBackProc アナログ出力更新終了時に呼び出されるコールバック関数のブレースホルダー

35 データ変換 DaDataConv アナログデータの形式変換

Page 68: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 66 -

6.2 戻り値一覧 エラー識別子 値 意 味 対処方法

DA_ERROR_SUCCESS 0 正常終了 DA_ERROR_NOT_DEVICE C0000001h ドライバが呼び出せ

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

DA_ERROR_NOT_OPEN C0000002h ドライバがオープンできません

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

DA_ERROR_INVALID_ DEVICE_NUMBER

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

不正なデバイス番号で呼び出しを行おうとしました。オープン関数で返されたデバイス番号を使用してください。

DA_ERROR_ALREADY_ OPEN

C0000004h 既にオープンされているデバイスです。

既にオープンされているデバイスをオープンしようとしました。

DA_ERROR_NOT_ SUPPORTED

C0000009h 製品がサポートしていない関数です。

製品がサポートしていない関数を使用しようとしています。

DA_ERROR_NOW_ SAMPLING

C0001001h アナログ出力更新中です。

指定件数のアナログ出力更新が完了する前に再度、アナログ出力更新を開始を実行しようとしました。 指定件数のアナログ出力更新中に実行できない関数を呼び出そうとしました。

DA_ERROR_STOP_ SAMPLING

C0001002h アナログ出力更新は停止中しています。

アナログ出力更新停止中に実行できない関数を呼び出そうとしました。

DA_ERROR_START_ SAMPLING

C0001003h アナログ出力更新を開始できませんでした。

アナログ出力バッファにまだアナログ出力データがセットされていないため、アナログ出力を行うことができませんでした。

DA_ERROR_INVALID_ PARAMETER

C0001021h パラメータが不正です。

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

DA_ERROR_ILLEGAL_ PARAMETER

C0001022h アナログ出力設定が正しくありません。

アナログ出力設定値が正しくありません。 アナログ出力設定に矛盾があります。

DA_ERROR_NULL_POINTER C0001023h NULLポインタを指定しました。

アナログ出力データ領域の指定にNULLを指定しました。 データ変換APIにおいて、データ変換元となるデータへのポインタがNULLで指定された。 変換後のデータを返すためのポインタがNULLで指定された。

DA_ERROR_SET_DATA C0001024h アナログ出力データのセットができません。

既にセットされているアナログ出力データとの連結後のデータ長がバッファの最大長を越えているため、データのセットを行うことができませんでした。

DA_ERROR_USED_AD C0001025h ADドライバで使用中です。

AD側で使用中の機能を停止してから、関数を実行しなおしてください。

Page 69: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 67 - Interface Corporation

エラー識別子 値 意 味 対処方法

DA_ERROR_INVALID_DATA_FORMAT

C0001061h データ形式が無効です。 指定するデータ形式をご確認ください。

DA_ERROR_INVALID_AVERAGE_OR_SMOOTHING

C0001062h 平均またはスムージングの指定が正しくありません。

平均またはスムージングの回数が、0またはデータ件数を越えている。 平均またはスムージングの件数が0で指定された。

DA_ERROE_INVALID_SOURCE_DATA

C0001003h データ変換元として指定されたデータが正しくありません。

データ変換元のアドレス指定箇所等に間違いがないか確認してください。

DA_ERROR_NOT_ALLOCATE_MEMORY

C0001081h メモリが確保できません。 ドライバ内部で作業するためのメモリの確保に失敗しました。 メモリを増やすことが必要です。

Page 70: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

Interface Corporation - 68 -

技術資料紹介 弊社では下記の技術資料を提供しております。 詳しくは、弊社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 71: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040

- 69 - Interface Corporation

参考文献

著 者 題 名 森 友一郎,薬師 輝久, 馬場 秀忠

RTLinuxリアルタイム処理プログラミングハンドブック(株式会社秀和システム:2000年)

警告!

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

す。

Page 72: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

TUT-0040 2007年 6月 Ver. 1.5 発行 発行所

〒732-0828 広島県広島市南区京橋町10-21 TEL 082-262-7777 FAX 082-262-5066

定価 ¥2,000

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

Page 73: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

www.interface.co.jp

サポート体制

本製品についてのお問い合わせは、カスタマーサポートセンタで承ります。弊社Web siteのオ

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

利用ください。 お問い合わせ先 <カスタマーサポートセンタ> TEL 0120-447213 FAX 0120-458257 (祝日および弊社休業日を除く月~金 AM9:00~PM5:00迄) E-mail [email protected]

TUT-0040 Ver. 1.5 Vol. 1/1

Page 74: チュートリアルenomoto/kgrsr/hardware/data/tut...TUT-0040 Interface Corporation - 6 - 対象環境 本チュートリアルは以下の制約事項があります。 対象型式

www.interface.co.jp

RTLinuxによるDAボード制御プログラミング チュートリアル TUT-0040 Ver. 1.5