情報工学実験3 デバイス制御実験




目標:

デバイスドライバを作成してコンピュータに接続されたデバイスを制御するという実験を通じ、組み込み機器開発の基礎を学ぶ。


評価方法:

レポート点(100 点)


注意点:

ソースコードのコピペが発覚した場合はコピーをさせた側の点数を0 点とし、コピーした側はお咎め無しとする (理由はHP 参照)


演習内容:

(一週目) デバイスドライバの作成

(システム構成)

これまでスイッチを手動で切り替えることでレジスタの値を直接変更してデバイスを制御する実験は行なってきたが、 実際にコンピュータからデバイスを制御するためにはデバイスドライバを作成する必要がある。

そこで1週目は、ターゲットPCのシリアルインターフェース(RS232C)に接続された電子オルゴールのドライバを ホストPC上で作成し、ドライバをターゲットPCに転送し、ターゲットPC上でドライバをカーネルにインストールしてデバイスを動作させるという実験を行う。

今回使用するシステムの構成は以下の通りである。

制御対象デバイス:  電子オルゴール ( electronic music box )
ターゲットPC:  debian Linux 5 ( カーネル 2.6.26-2-686 )
ホストPC:  Windows XP + TeraTerm

ホストPCとターゲットPCはUSB-シリアル(RS-232C)変換クロスケーブルで接続されている。電子オルゴールはターゲットPCのシリアルインターフェース(RS232C)につながっている。

(電子オルゴール仕様)

ターゲットPCのシリアルインターフェース(RS-232C)の DTRピン( Dサブ9ピンの4番ピン) に電子オルゴール回路が接続されている。 したがってRTSピン を H にすれば音楽が再生され、Lにすれば停止する。

なお、シリアルインターフェースの詳細については今後行なわれるシリアルインターフェースに関する実験中に学ぶので今回は割愛する。

使用するデバイスの回路図を以下に示す。



(手順 1) UART(Universal Asynchronous Receiver Transmitter)とは パソコンや組み込み機器などで使われるシリアル回路のことで、PC/AT互換機 では16550 互換チップと呼ばれるチップが広く使われている (参考までに、この後の実験で行なわれるシリアルインターフェースに関する実験では8251Aというチップを用いる。)

ターゲットPCにインストールされたOS(Debian Linux)がどのようにシリアルインターフェースを認識しているかは次の様にデバイスのログを見て確認することが出来る。

$ dmesg


チェック[1] 教員がプロジェクタに映したdmesgコマンドの結果を見てOSが実際にUARTをどのように認識しているか確認し、手書きで記録した。


(手順 2) デバイスドライバはIOポートを経由してデバイス上にあるレジスタにデータを読み書きすることでデバイスを制御する。 OSによってデバイスごとに別々にIOボートのアドレスが割り当てられており、IOボートへの読み書きは通常のメモリへの読み書きと同様に行なわれる (なお、現在はIOポート経由でデバイスを制御する方法は若干古い方法となっており、 メモリマップドIO ( MMIO ) 方式と呼ばれる制御方式が主流となっている。詳しくは OS の講義の時間に説明される。)

実際にどのようにIOポートのアドレスが割り当てられているか調べたい場合はターゲットPC上の /proc/ioports というファイルの内容を見る。

$ cat /proc/ioports

今回はシリアルインターフェース(16550)のレジスタの値を書き換えることで電子オルゴールの操作を行う。


チェック[2] 教員がプロジェクタに映した /proc/ioports を見てシリアルインターフェース(16550)のIOボートアドレスを確認し、手書きで記録した。


(手順 3) ドライバのソースが入っているアーカイバ(devmbox.zip)をホストPC上にダウンロードする。

ドライバソース (.zip)


(手順 4) devmbox.zip を解凍し、ソリューションをホストPC上のVC++で開く。あとはソースファイル(devmbox.c)内の記述に従ってドライバを作成する。

(注意)

・16550 はモデムコントロールレジスタ(MCR) という8bitレジスタを内部に持っていて、レジスタの0bit目がDTR制御ビットとなっている。
・DTR制御ビットに1をセットするとDTRピンがHになる。0をセットするとLになる。
・DTRピンにはオルゴール回路が接続されている。
・MCRは IOポートの 0x3fc 番地に割り当てられている。
・IOボートへの8bit単位でのデータの読み書きは以下の inb()、outb()関数を用いる。

unsigned char inb ( unsigned short int port );

void outb ( unsigned char value, unsigned short int port );

例えば現在のMCRのレジスタ内容を reg という非負8bit整数型変数に取得してそのままMCRに書き込むには次のようにする。

unsigned char reg = inb( MCR );
outb( reg, MCR );

以上を下の図にまとめる。


チェック[3] ソースコードを作成し、ホストPC上でエミュレーションを実行して正しく動作した。


(手順 5) ターゲットPCをホストPCにクロスケーブルで接続してログインする。

(1) クロスケーブルをホストPCのRS-232Cに接続する。

(2) ターゲットPCの端末上で次のコマンドを実行する。

# /sbin/getty -L ttyUSB0 57600 vt100

(3) ホストPC上でTeraTermを起動する。最初の接続ダイアログはキャンセルする。

(4) 設定メニュー→シリアルからボートをCOM1、レートを57600にしてOKを押し、エンターキーを押すとログインプロンプトが表示される。ユーザー名、パスワードは実験時に知らせる。

(5) もし文字化けしたらターゲットPC側のUSBケーブルを外してCtrl+cで(2)のコマンドを止め、ケーブルを差し直して認識するまで少し待ってから(2)のコマンドを再実行する。

(6) ログインしたら ls してファイルを確認する。


(手順 6) デバイスドライバのソース(devmbox.c)を転送する。

今回はzmodemというバイナリ転送プロトコルを用いてファイルを転送する。

まずドライバをビルドするディレクトリに移動してファイルを確認する。

$ cd device
$ ls

前の人が使ったファイルを消す。

$ make clean
$ rm devmbox.*
$ ls

zmodemのリシーバを起動する。

$ rz

次にホストPC上で動かしているTeraTermのファイル → 転送 → zmodem → 送信から devmbox.c を転送する。転送したら ls で確認すること。

※ ファイルを転送する時に同じ名前のファイルがあると上書きで転送されないので、rz を起動する前に rm で消しておくこと。


(手順 7) ドライバをビルドする。ビルドが成功するとデバイスドライバ( devmbox.ko )が出来上がる。

$ make
$ ls


※ 実際にはドライバはターゲットPC上でビルドせずに、ホストPC上でクロスコンパイルして作成し、ソースではなくてドライバのバイナリだけをターゲットPCに転送することが多い。


(手順 8) デバイスには通常はOSか管理者(root)で無ければアクセス出来ない。 よって一般ユーザは直接デバイスを制御できないので、一般ユーザがデバイスを制御するためには、 ユーザーとデバイス間の橋渡し役であるデバイスドライバをカーネルにインストールする必要がある。 一度ドライバをカーネルにインストールすればOSがユーザーの代わりにデバイスを制御してくれる。

ただし、root でなければドライバをカーネルにインストールすることが出来ない。そこでsu (スイッチ・ユーザー) コマンドで root になり、 insmod (インストール・モジュール)コマンドでビルドしたドライバをカーネルに組み込む。

組み込んだらexitで管理者モードから抜けてdmsegコマンドで正しくドライバがインストールされたか確認する。

(注意)
・ rootのパスワードは実験時に知らせる。
rootになってコマンドを間違えるとハードディスク全体が消えることもあるので慎重に作業を行なうこと。
・ 端末の記号が root になると # に変わることに着目せよ。

$ su
# ls
# insmod devmbox.ko
# exit
$ dmesg


(手順 9) 一般ユーザー権限からデバイススペシャルファイル( /dev/musicbox0 )に文字列を書き込んで動作確認する。 終わったら su で再びrootになって rmmod (リムーブ・モジュール)コマンドでドライバをアンインストールする。

(注意)
・ > はリダイレクトと呼び、echo で出力した文字をそのまま > の後のファイルに書き込むものである(3年の実験を思い出せ)
・一般ユーザはデバイスを直接制御できないが、ドライバへのアクセスはスペシャルファイルに文字を書き込むことで一般ユーザーでも可能なことに注意せよ。


$ ls /dev
$ echo '0' > /dev/musicbox0
$ echo '1' > /dev/musicbox0
$ su
# rmmod devmbox
# exit
$ dmesg


チェック[4] 動作確認した。


(手順 10) exit コマンドでログアウトする。



(2週目) ユーザーアプリケーションの作成

2週目は、ホストPC上でユーザーアプリケーションを作成し、それらをターゲットPCに転送し、ターゲットPC上で電子オルゴールを一般ユーザー権限で操作する。


(手順 1) アプリ本体のソースが入っているアーカイバ(musicbox.zip)をホストPC上にダウンロードする。

アプリケーションソース (.zip)


(手順 2) musicbox.zip を解凍し、ソリューションをホストPC上のVC++で開く。あとはソースファイル(musicbox.cpp)内の記述に従ってアプリケーションを作成する。

ここで先週ターゲットPC上で

$ echo '0' > /dev/musicbox0

のようにデバイススペシャルファイル( /dev/musicbox0 ) へ 文字 '0' を書き込んだら演奏開始したことを思い出せ。
従って通常のファイルへの書き込みのように、プログラム内で fopen()で /dev/musicbox0 を書き込みモードでオープンしてから fwrite()又は fprintf() で '0' という文字を1バイト書き込めば演奏が開始する。最後にfclose()でファイルを閉じるのを忘れないこと。


チェック[5] ソースコードを作成し、ホストPC上でエミュレーションを実行して正しく動作した。



(手順 3) 先週と同様にターゲットPCをホストPCに接続してログインする。

(手順 4) 先週と同様にソースコード(musicbox.cpp)をzmodemで転送する(他のファイルは転送しなくてよい)。

まず前の人が使ったファイルを消す。

$ rm a.out
$ rm musicbox.cpp
$ ls

次にターゲットPC上でzmodemのリシーバを起動する。

$ rz

次にTeraTermのファイル → 転送 → zmodem → 送信から musicbox.cpp を転送する。転送したら ls で確認すること。

(注意) ファイルを転送する時に同じ名前のファイルがあると上書きで転送されないので、rz を起動する前に rm で消しておく。


(手順 5) アプリをビルドする。ビルドが成功するとアプリ(a.out)が出来上がる。

$ g++ musicbox.cpp
$ ls


(手順 6) アプリケーションを実行する。

(注意)

・ ドライバは既に組み込んでおくので先週の様に root になる必要は無い。そのまま実行し、ユーザ権限でターゲットPC上のデバイスを操作出来たことを確認せよ。

$ ./a.out


チェック[6] 動作確認した。


(手順 7) exit コマンドでログアウトする。






(問題 1) デバイスドライバとは何であるか自分なりに理解した内容を30字以内にまとめよ。 なおレポート提出時にデバイスドライバとは何か尋ねる。


(問題 2) カーネルとは何であるか自分なりに理解した内容を30字以内にまとめよ。 なおレポート提出時にカーネルとは何か尋ねる。


(問題 3) 何故ドライバとアプリケーションを分けてプログラムする必要があるのか 「デバイス」、「OS」、「管理者」、「一般ユーザー」という言葉を使用して100字以内にまとめよ。 なおレポート提出時に何故か尋ねる。


(問題 4) チェック[1]のUARTについて記述した内容をワープロで清書して記述せよ。


(問題 5) チェック[2]のシリアルインターフェースのIOボートアドレスをワープロで清書して記述せよ。


(問題 6) ドライバのソースのうち、自分がコーディングした部分をレポートに示せ。


(問題 7) ユーザーアプリケーションのソースをレポートに示せ。