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
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
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 | }
|
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...
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
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.
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?).
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.