マイコン工作実験日記

Microcontroller を用いての工作、実験記録

USB_LDDを使ってみる -- 解決編?

2015-07-26 15:17:11 | FRDM
前記事ではコントロール転送とインタラプト転送が同時に動かないで悩んでいたのですが、対処方法が見つかってあっさりと動いてしまいました。

SSPではコントロール転送、インタラプト転送に加えて、バルク転送も必要となるので、バルク転送のパイプも追加で開いて読み取りを始めたところ、なんと全ての転送が順調に動くようになってしまいました。もしかすると、インタラプト転送を使うためにはバルク転送も併用しないといけないというようなバグがドライバに潜んでいるのかもしれません。参考までに、各パイプを開くために使ったディスクリプタ定義を残しておきます。
LDD_USB_Host_TPipeDescr Pipe1Descr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    1,                  /* EP number */
    LDD_USB_DIR_IN,     /* EP direction */
    LDD_USB_INTERRUPT,  /* EP Transfer type */
    16,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    1,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

LDD_USB_Host_TPipeDescr Pipe2InDescr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    2,                  /* EP number */
    LDD_USB_DIR_IN,     /* EP direction */
    LDD_USB_BULK,       /* EP Transfer type */
    64,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    0,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

LDD_USB_Host_TPipeDescr Pipe2OutDescr = {
    1,                  /* Device address */
    LDD_USB_FULL_SPEED, /* Device speed */
    2,                  /* EP number */
    LDD_USB_DIR_OUT,    /* EP direction */
    LDD_USB_BULK,       /* EP Transfer type */
    64,                 /* EP max. packet size */
    0,                  /* Transaction pre microframe */
    0,                  /* Interval for polling endpoint for data transfer */
    0,                  /* NAK count */
    0                   /* 1 = ZLT */
};

USB_LDDのAPIでは、インタラプト転送やバルク転送の読み取りは、転送が完了するかエラーが発生するとコールバックがかかります。デバイス側からの読み取りデータが無い場合にはNACKが返ってきますが、その場合にはドライバが次のフレームで再度INトークンを送出してくれます。この周期処理はドライバが面倒を見てくれますので、アプリケーションでは、転送が完了した場合には再度読み取りを開始してやればいいことになります。

こうして無事にBTstackが動いてくれました。

BTStackが立ち上がった状態では、ペアリング待ちになっていますので、スマホからペアリングしてやります。




ペアリングが完了したらスマホからSPPで接続してやります。。






SSP counterアプリケーションは、毎秒インクリメントしていく数字を出力するだけの単純なアプリですが、その動作を確認することができました。

SPP counterは比較的あっさりと動いてしまいました。当初、ペアリングの途中でハングしていたのですが、BTstackタスクに割り当てるスタックが不足していたのが原因でした。




USB_LDDを使ってみる -- その3

2015-07-20 20:53:29 | FRDM
USB_LDDをつかってBluetoothドングルのエニュメレーションまではできたので、いよいよBTstackを動かし始めます。入門編としては、SPPをつかうspp_counterというサンプルを動かしてみるというのがお約束のようなので、まずはこれを動かすことにします。

BluetoothのUSBトランスポートでは、コマンドの送信にコントロール転送、Bluetoothからのイベントの受信にインタラプト転送、ACLリンクのデータ送受にバルク転送、そしてSCOリンクの送受にアイソクロナス転送と、USBの各転送方式を全て利用しますが、SPPであればアイソクロナス転送は必要ありません。BTstackが動くとHCIでコマンドを送信して、それに対する応答がドングルからインタラプト転送で返ってきますので、まずはこの部分の動作を確認することにします。新たにインタラプト転送のパイプを開いてやり、そこからの読み出しを開始しておき、パイプ0にHCIコマンドを送ってやります。


ところが、最初の2つ、3つのコマンドに対してはちゃんと応答が返ってくるのですが、その先に進んでくれません。どうやらパイプ0にコマンドを送信した後の、送信完了コールバックが動いていないようです。

USBの動きとしては、1ms間隔でインタラプト転送によるイベントの読み出しがかかる中で、コントロール転送によるコマンド送信が発生するという動作になります。そこで試しに、コントロール転送でコマンドを送信する際には、進行中のインタラプト転送をUSB1_HostCancelTransfer()を使って いったん止めてからコマンド送信をするようにしてみました。すると、


初期化に必要な一連のHCIコマンドが送信され、それに対する応答が返ってきてBTstackがちゃんと立ち上がるところまで進みました。

このようにコントロール転送とインタラプト転送を同時に動かさなければちゃんとBTstackが立ち上がるのですが、この先ではACLリンクの送受もしたいので、やはり複数の転送を同時に動かさなければSPPを動かすことができません。Processor Expertの生成したドライバコードをざっと見たところでは、複数のパイプを同時に使うことを意図して作られているようですので、何か使い方が悪いのか、生成されたコードにバグが潜んでいるかのいずれかだろうと思われます。そういうわけで、USBのコードを追いかけることになってしまいました。

USB_LDDを使ってみる -- その2

2015-07-18 09:57:42 | Weblog
前回の記事の続きです。

USB_LDDのヘルプに基づいて、Device Descriptorの先頭部分を読み出すことはできたので、エニュメレーション手順を続けてみます。次の段階としては、デバイスに対してのアドレス割付が必要となります。具体的には次の2つの処理が必要です。
  1. デバイス側に対してSet Addressリクエストを送信する。
  2. 自分側のアドレスを設定する。

1番の処理の方は、送信するSETUPデータを用意して、それをHostSendSetupメソッドを使って送信してやればOKです。このリクエストではSETUPの8バイトに続けて送信あるいは受信するデータはないので、TDの部分のBufferやBufferSizeを指定する必要はありません。
const LDD_USB_TSDP SetAddress = {
    LDD_USB_DIR_OUT | LDD_USB_REQ_TYPE_STANDARD,        /* bmRequestType */
    LDD_USB_REQ_SET_ADDRESS,    /* bmRequest */
    toLittleEndian(0x0001),     /* wValue */
    toLittleEndian(0x0000),     /* wIndex */
    toLittleEndian(0x0000)      /* wLength */
};

...
...
    TD = InitTtDescr;       /* Set all items of TD to zero */
    TD.SDPPrt = (void *)&SetAddress;
    Error = USB1_HostSendSetup(MyUSBPtr, PipeHandle, &TD, &TrHandle);  
2番目の自分側アドレスの指定に関しては、これに対応する明示的なAPIはありません。Processor Expertが生成したコードを確認したところ、HostOpenPipeが返すPipeHandleデータの中に含まれるDevAddressで指定していることがわかりました。同様にパケットサイズもPipeHandleにてDevice Descriptorから取得した値(devMaxPacketSize)に変更しておきます。

PipeHandle->DevAddress = 1;
PipeHandle->MaxPacketSize = devMaxPacketSize;

このように設定しておき、以後のHostSendSetupにてはPipeHandleを引数として渡せば、割り当てたアドレス(1)との間で送受信が行われます。


USB_LDDを使ってみる

2015-07-10 22:32:58 | FRDM
Kinetisでは、KSDKの一部としてUSBのプロトコルスタックが提供されています。実験的にプロジェクトの構成を試してみたのですが、RTOSとしてMQX Liteを選択するとメモリ管理プリミティブが不足しているために構成できないというエラーが発生してしまいます。どうやら、MQXかFreeRTOSを使う必要があるようです。KSDKのホストスタックにおいてもBluetoothのクラスドライバが用意されているわけでもないので、どのみちその部分は作らねばなりません。そこで、KSDSKを使わずともKDSのPEXコンポーネントとして用意されているUSB_LDD (USB Logical Device Driver)を使ってホスト機能を実装してみることにしました。




PEXを使ってUSB_LDDのコンポーネントを追加して、そのプロパティーを適切に設定した後、コード生成を行ってやれば、基本的なUSBホストドライバのコードが自動的に生成されます。ここまでは、非常にお手軽なのですが、問題はこのLDDの使い方について詳しい説明が無いことです。サンプルのプロジェクトとかがあればいいのですが、そのようなサンプルはみなKSDKに含まれるFreescaleのUSBスタックを使っており、USB_LDDとは別のAPIになっているようです。いちおう、USB_LDDのヘルプに簡単な使い方の例が示されているのですが、その例ではドライバの初期化とコントロール転送でSETUPを送るところまでの例しか示されていません。




このサンプルは、デバイスディスクリプタの最初の8バイトだけを読み取るというものなんですが、エニュメレーションの続きの具体例が示されているわけでもないので、自分でAPIの説明を読んで試してみるしかありません。とりあえず、例示されている部分のコードをそのまま書き写してビルド、実行してみたのですがPipe0を開こうとするとエラーになってしまいます。調べてみると、ホストスタックの初期化作業としてバスリセットをやっている際中にPipeを開こうとしてしまうのが原因でした。初期化後ポートの状態がリセット完了になるまで待つコードを追加してやると、正しくSETUPが送られて、ディスクリプタの最初の8バイトが読み取れることがわかりました。

出だしからこの調子なので、これはしばらく楽しめそうです。

USBホスト接続準備

2015-07-05 09:48:16 | Weblog
しばらく次のネタを探していましたが、以前からやるつもりはあったKL26のUSBホスト機能の実験を開始することとしました。使用するのは、積み基板化して埋もれつつあったFRDM-KL26Zです。

FRDM-KL26Zの出荷時設定ではUSBポートはデバイス用に配線されていますので、2箇所に部品を追加してホスト用に配線を変更してやる必要があります。
  1. J9ジャンパを実装して、これをクローズする。これにより、VBUSに5Vがかかってデバイス側に電源が供給されます。
  2. USBコネクタそばにR8(0Ω)を実装。ミニUSBの ID端子がプルダウンされることでホスト側動作に設定します。



USBデバイスをつなぐためには、Mini BオスとAメスの変換ケーブルも必要となります。近所の家電量販店を2店廻ってみましたが、売っているのはMicro Bとの変換ケーブルばかり。しょうがないのでAmazonで探して買い求めしました。



デバイスとしてつないでいるのはBluetoothのUSBドングル。部品箱に転がっているのを見つけました。数年前にかった3.0対応のもののようです。こいつをつなげて BTstackを動かしてみようかと思います。まずはSPPを動かすつもりですが、なんでも近日中にHSP/HFPにも対応予定となっているので、それに期待してI2Sインターフェースを持つKL26を使うことにしました。

Githubでの説明によれば、この夏にでもBLEセントラル側とHSPの認証を取得予定とのことなので、HFP対応にはまだ時間がかかるかもしれません。BLEセントラル側もできると応用範囲も広がりそうです。

Pebble Time

2015-07-03 12:55:35 | Weblog
いつものEEVblogで、Pebble Timeの分解をやっていたので、30分視聴。


初期のPebbleはSTM32F205だったようですが、こいつはSTM32F439になっています。BluetoothがCC2564、加速度センサーがBMI160で、磁気センサーがMAG3110と、入手性の良い部品が使われているのが見ていても楽しいところ。意外だったのは表示がJapan Displayだったこと。E-paperといえば、E-Inkだと思い込んでいました。