FrontPage

2008/10/14 からのアクセス回数 15532

インターネット・ガジェット設計にlibusbとUSBプロトコルスタックを使って自作のUSBデバイスにアクセスする 例があったので、Mac OSXで動作を確認しました。

必要なライブラリ

libusbを使った自作デバイスには、以下のライブラリが必要です。

  • libusb から最新版v0.1.12をダウンロードしました。しかし、MacOSXには最初からインストールされていたので、不要でした。
  • AVR-USB はAVR用のUSBプロトコルスタックです。avrusb-20080513.zipをダウンロードしました。

USBデバイス

テストに使用するデバイスは、5章の「USBプロトコール・スタックを使う」のTiny45を使った例題に従いました。

回路

5章の「USBプロトコール・スタックを使う」の図5.9の回路図

Tiny45Cirkit.jpg

には、誤植がありTA48M033Fのピン番号が1と2が入れ替わっています。

ブレッドボード

最終のブレッドボードの回路は、USBとTiny45(書込用)の2個を連結しました。

回路を組み立てるときには、データシートでピン番号の配置を確認して、接続しましょう。

私は、http://www.alldatasheet.com/ からTiny45, TA48M033Fのデータシートをダウンロードしました。

usbTiny45.jpg

プログラムの動作

テストプログラムは、ホストのshow.cとターゲットデバイスのfirmware/main.cで主な処理をしています。

処理の流れ

ホストプログラムは、usbデバイスをオープンした後、usb_control_msg関数を使ってデバイスにデータを 送信します。

show.cでは、usb_control_msgの引数を使ってデバイスにデータを渡しているのですが、その仕組みが分かりにくいので、少し補足をします。

AVR-USB Driver APIによると、

  • usb_control_msg関数によって
    typedef struct usbRequest{
        uchar       bmRequestType;
        uchar       bRequest;
        usbWord_t   wValue;
        usbWord_t   wIndex;
        usbWord_t   wLength;
    }usbRequest_t;
    
    の8バイトの要求が送られます。 show.cの例題では、この要求メッセージをデータとしてターゲットに渡しているのです。
  • ターゲットのUSBデバイスでは、usbFunctionSetupがコールされ要求メッセージが渡されます。

例題では、送られたデータを1つシフトした7バイトの情報を返します。

ホストのプログラム

show.cのUSBデバイスのオープン

static int usbOpenDevice(usb_dev_handle **device, int idvendor, int idproduct)
{
  struct usb_bus *bus;
  struct usb_device *dev;
  usb_dev_handle *udh=NULL;
  int ret,retp, retm,errors;
  char string[256];
  usb_init();
  usb_find_busses();
  ret=usb_find_devices();
  if(ret==0){return errors=1;}
  for (bus = usb_busses; bus; bus = bus->next)
  {
    for (dev = bus->devices; dev; dev = dev->next)
    {
      udh=usb_open(dev);
      retp = usb_get_string_simple(udh, dev->descriptor.iProduct, string, sizeof(string));
      retm=usb_get_string_simple(udh, dev->descriptor.iManufacturer, string, sizeof(string));
      if (retp > 0 && retm > 0)
        if (idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct){ 
          *device=udh;return errors=0;}
    }
  }
         usb_close(udh);return errors=1;
}

メイン関数は、

int main(int argc, char **argv)
{
  usb_dev_handle *d=NULL;
  unsigned char buffer[16];
  unsigned char i=3,j=4,k=5,l=6,m=7,n=8,o=9,p=0,ret;
  char string[256];
//if(argc<2){return 0;}
//j=atoi(argv[1]);
ret=usbOpenDevice(&d, IDVendor,IDProduct);
if(ret!=0){printf("usbOpenDevice failed\n"); return 0;}

  ret=usb_control_msg(d, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
           i, j+256*k, l+256*m,(char *)buffer, n+256*o,5000);
printf("ret=%d \n",ret);
for(p=0;p<ret;p++){printf("buffer[%d]=%d \n",p, buffer[p]);}

  return 0;
}

ターゲットのプログラム

ターゲットusbFunctionSetupは、

uchar usbFunctionSetup(uchar data[8])
{
static uchar replybuf[8];
usbMsgPtr = replybuf;

        replybuf[0]=data[7];
        replybuf[1]=data[1];
        replybuf[2]=data[2];
        replybuf[3]=data[3];
        replybuf[4]=data[4];
        replybuf[5]=data[5];
        replybuf[6]=data[6];
return 7;
}

となります。

完全なソースは、Ohmshaのページからダウンロードできます。

動作確認

ダウンロードしたファイルのUSBtesttiny45ディレクトリに移動します。

ホストのコンパイル

ホストのコンパイルは、

$ cc -o show show.c -lusb

でshowが作成されます。

ターゲットコンパイル

今回は、AVR ISP mkIIを使用するので、 firmwareディレクトリに移動して、Makefileを以下のように修正しました。

avrdude:
        avrdude -c avrispmkII -P usb -p $(TARGET) -U flash:w:main.hex

lfuse:
        avrdude -c avrispmkII -P usb -p $(TARGET) -u -U lfuse:w:0xc0:m

後は、makeコマンドでターゲットデバイスへの書き込みまで実行します。

$ make 

showの実行

最後にshowを実行します。

$ ./show
ret=7 
buffer[0]=9 
buffer[1]=3 
buffer[2]=4 
buffer[3]=5 
buffer[4]=6 
buffer[5]=7 
buffer[6]=8 

と出力されたら、完成です。

コメント

この記事は、

選択肢 投票
おもしろかった 13  
そうでもない 1  
わかりずらい 3  

皆様のご意見、ご希望をお待ちしております。

  • MacOSXにlibusbが最初から入っていたというのは、私の勘違いでした。 -- 竹本 浩? 2009-08-10 (月) 14:44:04

(Input image string)


添付ファイル: fileTiny45Cirkit.jpg 1185件 [詳細] fileusbTiny45.jpg 1143件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-11-20 (日) 20:58:21 (333d)
SmartDoc