--- /dev/null
+/*\r
+ * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!\r
+ * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ * Authors include James Walmsley, Hein Tibosch and Richard Barry\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * https://www.FreeRTOS.org\r
+ *\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "semphr.h"\r
+#include "portmacro.h"\r
+\r
+/* FreeRTOS+FAT includes. */\r
+#include "ff_sddisk.h"\r
+#include "ff_sys.h"\r
+\r
+/* ST HAL includes. */\r
+#ifdef STM32F7xx\r
+ #include "stm32f7xx_hal.h"\r
+#else\r
+ #include "stm32f4xx_hal.h"\r
+#endif\r
+\r
+/* Misc definitions. */\r
+#define sdSIGNATURE 0x41404342UL\r
+#define sdHUNDRED_64_BIT ( 100ull )\r
+#define sdBYTES_PER_MB ( 1024ull * 1024ull )\r
+#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull )\r
+#define sdIOMAN_MEM_SIZE 4096\r
+\r
+/* DMA constants. */\r
+#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4\r
+#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4\r
+#define SD_DMAx_Tx_STREAM DMA2_Stream6\r
+#define SD_DMAx_Rx_STREAM DMA2_Stream3\r
+#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn\r
+#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn\r
+#define __DMAx_TxRx_CLK_ENABLE __DMA2_CLK_ENABLE\r
+#define configSDIO_DMA_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY )\r
+\r
+/* Define a time-out for all DMA transactions in msec. */\r
+#ifndef sdMAX_TIME_TICKS\r
+ #define sdMAX_TIME_TICKS pdMS_TO_TICKS( 2000UL )\r
+#endif\r
+\r
+#ifndef configSD_DETECT_PIN\r
+ #error configSD_DETECT_PIN must be defined in FreeRTOSConfig.h to the pin used to detect if the SD card is present.\r
+#endif\r
+\r
+#ifndef configSD_DETECT_GPIO_PORT\r
+ #error configSD_DETECT_GPIO_PORT must be defined in FreeRTOSConfig.h to the port on which configSD_DETECT_PIN is located.\r
+#endif\r
+\r
+#ifndef sdCARD_DETECT_DEBOUNCE_TIME_MS\r
+ /* Debouncing time is applied only after card gets inserted. */\r
+ #define sdCARD_DETECT_DEBOUNCE_TIME_MS ( 5000 )\r
+#endif\r
+\r
+#ifndef sdARRAY_SIZE\r
+ #define sdARRAY_SIZE( x ) ( int )( sizeof( x ) / sizeof( x )[ 0 ] )\r
+#endif\r
+\r
+#ifdef STM32F7xx\r
+\r
+ /* This driver was originally developed for STM32F4xx.\r
+ With a few defines it can also be used for STM32F7xx : */\r
+ /* The Instance of the MMC peripheral. */\r
+ #define SDIO SDMMC1\r
+\r
+ #ifdef GPIO_AF12_SDIO\r
+ #undef GPIO_AF12_SDIO\r
+ #endif\r
+ #define GPIO_AF12_SDIO GPIO_AF12_SDMMC1\r
+\r
+ #define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING\r
+ #define SDIO_CLOCK_BYPASS_DISABLE SDMMC_CLOCK_BYPASS_DISABLE\r
+ #define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE\r
+ #define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B\r
+ #define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B\r
+ #define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE\r
+\r
+\r
+ #define SD_SDIO_DISABLED SD_SDMMC_DISABLED\r
+ #define SD_SDIO_FUNCTION_BUSY SD_SDMMC_FUNCTION_BUSY\r
+ #define SD_SDIO_FUNCTION_FAILED SD_SDMMC_FUNCTION_FAILED\r
+ #define SD_SDIO_UNKNOWN_FUNCTION SD_SDMMC_UNKNOWN_FUNCTION\r
+\r
+ #define SDIO_IRQn SDMMC1_IRQn\r
+\r
+#endif /* STM32F7xx */\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Return pdFALSE if the SD card is not inserted. This function just reads the\r
+ * value of the GPIO C/D pin.\r
+ */\r
+static BaseType_t prvSDDetect( void );\r
+\r
+/*\r
+ * Translate a numeric code like 'SD_TX_UNDERRUN' to a printable string.\r
+ */\r
+static const char *prvSDCodePrintable( uint32_t ulCode );\r
+\r
+/*\r
+ * The following 'hook' must be provided by the user of this module. It will be\r
+ * called from a GPIO ISR after every change. Note that during the ISR, the\r
+ * value of the GPIO is not stable and it can not be used. All you can do from\r
+ * this hook is wake-up some task, which will call FF_SDDiskDetect().\r
+ */\r
+extern void vApplicationCardDetectChangeHookFromISR( BaseType_t *pxHigherPriorityTaskWoken );\r
+\r
+/*\r
+ * Hardware initialisation.\r
+ */\r
+static void prvSDIO_SD_Init( void );\r
+static void vGPIO_SD_Init( SD_HandleTypeDef* xSDHandle );\r
+\r
+/*\r
+ * Check if the card is present, and if so, print out some info on the card.\r
+ */\r
+static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber );\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+ /*\r
+ * Initialise the DMA for SDIO cards.\r
+ */\r
+ static void prvSDIO_DMA_Init( void );\r
+#endif\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+ /*\r
+ * A function will be called at the start of a DMA action.\r
+ */\r
+ static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle );\r
+#endif\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+ /*\r
+ * This function is supposed to wait for an event: SDIO or DMA.\r
+ * Return non-zero if a timeout has been reached.\r
+ */\r
+ static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle );\r
+#endif\r
+\r
+#ifdef STM32F7xx\r
+ static void prvCacheClean( uint32_t *pulAddress, int32_t ulSize );\r
+ static void prvCacheInvalidate( uint32_t *pulAddress, int32_t ulSize );\r
+#else\r
+ /* No cache: empty macro's. */\r
+ #define prvCacheClean( pulAddress, ulSize ) do {} while ( 0 )\r
+ #define prvCacheInvalidate( pulAddress, ulSize ) do {} while ( 0 )\r
+#endif\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+typedef struct\r
+{\r
+ /* Only after a card has been inserted, debouncing is necessary. */\r
+ TickType_t xRemainingTime;\r
+ TimeOut_t xTimeOut;\r
+ UBaseType_t\r
+ bLastPresent : 1,\r
+ bStableSignal : 1;\r
+} CardDetect_t;\r
+\r
+/* Used to handle timeouts. */\r
+static TickType_t xDMARemainingTime;\r
+static TimeOut_t xDMATimeOut;\r
+\r
+/* Used to unblock the task that calls prvEventWaitFunction() after an event has\r
+occurred. */\r
+static SemaphoreHandle_t xSDCardSemaphore = NULL;\r
+\r
+/* Handle of the SD card being used. */\r
+static SD_HandleTypeDef xSDHandle;\r
+\r
+/* Holds parameters for the detected SD card. */\r
+static HAL_SD_CardInfoTypedef xSDCardInfo;\r
+\r
+/* Mutex for partition. */\r
+static SemaphoreHandle_t xPlusFATMutex = NULL;\r
+\r
+/* Remembers if the card is currently considered to be present. */\r
+static BaseType_t xSDCardStatus = pdFALSE;\r
+\r
+/* Maintains state for card detection. */\r
+static CardDetect_t xCardDetect;\r
+\r
+static __attribute__ ((section(".first_data"))) uint8_t pucDMABuffer[ 512 ] __attribute__ ( ( aligned( 32 ) ) );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )\r
+{\r
+int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;\r
+\r
+ if( ( pxDisk != NULL ) &&\r
+ ( xSDCardStatus == pdPASS ) &&\r
+ ( pxDisk->ulSignature == sdSIGNATURE ) &&\r
+ ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&\r
+ ( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&\r
+ ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )\r
+ {\r
+ uint64_t ullReadAddr;\r
+ HAL_SD_ErrorTypedef sd_result;\r
+\r
+ ullReadAddr = 512ull * ( uint64_t ) ulSectorNumber;\r
+\r
+ #if( SDIO_USES_DMA == 0 )\r
+ {\r
+ sd_result = HAL_SD_ReadBlocks( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount );\r
+ }\r
+ #else\r
+ {\r
+ if( ( ( ( size_t )pucBuffer ) & 0x1Ful ) == 0ul )\r
+ {\r
+ /* The buffer is word-aligned, call DMA read directly. */\r
+ sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount);\r
+ if( sd_result == SD_OK )\r
+ {\r
+ sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS );\r
+ prvCacheInvalidate ( ( uint32_t * )pucBuffer, 512ul * ulSectorCount );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uint32_t ulSector;\r
+\r
+ /* The buffer is NOT word-aligned, copy first to an aligned buffer. */\r
+ sd_result = SD_OK;\r
+ for( ulSector = 0; ulSector < ulSectorCount; ulSector++ )\r
+ {\r
+ ullReadAddr = 512ull * ( ( uint64_t ) ulSectorNumber + ( uint64_t ) ulSector );\r
+ sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullReadAddr, 512ul, 1 );\r
+\r
+ if( sd_result == SD_OK )\r
+ {\r
+ sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS );\r
+ if( sd_result != SD_OK )\r
+ {\r
+ break;\r
+ }\r
+ prvCacheInvalidate ( ( uint32_t * )pucDMABuffer, 512ul * 1 );\r
+ memcpy( pucBuffer + 512ul * ulSector, pucDMABuffer, 512ul );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ #endif /* SDIO_USES_DMA */\r
+\r
+ if( sd_result == SD_OK )\r
+ {\r
+ lReturnCode = 0L;\r
+ }\r
+ else\r
+ {\r
+ /* Some error occurred. */\r
+ FF_PRINTF( "prvFFRead: %lu: %lu (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Make sure no random data is in the returned buffer. */\r
+ memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL );\r
+\r
+ if( pxDisk->xStatus.bIsInitialised != pdFALSE )\r
+ {\r
+ FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );\r
+ }\r
+ }\r
+\r
+ return lReturnCode;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )\r
+{\r
+int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;\r
+\r
+ if( ( pxDisk != NULL ) &&\r
+ ( xSDCardStatus == pdPASS ) &&\r
+ ( pxDisk->ulSignature == sdSIGNATURE ) &&\r
+ ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&\r
+ ( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&\r
+ ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )\r
+ {\r
+ HAL_SD_ErrorTypedef sd_result;\r
+ uint64_t ullWriteAddr;\r
+ ullWriteAddr = 512ull * ulSectorNumber;\r
+\r
+ #if( SDIO_USES_DMA == 0 )\r
+ {\r
+ sd_result = HAL_SD_WriteBlocks( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount );\r
+ }\r
+ #else\r
+ {\r
+ if( ( ( ( size_t )pucBuffer ) & 0x1Ful ) == 0ul )\r
+ {\r
+ /* The buffer is word-aligned, call DMA reawrite directly. */\r
+ prvCacheClean( ( uint32_t * )pucBuffer, 512ul * ulSectorCount );\r
+ sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount );\r
+ if( sd_result == SD_OK )\r
+ {\r
+ sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uint32_t ulSector;\r
+\r
+ /* The buffer is NOT word-aligned, read to an aligned buffer and then\r
+ copy the data to the user provided buffer. */\r
+ sd_result = SD_OK;\r
+ for( ulSector = 0; ulSector < ulSectorCount; ulSector++ )\r
+ {\r
+ memcpy( pucDMABuffer, pucBuffer + 512ul * ulSector, 512ul );\r
+ ullWriteAddr = 512ull * ( ulSectorNumber + ulSector );\r
+ prvCacheClean( ( uint32_t * )pucDMABuffer, 512ul * 1ul );\r
+ sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullWriteAddr, 512ul, 1 );\r
+ if( sd_result == SD_OK )\r
+ {\r
+ sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS );\r
+ if( sd_result != SD_OK )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ #endif /* SDIO_USES_DMA */\r
+\r
+ if( sd_result == SD_OK )\r
+ {\r
+ /* No errors. */\r
+ lReturnCode = 0L;\r
+ }\r
+ else\r
+ {\r
+ FF_PRINTF( "prvFFWrite: %lu: %lu (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if( pxDisk->xStatus.bIsInitialised != pdFALSE )\r
+ {\r
+ FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );\r
+ }\r
+ }\r
+\r
+ return lReturnCode;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#ifdef STM32F7xx\r
+\r
+ static BaseType_t xIsCachable( uint32_t ulAddress )\r
+ {\r
+ BaseType_t xReturn = pdFALSE;\r
+\r
+ /* Is D-cache enabled? */\r
+ if( ( SCB != NULL ) && ( ( SCB->CCR & (uint32_t)SCB_CCR_DC_Msk ) != 0ul ) )\r
+ {\r
+ /* Is this a chacheable area? */\r
+ if( ( ulAddress >= RAMDTCM_BASE + 0x10000 ) && ( ulAddress < RAMDTCM_BASE + 0x4CC00 ) )\r
+ {\r
+ xReturn = pdTRUE;\r
+ }\r
+ }\r
+ return xReturn;\r
+ }\r
+/*-----------------------------------------------------------*/\r
+#endif /* STM32F7xx */\r
+\r
+#ifdef STM32F7xx\r
+ static void prvCacheClean( uint32_t *pulAddress, int32_t ulSize )\r
+ {\r
+ if( xIsCachable( ( uint32_t ) pulAddress ) )\r
+ {\r
+ SCB_CleanDCache_by_Addr( pulAddress, ulSize );\r
+ }\r
+ }\r
+/*-----------------------------------------------------------*/\r
+#endif /* STM32F7xx */\r
+\r
+#ifdef STM32F7xx\r
+ static void prvCacheInvalidate( uint32_t *pulAddress, int32_t ulSize )\r
+ {\r
+ if( xIsCachable( ( uint32_t ) pulAddress ) )\r
+ {\r
+ SCB_InvalidateDCache_by_Addr( pulAddress, ulSize );\r
+ }\r
+ }\r
+/*-----------------------------------------------------------*/\r
+#endif /* STM32F7xx */\r
+\r
+void FF_SDDiskFlush( FF_Disk_t *pxDisk )\r
+{\r
+ if( ( pxDisk != NULL ) &&\r
+ ( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&\r
+ ( pxDisk->pxIOManager != NULL ) )\r
+ {\r
+ FF_FlushCache( pxDisk->pxIOManager );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void vGPIO_SD_Init(SD_HandleTypeDef* xSDHandle)\r
+{\r
+GPIO_InitTypeDef GPIO_InitStruct;\r
+\r
+ if( xSDHandle->Instance == SDIO )\r
+ {\r
+ /* Peripheral clock enable */\r
+ __SDIO_CLK_ENABLE();\r
+\r
+ /**SDIO GPIO Configuration\r
+ PC8 ------> SDIO_D0\r
+ PC9 ------> SDIO_D1\r
+ PC10 ------> SDIO_D2\r
+ PC11 ------> SDIO_D3\r
+ PC12 ------> SDIO_CK\r
+ PD2 ------> SDIO_CMD\r
+ */\r
+ /* Enable SDIO clock */\r
+ __HAL_RCC_SDMMC1_CLK_ENABLE();\r
+\r
+ /* Enable DMA2 clocks */\r
+ __DMAx_TxRx_CLK_ENABLE();\r
+\r
+ /* Enable GPIOs clock */\r
+ __HAL_RCC_GPIOC_CLK_ENABLE();\r
+ __HAL_RCC_GPIOD_CLK_ENABLE();\r
+\r
+ /* GPIOC configuration */\r
+ #if( BUS_4BITS != 0 )\r
+ {\r
+ GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;\r
+ }\r
+ #else\r
+ {\r
+ GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12;\r
+ }\r
+ #endif\r
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;\r
+ GPIO_InitStruct.Pull = GPIO_PULLUP;\r
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;\r
+ GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;\r
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);\r
+\r
+ /* GPIOD configuration */\r
+ GPIO_InitStruct.Pin = GPIO_PIN_2;\r
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;\r
+ GPIO_InitStruct.Pull = GPIO_PULLUP;\r
+ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;\r
+ GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;\r
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);\r
+\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+FF_Disk_t *FF_SDDiskInit( const char *pcName )\r
+{\r
+FF_Error_t xFFError;\r
+BaseType_t xPartitionNumber = 0;\r
+FF_CreationParameters_t xParameters;\r
+FF_Disk_t *pxDisk;\r
+\r
+ xSDCardStatus = prvSDMMCInit( 0 );\r
+\r
+ if( xSDCardStatus != pdPASS )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskInit: prvSDMMCInit failed\n" );\r
+ pxDisk = NULL;\r
+ }\r
+ else\r
+ {\r
+ pxDisk = (FF_Disk_t *)ffconfigMALLOC( sizeof( *pxDisk ) );\r
+ if( pxDisk == NULL )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );\r
+ }\r
+ else\r
+ {\r
+ /* Initialise the created disk structure. */\r
+ memset( pxDisk, '\0', sizeof( *pxDisk ) );\r
+\r
+ pxDisk->ulNumberOfSectors = xSDCardInfo.CardCapacity / 512;\r
+\r
+ if( xPlusFATMutex == NULL )\r
+ {\r
+ xPlusFATMutex = xSemaphoreCreateRecursiveMutex();\r
+ }\r
+ pxDisk->ulSignature = sdSIGNATURE;\r
+\r
+ if( xPlusFATMutex != NULL)\r
+ {\r
+ memset( &xParameters, '\0', sizeof( xParameters ) );\r
+ xParameters.ulMemorySize = sdIOMAN_MEM_SIZE;\r
+ xParameters.ulSectorSize = 512;\r
+ xParameters.fnWriteBlocks = prvFFWrite;\r
+ xParameters.fnReadBlocks = prvFFRead;\r
+ xParameters.pxDisk = pxDisk;\r
+\r
+ /* prvFFRead()/prvFFWrite() are not re-entrant and must be\r
+ protected with the use of a semaphore. */\r
+ xParameters.xBlockDeviceIsReentrant = pdFALSE;\r
+\r
+ /* The semaphore will be used to protect critical sections in\r
+ the +FAT driver, and also to avoid concurrent calls to\r
+ prvFFRead()/prvFFWrite() from different tasks. */\r
+ xParameters.pvSemaphore = ( void * ) xPlusFATMutex;\r
+\r
+ pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );\r
+\r
+ if( pxDisk->pxIOManager == NULL )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) );\r
+ FF_SDDiskDelete( pxDisk );\r
+ pxDisk = NULL;\r
+ }\r
+ else\r
+ {\r
+ pxDisk->xStatus.bIsInitialised = pdTRUE;\r
+ pxDisk->xStatus.bPartitionNumber = xPartitionNumber;\r
+ if( FF_SDDiskMount( pxDisk ) == 0 )\r
+ {\r
+ FF_SDDiskDelete( pxDisk );\r
+ pxDisk = NULL;\r
+ }\r
+ else\r
+ {\r
+ if( pcName == NULL )\r
+ {\r
+ pcName = "/";\r
+ }\r
+ FF_FS_Add( pcName, pxDisk );\r
+ FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );\r
+ FF_SDDiskShowPartition( pxDisk );\r
+ }\r
+ } /* if( pxDisk->pxIOManager != NULL ) */\r
+ } /* if( xPlusFATMutex != NULL) */\r
+ } /* if( pxDisk != NULL ) */\r
+ } /* if( xSDCardStatus == pdPASS ) */\r
+\r
+ return pxDisk;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )\r
+{\r
+FF_Error_t xError;\r
+BaseType_t xReturn = pdFAIL;\r
+\r
+ xError = FF_Unmount( pxDisk );\r
+\r
+ if( FF_isERR( xError ) != pdFALSE )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );\r
+ }\r
+ else\r
+ {\r
+ /* Format the drive - try FAT32 with large clusters. */\r
+ xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);\r
+\r
+ if( FF_isERR( xError ) )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );\r
+ }\r
+ else\r
+ {\r
+ FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );\r
+ pxDisk->xStatus.bPartitionNumber = xPartitionNumber;\r
+ xError = FF_SDDiskMount( pxDisk );\r
+ FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );\r
+ if( FF_isERR( xError ) == pdFALSE )\r
+ {\r
+ xReturn = pdPASS;\r
+ FF_SDDiskShowPartition( pxDisk );\r
+ }\r
+ }\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk )\r
+{\r
+FF_Error_t xFFError;\r
+BaseType_t xReturn = pdPASS;\r
+\r
+ if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) )\r
+ {\r
+ pxDisk->xStatus.bIsMounted = pdFALSE;\r
+ xFFError = FF_Unmount( pxDisk );\r
+\r
+ if( FF_isERR( xFFError ) )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError );\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ FF_PRINTF( "Drive unmounted\n" );\r
+ }\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk )\r
+{\r
+BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */\r
+\r
+ /*_RB_ parameter not used. */\r
+ ( void ) pxDisk;\r
+\r
+ FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus );\r
+ return xStatus;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )\r
+{\r
+FF_Error_t xFFError;\r
+BaseType_t xReturn;\r
+\r
+ /* Mount the partition */\r
+ xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );\r
+\r
+ if( FF_isERR( xFFError ) )\r
+ {\r
+ FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ pxDisk->xStatus.bIsMounted = pdTRUE;\r
+ FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );\r
+ xReturn = pdPASS;\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )\r
+{\r
+FF_IOManager_t *pxReturn;\r
+\r
+ if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )\r
+ {\r
+ pxReturn = pxDisk->pxIOManager;\r
+ }\r
+ else\r
+ {\r
+ pxReturn = NULL;\r
+ }\r
+ return pxReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Release all resources */\r
+BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )\r
+{\r
+ if( pxDisk != NULL )\r
+ {\r
+ pxDisk->ulSignature = 0;\r
+ pxDisk->xStatus.bIsInitialised = 0;\r
+ if( pxDisk->pxIOManager != NULL )\r
+ {\r
+ if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )\r
+ {\r
+ FF_Unmount( pxDisk );\r
+ }\r
+ FF_DeleteIOManager( pxDisk->pxIOManager );\r
+ }\r
+\r
+ vPortFree( pxDisk );\r
+ }\r
+ return 1;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )\r
+{\r
+FF_Error_t xError;\r
+uint64_t ullFreeSectors;\r
+uint32_t ulTotalSizeMB, ulFreeSizeMB;\r
+int iPercentageFree;\r
+FF_IOManager_t *pxIOManager;\r
+const char *pcTypeName = "unknown type";\r
+BaseType_t xReturn = pdPASS;\r
+\r
+ if( pxDisk == NULL )\r
+ {\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ pxIOManager = pxDisk->pxIOManager;\r
+\r
+ FF_PRINTF( "Reading FAT and calculating Free Space\n" );\r
+\r
+ switch( pxIOManager->xPartition.ucType )\r
+ {\r
+ case FF_T_FAT12:\r
+ pcTypeName = "FAT12";\r
+ break;\r
+\r
+ case FF_T_FAT16:\r
+ pcTypeName = "FAT16";\r
+ break;\r
+\r
+ case FF_T_FAT32:\r
+ pcTypeName = "FAT32";\r
+ break;\r
+\r
+ default:\r
+ pcTypeName = "UNKOWN";\r
+ break;\r
+ }\r
+\r
+ FF_GetFreeSize( pxIOManager, &xError );\r
+\r
+ ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;\r
+ iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /\r
+ ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );\r
+\r
+ ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB;\r
+ ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB );\r
+\r
+ /* It is better not to use the 64-bit format such as %Lu because it\r
+ might not be implemented. */\r
+ FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );\r
+ FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );\r
+ FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );\r
+ FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );\r
+ FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );\r
+ FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );\r
+ FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* SDIO init function */\r
+static void prvSDIO_SD_Init( void )\r
+{\r
+ xSDHandle.Instance = SDIO;\r
+ xSDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;\r
+ xSDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;\r
+ xSDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;\r
+\r
+ /* Start as a 1-bit bus and switch to 4-bits later on. */\r
+ xSDHandle.Init.BusWide = SDIO_BUS_WIDE_1B;\r
+\r
+ xSDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;\r
+\r
+ /* Use fastest CLOCK at 0. */\r
+ xSDHandle.Init.ClockDiv = 32;\r
+\r
+ #if( SDIO_USES_DMA != 0 )\r
+ {\r
+ xSDHandle.EventSetupFunction = prvEventSetupFunction;\r
+ xSDHandle.EventWaitFunction = prvEventWaitFunction;\r
+ }\r
+ #else\r
+ {\r
+ xSDHandle.EventSetupFunction = NULL;\r
+ xSDHandle.EventWaitFunction = NULL;\r
+ }\r
+ #endif\r
+ __HAL_RCC_SDIO_CLK_ENABLE( );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* This routine returns true if the SD-card is inserted. After insertion, it\r
+will wait for sdCARD_DETECT_DEBOUNCE_TIME_MS before returning pdTRUE. */\r
+BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk )\r
+{\r
+int xReturn;\r
+\r
+ xReturn = prvSDDetect();\r
+\r
+ if( xReturn != pdFALSE )\r
+ {\r
+ if( xCardDetect.bStableSignal == pdFALSE )\r
+ {\r
+ /* The card seems to be present. */\r
+ if( xCardDetect.bLastPresent == pdFALSE )\r
+ {\r
+ xCardDetect.bLastPresent = pdTRUE;\r
+ xCardDetect.xRemainingTime = pdMS_TO_TICKS( ( TickType_t ) sdCARD_DETECT_DEBOUNCE_TIME_MS );\r
+ /* Fetch the current time. */\r
+ vTaskSetTimeOutState( &xCardDetect.xTimeOut );\r
+ }\r
+ /* Has the timeout been reached? */\r
+ if( xTaskCheckForTimeOut( &xCardDetect.xTimeOut, &xCardDetect.xRemainingTime ) != pdFALSE )\r
+ {\r
+ xCardDetect.bStableSignal = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ /* keep returning false until de time-out is reached. */\r
+ xReturn = pdFALSE;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ xCardDetect.bLastPresent = pdFALSE;\r
+ xCardDetect.bStableSignal = pdFALSE;\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Raw SD-card detection, just return the GPIO status. */\r
+static BaseType_t prvSDDetect( void )\r
+{\r
+int iReturn;\r
+\r
+ /*!< Check GPIO to detect SD */\r
+ if( HAL_GPIO_ReadPin( configSD_DETECT_GPIO_PORT, configSD_DETECT_PIN ) != 0 )\r
+ {\r
+ /* The internal pull-up makes the signal high. */\r
+ iReturn = pdFALSE;\r
+ }\r
+ else\r
+ {\r
+ /* The card will pull the GPIO signal down. */\r
+ iReturn = pdTRUE;\r
+ }\r
+\r
+ return iReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber )\r
+{\r
+ /* 'xDriveNumber' not yet in use. */\r
+ ( void )xDriveNumber;\r
+\r
+ if( xSDCardSemaphore == NULL )\r
+ {\r
+ xSDCardSemaphore = xSemaphoreCreateBinary();\r
+ }\r
+ prvSDIO_SD_Init();\r
+\r
+ vGPIO_SD_Init( &xSDHandle );\r
+\r
+ #if( SDIO_USES_DMA != 0 )\r
+ {\r
+ prvSDIO_DMA_Init( );\r
+ }\r
+ #endif\r
+\r
+ int SD_state = SD_OK;\r
+ /* Check if the SD card is plugged in the slot */\r
+ if( prvSDDetect() == pdFALSE )\r
+ {\r
+ FF_PRINTF( "No SD card detected\n" );\r
+ return 0;\r
+ }\r
+ /* When starting up, skip debouncing of the Card Detect signal. */\r
+ xCardDetect.bLastPresent = pdTRUE;\r
+ xCardDetect.bStableSignal = pdTRUE;\r
+ /* Initialise the SDIO device and read the card parameters. */\r
+ SD_state = HAL_SD_Init( &xSDHandle, &xSDCardInfo );\r
+ #if( BUS_4BITS != 0 )\r
+ {\r
+ if( SD_state == SD_OK )\r
+ {\r
+ HAL_SD_ErrorTypedef rc;\r
+\r
+ xSDHandle.Init.BusWide = SDIO_BUS_WIDE_4B;\r
+ rc = HAL_SD_WideBusOperation_Config(&xSDHandle, SDIO_BUS_WIDE_4B);\r
+ if( rc != SD_OK )\r
+ {\r
+ FF_PRINTF( "HAL_SD_WideBus: %d: %s\n", rc, prvSDCodePrintable( ( uint32_t )rc ) );\r
+ }\r
+ }\r
+ }\r
+ #endif\r
+ FF_PRINTF( "HAL_SD_Init: %d: %s type: %s Capacity: %lu MB\n",\r
+ SD_state, prvSDCodePrintable( ( uint32_t )SD_state ),\r
+ xSDHandle.CardType == HIGH_CAPACITY_SD_CARD ? "SDHC" : "SD",\r
+ xSDCardInfo.CardCapacity / ( 1024 * 1024 ) );\r
+\r
+ return SD_state == SD_OK ? 1 : 0;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+struct xCODE_NAME\r
+{\r
+ uint32_t ulValue;\r
+ const char *pcName;\r
+};\r
+\r
+const struct xCODE_NAME xSD_CODES[] =\r
+{\r
+ { SD_CMD_CRC_FAIL, "CMD_CRC_FAIL: Command response received (but CRC check failed)" },\r
+ { SD_DATA_CRC_FAIL, "DATA_CRC_FAIL: Data block sent/received (CRC check failed)" },\r
+ { SD_CMD_RSP_TIMEOUT, "CMD_RSP_TIMEOUT: Command response timeout" },\r
+ { SD_DATA_TIMEOUT, "DATA_TIMEOUT: Data timeout" },\r
+ { SD_TX_UNDERRUN, "TX_UNDERRUN: Transmit FIFO underrun" },\r
+ { SD_RX_OVERRUN, "RX_OVERRUN: Receive FIFO overrun" },\r
+ { SD_START_BIT_ERR, "START_BIT_ERR: Start bit not detected on all data signals in wide bus mode" },\r
+ { SD_CMD_OUT_OF_RANGE, "CMD_OUT_OF_RANGE: Command's argument was out of range" },\r
+ { SD_ADDR_MISALIGNED, "ADDR_MISALIGNED: Misaligned address" },\r
+ { SD_BLOCK_LEN_ERR, "BLOCK_LEN_ERR: Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length" },\r
+ { SD_ERASE_SEQ_ERR, "ERASE_SEQ_ERR: An error in the sequence of erase command occurs." },\r
+ { SD_BAD_ERASE_PARAM, "BAD_ERASE_PARAM: An invalid selection for erase groups" },\r
+ { SD_WRITE_PROT_VIOLATION, "WRITE_PROT_VIOLATION: Attempt to program a write protect block" },\r
+ { SD_LOCK_UNLOCK_FAILED, "LOCK_UNLOCK_FAILED: Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card" },\r
+ { SD_COM_CRC_FAILED, "COM_CRC_FAILED: CRC check of the previous command failed" },\r
+ { SD_ILLEGAL_CMD, "ILLEGAL_CMD: Command is not legal for the card state" },\r
+ { SD_CARD_ECC_FAILED, "CARD_ECC_FAILED: Card internal ECC was applied but failed to correct the data" },\r
+ { SD_CC_ERROR, "CC_ERROR: Internal card controller error" },\r
+ { SD_GENERAL_UNKNOWN_ERROR, "GENERAL_UNKNOWN_ERROR: General or unknown error" },\r
+ { SD_STREAM_READ_UNDERRUN, "STREAM_READ_UNDERRUN: The card could not sustain data transfer in stream read operation" },\r
+ { SD_STREAM_WRITE_OVERRUN, "STREAM_WRITE_OVERRUN: The card could not sustain data programming in stream mode" },\r
+ { SD_CID_CSD_OVERWRITE, "CID_CSD_OVERWRITE: CID/CSD overwrite error" },\r
+ { SD_WP_ERASE_SKIP, "WP_ERASE_SKIP: Only partial address space was erased" },\r
+ { SD_CARD_ECC_DISABLED, "CARD_ECC_DISABLED: Command has been executed without using internal ECC" },\r
+ { SD_ERASE_RESET, "ERASE_RESET: Erase sequence was cleared before executing because an out of erase sequence command was received" },\r
+ { SD_AKE_SEQ_ERROR, "AKE_SEQ_ERROR: Error in sequence of authentication" },\r
+ { SD_INVALID_VOLTRANGE, "INVALID_VOLTRANGE" },\r
+ { SD_ADDR_OUT_OF_RANGE, "ADDR_OUT_OF_RANGE" },\r
+ { SD_SWITCH_ERROR, "SWITCH_ERROR" },\r
+ { SD_SDIO_DISABLED, "SDIO_DISABLED" },\r
+ { SD_SDIO_FUNCTION_BUSY, "SDIO_FUNCTION_BUSY" },\r
+ { SD_SDIO_FUNCTION_FAILED, "SDIO_FUNCTION_FAILED" },\r
+ { SD_SDIO_UNKNOWN_FUNCTION, "SDIO_UNKNOWN_FUNCTION" },\r
+\r
+ /**\r
+ * @brief Standard error defines\r
+ */\r
+ { SD_INTERNAL_ERROR, "INTERNAL_ERROR" },\r
+ { SD_NOT_CONFIGURED, "NOT_CONFIGURED" },\r
+ { SD_REQUEST_PENDING, "REQUEST_PENDING" },\r
+ { SD_REQUEST_NOT_APPLICABLE,"REQUEST_NOT_APPLICABLE" },\r
+ { SD_INVALID_PARAMETER, "INVALID_PARAMETER" },\r
+ { SD_UNSUPPORTED_FEATURE, "UNSUPPORTED_FEATURE" },\r
+ { SD_UNSUPPORTED_HW, "UNSUPPORTED_HW" },\r
+ { SD_ERROR, "ERROR" },\r
+ { SD_OK, "OK" },\r
+};\r
+/*-----------------------------------------------------------*/\r
+\r
+static const char *prvSDCodePrintable( uint32_t ulCode )\r
+{\r
+static char retString[32];\r
+const struct xCODE_NAME *pxCode;\r
+\r
+ for( pxCode = xSD_CODES; pxCode <= xSD_CODES + sdARRAY_SIZE( xSD_CODES ) - 1; pxCode++ )\r
+ {\r
+ if( pxCode->ulValue == ulCode )\r
+ {\r
+ return pxCode->pcName;\r
+ }\r
+ }\r
+ snprintf( retString, sizeof( retString ), "SD code %lu\n", ulCode );\r
+ return retString;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+\r
+ static void prvSDIO_DMA_Init( void )\r
+ {\r
+ static DMA_HandleTypeDef xRxDMAHandle;\r
+ static DMA_HandleTypeDef xTxDMAHandle;\r
+\r
+ /* Enable DMA2 clocks */\r
+ __DMAx_TxRx_CLK_ENABLE();\r
+\r
+ /* NVIC configuration for SDIO interrupts */\r
+ HAL_NVIC_SetPriority(SDIO_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY, 0);\r
+ HAL_NVIC_EnableIRQ(SDIO_IRQn);\r
+\r
+ /* Configure DMA Rx parameters */\r
+ xRxDMAHandle.Init.Channel = SD_DMAx_Rx_CHANNEL;\r
+ xRxDMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;\r
+ /* Peripheral address is fixed (FIFO). */\r
+ xRxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;\r
+ /* Memory address increases. */\r
+ xRxDMAHandle.Init.MemInc = DMA_MINC_ENABLE;\r
+ xRxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;\r
+ xRxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;\r
+ /* The peripheral has flow-control. */\r
+ xRxDMAHandle.Init.Mode = DMA_PFCTRL;\r
+ xRxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH;\r
+ xRxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
+ xRxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;\r
+ xRxDMAHandle.Init.MemBurst = DMA_MBURST_INC4;\r
+ xRxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4;\r
+\r
+ /* DMA2_Stream3. */\r
+ xRxDMAHandle.Instance = SD_DMAx_Rx_STREAM;\r
+\r
+ /* Associate the DMA handle */\r
+ __HAL_LINKDMA(&xSDHandle, hdmarx, xRxDMAHandle);\r
+\r
+ /* Deinitialize the stream for new transfer */\r
+ HAL_DMA_DeInit(&xRxDMAHandle);\r
+\r
+ /* Configure the DMA stream */\r
+ HAL_DMA_Init(&xRxDMAHandle);\r
+\r
+ /* Configure DMA Tx parameters */\r
+ xTxDMAHandle.Init.Channel = SD_DMAx_Tx_CHANNEL;\r
+ xTxDMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;\r
+ xTxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;\r
+ xTxDMAHandle.Init.MemInc = DMA_MINC_ENABLE;\r
+ xTxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;\r
+ xTxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;\r
+ xTxDMAHandle.Init.Mode = DMA_PFCTRL;\r
+ xTxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH;\r
+ xTxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
+ xTxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;\r
+ xTxDMAHandle.Init.MemBurst = DMA_MBURST_SINGLE;\r
+ xTxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4;\r
+\r
+ /* DMA2_Stream6. */\r
+ xTxDMAHandle.Instance = SD_DMAx_Tx_STREAM;\r
+\r
+ /* Associate the DMA handle */\r
+ __HAL_LINKDMA(&xSDHandle, hdmatx, xTxDMAHandle);\r
+\r
+ /* Deinitialize the stream for new transfer */\r
+ HAL_DMA_DeInit(&xTxDMAHandle);\r
+\r
+ /* Configure the DMA stream */\r
+ HAL_DMA_Init(&xTxDMAHandle);\r
+\r
+ /* NVIC configuration for DMA transfer complete interrupt */\r
+ HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0);\r
+ HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn);\r
+\r
+ /* NVIC configuration for DMA transfer complete interrupt */\r
+ HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0);\r
+ HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn);\r
+ }\r
+#endif /* SDIO_USES_DMA */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+// void SDIO_IRQHandler(void)\r
+ void SDMMC1_IRQHandler(void)\r
+ {\r
+ BaseType_t xHigherPriorityTaskWoken = 0;\r
+\r
+ HAL_SD_IRQHandler( &xSDHandle );\r
+ if( xSDCardSemaphore != NULL )\r
+ {\r
+ xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken );\r
+ }\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+ }\r
+\r
+#endif /* SDIO_USES_DMA */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+\r
+ void DMA2_Stream6_IRQHandler(void)\r
+ {\r
+ BaseType_t xHigherPriorityTaskWoken = 0;\r
+\r
+ /* DMA SDIO-TX interrupt handler. */\r
+ HAL_DMA_IRQHandler (xSDHandle.hdmatx);\r
+ if( xSDCardSemaphore != NULL )\r
+ {\r
+ xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken );\r
+ }\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+ }\r
+\r
+#endif /* SDIO_USES_DMA */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+\r
+ void DMA2_Stream3_IRQHandler(void)\r
+ {\r
+ BaseType_t xHigherPriorityTaskWoken = 0;\r
+\r
+ /* DMA SDIO-RX interrupt handler. */\r
+ HAL_DMA_IRQHandler (xSDHandle.hdmarx);\r
+ if( xSDCardSemaphore != NULL )\r
+ {\r
+ xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken );\r
+ }\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+ }\r
+\r
+#endif /* SDIO_USES_DMA */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+\r
+ static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle )\r
+ {\r
+ /* A DMA transfer to or from the SD-card is about to start.\r
+ Reset the timers that will be used in prvEventWaitFunction() */\r
+ xDMARemainingTime = sdMAX_TIME_TICKS;\r
+ vTaskSetTimeOutState( &xDMATimeOut );\r
+ }\r
+\r
+#endif /* SDIO_USES_DMA != 0 */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( SDIO_USES_DMA != 0 )\r
+\r
+ static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle )\r
+ {\r
+ uint32_t ulReturn;\r
+\r
+ /*\r
+ * It was measured how quickly a DMA interrupt was received. It varied\r
+ * between 0 and 4 ms.\r
+ * <= 1 ms : 8047\r
+ * <= 2 ms : 1850\r
+ * <= 3 ms : 99\r
+ * <= 4 ms : 79\r
+ * >= 5 ms : 0 times\r
+ */\r
+\r
+ if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE )\r
+ {\r
+ /* The timeout has been reached, no need to block. */\r
+ ulReturn = 1UL;\r
+ }\r
+ else\r
+ {\r
+ /* The timeout has not been reached yet, block on the semaphore. */\r
+ xSemaphoreTake( xSDCardSemaphore, xDMARemainingTime );\r
+ if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE )\r
+ {\r
+ ulReturn = 1UL;\r
+ }\r
+ else\r
+ {\r
+ ulReturn = 0UL;\r
+ }\r
+ }\r
+\r
+ return ulReturn;\r
+ }\r
+\r
+#endif /* SDIO_USES_DMA != 0 */\r
+/*-----------------------------------------------------------*/\r
+\r
+void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin )\r
+{\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ if( GPIO_Pin == configSD_DETECT_PIN )\r
+ {\r
+ vApplicationCardDetectChangeHookFromISR( &xHigherPriorityTaskWoken );\r
+ portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void EXTI15_10_IRQHandler( void )\r
+{\r
+ HAL_GPIO_EXTI_IRQHandler( configSD_DETECT_PIN ); /* GPIO PIN H.13 */\r
+}\r
+/*-----------------------------------------------------------*/\r