UVCカメラドライバーの製作 PIC24F/PIC32MX 2013.1.19


    1.はじめに

     USBインタフェースのWebCameraが世の中に出始めた頃は、接続プロトコルがメーカー独自のプロトコルであったために、 Linuxやマイコンに接続するには、ドライバーソフトが無く、難しかったが、Linuxにおいては、有志によりドライバーが順次開発され、今やほとんどのWebCameraを接続できるようになっている。

     RXマイコンやFM3マイコンなどの高機能マイコンでは、SDRAMを適度に増設してやることで、Linuxそのものを走らせることができ、豊富なLinuxのドライバーによりUSBWebCameraを簡単に扱うことができる。

     一方、PICにおいては、その貧弱な機能ゆえに、カメラドライバーが存在するとは思えず、USBカメラの接続は諦めていたのだが、 ネット検索を行ってみた所、PIC32を用いたドライバー製作記事が一つ見つかった。 この記事では、spca5xx のWebCameraドライバーを製作されており、Linuxのドライバーから情報を得て作られたようである。 ドライバーのソースファイルも公開されている。

     その他には、もう一つ、PICの本家、Microchip社のForumにて、PIC32MXによるUVCクラスのカメラドライバーの製作に関するディスカッションを見つけた。こちらのForumでは、ソースファイルは公開されていなかったが、PIC32MXでドライバーが製作できるという事実だけは知ることが出来た。

     UVCクラスのカメラは、安いものでは、500円ぐらいから手に入る。また、UVCクラスのプロトコルは、www.usb.org で公開されており、ドライバのサンプルソースとしてLinuxのドライバーソースは容易に入手できる。という訳で、PIC用のUVCドライバーの製作に挑戦して見ることにした。


    2.ハードウェアの製作

     PICは、当初、16ビットのPIC24FJ64GB002を採用した。PIC24FJ64GB002を搭載したミニBのUSBコネクタが付いたマイコンボードを ネットから入手した。このボードは、USBのバスパワーで動作する。

     UVCのWebカメラを接続するには、USBのコネクタは、Aコネクタが必要だ。そこで、AコネクターBコネクタ変換基板を自作して、カメラとマイコンボードを接続することにした。

     電源はACアダプタを使い、コネクタ変換基板からUSBコネクタを通してマイコンボードとWebカメラそれぞれに+5Vが供給できるようにした。

     Webカメラからの画像を表示する表示装置は、共立電子にて購入したディスプレーコントローラーIC評価ボードを採用した。

     この評価ボードでは、マイコンとの接続インタフェースが、ダイレクト接続・インダイレクト接続のパラレル接続とSPI接続の3つの中から選択することが出来る。

     伝送速度の観点からは、パラレル接続の方が有利であるが、PIC24FJ64GB002では、I/Oピンが少ないのでSPI接続で接続することにした。

    USBマイコンボード
    コネクタ変換基板
    TFT液晶とコントローラーIC評価ボード


    3.ソフトウェアーの製作

    3−1.UVCクラスについて

     www.usb.org にアクセスして、UVCクラスのドキュメントをダウンロードする。ダウンロードしたドキュメントは、以下のとおり。

      (1) Universal Serial Bus Device Class Definition for Video Device (Revision1.1 June 1,2005)
      (2) Universal Serial Bus Device Class Definition for Video Devices:Video Device Examples
      (3) Universal Serial Bus Device Class Definition for Video Devices:Frequentry Asked Questions
      (4) Universal Serial Bus Device Class Definition for Video Devices:Identifiers
      (5) Universal Serial Bus Device Class Definition for Video Devices:DV Payload
      (6) Universal Serial Bus Device Class Definition for Video Devices:Frame Based Payload
      (7) Universal Serial Bus Device Class Definition for Video Devices:Motion-JPEG Payload
      (8) Universal Serial Bus Device Class Definition for Video Devices:MPEG-2 TS Payload
      (9) Universal Serial Bus Device Class Definition for Video Devices:Stream Based Payload
      (10)Universal Serial Bus Device Class Definition for Video Devices:Uncompressed Payload

     ダウンロードしたドキュメントを読み、UVCクラスについて勉強する。

     UVCクラスでは、カメラの ブライトネスやコントラスト、色相、彩度などを設定する Video Controle Interface と、カメラの画像を転送する Video Streaming Interface の2つのインターフェースがある。

     画像転送は、転送方式に、アイソクロナス転送を使い、転送パケットサイズは、複数種類設定できる。画像フォーマットには、圧縮フォーマットや非圧縮フォーマットがあり、サポートされる画像フレームのサイズも複数設定できる。これらの情報は、カメラがホストに接続された時に、ディスクリプタにより通知される。

     ブライトネスやコントラストの設定・取得は、Video Control Interface に対して、エンドポイント0を通じてリクエストを発行して行うが、カメラ毎に、サポートされる機能はそれぞれであり、設定可能な項目は、VC Processing Unit ディスクリプタのbmControls で知ることが出来る。

     画像を取得する手順は、次のようだ。Video Streaming Interface に対して、Probe リクエストにより、画像フォーマットや画像フレームの大きさを指定して、ネゴシェーションを行う。その結果を Commit リクエストによりカメラに通知した後、希望する転送パケットサイズを持つ代替インタフェースへ切り替えを行い、ホスト側からINフレームを送出すると、INフレームに同期して、カメラから画像データが転送されてくる。

     以上が、にわか仕込みで得たUVCクラスに関する概要である。

     
    3−2. プログラムの作成

     PICのUSBホストのプログラムは、Microchipから提供されているUSBフレームワークを使った。作成の元にしたのは、「Host-MCHPUSB-Generic Driver Demo」だ。MPLABで新規プロジェクトを作成し、プロジェクトフォルダーに必要なソースファイルやヘッダファイルをコピーした。作成したプロジェクト名は、「UVCwebcam」とした。

     プロジェクトファイル一式:UVCwebcam.zip

     サンプルソースの usb_host_generic.c をまねて、usb_host_uvc.c というファイルを作成した。また、Microchipから提供される、USBのホスト機能を提供する usb_host.c については、USB割り込み処理の中の アイソクロナス転送に関する部分を一部修正した。

     usb_host_uvc.c で提供する関数を呼び出せば、Webカメラを制御したり、カメラからの画像データを取得出来るようにした。つまり、usb_host_uvc.c がドライバーソフトという訳だ。プロジェクトファイルの main.c は、 これらの関数を呼び出すサンプルプログラムとなっている。

     usb_host_c.c で提供する関数は、次のとおり。

      Application interface Functions
      BOOL USBHostUVCInit(void);UVCドライバーの初期化。
      下位レイヤーのUSBホストドライバー(usb_host.c)からUVCカメラの接続を検出した時に呼び出される。
      ユーザーアプリケーションからは、呼び出さないこと。
      BYTE USBHostUVCDeviceAttached(void);カメラの接続状態を返す。
      USB_DEVICE_ATTACHED,または USB_DEVICE_DETACHED を返す。
      char *USBHostUVCGetControlName(BYTE control);カメラコントロール(control) の名前文字列を返す。
      BYTE USBHostUVCGetControlValue(BYTE control, BYTE request, BYTE *data, BYTE *len, WORD *type);カメラコントロールの値を取得する。
      request には、GET_CUR,GET_DEF,GET_MAX,GET_MIN,GET_INFOのいずれかを指定する。
      BYTE USBHostUVCSetControlValue(BYTE control, BYTE request, BYTE *data, BYTE len);カメラコントロールの値を設定する。request には、SET_CURを指定する。
      BYTE USBHostUVCGetFormatCount(void);カメラがサポートしているフォーマットの数を返す。
      BYTE USBHostUVCGetFormat(BYTE number);カメラがサポートしている number 番目のフォーマットを返す。
       FMT_YUY2/FMT_NV12/FMT_MJPEG などが返る。
      UVC_FRAME_INFO *USBHostUVCGetFrame(BYTE number, BYTE *numframes);カメラがサポートしている number 番目のフォーマットのフレーム情報(Width,Hegiht,フレームレート)を格納した配列の先頭アドレスを返す。
      フレーム数(配列の要素数)をnumframesに設定する。
      BYTE USBHostUVCSetFrame(BYTE format_number, WORD width, WORD height);カメラから取得する画像のフォーマット、フレームサイズを指定する。
      BYTE USBHostUVCStartFrameCapturing(void);カメラからの画像取得を開始する。
      UVC_DATA_BUFFER *USBHostUVCGetFrameCapturing(void);カメラから画像を取得する。
      ドライバ内で確保されたバッファに画像データとその大きさが格納されてくるので、アプリケーション側で引き取りを行う。
      連続して呼び出すことでカメラから画像を取得できる。
      BYTE USBHostUVCStopFrameCapturing(void);カメラからの画像取得を終了する。



    4.UVCカメラを繋いで見る

     UVCドライバーのテストを行うにあたり、次の4つのWebカメラを使った。いずれのカメラも、特別な、ドライバーソフト不要のUVCクラス対応のカメラである。

      ELECOM DLK130TBK(130万画素)

      LOGICOOL HD Webcam C270(300万画素)

      BUFFALO BSW13K10H(130万画素)

      Etron Webcam(500万画素)

     カメラから通知されてくるディスクリプタの内容を以下の各ファイルに示す。これは、出来上がったドライバーのテストプログラムにて出力したものである。

     "Etron Webcam"を除く3つのカメラは、USB-Audioの機能も併せ持った複合デバイスとなっている。
     また、Device Descriptor の Vendorコードを見ると、BUFFALOのカメラチップは、 EtronのOEMであることが分かる。Audio機能の有無により、使用されているチップは異なるものと思われる。
     LOGICOOLのカメラは、JPEGフォーマットの出力も可能なようである。


    4−1テストプログラム操作方法

     マイコン基板のUART端子とパソコンをRS-232Cケーブルで接続し、パソコン側では、ハイパーターミナルを起動してマイコンを操作出来るようにしておく。
     コネクタ変換基板にACアダプタを接続し、電源を投入するとパソコンのターミナルウィンドウに、

      *** UVC webcamera driver test program.
      wait for Camera Attached.

    が表示される。カメラの接続を待っている状態である。
    ドライバーの動作テスト
    PIC32MX695Fを使ってテスト
    左上は、RS232Cレベル変換基盤
    ELECOMのカメラを接続
     この後、カメラをコネクタ変換基板のUSB-Aコネクタに接続すると、マイコンがカメラを認識し、パソコンのターミナル画面に、

      ***** UVC Camera Driver Test Menu ************
      d:display Test Bar on LCD.
      c:List Camera Control current value.
      f:List supported Format.
      i:List supported Image Resolution.
      p:Set capture image Format & Resolution.
      e:execute frame capturing.
      =>

    のような、テストメニューが表示される。ここで、DEBUGオプションを有効にしてコンパイルしてあると、先述のカメラのディスクリプタ情報がメニュー表示の前に表示される。

    d を入力すると、LCDにカラーのテストバーを表示する。
    c を入力すると、カメラのコントラストなどの現在値、最大値、最小値などを表示する。
      =>c
      Exposure Time(Absolute):
        Cur 338
        Min 1
        Max 10000
      Input Select:
        Cur 0
      Brightness:
        Cur 128
        Min 0
        Max 255
      Contrast:
        Cur 32
        Min 0
        Max 255
      Saturation:
        Cur 32
        Min 0
        Max 255

    f を入力すると、カメラのサポートする画像フォーマットを表示する。
      =>f
      Supported Format (Number is 0): YUY2
      Supported Format (Number is 1): MJPEG

    i を入力すると、カメラのサポートする画像フォーマット毎に、画像サイズの一覧を、 320x240 や 160x120 のように表示する。
      =>i
      Supported Format (Number is 0): YUY2
       Resolution:
        160x120 176x144
      Supported Format (Number is 1): MJPEG
       Resolution:
        640x480  160x120  176x144
        320x176  320x240  352x288
        432x240  544x288  640x360
        752x416  800x448  800x600

    p,e は、カメラから画像を取得してLCDに表示するものである。まず、pを入力すると、フォーマット番号や取得画像の大きさを質問されるので 次のように入力する。フォーマット指定は、予め f コマンドで出力されたフォーマット番号を入力する。

      =>p
      Format Number=>0
      Resolution width=>160
      Resolution height=>120

     "Format and Resolution, Set ok." が表示されたら、次に e を入力する。
     e の入力により、カメラから画像を取得し、LCDに表示する。何かキーが押されるまで、画像取得を連続して行う。 何かキーが押されると、 "Capture Stop!" を表示し、画像取得を停止し、再度、テストメニューを表示する。


    4−2画像変換等

     LCDへの書き込みは、RGB565フォーマットで行うようにしたので画像フォーマットの変換が必要になった。YUYVの場合には、 次の変換式を採用した。

      R=1.000Y+1.402V
      G=1.000Y-0.344U-0.714V
      B=1.000Y+1.772U

     PICでは、実数演算はできないので、この式を次のように、16倍してまた16で割ることで、整数演算で行えるようにした。

      R=16x(Y + 1.402V)/16=(16Y+22V)/16
      G=16x(Y-0.344U-0.714V)/16=(16Y+6U-11V)/16
      B=16x(Y+1.772U)/16=(16Y+28U)/16

     16倍ではなく256倍して256で割る方が演算精度は良くなるのだが、そうすると値によっては、32ビットの演算が必要になる。 PIC24Fは、16ビットマイコンなので、16ビットで演算できる範囲に収めるためにこのようにした。

     その後、PIC32MXに対応させた時には、256倍して256で割るようにプログラムした。

     LCDの表示をカラーではなくモノクロで行う場合には、輝度情報であるYのみ使えば良いので上記変換は不要である。

     LOGICOOLのカメラがサポートしているMJPEGフォーマットで取得する場合には、JPEGからRGBへの変換処理が必要になる。
     変換は、1フレームを受信してからとなり、1フレーム分の画像データを保存するメモリが必要になる。

     メモリの小さなPICでは、これは無理であり、テストプログラムでは、MJPEGフォーマットを指定した時には、カメラから画像データを受信するものの、 その後の変換処理は行わずに直ちに破棄するようにプログラムした。


    4−3 アイソクロナス転送

     フルスピードのアイソクロナス転送では、一定のパケットサイズのデータを、1msec毎に受信することになる。これは、USBホストドライバにて、1msec毎のSOF割り込みにより実現されている。

     選択した代替インタフェースによって、その転送パケットサイズは、小さいケースで160バイト程度、大きいものでは、1020バイト程度と、それぞれインタフェース毎に異なるが、受信したデータの処理は、 そのデータ転送時間も含めて1msec以内に完結しないと、次のデータの受信に間に合わないことになる。(受信オーバーフローが発生する)

     1020バイトものパケットとなると、12MHzのフルスピードでは、転送だけで1msec近い時間を消費してしまうので、画像データ受信後のフォーマット変換やLCDへの転送をおこなう時間余裕は全くない。

     そこで、受信用のバッファメモリを複数用意し、受信したデータの処理をしている間に、次の空いているバッファにデータを受信することで、この問題を解決することが出来る。 ただし、データ受信後の処理は、1msec以内に完結させないと、いずれオーバーフローをきたしてしまう。

     転送パケットサイズが小さいと、データ受信後の処理に要する時間は短くて済むので、転送パケットサイズの小さい代替インタフェースを選択すれば有利であるが、それが必ずしも良い訳ではない。

     画像フォーマットには、それぞれフレームサイズに応じて、フレームレートが定まっており、1秒間に転送されるべきデータ量が決められている。このために、転送パケットサイズを小さくすると、 カメラ側でフレームレートを達成できなくなり、カメラ内部で転送オーバーフローが発生したり、うまく動作しないケースが発生する。

     160x120のリゾリューションで、フレームレートが15fpsの場合、1秒間に転送されるデータ量は、160x120x2x15=576000バイト となり、 転送パケットサイズは、最小でも、576バイトでなければならない。

     320x240のリゾリューションで、フレームレートが4fpsの場合では、320x240x2x4=614400バイトとなり、転送パケットサイズは、615バイト以上となる。

     今回のプログラム作成にあたっては、SOFパケットの転送処理やペイロードヘッダなどのオーバーヘッドを考慮し、転送パケットサイズは、768バイト以上の 転送パケットサイズを持つ代替インタフェースを使用することとした。受信用のバッファメモリは、4バッファを確保した。



    5.テスト結果等

      機種フォーマットフレームサイズ
      ( )はフレームレート
      動作結果
      ELECOM DLK130TBK YUYV352x288 (5 fps)
      ○
      320x240 (5 fps)
      ○
      176x144 (10 fps)
      ○
      160x120 (10 fps)
      ○
      BUFFALO BSW13K10H YUYV640x480 (1 fps)
      X
      352x288 (3 fps)
      X
      320x240 (4 fps)
      X
      176x144 (8 fps)
      X
      160x120 (15 fps)
      X
      LOGICOOL HD Webcam C270 YUYV176x144 (15 fps)
      ○
      160x120 (15 fps)
      ○
      MJPEG160x120 
      △
      (データ受信のみ確認)
      176x144 
      △
      320x176 
      △
      320x240 
      △
      352x288 
      △
      432x240 
      △
      544x288 
      △
      640x360 
      △
      640x480 
      △
      752x416 
      △
      800x448 
      △
      800x600 
      △
      Etron Webcam YUYV640x480 (1 fps)
      X
      352x288 (3 fps)
      X
      320x240 (4 fps)
      X
      176x144 (8 fps)
      X
      160x120 (15 fps)
      X

     EtronとBUFFALOのカメラは、全くもって駄目であった。ProbeからCommitまではうまく行くが、その後の代替インタフェースの切り替え処理でエラーが発生し、画像転送処理に進めない。 Etronのカメラチップをうまく制御するには、何かまだ不足しているものがあるのかもしれない。

     LOGICOOLのHD Webcamでは、非圧縮フォーマットの他に、圧縮のMJPEGフォーマットがサポートされている。フルスピードでも最大 800x600 の リゾリューションが使える。なお、LCDへの表示のためには JPEG 圧縮を展開する必要があるが、JPEG展開をプログラムしていないので、 先述のようにデータを受信するだけでLCDへの表示確認は行っていない。


    6.対応PICを増やす

     PIC24FJ64GB002での動作を確認した後、PIC24FJ256GB106やPIC32MX696F512Hにも対応させた。
     PIC24FJ256GB106では、ディスプレーコントローラIC評価基板とのパラレル接続の実験を行った。
     PIC32MX695Fでは、命令クロック80MHzの高クロック速度による使い勝手などを確認した。
     なお、PIC32MX220Fにも対応するコードをプログラムしたが、プログラムサイズが32Kバイトを超えるのでメモリオーバーでリンクエラーとなり、 動作させることは出来なかった。