ウインドリバー 組込みとモバイルソフトウェアの世界的なリーダー
南角先生の組込み講座
ブックマーク/共有
ホーム : ウインドリバースクエア : 南角先生の組込み講座 : 第7回 デバイスドライバ
南角先生の組込み講座 南角 茂樹 大阪電気通信大学 准教授

第7回 デバイスドライバ

こんにちは。
まず最初に前回の問題の解を考えてみたいところですが、今回も分量が増えそうなので、分量が少ないであろう、次回最終回に回したいと思います。

さて、今回は、通常は組込みソフトウェアの中では最も難しいもののなかの一つとみなされ、おそらくみなさんが最も興味を持っているであろう、デバイスドライバに関する話題です。

デバイスとはペリフェラル、コントローラ、ドライバ、周辺、周辺チップあるいはチャンネルとよばれるCPUとは独立して動作できるもの ? CPUとは並列に実行できるものです。
そしてデバイスドライバには当然CPUとデバイスのやり取り、通信も含まれます。
基本的には速度の速いCPUが速度の遅いI/Oとのやり取りを直接実行する代わりに、CPUとは独立して実行できるデバイスにI/Oとのやり取りを依頼する、もちろん依頼しっぱなしではなく、処理終了時にはその結果を受け取らなければなりません。
当然デバイスとのやり取りは一種の通信であり、CPUとデバイスの同期をとるために割り込みの制御も必要です。そしてデータに関してもCPUとデバイスによる同じ領域へのアクセスが必然的に発生するため排他制御も必要です。
排他制御にしてもタスク間の排他制御ではなく、タスクと割り込み処理、あるいはOSと割り込み処理の排他制御が必要な場合もあり、RTOSを使用しているからと言って単純にセマフォが使えるわけでもありません。
またCPUとデバイスでは実行速度も異なりますが、そこにはたとえばEthernet通信などのフローコントロールのように規格化された手順があるわけではなく、使用するデバイスごとに固有の手順を用いて制御をおこなわなければなりません。
あるいは速度の差を吸収するために、リングバッファなどの方法を用いなければならないかも知れません。
これらすべての制御を一定の時間制約のもとで行わなければなりません。
これらの処理を行うソフトウェアがデバイスドライバであり、さまざまな要素が絡み合ってデバイスドライバの作成を難しいものにしています。
しかし組込みソフトウェアにおいてはデバイスも含めた最適化が必要であり、デバイスドライバの開発作成技術もが非常に重要となります。

図1に改めてCPUとデバイスの関係を示します。
ハードディスクコントローラやネットワークコントローラなどのデバイスは、CPUのように命令をデコードして動作することこそできませんが、デバイスの内蔵レジスタに書き込まれたビットパターンやアドレスデータなどにより、CPUとは独立して並列に動作を行うことが出来ます。
CPUはデバイスに指令のみを与えて、自分は別のことを実行しながら、デバイスが実行した結果を後で(適当なタイミングで)受け取ればよいことになります。
ただし、多くの場合最初にデバイスに対する要求を出すのはアプリケーション(タスク)です。そのためRTOSはタスクに対してもデバイスドライバを呼び出す仕組みを提供しなければなりません。

図1 CPUとデバイス

一般的にデバイスドライバは以下の二つの部分から構成されています。

  • アプリケーション(タスク)に提供され、タスクコンテキストで実行されるライブラリ
    I/Oが終了するまで待ち状態になる処理などもここに含まれます。
  • 対象とするデバイスからの割り込みに対応する割り込みハンドラ、割り込みサービスルーチン(ISR)、このISRの中でデバイス処理の終了後、待ち状態のタスクの起床処理なども行います。
    プロセスごとに独立したアドレス空間を持つような汎用OSの場合は、デバイスドライバ終了後OSに一旦制御が戻り、そこでデバイスからOS空間に生成されたデータを、改めてプロセス空間にコピーするなどの処理を行ったのち、プロセスに制御が戻る場合が多いのですが、そもそもアドレス空間が一意のRTOSの場合はデータのコピーも必要ではなく、デバイスドライバから直接タスクに制御が戻る場合が多いようです。 と言ってももちろんディスパッチャは経由します。RTOS環境で多くの処理を行わないという意味です。

図1にはデバイスからCPUへの通信手段として割り込み信号も示しています(バス経由の割り込み信号も、バスを経由しない割り込み信号もあります)。
デバイスがCPUから要求された処理を終了した時やCPUに対して新たな処理を要求する場合の手段と割り込みを使うことが最も一般的だからです。
もちろんポーリングやスピンロックを使う場合もありますが、最も一般的な割り込みを使う場合を説明します。
この割り込みに対応するために、デバイスドライバには割り込みハンドラや割り込みサービスルーチン(以後両者をまとめてISRと呼びます)も必要になります。

図2 アプリケーション(タスク)からの呼び出し

図2に示したものはアプリケーション(タスク)からのデバイスドライバの呼出し手順です。VxWorksは標準I/Oをサポートしているので、ほとんどのデバイスドライバの呼び出しは (create)、open、read、write、ioctl、close、(delete) で実行できます。
詳しい説明は省きますが、大部分のデバイスドライバの実行はread/write で実現できます。
ネットワークであるTCP socketからの呼び出しも、ハードディスクからの呼び出しもどちらもreadで実現できます。これは実際に使ってみると大変便利です。
I/Oを行うデバイスの変更を行う場合もopenの引数の変更のみで済む場合も多くなります。

図3 ライブラリ

図3はRTOSがアプリケーションに提供するデバイスドライバ呼び出しのための大枠を示したものです。このライブラリはタスクの実行環境で実行され、最終的にはデバイスドライバの実行が終わるまで待ちに入る場合が多いです。
待ち状態から復帰するのはデバイスドライバの処理が終了したか、あるいは何らかのエラーにより処理が中断した場合です。

図4 割り込みハンドラ(割り込みサービスルーチン)

図4がデバイスドライバの処理の大枠を示したものです。これはデバイスからの割り込みにより呼び出されます。たとえばデバイスの処理が終了した時の呼び出しではデバイスのレジスタにあるデータをRTOSやタスクの管理下にあるメモリにコピーしたりします。
デバイスドライバはデバイスによって異なりますし、処理を詳しく説明すると分量が大幅に増えてしまうので、ここではごく概要の説明だけにとどめます。
ひとつだけ注意しておきますが、待ち状態のタスクを実行可能状態に復帰させるのは、ISRだということです。そのためVxWorksではセマフォに対する操作のうちsemGiveは割り込みからも呼び出せるようになっています。一方待ちに入る可能性のあるsemTakeは呼び出せません。

個々の説明だけではイメージが掴みにくいと思うので、一例としてUARTデバイスのドライバの動きの概要を説明します。UARTデバイスも昔に比べるとバッファリングなど高度な機能を持つのが普通ですが、ここでは説明を単純化するためにごく単純な機能しか持たないUARTデバイスのドライバとして説明します。
図5をもとにデバイスドライバの動作について説明します。

図5 ドライバとRTOS

  1. デバイスは使用される前にopenしなければなりません。その処理を行います。openを行うことにより以後そのデバイスを特定するための識別子(通常ファイルディスクリプタfdと呼ばれます)が帰ってくるので、以後の操作にはそれを用いて操作対象のデバイスを指定します。
  2. アプリケーションのopenによって呼び出され、実際のデバイスの初期設定を行います。その他、デバイスを制御したりデータの保管などに必要な領域があればそれをメモリ上に確保します。図におけるリングバッファの作成などです。
  3. ファイルディスクリプタにより指定されたデバイスの動作(今回は読み込み)開始を指示します。
  4. デバイスレジスタの動作開始ビットをオンにするなどデバイスハードウェアの動作を開始します。
  5. その後ドライバの処理が終了するまでタスクは待ち状態となります。
  6. デバイスによって定まっている何らかの動作の終了による割り込みが発生します。この割り込みとそれに対応したISRの対応付けは(たとえば割り込みベクタの設定などはopen時あるいはそれより前のcreate時など)何らかの適切なタイミングで行っておきます。
  7. ISRではデバイスのデータをタスクとのインターフェース領域(この場合はリングバッファ)にコピーします。またすべてのデータを受け取った時、あるいは図では省略していますが、デバイスエラー発生時には終了処理を行います。終了処理とは、待ち状態のタスクを実行可能状態に戻したのち、スケジューラーに制御を移すなどの処理です。
  8. 優先度に応じいずれはタスクに制御が戻ってきます。
  9. ISRが作成したデータをタスクが用意した領域(ここではbuffer)にコピーします。
  10. 指定した領域にデータが用意された状態で、タスクが発行したreadから戻ってきます。

    以後タスクは読み込んだデータを使用すればよいことになります。

以上がデバイスドライバの動作の一例です。

並列動作がありわかりにくいと思うので説明は省略しますが、少し別の観点からデバイスドライバのread時の動作を図6として書いてみました。これも参考にしてみてください。
なお、この図に示した処理はあくまで一例であり、図に示した処理は最終データが来るまではISRが直接デバイスから次のデータを受け取るための処理を行い、スケジューラーを呼び出さないようになっていますが、ISRの最後に毎回スケジューラーを呼び出す場合のほうがむしろ一般的です。

図6 デバイスドライバの動作(read時)

最初に組込みシステムにおいてはデバイスなどのハードウェアも含めた最適化が必要であり、その処理内容もデバイスによって様々です。
しかしデバイスドライバが標準I/Oで隠ぺい化されていることは、アプリケーション(タスク)からは非常に使いやすく、また固有のデバイスのドライバこそ自作しなければなりませんが、VxWorksには多くのデバイスのドライバはあらかじめ用意されています。
また使用するデバイスのドライバが提供されていない場合も、似たデバイスがある場合も多く、その場合は提供されているデバイスドライバを参考にすることもできます。
また個々のデバイスドライバを標準I/O化するためのAPIやその他、デバイスドライバでも利用できるリングバッファやリストライブラリなども各種用意されており、デバイスドライバ作成を容易にするための工夫が随所に見られます。

この連載にも長い間お付き合いいただきましたが、次回は最終回です。
思いつくままにRTOSに対する希望などを書いてみたいと思います。

第7回おわり

■著者プロフィール

南角 茂樹(なんかく しげき)

大阪電気通信大学 総合情報学部 メディアコンピュータシステム学科 准教授、同大学院総合情報学研究科(コンピュータサイエンス専攻)、エイシップ・ソリューションズ株式会社 研究顧問。
慶應義塾大学工学部数理工学科卒業後、大手電機会社を経て現職。組み込みシステムおよびリアルタイムOSを専門とし、著書、解説記事、発表・講演、登録特許等多数。

南角先生の組込み講座 »
ページの先頭へ戻る »