Version 7 (modified by michkawa, 7 years ago) (diff) |
---|
FTDI FT260で実験
FT260をBBBに繋いで使い方の実験してみる。
パッケージインストール
始めにpythonで実験するために、hidapi周りのパッケージをインストールする。
root@beaglebone:~# apt-get install libhidapi-libusb0 libudev-dev libusb root@beaglebone:~# pip install --trusted-host pypi.python.org Cython hidapi
デバイスの接続
開発ボードにはI2C接続のEEPROMが搭載されていて、defaultではジャンパで接続されている。
なるべく余計な接続をしない状態で実験したかったのでEEPROMなしの状態にジャンパを設定する。
デバイスを接続すると、musb-hdrc musb-hdrc.1.auto: Babbleというメッセージが大量に出力されるが、一応認識されて繋がりはするようだ。
[ 6891.320644] musb-hdrc: 28/31 max ep, 16384/16384 memory [ 6891.659553] musb-hdrc musb-hdrc.1.auto: Babble [ 6891.664416] musb-hdrc musb-hdrc.1.auto: Babble [ 6891.668943] musb-hdrc: setup fifo_mode 4 [ 6891.668996] musb-hdrc: 28/31 max ep, 16384/16384 memory [ 6892.066437] usb 1-1: new full-speed USB device number 27 using musb-hdrc [ 6892.199679] usb 1-1: New USB device found, idVendor=0403, idProduct=6030 [ 6892.199741] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 6892.199773] usb 1-1: Product: FT260 [ 6892.199803] usb 1-1: Manufacturer: FTDI [ 6902.262497] hid-generic 0003:0403:6030.0005: usb_submit_urb(ctrl) failed: -1 [ 6902.276074] hid-generic 0003:0403:6030.0005: timeout initializing reports [ 6902.284785] hid-generic 0003:0403:6030.0005: hidraw0: USB HID v1.11 Device [FTDI FT260] on usb-musb-hdrc.1.auto-1/input0 [ 6912.310492] hid-generic 0003:0403:6030.0006: usb_submit_urb(ctrl) failed: -1 [ 6912.322341] hid-generic 0003:0403:6030.0006: timeout initializing reports [ 6912.330402] hid-generic 0003:0403:6030.0006: hidraw1: USB HID v1.11 Device [FTDI FT260] on usb-musb-hdrc.1.auto-1/input1
HIDデバイスが2つ認識されているが、FT260のアプリケーションノートの6ページ目1.2 FT260 HID Interfaces and Endpointsをみると、I2CとUARTがそれぞれ別のHIDとして認識されるようだ。
hidraw0がI2C、hidraw1がUARTらしい。
ジャンパを設定し直して、I2Cのみにしてみると、
[ 7774.216655] musb-hdrc: 28/31 max ep, 16384/16384 memory [ 7774.555547] musb-hdrc musb-hdrc.1.auto: Babble [ 7774.560500] musb-hdrc musb-hdrc.1.auto: Babble [ 7774.565029] musb-hdrc: setup fifo_mode 4 [ 7774.565083] musb-hdrc: 28/31 max ep, 16384/16384 memory [ 7774.962288] usb 1-1: new full-speed USB device number 31 using musb-hdrc [ 7775.093398] usb 1-1: New USB device found, idVendor=0403, idProduct=6030 [ 7775.093436] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 7775.093452] usb 1-1: Product: FT260 [ 7775.093467] usb 1-1: Manufacturer: FTDI [ 7785.130492] hid-generic 0003:0403:6030.0007: usb_submit_urb(ctrl) failed: -1 [ 7785.144095] hid-generic 0003:0403:6030.0007: timeout initializing reports [ 7785.153751] hid-generic 0003:0403:6030.0007: hidraw0: USB HID v1.11 Device [FTDI FT260] on usb-musb-hdrc.1.auto-1/input0
となり、I2Cのみになるので、これで実験することにする。
pythonでのテスト
以前、帯名さんがHIDデバイスのテストをした時のドキュメントを参考にしてみる。
まずは、FT260の設定を取得してみる。
oot@beaglebone:~# ipython --nosep Python 2.7.9 (default, Aug 13 2016, 17:56:53) Type "copyright", "credits" or "license" for more information. IPython 2.3.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: import hid In [2]: h = hid.device() In [3]: In [3]: h.open(0x0403, 0x6030) In [4]: h.set_nonblocking(1) Out[4]: 0 In [5]: h.write([0xA1] + [0]*63) Out[5]: 64 In [6]: h.read(64) Out[6]: [] In [7]: h.write([0xA0] + [0]*63) Out[7]: 64 In [8]: h.write([0xA0] + [0]*63) Out[8]: 64 In [9]: h.read(64) Out[9]: [] In [10]: h.write([0xA0] + [0]*11) Out[10]: -1 In [11]: h.write([0xA0] + [0]*63) Out[11]: -1 In [12]: h.read(64) Out[12]: [] In [13]: h.read(64) Out[13]: [] In [14]: h.write([0xA0] + [0]*63) Out[14]: -1 In [15]: h.write([0xC0] + [0]*63) Out[15]: -1 In [16]: h.close()
うまくいかない、、、
色々見ていったところ、取得するデータによって使用する関数が違うらしい。
FT260のアプリケーションノートを見てみると、15ページの4.3 FT260 Report ID Listには、
Report ID | Type | description |
0xA0 | Feature | Chip code |
0xA1 | Feature | System Setting |
0xB0 | Feature | GPIO |
0xB1 | Input | Interrupt Status (from UART interface) |
0xC0 | Feature | I2C Status |
0xC2 | Output | I2C Read Request |
0xD0 ~ 0xDE | Input, Output | I2C Report |
0xE0 | Feature | UART Status |
0xE2 | Feature | UART RI and DCD Status |
0xF0 ~0xFE | Input, Output | UART Report |
と書いてあり、Featureへのアクセスはsend_feature_report, get_feature_reportで行い、INPUT,OUTPUTはwrite,readで行うらしい。
root@beaglebone:~# ipython --nosep Python 2.7.9 (default, Aug 13 2016, 17:56:53) Type "copyright", "credits" or "license" for more information. IPython 2.3.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: import hid In [2]: h = hid.device() In [3]: h.open(0x0403, 0x6030) In [4]: h.get_feature_report(0xA0,13) Out[4]: [160, 2, 96, 2, 0, 2, 96, 1, 0, 1, 1, 3, 0] In [5]: h.get_feature_report(0xA1,64) Out[5]: [161, 1, 2, 0, 1, 1, 0, 0, 1, 3, 6, 1, 1, 12, 1, 0, 0, 0, 0, 0, 172, 0, 188, 0, 204]
これでやっと、FT260にアクセスできることが確認できた。
次にI2C上のスレーブデバイスにアクセス。
接続しているI2Cデバイスは、ADT7410を基板化した、秋月電子 ADT7410使用 高精度・高分解能 I2C・16Bit 温度センサモジュール。
FT260開発ボードの3.3V電源と、IO0,IO1を接続した。
FT260 <-> ADT7410 3.3V (JP6-1) VDD IO0 (JP6-11) SCL IO1 (JP6-10) SDA GND GND
温度センサのI2Cアドレスは0x48としておく。
In [1]: import hid In [2]: h = hid.device() In [3]: h.open(0x0403, 0x6030) In [4]: h.set_nonblocking(1) Out[4]: 0 In [5]: h.write([0xC2, 0x48, 0x06, 0x04, 0x00]) Out[5]: 5 In [6]: h.read(64) Out[6]: [208, 4, 13, 88, 128, 0, 50, 0]
先頭2byteはFT260のHIDコマンドヘッダなので、[13, 88, 128, 0, 50, 0]がデータ。
取得するデータ数は4byteだけど、6byteデータが出てくる。多分、HIDヘッダも含めて4byte単位でデータが出てくるのだろう。
ADT7410のデータシートから、[13, 88]が温度データ、次の[128]がStatus、[0]がConfigurationとなっているようだ。
Configurationの7bit目が1なら16bit,0なら13bitデータになる。
13bit時のデータは[15:3]が有効なデータなので、計算式は、
ADC_DEC = ((HSB<<8) | LSB)>>3 Positive_Temp[℃] = ADC_DEC /16.0 Negative_Temp[℃] = (ADC_DEC - 8192)/16
となるらしい。
この計算式に当てはめると、LSB=88,HSB=13の場合、26.6875[℃]となる。
今回は16bitで使いたいので、Configration Registorの7bit目を1にする必要がある。
どうやるか試行錯誤して、I2Cプロトコルにおける設定(書き込み)は、書き込みアドレスの後ろに設定データを付けて送ればいいことを思い出した。
In [25]: h.write([0xD0, 0x48, 0x06, 0x02, 0x03,0x80,0x00,0x00]) Out[25]: 8 In [26]: h.write([0xC2, 0x48, 0x06, 0x04, 0x00]) Out[26]: 5 In [27]: h.read(64) Out[27]: [208, 4, 13, 75, 128, 128, 0, 0]
レジスタ設定後にデータを読み出すと、Configuration Registorが128(0x80)となっていて、16bitになっていることがわかる。
16bit時の計算式は、
ADC_DEC = ((HSB<<8) | LSB) Positive_Temp[℃] = ADC_DEC /128 Negative_Temp[℃] = (ADC_DEC - 65536)/128
となる。計算式に当てはめると、LSB=75,HSB=13の場合、26.5859375[℃]となる。
これで、FT260をつかったI2Cデバイスの制御に必要なコマンドは全て使い方が分かったので、IOC化することができそうである。
複数デバイス接続
FT260開発ボードをUSBハブで複数繋いでみると、当たり前だが普通に認識して/dev/hidraw*が生成される。
FT232RやFT230Xには、デフォルトでチップ毎にシリアル番号が設定されていて、それを使えばデバイス名の固定が可能だが、FT260にはそれがない。
debian@beaglebone:~$ udevadm info -a -p $(udevadm info -q path -n /dev/hidraw0) : looking at parent device '/devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb1/1-1/1-1.2': KERNELS=="1-1.2" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="100mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="2200" ATTRS{bmAttributes}=="a0" ATTRS{busnum}=="1" ATTRS{configuration}=="" ATTRS{devnum}=="118" ATTRS{devpath}=="1.2" ATTRS{idProduct}=="6030" ATTRS{idVendor}=="0403" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="FTDI" ATTRS{maxchild}=="0" ATTRS{product}=="FT260" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{speed}=="12" ATTRS{urbnum}=="16" ATTRS{version}==" 2.00" :
FT232R等の他のチップでは、ATTRS{SerialNumber}==xxxxのような表示が入る。(詳細な属性名は不明)
データシートを見ると、I2C接続した外付けEEPROMに書き込むと、表示されるようになるらしい。
実験の初めにEEPROMを外して実験していたが、接続しなおしてから、シリアル番号を書き込んでみる。
設定の変更はI2Cコマンドでできるようだが、FT_ProgというユティリティをFTDIが用意してくれているので、今回はそれを使う。
USB String Descriptors -> Serial Number EnabledとAuto Generate Serial Noにチェックを入れて、メインメニューのDEVICES -> Programを選択すると、
のダイアログボックスでProgramすれば自動的にシリアル番号が生成されてEEPROMに書き込まれる。
ここでの注意点は、プログラムのデフォルトのままだとvendoridが0403から0803に書き変わってしまうので、書き込み前にチェックすること。
書き込み実行後に再度デバイス情報を見てみると、今度はATTRS{serial}==が設定されている。
debian@beaglebone:~$ udevadm info -a -p $(udevadm info -q path -n /dev/hidraw0) : looking at parent device '/devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb1/1-1/1-1.1': KERNELS=="1-1.1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="64" ATTRS{bMaxPower}=="128mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="2200" ATTRS{bmAttributes}=="a0" ATTRS{busnum}=="1" ATTRS{configuration}=="" ATTRS{devnum}=="124" ATTRS{devpath}=="1.1" ATTRS{idProduct}=="6030" ATTRS{idVendor}=="0403" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="FTDI" ATTRS{maxchild}=="0" ATTRS{product}=="FT260" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{serial}=="FT27KQDF" ATTRS{speed}=="12" ATTRS{urbnum}=="18" ATTRS{version}==" 2.00" :
デバイスを再接続後、pythonでアクセスしてみる。
root@beaglebone:~# ipython --nosep In [1]: import hid In [2]: h = hid.device() In [3]: h.open(0x0403, 0x6030, "FT27KQDF") --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-3-1e0fc914f0ab> in <module>() ----> 1 h.open(0x0403, 0x6030, "FT27KQDF") TypeError: Argument 'serial_number' has incorrect type (expected unicode, got str) In [4]: h.open(0x0403, 0x6030, u"FT27KQDF")
シリアル番号をunicodeで設定したら、オープンできたので、大丈夫そう。
IOC
接続方法と使用するコマンドがわかったので、IOCを作成する。
作成するレコードは、ADT7410のADCを16bitに設定するコマンドと、温度を取得するコマンドのみ。
以前作った、drvAsynUSBHIDを使って、コマンドを実装。
ここで気付いたのだが、drvAsynUSBHIDはInput,Outputを使った制御には使えるが、USBHIDデバイス自体を制御するFeatureコマンドには対応していない。
今回もFeatureコマンドを使わなくても目的は達成できたが、今後Featureコマンドが必須の制御をする場合には、何らかの解決策を考える必要がありそう。
使用コマンド(FT260)
今回使用するFT260上のコマンドは、
- I2C Write Request(0xD0~0xDE)
- I2C Read Request(0xC2)
- I2C Input Report(0xD0~0xDE)
のみである。I2C Input ReportはReadで返ってくるフォーマットの定義なので、I2C Write RequestとI2C Read Requestだけを実装する。
protocol ファイル
今回作成したプロトコルファイルがこれ。
TERMINATOR=""; LockTimeout = 500; ReplyTimeout = 100; ReadTimeout = 100; WriteTimeout = 100; MaxInput=8; wr_4 = 0xD0; rd = 0xC2; flg = 0x06; len = 0x04; ##################### # $1:I2C slave device addr ##################### # Set ADT7410 ADC Resolution(16bit) setADCRes { out $wr_4 $1 $flg 0x02 0x03 0x80 0x00 0x00; } # Read ADT7410 templature value getTemp { out $rd $1 $flg $len 0x00; in $wr_4 $len "%(\$2)01r" "%01r" "%*4r"; }
I2Cデバイスのアドレスをdbファイルから設定できるようにして、温度レジスタを別々に読み込んでCALCで計算するようにした。
DBファイル
record(bo, "$(user):ADT7410:init") { field(DESC, "Set ADT7410 ADC 16bit") field(DTYP, "stream") field(OUT, "@FT260_ADT7410.proto setADCRes($(i2caddr)) $(dev)") } record(longin, "$(user):temp:reg:HSB") { field(DESC, "Get temperature registor HSB") } record(longin, "$(user):temp:reg:LSB") { field(DESC, "Get temperature registor LSB") field(DTYP, "stream") field(INP, "@FT260_ADT7410.proto getTemp($(i2caddr),$(user):temp:reg:HSB) $(dev)") field(SCAN, "$(scan)") field(FLNK, "$(user):temp") } record(calc, "$(user):temp") { field(DESC, "Get temperature") field(INPA, "$(user):temp:reg:LSB") field(INPB, "$(user):temp:reg:HSB") field(CALC, "(B&0x80)=0x80?(((B<<8)|A)-65536)/128:((B<<8)|A)/128") field(PREC, "5") field(EGU, "degC") }
Attachments (2)
- FT_Prog.png (43.4 KB) - added by michkawa 7 years ago.
- FT_Prog_Write.png (8.6 KB) - added by michkawa 7 years ago.
Download all attachments as: .zip