2019年12月20日金曜日

EZ-USB FX2LP を動かしてみる (33) Audio Control Requestsというもの

年末です.誰かスターウォーズのラストを教えてくれないかな? わたしはその程度のSWファン度ですから.

年末なので久しぶりのEZ-USBです.

話せば長いことながら、簡単に言えばEZ-USBでDDCを自作できないかな?というのが最近のテーマです.経緯を振り返ります.

とても参考にさせていただいているのがこのサイトです.
  EZ-USB: Self made usb audio with Audio Class 1.0 interface (1/3)
  EZ-USB: Self made usb audio with Audio Class 1.0 interface (2/3)
このサイトにはTIのPCM2704というUSB DACのデバイスディスクリプタを真似たデバイスディスクリプタを掲載しているので、わたしもそれを真似てEZUSBを動かしてみました.
  EZ-USB FX2LP を動かしてみる (31)Audio class device descriptor
  EZ-USB FX2LP を動かしてみる (32) descriptorを読んでblock図を描いてみた
ここまでで、windowsのデバマネは「USBオーディオデバイス」と認識はしています.ただし三角マークがついていて稼動はしていません.どうやったら稼働させられるのでしょう?
参考サイトの(2/3)に気になる文言が書かれています.
「AudioControl Requests」は、「Get Terminal Control Request」に対応しておけば取り敢えずWindowsで認識はされるみたい。
これは重要情報ではないかな? これに対応すればデバドラが稼動するのでしょうか? でも対応って何をすればいいんだろう?

ということで、Audio Control Requestとは何かを調べました.

各種文献を渉猟した(うそ)わたしはAudio Control Requestを発見しました.
USB Audio Class 1.0の68ページにあります.
これが何を意味しているのか? それはあとで.

------
PCM2704擬態USBデバイスをwindowsに接続したとき「Get Terminal Control Request」がwindowsから飛んでくるはずです.それを観測してみたいと思います.

どうやって観測するか?  ハードウエアはこの写真です.
下側の基板は言わずと知れたEZUSB FX2LPが載った基板です.上は自作のArduino clone基板です.

2つの基板はSDA/SCLで接続されています.つまりI2Cで通信しています.EZUSBがI2C masterで、ArduinoがI2C slaveです.
EZUSBのfirmwareに、リクエストが来たらI2Cにメッセージを送信するような小細工をしておきます.
ArduinoはI2Cを読んでそれをCOM portへ転送します.
windowsのterminalはCOM portのキャラクタを表示します.

こういう仕組みによって、EZUSBのリクエスト状況を観測できます.

-----
EZUSBってI2Cが使えるの?って思うでしょう.datasheetにはしっかりI2Cと書かれています.Cypress提供のサンプルプログラムもあります.EZUSB.libとしてライブラリも提供されています.

EZUSBでI2Cを使うための勘所を少し書きます.

1)ライブラリソースは、i2c.cとi2c_rw.cの2つです.CypressからDLしたsampleの中を徘徊して探してください.projectの中に2つのファイルを入れます.関数のprototypeはfx2.hに記入済みで提供されています.

2)main()の最初の方に、EZUSB_InitI2C(); を書きます.I2C初期化です.

3)I2Cへ文字列を送信するには、EZUSB_WriteI2C(addr, strlen(dat), dat); を使います.
第1引数addrは、I2C slave addressです.わたしは12で運用してますが、3bitしか採用されないと何処かに書かれていた気がする.あとEEPROMが1番ですので1は使わない方がいいでしょう.
第2引数は送信する文字数.strlen()はstring.hをincludeすれば使えるみたいよ.
第3引数datが文字列のアドレスです.Keil IDEの癖ですけど、char dat[];のように宣言すると文字化けしちゃいます.BYTE xdata dat[];と宣言しないと正しく動きませんでした.普段はgccのキャストの賢さに甘えすぎているんだろうなぁ.

4)Cypressのサンプルにおいて、リクエストt処理は SetupCommand() に記述されています.その中のお好みの場所に、EZUSB_WriteI2C()を入れておけば何が起きているかをwidowsのterminalで観測できるようになります.

5)I2CやCOMの通信速度の遅さで文字化けするときは、EZUSB_Delay(N); をつかって無駄時間を与えましょう.NはmSecです.

6)各種割り込みルーチン内でEZUSB_WriteI2C()をcallするとEZUSBはhung-upしますのでやめておきましょう.


Arudinoのソースはこれだけです.解説はしませんが参考まで.
#include <Wire.h>
void setup() {
  Wire.begin(12);  // join i2c bus as slave address 12
  //Wire.setClock(100000);  // i2c clock 100kHz
  Wire.onReceive(isr_i2c_slave);
  Serial.begin(115200);  // start serial for output
}
void loop() {}
void isr_i2c_slave() {
    while (Wire.available()) {
      char c;
      c = Wire.read(); // receive a byte as character
      Serial.print(c); // print the character
    }
}

------
前置きがとても長くなりました.

EZUSBが受信したリクエストを観測できました.まず結果を記します.
先頭の8BYTEはセットアップトークンのセットアップデータです.
80 06 00 01 00 00 40 00 GetDesc
80 06 00 01 00 00 12 00 GetDesc
80 06 00 02 00 00 FF 00 GetDesc
80 06 00 03 00 00 FF 00 GetDesc
80 06 02 03 09 04 FF 00 GetDesc
80 06 00 01 00 00 12 00 GetDesc
80 06 00 02 00 00 09 00 GetDesc
80 06 00 02 00 00 91 00 GetDesc
00 09 01 00 00 00 00 00 SetConfig
01 0B 00 00 01 00 00 00 SetInter
80 06 02 03 09 04 04 00 GetDesc
80 06 02 03 09 04 16 00 GetDesc
80 06 02 03 09 04 04 00 GetDesc
80 06 02 03 09 04 16 00 GetDesc
80 06 02 03 09 04 04 00 GetDesc
80 06 02 03 09 04 16 00 GetDesc
A1 81 00 01 00 03 01 00 VendCom  ←Get Terminal Control Request
21 0A 00 00 02 00 00 00 GetInter
81 06 00 22 02 00 64 00 GetDesc
80 06 00 01 00 00 40 00 GetDesc
80 06 00 01 00 00 12 00 GetDesc
80 06 00 02 00 00 FF 00 GetDesc
00 09 01 00 00 00 00 00 SetConfig
01 0B 00 00 01 00 00 00 SetInter
02 01 00 00 81 00 00 00 ClrFeat
81 06 00 22 02 00 64 00 GetDesc
80 06 00 01 00 00 40 00 GetDesc
80 06 00 01 00 00 12 00 GetDesc
80 06 00 02 00 00 FF 00 GetDesc
00 09 01 00 00 00 00 00 SetConfig
01 0B 00 00 01 00 00 00 SetInter
02 01 00 00 81 00 00 00 ClrFeat
81 06 00 22 02 00 64 00 GetDesc
80 06 00 01 00 00 40 00 GetDesc
80 06 00 01 00 00 12 00 GetDesc
80 06 00 02 00 00 FF 00 GetDesc
00 09 01 00 00 00 00 00 SetConfig
01 0B 00 00 01 00 00 00 SetInter
02 01 00 00 81 00 00 00 ClrFeat

セットアップデータを読み解くにはこの表を使います.
ただしこの表で読み解けないのが1つだけあって、
  A1 81 00 01 00 03 01 00   VendCommand
のところです.
vendor commandというのは、EZUSB firmwareが知らないコマンドは「ベンダーが勝手に作ったコマンドなんじゃね?オレ知らないし」と判断したという程度の意味です.EZUSBのサンプルソースがそうなってます.

上で示したAudio class資料を再掲しますと、先頭バイトはA1になってるので、ああこれがGet Terminal Control Requestなのだなと想像されます.
A1 81 00 01 00 03 01 00 を解析してみます.
 A1  デバイス→ホストの方向、ベンダ用件、interfaceについて
 81  GET_CUR   今の状態を返答してくれ
 00  (下位)
 01  (上位) control selector  -->COPY_PROTECT_CONTROL   ←間違い
 00  (下位)
 03  (上位) terminal ID   -->ここでは3番はFeature Unitを指すようだ
 01  (下位) length 1 BYTE
 00  (上位)

windowsから飛んできたGet Terminal Control Requestの解析は以上であります.
これを人間の言葉に翻訳するとこうゆうことなのかと思います.
「windowsはUSB deviceに要求します.Feature Unit 3のcopy protect levelについて返答して下さい.返答の長さは1BYTEでよろしく」

USB Audio class 1.0の中にcopy protectについて書かれています.コピープロテクトなしを返答したければ、0を返信すればよいみたいです.
0: CPL0: Copying is permitted without restriction.
1: CPL1: One generation of copies may be made.
2: CPL2: The material is copyright protected and no digital copying is permitted.
次回で訂正しますが、これはcopy protectではなくて、muteのようです.

この投稿の最初の方で引用したこの部分.
「AudioControl Requests」は、「Get Terminal Control Request」に対応しておけば
取り敢えずWindowsで認識はされるみたい。
これが述べる「対応しておけば」の意味は、ゼロを返信することなのではないかな?

ということがわかったところで今日はおしまいです.EZUSB firmwareへの実装は後日.

かしこ

→INDEXページへ

0 件のコメント:

コメントを投稿