]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / portable / STM32F7xx / ff_sddisk.c
diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c
new file mode 100644 (file)
index 0000000..35a95d2
--- /dev/null
@@ -0,0 +1,1204 @@
+/*\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