今までファイル転送のたびに専用のカードリーダにSDカードを移して読み書きしていました。
地味にこの作業はめんどくさいものがあります。
そこで前回STBeeにMass Storage Classを実装できたので今度はシームレスなファイル転送を目指してみました。
↑マウント後、画像データをコピーしてアンマウントし、STBeeでコピーした画像を表示させている様子です。
専用カードリーダにSDカードを移さなくてもファイル転送ができるため楽です。
ただしFull Speedデバイスなため、数百メガバイト以上の大きなデータを移動するにはめちゃくちゃ時間かかりますが(^_^;A

↑SDカードをマウントしたときの画面
カードアクセス時にサーキュラープログレスバーをアニメーション表示してクルクル回るようにしてみました。
MSCはこの辺で区切りつけてそろそろ違うことがしたくなってきた(*ω*)~*
地味にこの作業はめんどくさいものがあります。
そこで前回STBeeにMass Storage Classを実装できたので今度はシームレスなファイル転送を目指してみました。
↑マウント後、画像データをコピーしてアンマウントし、STBeeでコピーした画像を表示させている様子です。
専用カードリーダにSDカードを移さなくてもファイル転送ができるため楽です。
ただしFull Speedデバイスなため、数百メガバイト以上の大きなデータを移動するにはめちゃくちゃ時間かかりますが(^_^;A

↑SDカードをマウントしたときの画面
カードアクセス時にサーキュラープログレスバーをアニメーション表示してクルクル回るようにしてみました。
MSCはこの辺で区切りつけてそろそろ違うことがしたくなってきた(*ω*)~*
STBeeボード(STM32マイコン)にUSBのMass Storage Class(マスストレージクラス)実装しました。

Windows XPで認識している様子

ドライブプロパティ
SCSIコマンドは以下の最低6つ実装すれば一応動くようになります。
TEST UNIT READY (00h)
REQUEST SENSE (03h)
INQUERY (12h)
READ CAPACITY (25h)
READ10 (28h)
WRITE10 (2Ah)
未実装のSCSIコマンドが来た場合、CSWでFAILを返し、次に来るREQUEST SENSEでInvalid Commandを返します。
どれくらいのスピードがでるか測ってみた。
まずはLinuxのddコマンドで1MBのデータ送受信をやってみた結果。
STBeeボード STM32F103VET6@72MHz SDIO:24MHz 4bit-wide
リード
>dd if=/dev/sdb of=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 1.80552 s, 581 kB/s
ライト
>dd of=/dev/sdb if=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 4.93733 s, 212 kB/s
CrystalDiskMarkで測った結果。

あれ?ddで測ったほうが遅い?
ddは直接ドライブにブロッグ単位でデータを転送するためファイルシステムを使うCrysralDiskMarkより速いと思ってましたがそうではないようです。
調べてみるとddは一回に8セクタ単位(4096バイト)で送受信していたのに対し、CrystalDiskMarkはもっと大きい64セクタや128セクタ単位で送受信していました。
ddは何度もパケットを送受信する分、CBWやCSWのコマンドラッパーやステータス応答等のオーバーヘッドが占める割合が増加しているのだと思います。
疑り深い性分なので今度は50MBのファイルの転送にかかる時間をtimeコマンドで測ってみた。
リード
$ time cp /cygdrive/d/data.img .
real 0m57.415s → 913KB/s
ライト
$ time cp data.img /cygdrive/d/
real 1m13.793s → 710KB/s
CrystalDiskMarkのベンチに近い!
Full Speed 12Mbps(1.5MB/s)の理論上の最大速度から1/2以上のスループットがでてます。
測り方次第でいろいろ違ってくるなぁー。どれを基準にすれば\(^o^)/
参考までにAVRで測った場合。STBeeで測ったときと同じカードで測ってます。
ATmega32U2@16MHz SDカードはSPIクロック8MHzで読書き
リード
>dd if=/dev/sdb of=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 5.14064 s, 204 kB/s
ライト
>dd of=/dev/sdb if=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 9.77148 s, 107 kB/s
STBeeはAVRに比べてリードは約3倍、ライトは約2倍速いといったところです。
ちなみにSDカードの読込みはマルチブロックリード(CMD18)、書込みはプリイレース後(ACMD23)にマルチブロックライト(CMD25)をしてます。
実はSTBeeにはまだ改良の余地があります。
エンドポイントにダブルバッファ機能がついているのでこれを使えば大幅な速度向上が見込めるかもしれません。
実装難しい・・・。
dmesg
cat /proc/bus/usb/devices
cat /proc/scsi/scsi
lsusb -v

Windows XPで認識している様子

ドライブプロパティ
SCSIコマンドは以下の最低6つ実装すれば一応動くようになります。
TEST UNIT READY (00h)
REQUEST SENSE (03h)
INQUERY (12h)
READ CAPACITY (25h)
READ10 (28h)
WRITE10 (2Ah)
未実装のSCSIコマンドが来た場合、CSWでFAILを返し、次に来るREQUEST SENSEでInvalid Commandを返します。
どれくらいのスピードがでるか測ってみた。
まずはLinuxのddコマンドで1MBのデータ送受信をやってみた結果。
STBeeボード STM32F103VET6@72MHz SDIO:24MHz 4bit-wide
リード
>dd if=/dev/sdb of=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 1.80552 s, 581 kB/s
ライト
>dd of=/dev/sdb if=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 4.93733 s, 212 kB/s
CrystalDiskMarkで測った結果。

あれ?ddで測ったほうが遅い?
ddは直接ドライブにブロッグ単位でデータを転送するためファイルシステムを使うCrysralDiskMarkより速いと思ってましたがそうではないようです。
調べてみるとddは一回に8セクタ単位(4096バイト)で送受信していたのに対し、CrystalDiskMarkはもっと大きい64セクタや128セクタ単位で送受信していました。
ddは何度もパケットを送受信する分、CBWやCSWのコマンドラッパーやステータス応答等のオーバーヘッドが占める割合が増加しているのだと思います。
疑り深い性分なので今度は50MBのファイルの転送にかかる時間をtimeコマンドで測ってみた。
リード
$ time cp /cygdrive/d/data.img .
real 0m57.415s → 913KB/s
ライト
$ time cp data.img /cygdrive/d/
real 1m13.793s → 710KB/s
CrystalDiskMarkのベンチに近い!
Full Speed 12Mbps(1.5MB/s)の理論上の最大速度から1/2以上のスループットがでてます。
測り方次第でいろいろ違ってくるなぁー。どれを基準にすれば\(^o^)/
参考までにAVRで測った場合。STBeeで測ったときと同じカードで測ってます。
ATmega32U2@16MHz SDカードはSPIクロック8MHzで読書き
リード
>dd if=/dev/sdb of=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 5.14064 s, 204 kB/s
ライト
>dd of=/dev/sdb if=~/image.img bs=512 count=2048
1048576 バイト (1.0 MB) コピー終了, 9.77148 s, 107 kB/s
STBeeはAVRに比べてリードは約3倍、ライトは約2倍速いといったところです。
ちなみにSDカードの読込みはマルチブロックリード(CMD18)、書込みはプリイレース後(ACMD23)にマルチブロックライト(CMD25)をしてます。
実はSTBeeにはまだ改良の余地があります。
エンドポイントにダブルバッファ機能がついているのでこれを使えば大幅な速度向上が見込めるかもしれません。
実装難しい・・・。
dmesg
usb 2-1: new full speed USB device using uhci_hcd and address 2
usb 2-1: configuration #1 chosen from 1 choice
Initializing USB Mass Storage driver...
scsi2 : SCSI emulation for USB Mass Storage devices
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usb-storage: device found at 2
usb-storage: waiting for device to settle before scanning
usb-storage: device scan complete
scsi 2:0:0:0: Direct-Access Tonsuke STBee SD Reader 1.00 PQ: 0 ANSI: 2
sd 2:0:0:0: Attached scsi generic sg2 type 0
sd 2:0:0:0: [sdb] 7733248 512-byte logical blocks: (3.95 GB/3.68 GiB)
sd 2:0:0:0: [sdb] Test WP failed, assume Write Enabled
sd 2:0:0:0: [sdb] Assuming drive cache: write through
sd 2:0:0:0: [sdb] Test WP failed, assume Write Enabled
sd 2:0:0:0: [sdb] Assuming drive cache: write through
sdb: sdb1
sd 2:0:0:0: [sdb] Test WP failed, assume Write Enabled
sd 2:0:0:0: [sdb] Assuming drive cache: write through
sd 2:0:0:0: [sdb] Attached SCSI removable disk
cat /proc/bus/usb/devices
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=abcd ProdID=1234 Rev= 1.00
S: Manufacturer=Tonsuke
S: Product=STBee SD Card Reader
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
cat /proc/scsi/scsi
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: Tonsuke Model: STBee SD Reader Rev: 1.00
Type: Direct-Access ANSI SCSI revision: 02
lsusb -v
Bus 002 Device 002: ID abcd:1234 Unknown
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0xabcd Unknown
idProduct 0x1234
bcdDevice 1.00
iManufacturer 1 Tonsuke
iProduct 2 STBee SD Card Reader
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 8 Mass Storage
bInterfaceSubClass 6 SCSI
bInterfaceProtocol 80 Bulk (Zip)
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled
STBeeボードをマスストレージクラスデバイスとして動かすため、連日実装作業に没頭しております。
ようやくエニュメレーション処理が一応できた。

テキトーな製品IDとベンダIDを割り当ててます。
カードリーダということでSTBee SD Card Readerと名付けてます。
↓Macでのエニュメレーションの様子
数字の羅列はホストから送られてきたデバイスリクエストです。
デバイス検出
RESET
SUSPEND
RESET
SUSPEND
RESET
80 06 00 01 00 00 00 08 GET_DESCRIPTOR->DEVICE_DESCRIPTOR
00 05 02 00 00 00 00 00 SET_ADDRESS
80 06 00 01 00 00 12 00 GET_DESCRIPTOR->DEVICE_DESCRIPTOR
80 06 02 03 09 04 02 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_PRODUCT_ID
80 06 02 03 09 04 2A 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_PRODUCT_ID
80 06 01 03 09 04 02 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_VENDOR_ID
80 06 01 03 09 04 10 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_VENDOR_ID
80 06 00 02 00 00 04 00 GET_DESCRIPTOR->CONFIGURATION_DESCRIPTOR
80 06 00 02 00 00 20 00 GET_DESCRIPTOR->CONFIGURATION_DESCRIPTOR
00 09 01 00 00 00 00 00 SET_INTERFACE
A1 FE 00 00 00 00 01 00 GETMAXLUN
GETMAXLUNで0(論理ドライブ)を返すといよいよSCSIコマンド通信。
↓自作MSCデバイスのデスクリプタ全体
もう少しだぁo(´∀`)o
ようやくエニュメレーション処理が一応できた。

テキトーな製品IDとベンダIDを割り当ててます。
カードリーダということでSTBee SD Card Readerと名付けてます。
↓Macでのエニュメレーションの様子
数字の羅列はホストから送られてきたデバイスリクエストです。
デバイス検出
RESET
SUSPEND
RESET
SUSPEND
RESET
80 06 00 01 00 00 00 08 GET_DESCRIPTOR->DEVICE_DESCRIPTOR
00 05 02 00 00 00 00 00 SET_ADDRESS
80 06 00 01 00 00 12 00 GET_DESCRIPTOR->DEVICE_DESCRIPTOR
80 06 02 03 09 04 02 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_PRODUCT_ID
80 06 02 03 09 04 2A 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_PRODUCT_ID
80 06 01 03 09 04 02 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_VENDOR_ID
80 06 01 03 09 04 10 00 GET_DESCRIPTOR->STRING_DESCRIPTOR->STRING_VENDOR_ID
80 06 00 02 00 00 04 00 GET_DESCRIPTOR->CONFIGURATION_DESCRIPTOR
80 06 00 02 00 00 20 00 GET_DESCRIPTOR->CONFIGURATION_DESCRIPTOR
00 09 01 00 00 00 00 00 SET_INTERFACE
A1 FE 00 00 00 00 01 00 GETMAXLUN
GETMAXLUNで0(論理ドライブ)を返すといよいよSCSIコマンド通信。
↓自作MSCデバイスのデスクリプタ全体
Full Speed device @ 2 (0x1D100000): Composite device: "STBee SD Card Reader"
Port Information: 0x001a
Not Captive
Attached to Root Hub
External Device
Connected
Enabled
Device Descriptor
Descriptor Version Number: 0x0110
Device Class: 0 (Composite)
Device Subclass: 0
Device Protocol: 0
Device MaxPacketSize: 64
Device VendorID/ProductID: 0xABCD/0x1234 (unknown vendor)
Device Version Number: 0x0100
Number of Configurations: 1
Manufacturer String: 1 "Tonsuke"
Product String: 2 "STBee SD Card Reader"
Serial Number String: 0 (none)
Configuration Descriptor
Length (and contents): 32
Raw Descriptor (hex) 0000: 09 02 20 00 01 01 00 A0 32 09 04 00
00 02 08 06
Raw Descriptor (hex) 0010: 50 00 07 05 81 02 40 00 00 07 05 02
02 40 00 00
Unknown Descriptor 0020:
Number of Interfaces: 1
Configuration Value: 1
Attributes: 0xA0 (bus-powered, remote wakeup)
MaxPower: 100 ma
Interface #0 - Mass Storage/SCSI
Alternate Setting 0
Number of Endpoints 2
Interface Class: 8 (Mass Storage)
Interface Subclass; 6 (SCSI)
Interface Protocol: 80
Endpoint 0x81 - Bulk Input
Address: 0x81 (IN)
Attributes: 0x02 (Bulk no synchronization data endpoint)
Max Packet Size: 64
Polling Interval: 0 ms
Endpoint 0x02 - Bulk Output
Address: 0x02 (OUT)
Attributes: 0x02 (Bulk no synchronization data endpoint)
Max Packet Size: 64
Polling Interval: 0 ms
もう少しだぁo(´∀`)o








