[[FrontPage]] 2008/10/14 からのアクセス回数 &counter; #contents インターネット・ガジェット設計にlibusbとUSBプロトコルスタックを使って自作のUSBデバイスにアクセスする 例があったので、Mac OSXで動作を確認しました。 ** 必要なライブラリ [#v00401ef] libusbを使った自作デバイスには、以下のライブラリが必要です。 - [[libusb>http://libusb.wiki.sourceforge.net/]] から最新版v0.1.12をダウンロードしました。しかし、MacOSXには最初からインストールされていたので、不要でした。 - [[AVR-USB>http://www.obdev.at/products/avrusb/index.html]] はAVR用のUSBプロトコルスタックです。avrusb-20080513.zipをダウンロードしました。 ** USBデバイス [#n9bc7fd4] テストに使用するデバイスは、5章の「USBプロトコール・スタックを使う」のTiny45を使った例題に従いました。 *** 回路 [#w5e18420] 5章の「USBプロトコール・スタックを使う」の図5.9の回路図 #ref(Tiny45Cirkit.jpg); には、誤植がありTA48M033Fのピン番号が1と2が入れ替わっています。 *** ブレッドボード [#u4833fdb] 最終のブレッドボードの回路は、USBとTiny45(書込用)の2個を連結しました。 回路を組み立てるときには、データシートでピン番号の配置を確認して、接続しましょう。 私は、http://www.alldatasheet.com/ からTiny45, TA48M033Fのデータシートをダウンロードしました。 #ref(usbTiny45.jpg); ** プログラムの動作 [#aa07038f] テストプログラムは、ホストのshow.cとターゲットデバイスのfirmware/main.cで主な処理をしています。 *** 処理の流れ [#ud07e4f1] ホストプログラムは、usbデバイスをオープンした後、usb_control_msg関数を使ってデバイスにデータを 送信します。 show.cでは、usb_control_msgの引数を使ってデバイスにデータを渡しているのですが、その仕組みが分かりにくいので、少し補足をします。 [[AVR-USB Driver API>http://avrusb.wikidot.com/driver-api]]によると、 - usb_control_msg関数によって #pre{{ 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バイトの情報を返します。 *** ホストのプログラム [#s3c33cb2] show.cのUSBデバイスのオープン #pre{{ 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; } }} メイン関数は、 #pre{{ 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; } }} *** ターゲットのプログラム [#u2cfd04f] ターゲットusbFunctionSetupは、 #pre{{ 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のページ>http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-50186-9]]からダウンロードできます。 ** 動作確認 [#cdd02566] ダウンロードしたファイルのUSBtesttiny45ディレクトリに移動します。 *** ホストのコンパイル [#hb95b5eb] ホストのコンパイルは、 #pre{{ $ cc -o show show.c -lusb }} でshowが作成されます。 *** ターゲットコンパイル [#j68858fb] 今回は、AVR ISP mkIIを使用するので、 firmwareディレクトリに移動して、Makefileを以下のように修正しました。 #pre{{ 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コマンドでターゲットデバイスへの書き込みまで実行します。 #pre{{ $ make }} *** showの実行 [#kd3f7c8f] 最後にshowを実行します。 #pre{{ $ ./show ret=7 buffer[0]=9 buffer[1]=3 buffer[2]=4 buffer[3]=5 buffer[4]=6 buffer[5]=7 buffer[6]=8 }} と出力されたら、完成です。 ** コメント [#u850f9e7] この記事は、 #vote(おもしろかった[22],そうでもない[1],わかりずらい[3]) #vote(おもしろかった[23],そうでもない[1],わかりずらい[3]) 皆様のご意見、ご希望をお待ちしております。 - MacOSXにlibusbが最初から入っていたというのは、私の勘違いでした。 -- [[竹本 浩]] &new{2009-08-10 (月) 14:44:04}; #comment_kcaptcha