2 * This file is part of Cleanflight and Betaflight.
4 * 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/>.
28 #include "drivers/nvic.h"
29 #include "drivers/io.h"
31 #include "dma_reqmap.h"
33 #include "drivers/bus_spi.h"
34 #include "drivers/time.h"
36 #include "pg/bus_spi.h"
37 #include "pg/sdcard.h"
40 #include "sdcard_impl.h"
41 #include "sdcard_standard.h"
43 #ifdef AFATFS_USE_INTROSPECTIVE_LOGGING
44 #define SDCARD_PROFILING
47 #define SDCARD_INIT_NUM_DUMMY_BYTES 10
48 #define SDCARD_MAXIMUM_BYTE_DELAY_FOR_CMD_REPLY 8
49 // Chosen so that CMD8 will have the same CRC as CMD0:
50 #define SDCARD_IF_COND_CHECK_PATTERN 0xAB
52 #define SDCARD_TIMEOUT_INIT_MILLIS 200
53 #define SDCARD_MAX_CONSECUTIVE_FAILURES 8
55 /* SPI_CLOCK_INITIALIZATION (256) is the slowest (Spec calls for under 400KHz) */
56 #define SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER SPI_CLOCK_INITIALIZATION
58 /* Operational speed <= 25MHz */
59 #define SDCARD_SPI_FULL_SPEED_CLOCK_DIVIDER SPI_CLOCK_FAST
61 /* Break up 512-byte SD card sectors into chunks of this size when writing without DMA to reduce the peak overhead
62 * per call to sdcard_poll().
64 #define SDCARD_NON_DMA_CHUNK_SIZE 256
68 STATIC_ASSERT(sizeof(sdcardCSD_t
) == 16, sdcard_csd_bitfields_didnt_pack_properly
);
70 static void sdcardInsertionDetectInit(const sdcardConfig_t
*config
)
72 if (config
->cardDetectTag
) {
73 sdcard
.cardDetectPin
= IOGetByTag(config
->cardDetectTag
);
74 sdcard
.detectionInverted
= config
->cardDetectInverted
;
76 sdcard
.cardDetectPin
= IO_NONE
;
77 sdcard
.detectionInverted
= false;
80 if (sdcard
.cardDetectPin
) {
81 IOInit(sdcard
.cardDetectPin
, OWNER_SDCARD_DETECT
, 0);
82 IOConfigGPIO(sdcard
.cardDetectPin
, IOCFG_IPU
);
87 * Detect if a SD card is physically present in the memory slot.
89 bool sdcard_isInserted(void)
92 if (sdcard
.cardDetectPin
) {
93 result
= IORead(sdcard
.cardDetectPin
) != 0;
94 if (sdcard
.detectionInverted
) {
104 sdcardVTable_t
*sdcardVTable
;
106 void sdcard_preInit(const sdcardConfig_t
*config
)
108 #ifdef USE_SDCARD_SPI
109 sdcardSpiVTable
.sdcard_preInit(config
);
115 void sdcard_init(const sdcardConfig_t
*config
)
117 sdcardInsertionDetectInit(config
);
119 switch (config
->mode
) {
120 #ifdef USE_SDCARD_SPI
121 case SDCARD_MODE_SPI
:
122 sdcardVTable
= &sdcardSpiVTable
;
125 #ifdef USE_SDCARD_SDIO
126 case SDCARD_MODE_SDIO
:
127 sdcardVTable
= &sdcardSdioVTable
;
135 sdcardVTable
->sdcard_init(config
, spiPinConfig(0));
139 bool sdcard_readBlock(uint32_t blockIndex
, uint8_t *buffer
, sdcard_operationCompleteCallback_c callback
, uint32_t callbackData
)
141 return sdcardVTable
->sdcard_readBlock(blockIndex
, buffer
, callback
, callbackData
);
144 sdcardOperationStatus_e
sdcard_beginWriteBlocks(uint32_t blockIndex
, uint32_t blockCount
)
146 return sdcardVTable
->sdcard_beginWriteBlocks(blockIndex
, blockCount
);
149 sdcardOperationStatus_e
sdcard_writeBlock(uint32_t blockIndex
, uint8_t *buffer
, sdcard_operationCompleteCallback_c callback
, uint32_t callbackData
)
151 return sdcardVTable
->sdcard_writeBlock(blockIndex
, buffer
, callback
, callbackData
);
154 bool sdcard_poll(void)
156 // sdcard_poll is called from taskMain() via afatfs_poll() and for USE_SDCARD.
158 return sdcardVTable
->sdcard_poll();
164 bool sdcard_isFunctional(void)
166 // sdcard_isFunctional is called from multiple places, including the case of hardware implementation
167 // without a detect pin in which case sdcard_isInserted() always returns true.
169 return sdcardVTable
->sdcard_isFunctional();
175 bool sdcard_isInitialized(void)
177 return sdcardVTable
->sdcard_isInitialized();
180 const sdcardMetadata_t
* sdcard_getMetadata(void)
182 return sdcardVTable
->sdcard_getMetadata();