Forum: Mikrocontroller und Digitale Elektronik USB Mass Storage mit ARM LPC


von Mike (Gast)


Lesenswert?

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

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

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).

von whitenoise (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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

von Mike (Gast)


Lesenswert?

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

von Ralf S. (spacedog) Benutzerseite


Lesenswert?

> 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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Und welche ist Deiner Ansicht nach die "natürliche" Reihenfolge? Die 
Verfechter beider Varianten sehen ihre als die "natürliche" an ...

von Mike (Gast)


Lesenswert?

> 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

von Daniel (Gast)


Lesenswert?

Hi, Mike, kannst du deinen Quellcode hier posten? Gruß Daniel

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
Noch kein Account? Hier anmelden.