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番が転送レートです.
スマホアプリを起動しておいてからUSB cableを接続する感じ.スマホから接続許可を求められます.ダメだったらSTM32のresetをするとかいろいろ試す.
STM32とPCの接続.
STM32の内部状態を表示するためのものです.FT232のようなUSB COM変換が必要です.
ーーーー
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にするやり方でトライしてみます.出来るかどうかは知りません.
かしこ