/* * This file is part of Cleanflight and Betaflight. * * Cleanflight and Betaflight are free software. You can redistribute * this software and/or modify this software under the terms of the * GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) * any later version. * * Cleanflight and Betaflight are distributed in the hope that they * will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. * * If not, see . */ #include #include #include "platform.h" #ifdef USE_SDCARD #include "drivers/nvic.h" #include "drivers/io.h" #include "dma.h" #include "dma_reqmap.h" #include "drivers/bus_spi.h" #include "drivers/time.h" #include "pg/bus_spi.h" #include "pg/sdcard.h" #include "sdcard.h" #include "sdcard_impl.h" #include "sdcard_standard.h" #ifdef AFATFS_USE_INTROSPECTIVE_LOGGING #define SDCARD_PROFILING #endif #define SDCARD_INIT_NUM_DUMMY_BYTES 10 #define SDCARD_MAXIMUM_BYTE_DELAY_FOR_CMD_REPLY 8 // Chosen so that CMD8 will have the same CRC as CMD0: #define SDCARD_IF_COND_CHECK_PATTERN 0xAB #define SDCARD_TIMEOUT_INIT_MILLIS 200 #define SDCARD_MAX_CONSECUTIVE_FAILURES 8 /* SPI_CLOCK_INITIALIZATION (256) is the slowest (Spec calls for under 400KHz) */ #define SDCARD_SPI_INITIALIZATION_CLOCK_DIVIDER SPI_CLOCK_INITIALIZATION /* Operational speed <= 25MHz */ #define SDCARD_SPI_FULL_SPEED_CLOCK_DIVIDER SPI_CLOCK_FAST /* Break up 512-byte SD card sectors into chunks of this size when writing without DMA to reduce the peak overhead * per call to sdcard_poll(). */ #define SDCARD_NON_DMA_CHUNK_SIZE 256 sdcard_t sdcard; STATIC_ASSERT(sizeof(sdcardCSD_t) == 16, sdcard_csd_bitfields_didnt_pack_properly); static void sdcardInsertionDetectInit(const sdcardConfig_t *config) { if (config->cardDetectTag) { sdcard.cardDetectPin = IOGetByTag(config->cardDetectTag); sdcard.detectionInverted = config->cardDetectInverted; } else { sdcard.cardDetectPin = IO_NONE; sdcard.detectionInverted = false; } if (sdcard.cardDetectPin) { IOInit(sdcard.cardDetectPin, OWNER_SDCARD_DETECT, 0); IOConfigGPIO(sdcard.cardDetectPin, IOCFG_IPU); } } /** * Detect if a SD card is physically present in the memory slot. */ bool sdcard_isInserted(void) { bool result = true; if (sdcard.cardDetectPin) { result = IORead(sdcard.cardDetectPin) != 0; if (sdcard.detectionInverted) { result = !result; } } return result; } /** * Dispatch */ sdcardVTable_t *sdcardVTable; void sdcard_preInit(const sdcardConfig_t *config) { #ifdef USE_SDCARD_SPI sdcardSpiVTable.sdcard_preInit(config); #else UNUSED(config); #endif } void sdcard_init(const sdcardConfig_t *config) { sdcardInsertionDetectInit(config); switch (config->mode) { #ifdef USE_SDCARD_SPI case SDCARD_MODE_SPI: sdcardVTable = &sdcardSpiVTable; break; #endif #ifdef USE_SDCARD_SDIO case SDCARD_MODE_SDIO: sdcardVTable = &sdcardSdioVTable; break; #endif default: break; } if (sdcardVTable) { sdcardVTable->sdcard_init(config, spiPinConfig(0)); } } bool sdcard_readBlock(uint32_t blockIndex, uint8_t *buffer, sdcard_operationCompleteCallback_c callback, uint32_t callbackData) { return sdcardVTable->sdcard_readBlock(blockIndex, buffer, callback, callbackData); } sdcardOperationStatus_e sdcard_beginWriteBlocks(uint32_t blockIndex, uint32_t blockCount) { return sdcardVTable->sdcard_beginWriteBlocks(blockIndex, blockCount); } sdcardOperationStatus_e sdcard_writeBlock(uint32_t blockIndex, uint8_t *buffer, sdcard_operationCompleteCallback_c callback, uint32_t callbackData) { return sdcardVTable->sdcard_writeBlock(blockIndex, buffer, callback, callbackData); } bool sdcard_poll(void) { // sdcard_poll is called from taskMain() via afatfs_poll() and for USE_SDCARD. if (sdcardVTable) { return sdcardVTable->sdcard_poll(); } else { return false; } } bool sdcard_isFunctional(void) { // sdcard_isFunctional is called from multiple places, including the case of hardware implementation // without a detect pin in which case sdcard_isInserted() always returns true. if (sdcardVTable) { return sdcardVTable->sdcard_isFunctional(); } else { return false; } } bool sdcard_isInitialized(void) { return sdcardVTable->sdcard_isInitialized(); } const sdcardMetadata_t* sdcard_getMetadata(void) { return sdcardVTable->sdcard_getMetadata(); } #endif