Forum: Mikrocontroller und Digitale Elektronik SD Karte (SDIO) Multi Block Operationen Ende


von M. Н. (Gast)


Lesenswert?

Hallo,


ich bin gerade dabei einen eigenen Treiber für das SDIO Modul des 
STM32F4 zu schreiben.

Ich habe eine Frage zu den Multiple Block Operationen (Read/Write).
Laut Spec, muss ich am Ende der Sequenz CMD12 (Stop transmission) 
senden, um die operation sauber zu beenden.

Ich habe mir einige Codes angeschaut, auch von einem LPC1788 mit 
ähnlichem Interface.

Dort wird zum lesen nur das Kommando für Multi-Block-Read gesendet und 
dann empfangen. Es wird nie ein Stop Kommando gesendet.

Da ich im SDIO Modul die Länge der Übertragung angeben kann, wäre eine 
Möglichkeit, dass der SDIO Controller eine Art Token sendet, dass der SD 
Karte anzeigt, dass die notwendige Anzahl an Blöcken übertragen wurde.

Leider finde ich im Reference Manual des Controllers und auch in der 
Spec der SD Karte so etwas nicht für SDIO, nur SPI.

Wie implementiert man diese Multi-Block Zugriffe richtig?
Muss ich ein Stop Command (CMD12) senden?

Vielen Dank

von Jim M. (turboj)


Lesenswert?

M. H. schrieb:
> Dort wird zum lesen nur das Kommando für Multi-Block-Read gesendet und
> dann empfangen. Es wird nie ein Stop Kommando gesendet.

Simplfied Spec 4.14.5 sagt: CMD23 kann als Stop Ersatz benutzt werden,
d.h. vor dem Lese/Schreib Kommando wird die Block Anzahl gesetzt. Das 
Kommando ist optional, dürfte aber von modernen Karten implementiert 
werden.

: Bearbeitet durch User
von M. Н. (Gast)


Lesenswert?

Jim M. schrieb:
> Simplfied Spec 4.14.5 sagt: CMD23 kann als Stop Ersatz benutzt werden,
> d.h. vor dem Lese/Schreib Kommando wird die Block Anzahl gesetzt. Das
> Kommando ist optional, dürfte aber von modernen Karten implementiert
> werden.

Ja. Das habe ich auch gelesen. Leider wird das Kommando nicht verwendet.
Das hier ist der source Code: 
https://www.lpcware.com/system/files/lpc177x_8x_mci.c

Das ist die Funktion zum Lesen eines Blocks.
Es wird lediglich der DMA initialisiert, der die Daten automatisch vom 
SDIO-FIFO in den RAM kopiert, und über eine weitere Funktion das 
Kommando an die SD Karte gesendet. Die MCI_Cmd_ReadBlock(blockNum, 
numOfBlock) Funktion evaluiert lediglich, ob 1 Block oder mehrere 
gelesen werden sollen und setzt das Kommando und die parameter richtig.

Nichts mit CMD23...
Übersehe ich etwas?
Mir ist nicht klar, wie diese Implementierung funktioniert/funktionieren 
kann.
1
int32_t MCI_ReadBlock(volatile uint8_t* destBlock, uint32_t blockNum, uint32_t numOfBlock)
2
{
3
    volatile uint32_t i;
4
    uint32_t DataCtrl = 0;
5
6
    if(BLOCK_LENGTH*numOfBlock > DATA_RW_MAX_LEN)
7
        return MCI_FUNC_BAD_PARAMETERS;
8
    
9
    dataDestBlock = destBlock;
10
11
    LPC_MCI->CLEAR = 0x7FF;
12
13
    LPC_MCI->DATACTRL = 0;
14
15
    for ( i = 0; i < 0x10; i++ );
16
17
    /* Wait the SD Card enters to TRANS state. */
18
    if (MCI_CheckStatus(CARD_STATE_TRAN) != MCI_FUNC_OK)
19
        return MCI_FUNC_ERR_STATE;
20
    
21
    MCI_RXEnable();
22
23
    LPC_MCI->DATATMR = DATA_TIMER_VALUE_R;
24
25
    LPC_MCI->DATALEN = BLOCK_LENGTH*numOfBlock;
26
27
    Mci_Data_Xfer_End = 1;
28
    Mci_Data_Xfer_ERR = 0;
29
    rxBlockCnt = 0;
30
    fifo_plane = 0;
31
32
33
    // Start data engine on READ before command to avoid overflow of the FIFO.
34
    {        
35
#if MCI_DMA_ENABLED
36
        MCI_SettingDma((uint8_t*) dataDestBlock, MCI_DMA_READ_CHANNEL, GPDMA_TRANSFERTYPE_P2M_SRC_CTRL);
37
38
        /* Write, block transfer, DMA, and data length */
39
        DataCtrl |= MCI_DATACTRL_ENABLE | MCI_DATACTRL_DIR_FROM_CARD
40
                        | MCI_DATACTRL_DMA_ENABLE | MCI_DTATCTRL_BLOCKSIZE(DATA_BLOCK_LEN);
41
#else
42
        //Retrieving the result after reading the card is done by the FIFO handling for interrupt
43
        
44
        /* Read, enable, block transfer, and data length */
45
        DataCtrl |= MCI_DATACTRL_ENABLE | MCI_DATACTRL_DIR_FROM_CARD | MCI_DTATCTRL_BLOCKSIZE(DATA_BLOCK_LEN);
46
47
#endif
48
    }
49
    
50
    LPC_MCI->DATACTRL = DataCtrl;
51
52
    for ( i = 0; i < 0x10; i++ );
53
54
    if ( MCI_Cmd_ReadBlock(blockNum, numOfBlock) != MCI_FUNC_OK )
55
    {
56
        return MCI_FUNC_FAILED;
57
    }
58
59
    return MCI_FUNC_OK;
60
}

von Jim M. (turboj)


Lesenswert?

Angesichts diverser Leerschleifen, die moderne Compiler wegoptimieren:
1
for ( i = 0; i < 0x10; i++ );

würde ich von oben gepostetem Code nix halten. Ich denke der 
funktioniert nur wenn jeweils ein einzelner Block gelesen oder 
geschrieben wird - was übrigens gängige FAT Implementationen genau so 
machen, solange man nicht viele Daten am Stück schreibt.

Wäre nich das erste Mal das NXP Code nicht tut...

von Jim M. (turboj)


Lesenswert?

M. H. schrieb:
> Mir ist nicht klar, wie diese Implementierung funktioniert/funktionieren
> kann.

Er schmeisst DMA an und jagt dann das Lesekommando raus.
Das "Stop Transmission" müsste dann irgendwie hinterher erfolgen,
wenn der DMA Transfer abgeschlossen ist.

Siehe: https://www.lpcware.com/system/files/Mci_ReadWrite.c

von M. Н. (Gast)


Lesenswert?

Jim M. schrieb:
> Das "Stop Transmission" müsste dann irgendwie hinterher erfolgen,
> wenn der DMA Transfer abgeschlossen ist.

Ja. Das macht Sinn.

Wäre es möglich bei der Initilisierung der Karte das CMD23 zu senden und 
zu schauen, ob ein INVALID_CMD Error auftritt, um zu überprüfen, ob die 
Karte dieses Kommando unterstützt?
Sollte ja keinen Einfluss auf die nachfolgenden Befehle haben, solange 
die Karte bereits vollständig initialisiert ist und vor einer Multi 
Block Operation das Kommando erneut gesendet wird.

von Dr. Sommer (Gast)


Lesenswert?

M. H. schrieb:
> Wäre es möglich bei der Initilisierung der Karte das CMD23 zu senden und
> zu schauen, ob ein INVALID_CMD Error auftritt, um zu überprüfen, ob die
> Karte dieses Kommando unterstützt?

Es gibt sogar ein Kommando mit dem man abfragen kann welche Kommandos 
unterstützt werden, ich weiß gerade nur nicht mehr genau welches (22 
oder 42?).

von Dr. Sommer (Gast)


Lesenswert?

Oh, es war ACMD51. Dies liest das SCR Register aus, welches die "Command 
Support Bits" (CMD_SUPPORT) enthält. Wenn Bit 33 gesetzt ist, wird CMD23 
unterstützt (siehe S. 128 in den SD Simplified Specifications). SDSC 
Karten (bis 2 GB) unterstützen CMD23 grundsätzlich nicht. Es ist aber 
auch kein Problem, CMD12 zu senden wenn der DMA fertig ist. Die nach der 
Beendigung des DMA-Transfers, und vor der Ankunft von CMD12 gesendeten 
Datenblöcke werden einfach ignoriert und stören nicht.

von M. Н. (Gast)


Lesenswert?

Okay. Danke

Dann weiß ich jetzt, wie ich das mache.
Eine Frage hab ich noch:

Und zwar bezüglich des Card Status, der in der R1 Antwort zurückkommt.
Wann bzw. wodurch werden etwaige Fehlerflags gelöscht?

Werden diese gelöscht, durch reines Auslesen, oder sobald ein weiteres 
Kommando gesendet wird und sich der Status somit ändert?

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.