2 * This file is part of INAV, Cleanflight and Betaflight.
4 * INAV, Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 /* Adaptation of original driver to SDIO: Chris Hockuba (https://github.com/conkerkh) */
29 #include "build/debug.h"
30 #include "common/utils.h"
32 #include "drivers/time.h"
33 #include "drivers/nvic.h"
34 #include "drivers/io.h"
35 #include "drivers/bus.h"
36 #include "drivers/bus_spi.h"
37 #include "drivers/dma.h"
39 #include "drivers/sdcard/sdcard.h"
40 #include "drivers/sdcard/sdcard_impl.h"
41 #include "drivers/sdcard/sdcard_standard.h"
42 #include "drivers/sdcard/sdmmc_sdio.h"
44 #include "scheduler/protothreads.h"
46 #ifdef USE_SDCARD_SDIO
48 //#define USE_SDCARD_SDIO_CACHE
50 #if !defined(SDCARD_SDIO_DMA)
51 #define SDCARD_SDIO_DMA DMA_TAG(2,3,4)
54 #if defined(USE_SDCARD_SDIO_CACHE)
55 // Use this to speed up writing to SDCARD... asyncfatfs has limited support for multiblock write
56 #define FATFS_BLOCK_CACHE_SIZE 16
57 uint8_t writeCache
[512 * FATFS_BLOCK_CACHE_SIZE
] __attribute__ ((aligned (4)));
58 uint32_t cacheCount
= 0;
60 void cache_write(uint8_t *buffer
)
62 if (cacheCount
== sizeof(writeCache
)) {
66 memcpy(&writeCache
[cacheCount
], buffer
, 512);
70 uint16_t cache_getCount(void)
72 return (cacheCount
/ 512);
75 void cache_reset(void)
82 * Returns true if the card has already been, or is currently, initializing and hasn't encountered enough errors to
83 * trip our error threshold and be disabled (i.e. our card is in and working!)
85 static bool sdcardSdio_isFunctional(void)
87 return sdcard
.state
!= SDCARD_STATE_NOT_PRESENT
;
91 * Handle a failure of an SD card operation by resetting the card back to its initialization phase.
93 * Increments the failure counter, and when the failure threshold is reached, disables the card until
94 * the next call to sdcard_init().
96 static void sdcardSdio_reset(void)
99 sdcard
.failureCount
++;
100 if (sdcard
.failureCount
>= SDCARD_MAX_CONSECUTIVE_FAILURES
|| !sdcard_isInserted()) {
101 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
103 sdcard
.operationStartTime
= millis();
104 sdcard
.state
= SDCARD_STATE_RESET
;
110 SDCARD_RECEIVE_SUCCESS
,
111 SDCARD_RECEIVE_BLOCK_IN_PROGRESS
,
113 } sdcardReceiveBlockStatus_e
;
116 * Attempt to receive a data block from the SD card.
118 * Return true on success, otherwise the card has not responded yet and you should retry later.
120 static sdcardReceiveBlockStatus_e
sdcard_receiveDataBlock(uint8_t *buffer
, int count
)
124 SD_Error_t ret
= SD_CheckRead();
126 if (ret
== SD_BUSY
) {
127 return SDCARD_RECEIVE_BLOCK_IN_PROGRESS
;
130 if (SD_GetState() != true) {
131 return SDCARD_RECEIVE_ERROR
;
134 return SDCARD_RECEIVE_SUCCESS
;
137 static bool sdcard_receiveCID(void)
139 SD_CardInfo_t
*sdinfo
= &SD_CardInfo
;
140 SD_Error_t error
= SD_GetCardInfo();
145 sdcard
.metadata
.manufacturerID
= sdinfo
->SD_cid
.ManufacturerID
;
146 sdcard
.metadata
.oemID
= sdinfo
->SD_cid
.OEM_AppliID
;
147 sdcard
.metadata
.productName
[0] = (sdinfo
->SD_cid
.ProdName1
& 0xFF000000) >> 24;
148 sdcard
.metadata
.productName
[1] = (sdinfo
->SD_cid
.ProdName1
& 0x00FF0000) >> 16;
149 sdcard
.metadata
.productName
[2] = (sdinfo
->SD_cid
.ProdName1
& 0x0000FF00) >> 8;
150 sdcard
.metadata
.productName
[3] = (sdinfo
->SD_cid
.ProdName1
& 0x000000FF) >> 0;
151 sdcard
.metadata
.productName
[4] = sdinfo
->SD_cid
.ProdName2
;
152 sdcard
.metadata
.productRevisionMajor
= sdinfo
->SD_cid
.ProdRev
>> 4;
153 sdcard
.metadata
.productRevisionMinor
= sdinfo
->SD_cid
.ProdRev
& 0x0F;
154 sdcard
.metadata
.productSerial
= sdinfo
->SD_cid
.ProdSN
;
155 sdcard
.metadata
.productionYear
= (((sdinfo
->SD_cid
.ManufactDate
& 0x0F00) >> 8) | ((sdinfo
->SD_cid
.ManufactDate
& 0xFF) >> 4)) + 2000;
156 sdcard
.metadata
.productionMonth
= sdinfo
->SD_cid
.ManufactDate
& 0x000F;
161 static bool sdcard_fetchCSD(void)
163 /* The CSD command's data block should always arrive within 8 idle clock cycles (SD card spec). This is because
164 * the information about card latency is stored in the CSD register itself, so we can't use that yet!
166 SD_CardInfo_t
*sdinfo
= &SD_CardInfo
;
168 error
= SD_GetCardInfo();
173 sdcard
.metadata
.numBlocks
= sdinfo
->CardCapacity
;
178 * Check if the SD Card has completed its startup sequence. Must be called with sdcard.state == SDCARD_STATE_INITIALIZATION.
180 * Returns true if the card has finished its init process.
182 static bool sdcard_checkInitDone(void)
185 SD_CardType_t
*sdtype
= &SD_CardType
;
186 SD_Error_t errorState
= SD_GetCardInfo();
187 if (errorState
!= SD_OK
) {
191 sdcard
.version
= (*sdtype
) ? 2 : 1;
192 sdcard
.highCapacity
= (*sdtype
== 2) ? 1 : 0;
196 // When card init is complete, the idle bit in the response becomes zero.
201 * Returns true if the card is ready to accept read/write commands.
203 static bool sdcard_isReady(void)
205 return sdcard
.state
== SDCARD_STATE_READY
|| sdcard
.state
== SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
;
209 * Send the stop-transmission token to complete a multi-block write.
212 * SDCARD_OPERATION_IN_PROGRESS - We're now waiting for that stop to complete, the card will enter
213 * the SDCARD_STATE_STOPPING_MULTIPLE_BLOCK_WRITE state.
214 * SDCARD_OPERATION_SUCCESS - The multi-block write finished immediately, the card will enter
215 * the SDCARD_READY state.
218 static sdcardOperationStatus_e
sdcard_endWriteBlocks(void)
220 sdcard
.multiWriteBlocksRemain
= 0;
222 #if defined(USE_SDCARD_SDIO_CACHE)
226 // Card may choose to raise a busy (non-0xFF) signal after at most N_BR (1 byte) delay
228 sdcard
.state
= SDCARD_STATE_READY
;
229 return SDCARD_OPERATION_SUCCESS
;
231 sdcard
.state
= SDCARD_STATE_STOPPING_MULTIPLE_BLOCK_WRITE
;
232 sdcard
.operationStartTime
= millis();
234 return SDCARD_OPERATION_IN_PROGRESS
;
238 * Call periodically for the SD card to perform in-progress transfers.
240 * Returns true if the card is ready to accept commands.
242 static bool sdcardSdio_poll(void)
244 #if !defined(STM32H7) // H7 uses IDMA
246 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
251 switch (sdcard
.state
) {
252 case SDCARD_STATE_RESET
:
253 //HAL Takes care of voltage crap.
254 sdcard
.state
= SDCARD_STATE_CARD_INIT_IN_PROGRESS
;
258 case SDCARD_STATE_CARD_INIT_IN_PROGRESS
:
259 if (sdcard_checkInitDone()) {
260 // Now fetch the CSD and CID registers
261 if (sdcard_fetchCSD()) {
262 sdcard
.state
= SDCARD_STATE_INITIALIZATION_RECEIVE_CID
;
270 case SDCARD_STATE_INITIALIZATION_RECEIVE_CID
:
271 if (sdcard_receiveCID()) {
273 /* The spec is a little iffy on what the default block size is for Standard Size cards (it can be changed on
274 * standard size cards) so let's just set it to 512 explicitly so we don't have a problem.
276 // if (!sdcard.highCapacity && SDMMC_CmdBlockLength(_HSD.Instance, SDCARD_BLOCK_SIZE)) {
277 // sdcardSdio_reset();
281 sdcard
.multiWriteBlocksRemain
= 0;
283 sdcard
.state
= SDCARD_STATE_READY
;
285 } // else keep waiting for the CID to arrive
287 case SDCARD_STATE_SENDING_WRITE
:
288 // Have we finished sending the write yet?
289 if (SD_CheckWrite() == SD_OK
) {
291 // The SD card is now busy committing that write to the card
292 sdcard
.state
= SDCARD_STATE_WAITING_FOR_WRITE
;
293 sdcard
.operationStartTime
= millis();
295 // Since we've transmitted the buffer we can go ahead and tell the caller their operation is complete
296 if (sdcard
.pendingOperation
.callback
) {
297 sdcard
.pendingOperation
.callback(SDCARD_BLOCK_OPERATION_WRITE
, sdcard
.pendingOperation
.blockIndex
, sdcard
.pendingOperation
.buffer
, sdcard
.pendingOperation
.callbackData
);
301 case SDCARD_STATE_WAITING_FOR_WRITE
:
303 sdcard
.failureCount
= 0; // Assume the card is good if it can complete a write
305 // Still more blocks left to write in a multi-block chain?
306 if (sdcard
.multiWriteBlocksRemain
> 1) {
307 sdcard
.multiWriteBlocksRemain
--;
308 sdcard
.multiWriteNextBlock
++;
309 #if defined(USE_SDCARD_SDIO_CACHE)
312 sdcard
.state
= SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
;
313 } else if (sdcard
.multiWriteBlocksRemain
== 1) {
314 // This function changes the sd card state for us whether immediately succesful or delayed:
315 sdcard_endWriteBlocks();
317 sdcard
.state
= SDCARD_STATE_READY
;
319 } else if (millis() > sdcard
.operationStartTime
+ SDCARD_TIMEOUT_WRITE_MSEC
) {
321 * The caller has already been told that their write has completed, so they will have discarded
322 * their buffer and have no hope of retrying the operation. But this should be very rare and it allows
323 * them to reuse their buffer milliseconds faster than they otherwise would.
329 case SDCARD_STATE_READING
:
330 switch (sdcard_receiveDataBlock(sdcard
.pendingOperation
.buffer
, SDCARD_BLOCK_SIZE
)) {
331 case SDCARD_RECEIVE_SUCCESS
:
333 sdcard
.state
= SDCARD_STATE_READY
;
334 sdcard
.failureCount
= 0; // Assume the card is good if it can complete a read
336 if (sdcard
.pendingOperation
.callback
) {
337 sdcard
.pendingOperation
.callback(
338 SDCARD_BLOCK_OPERATION_READ
,
339 sdcard
.pendingOperation
.blockIndex
,
340 sdcard
.pendingOperation
.buffer
,
341 sdcard
.pendingOperation
.callbackData
345 case SDCARD_RECEIVE_BLOCK_IN_PROGRESS
:
346 if (millis() <= sdcard
.operationStartTime
+ SDCARD_TIMEOUT_READ_MSEC
) {
347 break; // Timeout not reached yet so keep waiting
349 // Timeout has expired, so fall through to convert to a fatal error
351 case SDCARD_RECEIVE_ERROR
:
356 case SDCARD_STATE_STOPPING_MULTIPLE_BLOCK_WRITE
:
358 sdcard
.state
= SDCARD_STATE_READY
;
359 } else if (millis() > sdcard
.operationStartTime
+ SDCARD_TIMEOUT_WRITE_MSEC
) {
364 case SDCARD_STATE_NOT_PRESENT
:
369 // Is the card's initialization taking too long?
370 if (sdcard
.state
>= SDCARD_STATE_RESET
&& sdcard
.state
< SDCARD_STATE_READY
371 && millis() - sdcard
.operationStartTime
> SDCARD_TIMEOUT_INIT_MILLIS
) {
375 return sdcard_isReady();
379 * Write the 512-byte block from the given buffer into the block with the given index.
381 * If the write does not complete immediately, your callback will be called later. If the write was successful, the
382 * buffer pointer will be the same buffer you originally passed in, otherwise the buffer will be set to NULL.
385 * SDCARD_OPERATION_IN_PROGRESS - Your buffer is currently being transmitted to the card and your callback will be
386 * called later to report the completion. The buffer pointer must remain valid until
388 * SDCARD_OPERATION_SUCCESS - Your buffer has been transmitted to the card now.
389 * SDCARD_OPERATION_BUSY - The card is already busy and cannot accept your write
390 * SDCARD_OPERATION_FAILURE - Your write was rejected by the card, card will be reset
392 static sdcardOperationStatus_e
sdcardSdio_writeBlock(uint32_t blockIndex
, uint8_t *buffer
, sdcard_operationCompleteCallback_c callback
, uint32_t callbackData
)
395 switch (sdcard
.state
) {
396 case SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
:
397 // Do we need to cancel the previous multi-block write?
398 if (blockIndex
!= sdcard
.multiWriteNextBlock
) {
399 if (sdcard_endWriteBlocks() == SDCARD_OPERATION_SUCCESS
) {
400 // Now we've entered the ready state, we can try again
403 return SDCARD_OPERATION_BUSY
;
407 // We're continuing a multi-block write
409 case SDCARD_STATE_READY
:
412 return SDCARD_OPERATION_BUSY
;
415 sdcard
.pendingOperation
.buffer
= buffer
;
416 sdcard
.pendingOperation
.blockIndex
= blockIndex
;
418 unsigned block_count
= 1;
420 #if defined(USE_SDCARD_SDIO_CACHE)
421 if ((cache_getCount() < FATFS_BLOCK_CACHE_SIZE
) && (sdcard
.multiWriteBlocksRemain
!= 0)) {
424 if (cache_getCount() == FATFS_BLOCK_CACHE_SIZE
|| sdcard
.multiWriteBlocksRemain
== 1) {
425 //Relocate buffer and recalculate block index
426 buffer
= (uint8_t*)writeCache
;
427 blockIndex
-= cache_getCount() - 1;
428 block_count
= cache_getCount();
430 sdcard
.multiWriteBlocksRemain
--;
431 sdcard
.multiWriteNextBlock
++;
432 sdcard
.state
= SDCARD_STATE_READY
;
433 return SDCARD_OPERATION_SUCCESS
;
438 sdcard
.pendingOperation
.callback
= callback
;
439 sdcard
.pendingOperation
.callbackData
= callbackData
;
440 sdcard
.pendingOperation
.chunkIndex
= 1; // (for non-DMA transfers) we've sent chunk #0 already
441 sdcard
.state
= SDCARD_STATE_SENDING_WRITE
;
443 if (SD_WriteBlocks_DMA(blockIndex
, (uint32_t*) buffer
, 512, block_count
) != SD_OK
) {
444 /* Our write was rejected! This could be due to a bad address but we hope not to attempt that, so assume
445 * the card is broken and needs reset.
449 // Announce write failure:
450 if (sdcard
.pendingOperation
.callback
) {
451 sdcard
.pendingOperation
.callback(SDCARD_BLOCK_OPERATION_WRITE
, sdcard
.pendingOperation
.blockIndex
, NULL
, sdcard
.pendingOperation
.callbackData
);
453 return SDCARD_OPERATION_FAILURE
;
456 return SDCARD_OPERATION_IN_PROGRESS
;
460 * Begin writing a series of consecutive blocks beginning at the given block index. This will allow (but not require)
461 * the SD card to pre-erase the number of blocks you specifiy, which can allow the writes to complete faster.
463 * Afterwards, just call sdcard_writeBlock() as normal to write those blocks consecutively.
465 * It's okay to abort the multi-block write at any time by writing to a non-consecutive address, or by performing a read.
468 * SDCARD_OPERATION_SUCCESS - Multi-block write has been queued
469 * SDCARD_OPERATION_BUSY - The card is already busy and cannot accept your write
470 * SDCARD_OPERATION_FAILURE - A fatal error occured, card will be reset
472 static sdcardOperationStatus_e
sdcardSdio_beginWriteBlocks(uint32_t blockIndex
, uint32_t blockCount
)
474 if (sdcard
.state
!= SDCARD_STATE_READY
) {
475 if (sdcard
.state
== SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
) {
476 if (blockIndex
== sdcard
.multiWriteNextBlock
) {
477 // Assume that the caller wants to continue the multi-block write they already have in progress!
478 return SDCARD_OPERATION_SUCCESS
;
479 } else if (sdcard_endWriteBlocks() != SDCARD_OPERATION_SUCCESS
) {
480 return SDCARD_OPERATION_BUSY
;
481 } // Else we've completed the previous multi-block write and can fall through to start the new one
483 return SDCARD_OPERATION_BUSY
;
487 sdcard
.state
= SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
;
488 sdcard
.multiWriteBlocksRemain
= blockCount
;
489 sdcard
.multiWriteNextBlock
= blockIndex
;
490 return SDCARD_OPERATION_SUCCESS
;
494 * Read the 512-byte block with the given index into the given 512-byte buffer.
496 * When the read completes, your callback will be called. If the read was successful, the buffer pointer will be the
497 * same buffer you originally passed in, otherwise the buffer will be set to NULL.
499 * You must keep the pointer to the buffer valid until the operation completes!
502 * true - The operation was successfully queued for later completion, your callback will be called later
503 * false - The operation could not be started due to the card being busy (try again later).
505 static bool sdcardSdio_readBlock(uint32_t blockIndex
, uint8_t *buffer
, sdcard_operationCompleteCallback_c callback
, uint32_t callbackData
)
507 if (sdcard
.state
!= SDCARD_STATE_READY
) {
508 if (sdcard
.state
== SDCARD_STATE_WRITING_MULTIPLE_BLOCKS
) {
509 if (sdcard_endWriteBlocks() != SDCARD_OPERATION_SUCCESS
) {
517 // Standard size cards use byte addressing, high capacity cards use block addressing
518 uint8_t status
= SD_ReadBlocks_DMA(blockIndex
, (uint32_t*) buffer
, 512, 1);
520 if (status
== SD_OK
) {
521 sdcard
.pendingOperation
.buffer
= buffer
;
522 sdcard
.pendingOperation
.blockIndex
= blockIndex
;
523 sdcard
.pendingOperation
.callback
= callback
;
524 sdcard
.pendingOperation
.callbackData
= callbackData
;
526 sdcard
.state
= SDCARD_STATE_READING
;
527 sdcard
.operationStartTime
= millis();
532 if (sdcard
.pendingOperation
.callback
) {
533 sdcard
.pendingOperation
.callback(
534 SDCARD_BLOCK_OPERATION_READ
,
535 sdcard
.pendingOperation
.blockIndex
,
537 sdcard
.pendingOperation
.callbackData
545 * Begin the initialization process for the SD card. This must be called first before any other sdcard_ routine.
547 void sdcardSdio_init(void)
549 #if !defined(STM32H7) // H7 uses IDMA
550 sdcard
.dma
= dmaGetByTag(SDCARD_SDIO_DMA
);
553 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
557 // Check if somebody already occupies this DMA channel
558 if (dmaGetOwner(sdcard
.dma
) != OWNER_FREE
) {
560 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
564 if (!SD_Initialize_LL(sdcard
.dma
->ref
)) {
566 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
570 if (!SD_Initialize_LL(0)) {
571 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
575 // We don't support hot insertion
576 if (!sdcard_isInserted()) {
577 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
581 if (SD_Init() != 0) {
582 sdcard
.state
= SDCARD_STATE_NOT_PRESENT
;
586 sdcard
.operationStartTime
= millis();
587 sdcard
.state
= SDCARD_STATE_RESET
;
588 sdcard
.failureCount
= 0;
592 * Returns true if the SD card has successfully completed its startup procedures.
594 static bool sdcardSdio_isInitialized(void)
596 return sdcard
.state
>= SDCARD_STATE_READY
;
599 static const sdcardMetadata_t
* sdcardSdio_getMetadata(void)
601 return &sdcard
.metadata
;
604 sdcardVTable_t sdcardSdioVTable
= {
605 .init
= &sdcardSdio_init
,
606 .readBlock
= &sdcardSdio_readBlock
,
607 .beginWriteBlocks
= &sdcardSdio_beginWriteBlocks
,
608 .writeBlock
= &sdcardSdio_writeBlock
,
609 .poll
= &sdcardSdio_poll
,
610 .isFunctional
= &sdcardSdio_isFunctional
,
611 .isInitialized
= &sdcardSdio_isInitialized
,
612 .getMetadata
= &sdcardSdio_getMetadata
,