Hallo, ich versuche gerade, eine SD-Karte über den USB auszulesen. Die Karte befindet sich an einem LPC2378. Dazu habe ich die USB Mass storage Spezifikation auf dem ARM implementiert. Vorlage war das Buch "USB Mass Storage" von Jan Axelson. Es wird das Bulk Only Protocol benutzt. Leider ist mir nicht ganz klar, welche SCSI-Kommandos unterstützt werden müssen, die Beschreibung einiger Kommandos ist auch in diesem Buch recht rudimentär. Enumeration scheint zu funktionieren, nach dem Anstöpseln des Boards an den USB eine Win-XP PC's ertönt das Windows-Pling und eine Laufwerksbuchstabe erscheint. Das Laufwerk lässt sich öffnen, egal ob eine Karte gesteckt ist oder nicht, hat aber immer Kapazität 0. Meine Debugausgabe zeigt mir, dass folgende SCSI-Kommandos verschickt werden (nur Verkehr auf den BULK endpoints): 1. 0x12 (INQUIRY) 2. 0x23 (READ FORMAT CAPACITY) 3. 0x25 (READ CAPACITY) 4. 0x28 (READ 10) ... -lange Pause -- 5. Reset (2mal) Konkret nun meine Fragen, vielleicht kennt sich jemand hier im Forum aus: 1. Wieso wird READ FORMAT CAPACITY gesendet, laut Spezifikation ist dieses Kommando nur für UFI devices, also Floppy Disks. Was muss ich als "Formattable Capacity" angeben, wenn noch gar keine Karte im SLot steckt? 2. Wie teile ich mit, dass kein Medium im Slot steckt? In diesem Fall setze ich den Descriptor code auf "No Cartridge in Drive", ist das richtig? Warum tut Windows dann so, ob doch ein Medium im Laufwerk ist und sendet Lesebefehle? Was sende ich dann in der Antwort auf READ CAPACITY als maximalen Block ? 0 oder -1? 3. Das READ10 Kommando hat im SCSI Block (CBWCB) eine Transfer Länge von 0, aber das entsprechende Feld CBW.dCBWDataTransferLength ist 0x10000. Wieviele Byte soll ich senden 0 oder 64k? Wenn irgendjemand Informationen dazu hat, wäre ich ihm sehr dankbar. Gruss Mike
Mit den MSD-Dateils kann ich nicht weiterhelfen aber es gibt Code für LPC23xx/24xx zur Inspiration in den Eval.-Versionen von Keil/ARM MDK-ARM (sehr ähnlich dem Code-Bundle von NXP) und IAR EWARM (sehr ähnlich den Beispielen die Olimex bei deren LPC23xx-Boards mitliefert). Zumindest die Handhabung und Verarbeitung SCSI-Kommandos kann man draus ablesen. Zumindest der Olimex/IAR-Code nutzt als Speichermedium wenn richtig erinnert auch SD-Karte via MCI (ist allerdings nicht ganz leicht auf andere Compiler zu übertragen).
Ich habe leider keine konkreten antworten auf die speziellen fragen, aber ein paar links aus meiner recherche zu scsi commands und der spec. Ich habe damit den bootsektor eines usb sticks ausgelesen, also mit einem rechner und den scsi commands, weiter bin ich noch nicht gekommen... schau dir mal das an: http://mcu.emea.fujitsu.com/document/appnotes/Public/16Bit/mcu-an-300243-e-16fx_usb_host_mass_storage/mcu-an-300243-e-v10-16fx_usb_host_mass_storage.pdf http://www.nxp.com/acrobat_download/usermanuals/d12_masssto_usb2ide_cf_guide.pdf http://www.usb.org/developers/devclass_docs/HID1_11.pdf http://ece-www.colorado.edu/~mcclurel/USBDevBrd2.pdf das war meine routine: unsigned char buffer[1024],ibuffer[1024]; bool success; LONG len=0; int i=0; memset(buffer,0x30,1024); memset(ibuffer,0x30,1024); /* get endpoint adress of the first endpoint usb adr 0x02*/ OutEndpt=USBDevice->EndPoints[2]; InEndpt=USBDevice->EndPoints[1]; OutEndpt->TimeOut = 2000; InEndpt->TimeOut = 2000; printf("***************************\n"); printf("* inquiri... *\n"); printf("***************************\n\n"); /* inquiri */ buffer[0]=0x55;// buffer[1]=0x53; buffer[2]=0x42; buffer[3]=0x43; buffer[4]=0x12; buffer[5]=0x23; buffer[6]=0x34; buffer[7]=0x45;// buffer[8]=0x24; buffer[9]=0x00; buffer[10]=0x00; buffer[11]=0x00;// buffer[12]=0x80;//flagbit7 =0 ->host do dev - 1 dev to host buffer[13]=0x00;//cbwlun buffer[14]=0x06;//cbwcblength buffer[15]=0x12;// 0 buffer[16]=0x00;// 1 buffer[17]=0x00;// 2 buffer[18]=0x00;// 3 buffer[19]=0x24;// 4 buffer[20]=0x00;// 5 buffer[21]=0x00;// 6 buffer[22]=0x00;// 7 buffer[23]=0x00;// 8 buffer[24]=0x00;// 9 buffer[25]=0x00;// 10 buffer[26]=0x00;// 11 buffer[27]=0x00;// 12 buffer[28]=0x00;// 13 buffer[29]=0x00;// 14 buffer[30]=0x00;// 15 len=0x1f; success=OutEndpt->XferData(buffer,len); printf("sending answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); /*read inquiri data*/ len=0x24; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0x24) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } i=0; while(i<0x24) { if(i%16==0) { printf("\n %08x:",i); } printf(" %c",ibuffer[i]); i++; } printf("\n\n"); /*read inquiri csw*/ len=0xd; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0xd) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } printf("\n\n"); /* read capacity */ printf("***************************\n"); printf("* reading capacity... *\n"); printf("***************************\n\n"); memset(buffer,0x30,1024); memset(ibuffer,0x30,1024); buffer[0]=0x55;// buffer[1]=0x53; buffer[2]=0x42; buffer[3]=0x43; buffer[4]=0xaa; buffer[5]=0xff; buffer[6]=0xee; buffer[7]=0x00;// buffer[8]=0x08; buffer[9]=0x00; buffer[10]=0x00; buffer[11]=0x00;// buffer[12]=0x80;//flagbit7 =0 ->host do dev - 1 dev to host buffer[13]=0x00;//cbwlun buffer[14]=0x0a;//cbwcblength buffer[15]=0x25;// 0 buffer[16]=0x00;// 1 buffer[17]=0x00;// 2 buffer[18]=0x00;// 3 buffer[19]=0x00;// 4 buffer[20]=0x00;// 5 buffer[21]=0x00;// 6 buffer[22]=0x00;// 7 buffer[23]=0x00;// 8 buffer[24]=0x00;// 9 buffer[25]=0x00;// 10 buffer[26]=0x00;// 11 buffer[27]=0x00;// 12 buffer[28]=0x00;// 13 buffer[29]=0x00;// 14 buffer[30]=0x00;// 15 len=0x1f; success=OutEndpt->XferData(buffer,len); printf("sending request: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); /*read capacity data*/ len=0x8; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0x8) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } i=0; while(i<0x8) { if(i%16==0) { printf("\n %08x:",i); } printf(" %c",ibuffer[i]); i++; } printf("\n\n"); printf("Capacity is: %iMb\n",((ibuffer[0]*0x1000000+ ibuffer[1]*0x10000+ ibuffer[2]*0x100+ ibuffer[3])* (ibuffer[4]*0x1000000+ ibuffer[5]*0x10000+ ibuffer[6]*0x100+ ibuffer[7]))/1048576); len=0xd; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0xd) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } i=0; while(i<0xd) { if(i%16==0) { printf("\n %08x:",i); } printf(" %c",ibuffer[i]); i++; } printf("\n\n"); /* read capacity */ printf("***************************\n"); printf("* reading mbr... *\n"); printf("***************************\n\n"); memset(buffer,0x30,1024); memset(ibuffer,0x30,1024); buffer[0]=0x55;// buffer[1]=0x53; buffer[2]=0x42; buffer[3]=0x43; buffer[4]=0x00; buffer[5]=0xaa; buffer[6]=0xff; buffer[7]=0xcd;// buffer[8]=0x00; buffer[9]=0x02; buffer[10]=0x00; buffer[11]=0x00;//trans len = 512byte buffer[12]=0x80;//flagbit7 =0 ->host do dev - 1 dev to host buffer[13]=0x00;//cbwlun buffer[14]=0x0a;//cbwcblength buffer[15]=0x28;// 0 command code "read" buffer[16]=0x00;// 1 reserved buffer[17]=0x00;// 2 buffer[18]=0x00;// 3 buffer[19]=0x00;// 4 buffer[20]=0x00;// 5 logical adr buffer[21]=0x00;// 6 reserved buffer[22]=0x00;// 7 buffer[23]=0x01;// 8 one block buffer[24]=0x00;// 9 buffer[25]=0x00;// 10 buffer[26]=0x00;// 11 buffer[27]=0x00;// 12 buffer[28]=0x00;// 13 buffer[29]=0x00;// 14 buffer[30]=0x00;// 15 len=0x1f; success=OutEndpt->XferData(buffer,len); printf("sending request: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); /*read mbr data*/ len=0x200; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0x200) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } i=0; while(i<0x200) { if(i%16==0) { printf("\n %08x:",i); } if(ibuffer[i]>0x20&&ibuffer[i]<0x80) { printf(" %c",ibuffer[i]); } else { printf(" ."); } i++; } printf("\n\n"); len=0xd; success=InEndpt->XferData(ibuffer,len); printf("receiving answer: "); if(success) { printf("success"); } else { printf("fail"); } printf("\n\n"); i=0; while(i<0xd) { if(i%16==0) { printf("\n %08x:",i); } printf(" %02x",ibuffer[i]); i++; } i=0; while(i<0xd) { if(i%16==0) { printf("\n %08x:",i); } printf(" %c",ibuffer[i]); i++; } printf("\n\n"); vielleicht hilft es weiter, gruß, w.
Danke für die Tips, nach langem Suchen habe ich den Fehler gefunden: SCSI Parameter sind BIG Endian, der ARM aber Little endian. Ich hätte eher darauf kommen können. Dadurch wurden unsinnige Parameter beim READ CAPACITY Befehl an den Mass Storage Treiber von Windows übermittelt, wodurch dieser verwirrt wurde. Inzwischen kann ich schon mal eine SD-Karte lesen, schreiben kommt später. Gruss Mike
Hurra, es klappt! Meine SD-Karte wird erkannt und kann gelesen und geschrieben werden. Läuft unter Windows stabil, leider noch nicht mit Linux, woran könnte das liegen? Die Geschwindigkeit ist noch nicht so berauschend, vielmehr dürfte aber bei USB Full speed nicht drin sein. Zum Test habe ich eine 495 Mb Datei auf eine leere 4G SD Karte geschrieben und wieder heruntergelesen: Lesen: 495831 kB: 885 s <> 560 kB/s Schreiben: 495831 kB: 875 s <> 554 kB/s Lesen ist also nur marginal schneller als Schreiben. In einem Standard USB-Kartenleser schafft die Karte 12.7 Mb/s beim Lesen und 7.3 beim Schreiben. Aber der hat ja auch High-Speed. Gruss Mike
> nach langem Suchen habe ich den Fehler gefunden: SCSI Parameter sind BIG > Endian, der ARM aber Little endian. [...] Haha, wie oft bin ich selber darauf schon reingefallen. Ich weiss echt nicht, warum man die Bits und Bytes nicht einfach überall in der natürlichen Reihenfolge abspeichern kann.
Und welche ist Deiner Ansicht nach die "natürliche" Reihenfolge? Die Verfechter beider Varianten sehen ihre als die "natürliche" an ...
> Und welche ist Deiner Ansicht nach die "natürliche" Reihenfolge? Die > Verfechter beider Varianten sehen ihre als die "natürliche" an ... Jetzt bitte keinen Streit! Das ist genaus sinnvoll wie die Frage, an welchem Ende man das Frühstücksei aufschlagen sollte! (s. Gulliver's Reisen). Fakt ist jedoch, dass die meisten heutigen Prozessoren Little-endian sind. Big-endian gibt es eigentlich nur beim 68000 und deren Derivaten, z.B. PowerPC. Vermutlich stammt SCSI aus Zeiten, in denen der 68000 noch stark verbreitet war, d.h. vor der Intel-Dominanz. Gruss Mike
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.