2023年2月25日土曜日

【Android USB oscilloscope】(33) USB2.0 BULK転送 3MByte/Sec

USB2.0で、STM32をUSB hostとし、USB deviceであるスマホを接続する.こういう図になっている.
これで転送レートは3MByte/SecのBULK転送が限界という結果を得ました.スマホのUSB受信はUIとは別のスレッドでやってます.もっと速くなってほしいんですけど、残念です.
ちなみに、こちらで書いたようにUSB2.0で16MByte/Secを出した実績はありますが、EZ-USBとLinuxの組み合わせであって、スマホが16MByte/Secを出すのは難しいみたいです.

今回の実験の諸条件です.
 USB    2.0 BULK transfer 512Byte packet
 スマホ   2016年製 HUAEWI P9-Lite Android7
 CPU    STM32F205
 開発環境1 STM32CubeIDE 1.5.1
 開発環境2 Android Studio Bumblebee 2021.1.1 Patch2

接続状況の写真.
白い変換コネクタはOTG cableではありますが、OTGを目的とした使い方ではなく、ただのマイクロ-タイプA変換として使っています.

動作を詩的に表現するとこんなことをやっています.
 0)USB cableが挿されたらAOA接続する ※
 1)hostであるSTM32は、10mSec割込みでBULK転送を試みる
  1a)USBがNAKだったら何もしない
  1b)USBがACKなら511BYTEをBULK転送する(512だとスマホがhungる)
  1c)NAK比率をCOM portに出力表示する
 2)スマホは、MainActivity内のRunnableで1000回USB read loopを記述する
  2a)スマホのボタンが押されるとRunnnableが起動される
  2b)Runnable内で転送レートを計算しUIに表示する

(※)スマホのUSB接続は特殊です.USB hostにスマホ(USB device)を挿すと、descriptorのやり取りなどを経て、一旦USBを切断し、再度接続するという凝ったことをします.AOAという作法です.AOAについてはこちらに書きました.

スマホアプリ画面.
READボタンを押すと数値が更新されます.4番が転送レートです.

STM32とスマホの接続.
スマホアプリを起動しておいてからUSB cableを接続する感じ.スマホから接続許可を求められます.ダメだったらSTM32のresetをするとかいろいろ試す.

STM32とPCの接続.
STM32の内部状態を表示するためのものです.FT232のようなUSB COM変換が必要です.

sourceと回路図の詰め合わせzipをupしておきます.テストコード満載の糞コードですのでゲロです、反吐です、要注意です.読者に損害を与えましても賠償とかしません.

ーーーー
STM32ソースの簡単な説明.

まずAOA接続について.
AOA接続の手続きは、main loopから繰り返しcallされています.
  while (1)  {
    MX_USB_HOST_Process(); // invoke AOA procerss
  略
  }
MX_USB_HOST_Process()の先ではUSBH_Process()をcallしてるのでそっちへ行きます.
この関数ではUSB接続時の手続きがいろいろ記述されていて、USB classを分析とかしていますが、知らないUSB classに悩んでabortする間際に藁を掴んでaoa_setupAccessory()をcallします.そこからAOA接続が始まります.
Linux hostのAOA接続についてはこちらを参照.これをSTM32に移植して動かしています.
AOAが接続成功した結果、OUT方向の設定は「EP2 max packet size 512Byte」になりました.いままでpacketを2000ByteとかにできないのはSTM32のバグだと何度も書きましたが、スマホにも512で制限かかってます.ちっ、なんだかなー

次にBULK転送について.
TIM7で10mSec割込みをかけています.割り込みルーチンでBULK転送をcallします.
void TIM7_IRQHandler(void){
if(aoa_ok==2) aoa_bulkTransfer(&hUsbHostHS);
}
aoa_bulkTransfer()を見ると、USBH_BulkSendData()をcallしています.511ByteでDMAです.そんな頻繁にBULK転送しようとしてもUSBが追い付きゃしませんが、構わずcallする理由は、USB statusを採取するためです.BUSYだったら無視されます.
void aoa_bulkTransfer( USBH_HandleTypeDef *phost ) {
USBH_BulkSendData(phost, buffer, 511, phost->Control.pipe_out, 1);
}

ーーーー
スマホアプリの簡単な説明.

一番最初、スマホにUSB cableが挿された時に、このアプリにeventが飛んできてもらわなくちゃ困りますよね.このアプリが「USB挿入で声かけてくれ」とOSに依頼する仕組みをintent-filterと呼ぶそうです.projectの中のAndroidManifest.xmlを開くと、USB device attachedという文字があります.細かくは知りませんがこんなもんだっつうことで.
<intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />

次のUSB接続過程はAOAです.accessory_filter.xmlを開くと見える文字があります.
 manufacturer="bangflat" model="aoatest"
この2つは、STM32 hostのAOAルーチンにも記述されており、AOAの先頭で軽く認証するのに使われます.hostとdeviceで一致してなくちゃいけません.あとはスマホがやってくれます.

USB BULK受信について.
MainActivity.ktの中で別スレッドを記述します.USBの受信を1000回やってます.usbDriverが肝です.
    val runnable = object : Runnable {
        override fun run() {
            for (i in 0..999) {
                try {
                    val rmsg: String = usbDriver!!.receive()
                    USBparams.sum += rmsg.length
                } catch (e: IOException) {
                    errorDialog(e.message)
                }
MainActivity.ktのonCreateの中で、READボタンが押されたらRunnableを起動するようにしてます.別スレッドでUSBの1000回readが始まります.
  b.IDreadBTN.setOnClickListener {
  handle.post(runnable)
 }

ーーーー
3MByte/Secでは不満なので、以上で投了です.

次はスマホをUSB hostにするやり方でトライしてみます.出来るかどうかは知りません.

32へ    34へ

かしこ

0 件のコメント:

コメントを投稿