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