Add the Labs projects provided in the V10.2.1_191129 zip file.

This commit is contained in:
Richard Barry 2019-12-02 23:39:25 +00:00
parent 46e5937529
commit e5708b38e9
801 changed files with 356576 additions and 0 deletions

View file

@ -0,0 +1,815 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_sddisk.h"
#include "ff_sys.h"
/* Atmel includes. */
#include <board.h>
#include <sd_mmc.h>
#include "hr_gettime.h"
/* Misc definitions. */
#define sdSIGNATURE 0x41404342UL
#define sdHUNDRED_64_BIT ( 100ull )
#define sdBYTES_PER_MB ( 1024ull * 1024ull )
#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull )
#define sdIOMAN_MEM_SIZE 4096
#define xSDCardInfo ( sd_mmc_cards[ 0 ] )
#define sdAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
/* Define a time-out for all DMA transactions in msec. */
#ifndef sdMAX_TRANSFER_TIME
#define sdMAX_TRANSFER_TIME 4000
#endif
/* Define all possible interrupts of interest. */
#define sdHSMCI_INTERRUPT_FLAGS \
HSMCI_IER_NOTBUSY | \
HSMCI_IER_UNRE | \
HSMCI_IER_OVRE | \
HSMCI_IER_DTOE | \
HSMCI_IER_DCRCE | \
HSMCI_IER_TXBUFE | \
HSMCI_IER_RXBUFF | \
HSMCI_IER_XFRDONE
#define sdMSMCI_USE_SEMAPHORE 1
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
static TickType_t xDMARemainingTime;
static TimeOut_t xDMATimeOut;
static volatile uint32_t ulSDInterruptStatus;
static volatile int iWaitForWriting;
#if( sdMSMCI_USE_SEMAPHORE != 0 )
static SemaphoreHandle_t xSDSemaphore = NULL;
#else
static TaskHandle_t xSDTaskHandle = NULL;
#endif
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*
* Return pdFALSE if the SD card is not inserted.
*/
static BaseType_t prvSDDetect( void );
/*
* Check if the card is present, and if so, print out some info on the card.
*/
static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber );
/*-----------------------------------------------------------*/
/*
* Mutex for partition.
*/
static SemaphoreHandle_t xPlusFATMutex = NULL;
/*
* Remembers if the card is currently considered to be present.
*/
static BaseType_t xSDCardStatus = pdFALSE;
/*-----------------------------------------------------------*/
typedef struct {
uint32_t ulStart;
uint32_t ulSize;
} MemoryGroup_t;
#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x)[0])
static const MemoryGroup_t xMemories[] = {
{ IRAM_ADDR, IRAM_SIZE },
{ EBI_CS1_ADDR, 512ul * 1024ul },
{ EBI_CS3_ADDR, 512ul * 1024ul },
};
static BaseType_t prvIsInternalRAM( uint8_t *pucBuffer )
{
BaseType_t xResult = pdFALSE, xIndex;
uint32_t ulAddress = ( uint32_t ) pucBuffer;
for( xIndex = 0; xIndex < ARRAY_SIZE( xMemories ); xIndex++ )
{
if( ( ulAddress >= xMemories[ xIndex].ulStart ) && ( ulAddress < xMemories[ xIndex].ulStart + xMemories[ xIndex].ulSize ) )
{
xResult = pdTRUE;
break;
}
}
return xResult;
}
/*-----------------------------------------------------------*/
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult = pdFALSE;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
/* As the MCI driver is configured to use DMA, it must be tested that
the buffer is located in internal SRAM ("IRAM") and if it is 4-byte aligned. */
if( sdAligned( pucBuffer ) && prvIsInternalRAM( pucBuffer ) )
{
lResult = sd_physical_read( ulSectorNumber, pucBuffer, ulSectorCount );
}
else
{
uint32_t ulSector;
uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul );
/* The buffer is NOT word-aligned, read to an aligned buffer and then
copy the data to the user provided buffer. */
if( pucDMABuffer != NULL )
{
for( ulSector = 0; ulSector < ulSectorCount; ulSector++ )
{
lResult = sd_physical_read( ulSectorNumber + ulSector, pucDMABuffer, 1 );
if( lResult == pdFALSE )
{
break;
}
/* Copy to the user-provided buffer. */
memcpy( pucBuffer + 512ul * ulSector, pucDMABuffer, 512ul );
}
ffconfigFREE( pucDMABuffer );
}
else
{
FF_PRINTF( "prvFFRead: malloc failed\n" );
lResult = pdFALSE;
}
}
if( lResult != pdFALSE )
{
lReturnCode = 0L;
}
else
{
/* Some error occurred. */
FF_PRINTF( "prvFFRead: %lu: %ld\n", ulSectorNumber, lResult );
}
}
else
{
/* Make sure no random data is in the returned buffer. */
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL );
if( pxDisk->xStatus.bIsInitialised != pdFALSE )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult = pdFALSE;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
/* As the MCI driver is configured to use DMA, it must be tested that
the buffer is located in internal SRAM ("IRAM") and if it is 4-byte aligned. */
if( sdAligned( pucBuffer ) && prvIsInternalRAM( pucBuffer ) )
{
lResult = sd_physical_write( ulSectorNumber, pucBuffer, ulSectorCount );
}
else
{
uint32_t ulSector;
uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul );
/* The buffer is NOT word-aligned, read to an aligned buffer and then
copy the data to the user provided buffer. */
if( pucDMABuffer != NULL )
{
for( ulSector = 0; ulSector < ulSectorCount; ulSector++ )
{
/* Copy from the user provided buffer to the temporary buffer. */
memcpy( pucDMABuffer, pucBuffer + 512ul * ulSector, 512ul );
lResult = sd_physical_write( ulSectorNumber + ulSector, pucDMABuffer, 1 );
if( lResult == pdFALSE )
{
break;
}
}
ffconfigFREE( pucDMABuffer );
}
else
{
FF_PRINTF( "prvFFWrite: malloc failed\n" );
lResult = pdFALSE;
}
}
if( lResult != pdFALSE )
{
/* No errors. */
lReturnCode = 0L;
}
else
{
FF_PRINTF( "prvFFWrite: %lu: %ld\n", ulSectorNumber, lResult );
}
}
else
{
if( pxDisk->xStatus.bIsInitialised != pdFALSE )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
void FF_SDDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
/* Initialise the SDIO driver and mount an SD card */
FF_Disk_t *FF_SDDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t *pxDisk;
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
{
NVIC_SetPriority( HSMCI_IRQn, configHSMCI_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( HSMCI_IRQn );
#if( sdMSMCI_USE_SEMAPHORE != 0 )
{
if( xSDSemaphore == NULL )
{
xSDSemaphore = xSemaphoreCreateBinary();
}
}
#endif /* sdMSMCI_USE_SEMAPHORE */
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
xSDCardStatus = prvSDMMCInit( 0 );
if( xSDCardStatus == pdPASS )
{
pxDisk = (FF_Disk_t *)ffconfigMALLOC( sizeof( *pxDisk ) );
if( pxDisk != NULL )
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
/* The Atmel MMC driver sets capacity as a number of KB.
Divide by two to get the number of 512-byte sectors. */
pxDisk->ulNumberOfSectors = xSDCardInfo.capacity << 1;
if( xPlusFATMutex == NULL )
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulSignature = sdSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = sdIOMAN_MEM_SIZE;
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) );
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SDDiskMount( pxDisk ) == 0 )
{
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
else
{
FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );
}
} /* if( xSDCardStatus == pdPASS ) */
else
{
FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\n" );
pxDisk = NULL;
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
xError = FF_SDDiskMount( pxDisk );
FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn = pdPASS;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) )
{
pxDisk->xStatus.bIsMounted = pdFALSE;
xFFError = FF_Unmount( pxDisk );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError );
xReturn = pdFAIL;
}
else
{
FF_PRINTF( "Drive unmounted\n" );
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk )
{
BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */
/*_RB_ parameter not used. */
( void ) pxDisk;
FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus );
return xStatus;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
FF_SDDiskShowPartition( pxDisk );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk )
{
BaseType_t xIsPresent;
void *pvSemaphore;
if( ( pxDisk != NULL ) && ( pxDisk->pxIOManager ) )
{
pvSemaphore = pxDisk->pxIOManager->pvSemaphore;
}
else
{
pvSemaphore = NULL;
}
/*_RB_ Can these NULL checks be moved inside the FF_nnnSemaphore() functions? */
/*_HT_ I'm afraid not, both functions start with configASSERT( pxSemaphore ); */
if( pvSemaphore != NULL )
{
FF_PendSemaphore( pvSemaphore );
}
xIsPresent = prvSDDetect();
if( pvSemaphore != NULL )
{
FF_ReleaseSemaphore( pvSemaphore );
}
return xIsPresent;
}
/*-----------------------------------------------------------*/
static BaseType_t prvSDDetect( void )
{
static BaseType_t xWasPresent;
BaseType_t xIsPresent;
sd_mmc_err_t xSDPresence;
if( xWasPresent == pdFALSE )
{
/* Try to initialize SD MMC stack */
sd_mmc_init();
xSDPresence = sd_mmc_check( 0 );
if( ( xSDPresence == SD_MMC_OK ) || ( xSDPresence == SD_MMC_INIT_ONGOING ) )
{
xIsPresent = pdTRUE;
}
else
{
xIsPresent = pdFALSE;
}
}
else
{
/* See if the card is still present. */
xSDPresence = sd_mmc_check_status(0);
if( xSDPresence == SD_MMC_OK )
{
xIsPresent = pdTRUE;
}
else
{
xIsPresent = pdFALSE;
}
}
xWasPresent = xIsPresent;
return xIsPresent;
}
/*-----------------------------------------------------------*/
static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber )
{
BaseType_t xReturn;
/* 'xDriveNumber' not yet in use. */
( void ) xDriveNumber;
/* Check if the SD card is plugged in the slot */
if( prvSDDetect() == pdFALSE )
{
FF_PRINTF( "No SD card detected\n" );
xReturn = pdFAIL;
}
else
{
FF_PRINTF( "HAL_SD_Init: type: %s Capacity: %lu MB\n",
xSDCardInfo.type & CARD_TYPE_HC ? "SDHC" : "SD",
( xSDCardInfo.capacity << 1 ) / 2048 );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
void HSMCI_Handler( void )
{
uint32_t ulSR;
BaseType_t xSwitchRequired = pdFALSE;
ulSR = HSMCI->HSMCI_SR & HSMCI->HSMCI_IMR;
HSMCI->HSMCI_IDR = ulSR;
ulSDInterruptStatus |= ulSR;
#if( sdMSMCI_USE_SEMAPHORE != 0 )
{
if( xSDSemaphore != NULL )
{
xSemaphoreGiveFromISR( xSDSemaphore, &xSwitchRequired );
}
}
#else
{
if( xSDTaskHandle != NULL )
{
vTaskNotifyGiveFromISR( xSDTaskHandle, ( BaseType_t * ) &xSwitchRequired );
}
}
#endif
if( xSwitchRequired != pdFALSE )
{
portEND_SWITCHING_ISR( xSwitchRequired );
}
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
void vMCIEventSetupFunction( int iForWriting )
{
iWaitForWriting = iForWriting != 0;
#if( sdMSMCI_USE_SEMAPHORE == 0 )
{
xSDTaskHandle = xTaskGetCurrentTaskHandle();
}
#endif
ulSDInterruptStatus = 0;
HSMCI->HSMCI_IER = sdHSMCI_INTERRUPT_FLAGS;
/* A DMA transfer to or from the SD-card is about to start.
Reset the timers that will be used in prvEventWaitFunction() */
xDMARemainingTime = pdMS_TO_TICKS( sdMAX_TRANSFER_TIME );
vTaskSetTimeOutState( &xDMATimeOut );
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
void vMCIEventReadyFunction()
{
#if( sdMSMCI_USE_SEMAPHORE == 0 )
{
xSDTaskHandle = NULL;
}
#endif
ulSDInterruptStatus = 0;
HSMCI->HSMCI_IDR = sdHSMCI_INTERRUPT_FLAGS;
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
uint32_t ulMCIEventWaitFunction( uint32_t ulMask )
{
/*
* It was measured how quickly a DMA interrupt was received. It varied
* between 0 and 4 ms.
* <= 1 ms : 8047
* <= 2 ms : 1850
* <= 3 ms : 99
* <= 4 ms : 79
* >= 5 ms : 0 times
*/
if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE )
{
/* The timeout has been reached, no need to block. */
FF_PRINTF( "ulMCIEventWaitFunction: %s timed out. SR = %08x\n",
iWaitForWriting ? "Write" : "Read", ulSDInterruptStatus );
}
else
{
/* The timeout has not been reached yet, block on the semaphore. */
#if( sdMSMCI_USE_SEMAPHORE != 0 )
{
if( ( ulSDInterruptStatus & ulMask ) == 0ul )
{
xSemaphoreTake( xSDSemaphore, xDMARemainingTime );
}
}
#else
{
if( ( ulSDInterruptStatus & ulMask ) == 0ul )
{
ulTaskNotifyTake( pdFALSE, xDMARemainingTime );
}
}
#endif
if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE )
{
FF_PRINTF( "ulMCIEventWaitFunction: %s timed out. SR = %08x\n",
iWaitForWriting ? "Write" : "Read", ulSDInterruptStatus );
}
}
return ulSDInterruptStatus;
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,552 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_sddisk.h"
#include "ff_sys.h"
/* Atmel includes. */
#include <sd_mmc.h>
/* Misc definitions. */
#define sdSIGNATURE 0x41404342UL
#define sdHUNDRED_64_BIT ( 100ull )
#define sdBYTES_PER_MB ( 1024ull * 1024ull )
#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull )
#define sdIOMAN_MEM_SIZE 4096
#define xSDCardInfo ( sd_mmc_cards[ 0 ] )
/*-----------------------------------------------------------*/
/*
* Return pdFALSE if the SD card is not inserted.
*/
static BaseType_t prvSDDetect( void );
/*
* Check if the card is present, and if so, print out some info on the card.
*/
static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber );
/*-----------------------------------------------------------*/
/*
* Mutex for partition.
*/
static SemaphoreHandle_t xPlusFATMutex = NULL;
/*
* Remembers if the card is currently considered to be present.
*/
static BaseType_t xSDCardStatus = pdFALSE;
/*-----------------------------------------------------------*/
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
lResult = sd_physical_read( ulSectorNumber, pucBuffer, ulSectorCount);
if( lResult != pdFALSE )
{
lReturnCode = 0L;
}
else
{
/* Some error occurred. */
FF_PRINTF( "prvFFRead: %lu: %lu\n", ulSectorNumber, lResult );
}
}
else
{
/* Make sure no random data is in the returned buffer. */
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL );
if( pxDisk->xStatus.bIsInitialised != pdFALSE )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;
BaseType_t xResult;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
xResult = sd_physical_write( ulSectorNumber, pucBuffer, ulSectorCount );
if( xResult != pdFALSE )
{
/* No errors. */
lReturnCode = 0L;
}
else
{
FF_PRINTF( "prvFFWrite: %lu: %lu\n", ulSectorNumber, xResult );
}
}
else
{
if( pxDisk->xStatus.bIsInitialised != pdFALSE )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
void FF_SDDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
/* Initialise the SDIO driver and mount an SD card */
FF_Disk_t *FF_SDDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t *pxDisk;
xSDCardStatus = prvSDMMCInit( 0 );
if( xSDCardStatus != pdPASS )
{
FF_PRINTF( "FF_SDDiskInit: prvSDMMCInit failed\n" );
pxDisk = NULL;
}
else
{
pxDisk = ( FF_Disk_t * )pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk == NULL )
{
FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );
}
else
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
/* The Atmel MMC driver sets capacity as a number of KB.
Divide by two to get the number of 512-byte sectors. */
pxDisk->ulNumberOfSectors = xSDCardInfo.capacity << 1;
if( xPlusFATMutex == NULL )
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulSignature = sdSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = sdIOMAN_MEM_SIZE;
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) );
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SDDiskMount( pxDisk ) == 0 )
{
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );
FF_SDDiskShowPartition( pxDisk );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
} /* if( xSDCardStatus == pdPASS ) */
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, aPart, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = aPart;
xError = FF_SDDiskMount( pxDisk );
FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
FF_SDDiskShowPartition( pxDisk );
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn = pdPASS;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) )
{
pxDisk->xStatus.bIsMounted = pdFALSE;
xFFError = FF_Unmount( pxDisk );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError );
xReturn = pdFAIL;
}
else
{
FF_PRINTF( "Drive unmounted\n" );
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk )
{
BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */
/*_RB_ parameter not used. */
( void ) pxDisk;
FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus );
return xStatus;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk )
{
BaseType_t xIsPresent;
void *pvSemaphore;
if( ( pxDisk != NULL ) &&
( pxDisk->pxIOManager ) )
{
pvSemaphore = pxDisk->pxIOManager->pvSemaphore;
}
else
{
pvSemaphore = NULL;
}
/*_RB_ Can these NULL checks be moved inside the FF_nnnSemaphore() functions? */
/*_HT_ I'm afraid not, both functions start with configASSERT( pxSemaphore ); */
if( pvSemaphore != NULL )
{
FF_PendSemaphore( pvSemaphore );
}
xIsPresent = prvSDDetect();
if( pvSemaphore != NULL )
{
FF_ReleaseSemaphore( pvSemaphore );
}
return xIsPresent;
}
/*-----------------------------------------------------------*/
static BaseType_t prvSDDetect( void )
{
static BaseType_t xWasPresent;
BaseType_t xIsPresent;
sd_mmc_err_t xSDPresence;
if( xWasPresent == pdFALSE )
{
/* Try to initialize SD MMC stack */
sd_mmc_init();
xSDPresence = sd_mmc_check( 0 );
if( ( xSDPresence == SD_MMC_OK ) || ( xSDPresence == SD_MMC_INIT_ONGOING ) )
{
xIsPresent = pdTRUE;
}
else
{
xIsPresent = pdFALSE;
}
}
else
{
/* See if the card is still present. */
xSDPresence = sd_mmc_check_status(0);
if( xSDPresence == SD_MMC_OK )
{
xIsPresent = pdTRUE;
}
else
{
xIsPresent = pdFALSE;
}
}
xWasPresent = xIsPresent;
return xIsPresent;
}
/*-----------------------------------------------------------*/
static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber )
{
BaseType_t xReturn;
/* 'xDriveNumber' not yet in use. */
( void ) xDriveNumber;
/* Check if the SD card is plugged in the slot */
if( prvSDDetect() == pdFALSE )
{
FF_PRINTF( "No SD card detected\n" );
xReturn = pdFAIL;
}
else
{
FF_PRINTF( "HAL_SD_Init: type: %s Capacity: %lu MB\n",
xSDCardInfo.type & CARD_TYPE_HC ? "SDHC" : "SD",
( xSDCardInfo.capacity << 1 ) / 2048 );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,11 @@
Disk drivers are provided as examples only, and do not form part of the
FreeRTOS+FAT itself. They:
+ May be based on driver code provided by the chip vendors,
+ May not have been tested in all possible configurations,
+ Will not necessarily be optimised.
+ May not necessarily comply with any particular coding standard.
+ May have dependencies on chip company libraries.
+ May include other hardware board dependencies.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,802 @@
/**
******************************************************************************
* @file stm32f4xx_hal_sd.h
* @author MCD Application Team
* @version V1.3.2
* @date 26-June-2015
* @brief Header file of SD HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_SD_H
#define __STM32F4xx_HAL_SD_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_ll_sdmmc.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @defgroup SD SD
* @brief SD HAL module driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup SD_Exported_Types SD Exported Types
* @{
*/
/** @defgroup SD_Exported_Types_Group1 SD Handle Structure definition
* @{
*/
#define SD_InitTypeDef SDIO_InitTypeDef
#define SD_TypeDef SDIO_TypeDef
struct xSD_Handle;
/* A function will be called at the start of a DMA action. */
typedef void ( * SD_EventSetupFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ );
/* This function is supposed to wait for an event: SDIO or DMA.
* Return non-zero if a timeout has been reached. */
typedef uint32_t ( * SD_EventWaitFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ );
typedef struct xSD_Handle
{
SD_TypeDef *Instance; /*!< SDIO register base address */
SD_InitTypeDef Init; /*!< SD required parameters */
HAL_LockTypeDef Lock; /*!< SD locking object */
uint32_t CardType; /*!< SD card type */
uint32_t RCA; /*!< SD relative card address */
uint32_t CSD[4]; /*!< SD card specific data table */
uint32_t CID[4]; /*!< SD card identification number table */
__IO uint32_t SdTransferCplt; /*!< SD transfer complete flag in non blocking mode */
__IO uint32_t SdTransferErr; /*!< SD transfer error flag in non blocking mode */
__IO uint32_t DmaTransferCplt; /*!< SD DMA transfer complete flag */
__IO uint32_t SdOperation; /*!< SD transfer operation (read/write) */
DMA_HandleTypeDef *hdmarx; /*!< SD Rx DMA handle parameters */
DMA_HandleTypeDef *hdmatx; /*!< SD Tx DMA handle parameters */
SD_EventSetupFunctionTypeDef EventSetupFunction;
SD_EventWaitFunctionTypeDef EventWaitFunction;
}SD_HandleTypeDef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group2 Card Specific Data: CSD Register
* @{
*/
typedef struct
{
__IO uint8_t CSDStruct; /*!< CSD structure */
__IO uint8_t SysSpecVersion; /*!< System specification version */
__IO uint8_t Reserved1; /*!< Reserved */
__IO uint8_t TAAC; /*!< Data read access time 1 */
__IO uint8_t NSAC; /*!< Data read access time 2 in CLK cycles */
__IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */
__IO uint16_t CardComdClasses; /*!< Card command classes */
__IO uint8_t RdBlockLen; /*!< Max. read data block length */
__IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */
__IO uint8_t WrBlockMisalign; /*!< Write block misalignment */
__IO uint8_t RdBlockMisalign; /*!< Read block misalignment */
__IO uint8_t DSRImpl; /*!< DSR implemented */
__IO uint8_t Reserved2; /*!< Reserved */
__IO uint32_t DeviceSize; /*!< Device Size */
__IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
__IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
__IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
__IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
__IO uint8_t DeviceSizeMul; /*!< Device size multiplier */
__IO uint8_t EraseGrSize; /*!< Erase group size */
__IO uint8_t EraseGrMul; /*!< Erase group size multiplier */
__IO uint8_t WrProtectGrSize; /*!< Write protect group size */
__IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */
__IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */
__IO uint8_t WrSpeedFact; /*!< Write speed factor */
__IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */
__IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
__IO uint8_t Reserved3; /*!< Reserved */
__IO uint8_t ContentProtectAppli; /*!< Content protection application */
__IO uint8_t FileFormatGrouop; /*!< File format group */
__IO uint8_t CopyFlag; /*!< Copy flag (OTP) */
__IO uint8_t PermWrProtect; /*!< Permanent write protection */
__IO uint8_t TempWrProtect; /*!< Temporary write protection */
__IO uint8_t FileFormat; /*!< File format */
__IO uint8_t ECC; /*!< ECC code */
__IO uint8_t CSD_CRC; /*!< CSD CRC */
__IO uint8_t Reserved4; /*!< Always 1 */
}HAL_SD_CSDTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group3 Card Identification Data: CID Register
* @{
*/
typedef struct
{
__IO uint8_t ManufacturerID; /*!< Manufacturer ID */
__IO uint16_t OEM_AppliID; /*!< OEM/Application ID */
__IO uint32_t ProdName1; /*!< Product Name part1 */
__IO uint8_t ProdName2; /*!< Product Name part2 */
__IO uint8_t ProdRev; /*!< Product Revision */
__IO uint32_t ProdSN; /*!< Product Serial Number */
__IO uint8_t Reserved1; /*!< Reserved1 */
__IO uint16_t ManufactDate; /*!< Manufacturing Date */
__IO uint8_t CID_CRC; /*!< CID CRC */
__IO uint8_t Reserved2; /*!< Always 1 */
}HAL_SD_CIDTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group4 SD Card Status returned by ACMD13
* @{
*/
typedef struct
{
__IO uint8_t DAT_BUS_WIDTH; /*!< Shows the currently defined data bus width */
__IO uint8_t SECURED_MODE; /*!< Card is in secured mode of operation */
__IO uint16_t SD_CARD_TYPE; /*!< Carries information about card type */
__IO uint32_t SIZE_OF_PROTECTED_AREA; /*!< Carries information about the capacity of protected area */
__IO uint8_t SPEED_CLASS; /*!< Carries information about the speed class of the card */
__IO uint8_t PERFORMANCE_MOVE; /*!< Carries information about the card's performance move */
__IO uint8_t AU_SIZE; /*!< Carries information about the card's allocation unit size */
__IO uint16_t ERASE_SIZE; /*!< Determines the number of AUs to be erased in one operation */
__IO uint8_t ERASE_TIMEOUT; /*!< Determines the timeout for any number of AU erase */
__IO uint8_t ERASE_OFFSET; /*!< Carries information about the erase offset */
}HAL_SD_CardStatusTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group5 SD Card information structure
* @{
*/
typedef struct
{
HAL_SD_CSDTypedef SD_csd; /*!< SD card specific data register */
HAL_SD_CIDTypedef SD_cid; /*!< SD card identification number register */
uint64_t CardCapacity; /*!< Card capacity */
uint32_t CardBlockSize; /*!< Card block size */
uint16_t RCA; /*!< SD relative card address */
uint8_t CardType; /*!< SD card type */
}HAL_SD_CardInfoTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group6 SD Error status enumeration Structure definition
* @{
*/
typedef enum
{
/**
* @brief SD specific error defines
*/
SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */
SD_DATA_CRC_FAIL = (2), /*!< Data block sent/received (CRC check failed) */
SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */
SD_DATA_TIMEOUT = (4), /*!< Data timeout */
SD_TX_UNDERRUN = (5), /*!< Transmit FIFO underrun */
SD_RX_OVERRUN = (6), /*!< Receive FIFO overrun */
SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in wide bus mode */
SD_CMD_OUT_OF_RANGE = (8), /*!< Command's argument was out of range. */
SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */
SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs. */
SD_BAD_ERASE_PARAM = (12), /*!< An invalid selection for erase groups */
SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */
SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */
SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */
SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */
SD_CC_ERROR = (18), /*!< Internal card controller error */
SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or unknown error */
SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */
SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */
SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */
SD_WP_ERASE_SKIP = (23), /*!< Only partial address space was erased */
SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */
SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */
SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */
SD_INVALID_VOLTRANGE = (27),
SD_ADDR_OUT_OF_RANGE = (28),
SD_SWITCH_ERROR = (29),
SD_SDIO_DISABLED = (30),
SD_SDIO_FUNCTION_BUSY = (31),
SD_SDIO_FUNCTION_FAILED = (32),
SD_SDIO_UNKNOWN_FUNCTION = (33),
/**
* @brief Standard error defines
*/
SD_INTERNAL_ERROR = (34),
SD_NOT_CONFIGURED = (35),
SD_REQUEST_PENDING = (36),
SD_REQUEST_NOT_APPLICABLE = (37),
SD_INVALID_PARAMETER = (38),
SD_UNSUPPORTED_FEATURE = (39),
SD_UNSUPPORTED_HW = (40),
SD_ERROR = (41),
SD_OK = (0)
}HAL_SD_ErrorTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group7 SD Transfer state enumeration structure
* @{
*/
typedef enum
{
SD_TRANSFER_OK = 0, /*!< Transfer success */
SD_TRANSFER_BUSY = 1, /*!< Transfer is occurring */
SD_TRANSFER_ERROR = 2 /*!< Transfer failed */
}HAL_SD_TransferStateTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group8 SD Card State enumeration structure
* @{
*/
typedef enum
{
SD_CARD_READY = ((uint32_t)0x00000001), /*!< Card state is ready */
SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002), /*!< Card is in identification state */
SD_CARD_STANDBY = ((uint32_t)0x00000003), /*!< Card is in standby state */
SD_CARD_TRANSFER = ((uint32_t)0x00000004), /*!< Card is in transfer state */
SD_CARD_SENDING = ((uint32_t)0x00000005), /*!< Card is sending an operation */
SD_CARD_RECEIVING = ((uint32_t)0x00000006), /*!< Card is receiving operation information */
SD_CARD_PROGRAMMING = ((uint32_t)0x00000007), /*!< Card is in programming state */
SD_CARD_DISCONNECTED = ((uint32_t)0x00000008), /*!< Card is disconnected */
SD_CARD_ERROR = ((uint32_t)0x000000FF) /*!< Card is in error state */
}HAL_SD_CardStateTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group9 SD Operation enumeration structure
* @{
*/
typedef enum
{
SD_READ_SINGLE_BLOCK = 0, /*!< Read single block operation */
SD_READ_MULTIPLE_BLOCK = 1, /*!< Read multiple blocks operation */
SD_WRITE_SINGLE_BLOCK = 2, /*!< Write single block operation */
SD_WRITE_MULTIPLE_BLOCK = 3 /*!< Write multiple blocks operation */
}HAL_SD_OperationTypedef;
/**
* @}
*/
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup SD_Exported_Constants SD Exported Constants
* @{
*/
/**
* @brief SD Commands Index
*/
#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /*!< Resets the SD memory card. */
#define SD_CMD_SEND_OP_COND ((uint8_t)1) /*!< Sends host capacity support information and activates the card's initialization process. */
#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /*!< Asks any card connected to the host to send the CID numbers on the CMD line. */
#define SD_CMD_SET_REL_ADDR ((uint8_t)3) /*!< Asks the card to publish a new relative address (RCA). */
#define SD_CMD_SET_DSR ((uint8_t)4) /*!< Programs the DSR of all cards. */
#define SD_CMD_SDIO_SEN_OP_COND ((uint8_t)5) /*!< Sends host capacity support information (HCS) and asks the accessed card to send its
operating condition register (OCR) content in the response on the CMD line. */
#define SD_CMD_HS_SWITCH ((uint8_t)6) /*!< Checks switchable function (mode 0) and switch card function (mode 1). */
#define SD_CMD_SEL_DESEL_CARD ((uint8_t)7) /*!< Selects the card by its own relative address and gets deselected by any other address */
#define SD_CMD_HS_SEND_EXT_CSD ((uint8_t)8) /*!< Sends SD Memory Card interface condition, which includes host supply voltage information
and asks the card whether card supports voltage. */
#define SD_CMD_SEND_CSD ((uint8_t)9) /*!< Addressed card sends its card specific data (CSD) on the CMD line. */
#define SD_CMD_SEND_CID ((uint8_t)10) /*!< Addressed card sends its card identification (CID) on the CMD line. */
#define SD_CMD_READ_DAT_UNTIL_STOP ((uint8_t)11) /*!< SD card doesn't support it. */
#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /*!< Forces the card to stop transmission. */
#define SD_CMD_SEND_STATUS ((uint8_t)13) /*!< Addressed card sends its status register. */
#define SD_CMD_HS_BUSTEST_READ ((uint8_t)14)
#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /*!< Sends an addressed card into the inactive state. */
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /*!< Sets the block length (in bytes for SDSC) for all following block commands
(read, write, lock). Default block length is fixed to 512 Bytes. Not effective
for SDHS and SDXC. */
#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of
fixed 512 bytes in case of SDHC and SDXC. */
#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18) /*!< Continuously transfers data blocks from card to host until interrupted by
STOP_TRANSMISSION command. */
#define SD_CMD_HS_BUSTEST_WRITE ((uint8_t)19) /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104. */
#define SD_CMD_WRITE_DAT_UNTIL_STOP ((uint8_t)20) /*!< Speed class control command. */
#define SD_CMD_SET_BLOCK_COUNT ((uint8_t)23) /*!< Specify block count for CMD18 and CMD25. */
#define SD_CMD_WRITE_SINGLE_BLOCK ((uint8_t)24) /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of
fixed 512 bytes in case of SDHC and SDXC. */
#define SD_CMD_WRITE_MULT_BLOCK ((uint8_t)25) /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows. */
#define SD_CMD_PROG_CID ((uint8_t)26) /*!< Reserved for manufacturers. */
#define SD_CMD_PROG_CSD ((uint8_t)27) /*!< Programming of the programmable bits of the CSD. */
#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /*!< Sets the write protection bit of the addressed group. */
#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /*!< Clears the write protection bit of the addressed group. */
#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /*!< Asks the card to send the status of the write protection bits. */
#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< Sets the address of the first write block to be erased. (For SD card only). */
#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< Sets the address of the last write block of the continuous range to be erased. */
#define SD_CMD_ERASE_GRP_START ((uint8_t)35) /*!< Sets the address of the first write block to be erased. Reserved for each command
system set by switch function command (CMD6). */
#define SD_CMD_ERASE_GRP_END ((uint8_t)36) /*!< Sets the address of the last write block of the continuous range to be erased.
Reserved for each command system set by switch function command (CMD6). */
#define SD_CMD_ERASE ((uint8_t)38) /*!< Reserved for SD security applications. */
#define SD_CMD_FAST_IO ((uint8_t)39) /*!< SD card doesn't support it (Reserved). */
#define SD_CMD_GO_IRQ_STATE ((uint8_t)40) /*!< SD card doesn't support it (Reserved). */
#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by
the SET_BLOCK_LEN command. */
#define SD_CMD_APP_CMD ((uint8_t)55) /*!< Indicates to the card that the next command is an application specific command rather
than a standard command. */
#define SD_CMD_GEN_CMD ((uint8_t)56) /*!< Used either to transfer a data block to the card or to get a data block from the card
for general purpose/application specific commands. */
#define SD_CMD_NO_CMD ((uint8_t)64)
/**
* @brief Following commands are SD Card Specific commands.
* SDIO_APP_CMD should be sent before sending these commands.
*/
#define SD_CMD_APP_SD_SET_BUSWIDTH ((uint8_t)6) /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus
widths are given in SCR register. */
#define SD_CMD_SD_APP_STATUS ((uint8_t)13) /*!< (ACMD13) Sends the SD status. */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS ((uint8_t)22) /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with
32bit+CRC data block. */
#define SD_CMD_SD_APP_OP_COND ((uint8_t)41) /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to
send its operating condition register (OCR) content in the response on the CMD line. */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT ((uint8_t)42) /*!< (ACMD42) Connects/Disconnects the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card. */
#define SD_CMD_SD_APP_SEND_SCR ((uint8_t)51) /*!< Reads the SD Configuration Register (SCR). */
#define SD_CMD_SDIO_RW_DIRECT ((uint8_t)52) /*!< For SD I/O card only, reserved for security specification. */
#define SD_CMD_SDIO_RW_EXTENDED ((uint8_t)53) /*!< For SD I/O card only, reserved for security specification. */
/**
* @brief Following commands are SD Card Specific security commands.
* SD_CMD_APP_CMD should be sent before sending these commands.
*/
#define SD_CMD_SD_APP_GET_MKB ((uint8_t)43) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_MID ((uint8_t)44) /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RN1 ((uint8_t)45) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RN2 ((uint8_t)46) /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RES2 ((uint8_t)47) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RES1 ((uint8_t)48) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK ((uint8_t)18) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_ERASE ((uint8_t)38) /*!< For SD card only */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA ((uint8_t)49) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB ((uint8_t)48) /*!< For SD card only */
/**
* @brief Supported SD Memory Cards
*/
#define STD_CAPACITY_SD_CARD_V1_1 ((uint32_t)0x00000000)
#define STD_CAPACITY_SD_CARD_V2_0 ((uint32_t)0x00000001)
#define HIGH_CAPACITY_SD_CARD ((uint32_t)0x00000002)
#define MULTIMEDIA_CARD ((uint32_t)0x00000003)
#define SECURE_DIGITAL_IO_CARD ((uint32_t)0x00000004)
#define HIGH_SPEED_MULTIMEDIA_CARD ((uint32_t)0x00000005)
#define SECURE_DIGITAL_IO_COMBO_CARD ((uint32_t)0x00000006)
#define HIGH_CAPACITY_MMC_CARD ((uint32_t)0x00000007)
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup SD_Exported_macros SD Exported Macros
* @brief macros to handle interrupts and specific clock configurations
* @{
*/
/**
* @brief Enable the SD device.
* @retval None
*/
#define __HAL_SD_SDIO_ENABLE() __SDIO_ENABLE()
/**
* @brief Disable the SD device.
* @retval None
*/
#define __HAL_SD_SDIO_DISABLE() __SDIO_DISABLE()
/**
* @brief Enable the SDIO DMA transfer.
* @retval None
*/
#define __HAL_SD_SDIO_DMA_ENABLE() __SDIO_DMA_ENABLE()
/**
* @brief Disable the SDIO DMA transfer.
* @retval None
*/
#define __HAL_SD_SDIO_DMA_DISABLE() __SDIO_DMA_DISABLE()
/**
* @brief Enable the SD device interrupt.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDIO interrupt sources to be enabled.
* This parameter can be one or a combination of the following values:
* @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDIO_IT_DTIMEOUT: Data timeout interrupt
* @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide
* bus mode interrupt
* @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDIO_IT_CMDACT: Command transfer in progress interrupt
* @arg SDIO_IT_TXACT: Data transmit in progress interrupt
* @arg SDIO_IT_RXACT: Data receive in progress interrupt
* @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt
* @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt
* @retval None
*/
#define __HAL_SD_SDIO_ENABLE_IT(__HANDLE__, __INTERRUPT__) __SDIO_ENABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @brief Disable the SD device interrupt.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDIO interrupt sources to be disabled.
* This parameter can be one or a combination of the following values:
* @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDIO_IT_DTIMEOUT: Data timeout interrupt
* @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide
* bus mode interrupt
* @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDIO_IT_CMDACT: Command transfer in progress interrupt
* @arg SDIO_IT_TXACT: Data transmit in progress interrupt
* @arg SDIO_IT_RXACT: Data receive in progress interrupt
* @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt
* @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt
* @retval None
*/
#define __HAL_SD_SDIO_DISABLE_IT(__HANDLE__, __INTERRUPT__) __SDIO_DISABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @brief Check whether the specified SD flag is set or not.
* @param __HANDLE__: SD Handle
* @param __FLAG__: specifies the flag to check.
* This parameter can be one of the following values:
* @arg SDIO_FLAG_CCRCFAIL: Command response received (CRC check failed)
* @arg SDIO_FLAG_DCRCFAIL: Data block sent/received (CRC check failed)
* @arg SDIO_FLAG_CTIMEOUT: Command response timeout
* @arg SDIO_FLAG_DTIMEOUT: Data timeout
* @arg SDIO_FLAG_TXUNDERR: Transmit FIFO underrun error
* @arg SDIO_FLAG_RXOVERR: Received FIFO overrun error
* @arg SDIO_FLAG_CMDREND: Command response received (CRC check passed)
* @arg SDIO_FLAG_CMDSENT: Command sent (no response required)
* @arg SDIO_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero)
* @arg SDIO_FLAG_STBITERR: Start bit not detected on all data signals in wide bus mode.
* @arg SDIO_FLAG_DBCKEND: Data block sent/received (CRC check passed)
* @arg SDIO_FLAG_CMDACT: Command transfer in progress
* @arg SDIO_FLAG_TXACT: Data transmit in progress
* @arg SDIO_FLAG_RXACT: Data receive in progress
* @arg SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty
* @arg SDIO_FLAG_RXFIFOHF: Receive FIFO Half Full
* @arg SDIO_FLAG_TXFIFOF: Transmit FIFO full
* @arg SDIO_FLAG_RXFIFOF: Receive FIFO full
* @arg SDIO_FLAG_TXFIFOE: Transmit FIFO empty
* @arg SDIO_FLAG_RXFIFOE: Receive FIFO empty
* @arg SDIO_FLAG_TXDAVL: Data available in transmit FIFO
* @arg SDIO_FLAG_RXDAVL: Data available in receive FIFO
* @arg SDIO_FLAG_SDIOIT: SD I/O interrupt received
* @arg SDIO_FLAG_CEATAEND: CE-ATA command completion signal received for CMD61
* @retval The new state of SD FLAG (SET or RESET).
*/
#define __HAL_SD_SDIO_GET_FLAG(__HANDLE__, __FLAG__) __SDIO_GET_FLAG((__HANDLE__)->Instance, (__FLAG__))
/**
* @brief Clear the SD's pending flags.
* @param __HANDLE__: SD Handle
* @param __FLAG__: specifies the flag to clear.
* This parameter can be one or a combination of the following values:
* @arg SDIO_FLAG_CCRCFAIL: Command response received (CRC check failed)
* @arg SDIO_FLAG_DCRCFAIL: Data block sent/received (CRC check failed)
* @arg SDIO_FLAG_CTIMEOUT: Command response timeout
* @arg SDIO_FLAG_DTIMEOUT: Data timeout
* @arg SDIO_FLAG_TXUNDERR: Transmit FIFO underrun error
* @arg SDIO_FLAG_RXOVERR: Received FIFO overrun error
* @arg SDIO_FLAG_CMDREND: Command response received (CRC check passed)
* @arg SDIO_FLAG_CMDSENT: Command sent (no response required)
* @arg SDIO_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero)
* @arg SDIO_FLAG_STBITERR: Start bit not detected on all data signals in wide bus mode
* @arg SDIO_FLAG_DBCKEND: Data block sent/received (CRC check passed)
* @arg SDIO_FLAG_SDIOIT: SD I/O interrupt received
* @arg SDIO_FLAG_CEATAEND: CE-ATA command completion signal received for CMD61
* @retval None
*/
#define __HAL_SD_SDIO_CLEAR_FLAG(__HANDLE__, __FLAG__) __SDIO_CLEAR_FLAG((__HANDLE__)->Instance, (__FLAG__))
/**
* @brief Check whether the specified SD interrupt has occurred or not.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDIO interrupt source to check.
* This parameter can be one of the following values:
* @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDIO_IT_DTIMEOUT: Data timeout interrupt
* @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide
* bus mode interrupt
* @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDIO_IT_CMDACT: Command transfer in progress interrupt
* @arg SDIO_IT_TXACT: Data transmit in progress interrupt
* @arg SDIO_IT_RXACT: Data receive in progress interrupt
* @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt
* @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt
* @retval The new state of SD IT (SET or RESET).
*/
#define __HAL_SD_SDIO_GET_IT (__HANDLE__, __INTERRUPT__) __SDIO_GET_IT ((__HANDLE__)->Instance, __INTERRUPT__)
/**
* @brief Clear the SD's interrupt pending bits.
* @param __HANDLE__ : SD Handle
* @param __INTERRUPT__: specifies the interrupt pending bit to clear.
* This parameter can be one or a combination of the following values:
* @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDIO_IT_DTIMEOUT: Data timeout interrupt
* @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDIO_IT_DATAEND: Data end (data counter, SDIO_DCOUNT, is zero) interrupt
* @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide
* bus mode interrupt
* @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt
* @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61
* @retval None
*/
#define __HAL_SD_SDIO_CLEAR_IT(__HANDLE__, __INTERRUPT__) __SDIO_CLEAR_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup SD_Exported_Functions SD Exported Functions
* @{
*/
/** @defgroup SD_Exported_Functions_Group1 Initialization and de-initialization functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo);
HAL_StatusTypeDef HAL_SD_DeInit (SD_HandleTypeDef *hsd);
void HAL_SD_MspInit(SD_HandleTypeDef *hsd);
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd);
/**
* @}
*/
/** @defgroup SD_Exported_Functions_Group2 I/O operation functions
* @{
*/
/* Blocking mode: Polling */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr);
/* Non-Blocking mode: Interrupt */
void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd);
/* Callback in non blocking modes (DMA) */
void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd);
void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd);
/* Non-Blocking mode: DMA */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
/**
* @}
*/
/** @defgroup SD_Exported_Functions_Group3 Peripheral Control functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo);
HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode);
HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd);
HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd);
/**
* @}
*/
/* Peripheral State functions ************************************************/
/** @defgroup SD_Exported_Functions_Group4 Peripheral State functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus);
HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus);
HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/** @defgroup SD_Private_Types SD Private Types
* @{
*/
/**
* @}
*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup SD_Private_Defines SD Private Defines
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup SD_Private_Variables SD Private Variables
* @{
*/
/**
* @}
*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup SD_Private_Constants SD Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup SD_Private_Macros SD Private Macros
* @{
*/
/**
* @}
*/
/* Private functions prototypes ----------------------------------------------*/
/** @defgroup SD_Private_Functions_Prototypes SD Private Functions Prototypes
* @{
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup SD_Private_Functions SD Private Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_HAL_SD_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,788 @@
/**
******************************************************************************
* @file stm32f7xx_hal_sd.h
* @author MCD Application Team
* @version V1.0.0
* @date 12-May-2015
* @brief Header file of SD HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_SD_H
#define __STM32F7xx_HAL_SD_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_ll_sdmmc.h"
/** @addtogroup STM32F7xx_HAL_Driver
* @{
*/
/** @defgroup SD SD
* @brief SD HAL module driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup SD_Exported_Types SD Exported Types
* @{
*/
/** @defgroup SD_Exported_Types_Group1 SD Handle Structure definition
* @{
*/
#define SD_InitTypeDef SDMMC_InitTypeDef
#define SD_TypeDef SDMMC_TypeDef
struct xSD_Handle;
/* A function will be called at the start of a DMA action. */
typedef void ( * SD_EventSetupFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ );
/* This function is supposed to wait for an event: SDIO or DMA.
* Return non-zero if a timeout has been reached. */
typedef uint32_t ( * SD_EventWaitFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ );
typedef struct xSD_Handle
{
SD_TypeDef *Instance; /*!< SDMMC register base address */
SD_InitTypeDef Init; /*!< SD required parameters */
HAL_LockTypeDef Lock; /*!< SD locking object */
uint32_t CardType; /*!< SD card type */
uint32_t RCA; /*!< SD relative card address */
uint32_t CSD[4]; /*!< SD card specific data table */
uint32_t CID[4]; /*!< SD card identification number table */
__IO uint32_t SdTransferCplt; /*!< SD transfer complete flag in non blocking mode */
__IO uint32_t SdTransferErr; /*!< SD transfer error flag in non blocking mode */
__IO uint32_t DmaTransferCplt; /*!< SD DMA transfer complete flag */
__IO uint32_t SdOperation; /*!< SD transfer operation (read/write) */
DMA_HandleTypeDef *hdmarx; /*!< SD Rx DMA handle parameters */
DMA_HandleTypeDef *hdmatx; /*!< SD Tx DMA handle parameters */
SD_EventSetupFunctionTypeDef EventSetupFunction;
SD_EventWaitFunctionTypeDef EventWaitFunction;
}SD_HandleTypeDef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group2 Card Specific Data: CSD Register
* @{
*/
typedef struct
{
__IO uint8_t CSDStruct; /*!< CSD structure */
__IO uint8_t SysSpecVersion; /*!< System specification version */
__IO uint8_t Reserved1; /*!< Reserved */
__IO uint8_t TAAC; /*!< Data read access time 1 */
__IO uint8_t NSAC; /*!< Data read access time 2 in CLK cycles */
__IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */
__IO uint16_t CardComdClasses; /*!< Card command classes */
__IO uint8_t RdBlockLen; /*!< Max. read data block length */
__IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */
__IO uint8_t WrBlockMisalign; /*!< Write block misalignment */
__IO uint8_t RdBlockMisalign; /*!< Read block misalignment */
__IO uint8_t DSRImpl; /*!< DSR implemented */
__IO uint8_t Reserved2; /*!< Reserved */
__IO uint32_t DeviceSize; /*!< Device Size */
__IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
__IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
__IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
__IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
__IO uint8_t DeviceSizeMul; /*!< Device size multiplier */
__IO uint8_t EraseGrSize; /*!< Erase group size */
__IO uint8_t EraseGrMul; /*!< Erase group size multiplier */
__IO uint8_t WrProtectGrSize; /*!< Write protect group size */
__IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */
__IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */
__IO uint8_t WrSpeedFact; /*!< Write speed factor */
__IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */
__IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
__IO uint8_t Reserved3; /*!< Reserved */
__IO uint8_t ContentProtectAppli; /*!< Content protection application */
__IO uint8_t FileFormatGrouop; /*!< File format group */
__IO uint8_t CopyFlag; /*!< Copy flag (OTP) */
__IO uint8_t PermWrProtect; /*!< Permanent write protection */
__IO uint8_t TempWrProtect; /*!< Temporary write protection */
__IO uint8_t FileFormat; /*!< File format */
__IO uint8_t ECC; /*!< ECC code */
__IO uint8_t CSD_CRC; /*!< CSD CRC */
__IO uint8_t Reserved4; /*!< Always 1 */
}HAL_SD_CSDTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group3 Card Identification Data: CID Register
* @{
*/
typedef struct
{
__IO uint8_t ManufacturerID; /*!< Manufacturer ID */
__IO uint16_t OEM_AppliID; /*!< OEM/Application ID */
__IO uint32_t ProdName1; /*!< Product Name part1 */
__IO uint8_t ProdName2; /*!< Product Name part2 */
__IO uint8_t ProdRev; /*!< Product Revision */
__IO uint32_t ProdSN; /*!< Product Serial Number */
__IO uint8_t Reserved1; /*!< Reserved1 */
__IO uint16_t ManufactDate; /*!< Manufacturing Date */
__IO uint8_t CID_CRC; /*!< CID CRC */
__IO uint8_t Reserved2; /*!< Always 1 */
}HAL_SD_CIDTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group4 SD Card Status returned by ACMD13
* @{
*/
typedef struct
{
__IO uint8_t DAT_BUS_WIDTH; /*!< Shows the currently defined data bus width */
__IO uint8_t SECURED_MODE; /*!< Card is in secured mode of operation */
__IO uint16_t SD_CARD_TYPE; /*!< Carries information about card type */
__IO uint32_t SIZE_OF_PROTECTED_AREA; /*!< Carries information about the capacity of protected area */
__IO uint8_t SPEED_CLASS; /*!< Carries information about the speed class of the card */
__IO uint8_t PERFORMANCE_MOVE; /*!< Carries information about the card's performance move */
__IO uint8_t AU_SIZE; /*!< Carries information about the card's allocation unit size */
__IO uint16_t ERASE_SIZE; /*!< Determines the number of AUs to be erased in one operation */
__IO uint8_t ERASE_TIMEOUT; /*!< Determines the timeout for any number of AU erase */
__IO uint8_t ERASE_OFFSET; /*!< Carries information about the erase offset */
}HAL_SD_CardStatusTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group5 SD Card information structure
* @{
*/
typedef struct
{
HAL_SD_CSDTypedef SD_csd; /*!< SD card specific data register */
HAL_SD_CIDTypedef SD_cid; /*!< SD card identification number register */
uint64_t CardCapacity; /*!< Card capacity */
uint32_t CardBlockSize; /*!< Card block size */
uint16_t RCA; /*!< SD relative card address */
uint8_t CardType; /*!< SD card type */
}HAL_SD_CardInfoTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group6 SD Error status enumeration Structure definition
* @{
*/
typedef enum
{
/**
* @brief SD specific error defines
*/
SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */
SD_DATA_CRC_FAIL = (2), /*!< Data block sent/received (CRC check failed) */
SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */
SD_DATA_TIMEOUT = (4), /*!< Data timeout */
SD_TX_UNDERRUN = (5), /*!< Transmit FIFO underrun */
SD_RX_OVERRUN = (6), /*!< Receive FIFO overrun */
SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in wide bus mode */
SD_CMD_OUT_OF_RANGE = (8), /*!< Command's argument was out of range. */
SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */
SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs. */
SD_BAD_ERASE_PARAM = (12), /*!< An invalid selection for erase groups */
SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */
SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */
SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */
SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */
SD_CC_ERROR = (18), /*!< Internal card controller error */
SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or unknown error */
SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */
SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */
SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */
SD_WP_ERASE_SKIP = (23), /*!< Only partial address space was erased */
SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */
SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */
SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */
SD_INVALID_VOLTRANGE = (27),
SD_ADDR_OUT_OF_RANGE = (28),
SD_SWITCH_ERROR = (29),
SD_SDMMC_DISABLED = (30),
SD_SDMMC_FUNCTION_BUSY = (31),
SD_SDMMC_FUNCTION_FAILED = (32),
SD_SDMMC_UNKNOWN_FUNCTION = (33),
/**
* @brief Standard error defines
*/
SD_INTERNAL_ERROR = (34),
SD_NOT_CONFIGURED = (35),
SD_REQUEST_PENDING = (36),
SD_REQUEST_NOT_APPLICABLE = (37),
SD_INVALID_PARAMETER = (38),
SD_UNSUPPORTED_FEATURE = (39),
SD_UNSUPPORTED_HW = (40),
SD_ERROR = (41),
SD_OK = (0)
}HAL_SD_ErrorTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group7 SD Transfer state enumeration structure
* @{
*/
typedef enum
{
SD_TRANSFER_OK = 0, /*!< Transfer success */
SD_TRANSFER_BUSY = 1, /*!< Transfer is occurring */
SD_TRANSFER_ERROR = 2 /*!< Transfer failed */
}HAL_SD_TransferStateTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group8 SD Card State enumeration structure
* @{
*/
typedef enum
{
SD_CARD_READY = ((uint32_t)0x00000001), /*!< Card state is ready */
SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002), /*!< Card is in identification state */
SD_CARD_STANDBY = ((uint32_t)0x00000003), /*!< Card is in standby state */
SD_CARD_TRANSFER = ((uint32_t)0x00000004), /*!< Card is in transfer state */
SD_CARD_SENDING = ((uint32_t)0x00000005), /*!< Card is sending an operation */
SD_CARD_RECEIVING = ((uint32_t)0x00000006), /*!< Card is receiving operation information */
SD_CARD_PROGRAMMING = ((uint32_t)0x00000007), /*!< Card is in programming state */
SD_CARD_DISCONNECTED = ((uint32_t)0x00000008), /*!< Card is disconnected */
SD_CARD_ERROR = ((uint32_t)0x000000FF) /*!< Card is in error state */
}HAL_SD_CardStateTypedef;
/**
* @}
*/
/** @defgroup SD_Exported_Types_Group9 SD Operation enumeration structure
* @{
*/
typedef enum
{
SD_READ_SINGLE_BLOCK = 0, /*!< Read single block operation */
SD_READ_MULTIPLE_BLOCK = 1, /*!< Read multiple blocks operation */
SD_WRITE_SINGLE_BLOCK = 2, /*!< Write single block operation */
SD_WRITE_MULTIPLE_BLOCK = 3 /*!< Write multiple blocks operation */
}HAL_SD_OperationTypedef;
/**
* @}
*/
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup SD_Exported_Constants SD Exported Constants
* @{
*/
/**
* @brief SD Commands Index
*/
#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /*!< Resets the SD memory card. */
#define SD_CMD_SEND_OP_COND ((uint8_t)1) /*!< Sends host capacity support information and activates the card's initialization process. */
#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /*!< Asks any card connected to the host to send the CID numbers on the CMD line. */
#define SD_CMD_SET_REL_ADDR ((uint8_t)3) /*!< Asks the card to publish a new relative address (RCA). */
#define SD_CMD_SET_DSR ((uint8_t)4) /*!< Programs the DSR of all cards. */
#define SD_CMD_SDMMC_SEN_OP_COND ((uint8_t)5) /*!< Sends host capacity support information (HCS) and asks the accessed card to send its
operating condition register (OCR) content in the response on the CMD line. */
#define SD_CMD_HS_SWITCH ((uint8_t)6) /*!< Checks switchable function (mode 0) and switch card function (mode 1). */
#define SD_CMD_SEL_DESEL_CARD ((uint8_t)7) /*!< Selects the card by its own relative address and gets deselected by any other address */
#define SD_CMD_HS_SEND_EXT_CSD ((uint8_t)8) /*!< Sends SD Memory Card interface condition, which includes host supply voltage information
and asks the card whether card supports voltage. */
#define SD_CMD_SEND_CSD ((uint8_t)9) /*!< Addressed card sends its card specific data (CSD) on the CMD line. */
#define SD_CMD_SEND_CID ((uint8_t)10) /*!< Addressed card sends its card identification (CID) on the CMD line. */
#define SD_CMD_READ_DAT_UNTIL_STOP ((uint8_t)11) /*!< SD card doesn't support it. */
#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /*!< Forces the card to stop transmission. */
#define SD_CMD_SEND_STATUS ((uint8_t)13) /*!< Addressed card sends its status register. */
#define SD_CMD_HS_BUSTEST_READ ((uint8_t)14)
#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /*!< Sends an addressed card into the inactive state. */
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /*!< Sets the block length (in bytes for SDSC) for all following block commands
(read, write, lock). Default block length is fixed to 512 Bytes. Not effective
for SDHS and SDXC. */
#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of
fixed 512 bytes in case of SDHC and SDXC. */
#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18) /*!< Continuously transfers data blocks from card to host until interrupted by
STOP_TRANSMISSION command. */
#define SD_CMD_HS_BUSTEST_WRITE ((uint8_t)19) /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104. */
#define SD_CMD_WRITE_DAT_UNTIL_STOP ((uint8_t)20) /*!< Speed class control command. */
#define SD_CMD_SET_BLOCK_COUNT ((uint8_t)23) /*!< Specify block count for CMD18 and CMD25. */
#define SD_CMD_WRITE_SINGLE_BLOCK ((uint8_t)24) /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of
fixed 512 bytes in case of SDHC and SDXC. */
#define SD_CMD_WRITE_MULT_BLOCK ((uint8_t)25) /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows. */
#define SD_CMD_PROG_CID ((uint8_t)26) /*!< Reserved for manufacturers. */
#define SD_CMD_PROG_CSD ((uint8_t)27) /*!< Programming of the programmable bits of the CSD. */
#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /*!< Sets the write protection bit of the addressed group. */
#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /*!< Clears the write protection bit of the addressed group. */
#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /*!< Asks the card to send the status of the write protection bits. */
#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< Sets the address of the first write block to be erased. (For SD card only). */
#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< Sets the address of the last write block of the continuous range to be erased. */
#define SD_CMD_ERASE_GRP_START ((uint8_t)35) /*!< Sets the address of the first write block to be erased. Reserved for each command
system set by switch function command (CMD6). */
#define SD_CMD_ERASE_GRP_END ((uint8_t)36) /*!< Sets the address of the last write block of the continuous range to be erased.
Reserved for each command system set by switch function command (CMD6). */
#define SD_CMD_ERASE ((uint8_t)38) /*!< Reserved for SD security applications. */
#define SD_CMD_FAST_IO ((uint8_t)39) /*!< SD card doesn't support it (Reserved). */
#define SD_CMD_GO_IRQ_STATE ((uint8_t)40) /*!< SD card doesn't support it (Reserved). */
#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by
the SET_BLOCK_LEN command. */
#define SD_CMD_APP_CMD ((uint8_t)55) /*!< Indicates to the card that the next command is an application specific command rather
than a standard command. */
#define SD_CMD_GEN_CMD ((uint8_t)56) /*!< Used either to transfer a data block to the card or to get a data block from the card
for general purpose/application specific commands. */
#define SD_CMD_NO_CMD ((uint8_t)64)
/**
* @brief Following commands are SD Card Specific commands.
* SDMMC_APP_CMD should be sent before sending these commands.
*/
#define SD_CMD_APP_SD_SET_BUSWIDTH ((uint8_t)6) /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus
widths are given in SCR register. */
#define SD_CMD_SD_APP_STATUS ((uint8_t)13) /*!< (ACMD13) Sends the SD status. */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS ((uint8_t)22) /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with
32bit+CRC data block. */
#define SD_CMD_SD_APP_OP_COND ((uint8_t)41) /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to
send its operating condition register (OCR) content in the response on the CMD line. */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT ((uint8_t)42) /*!< (ACMD42) Connects/Disconnects the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card. */
#define SD_CMD_SD_APP_SEND_SCR ((uint8_t)51) /*!< Reads the SD Configuration Register (SCR). */
#define SD_CMD_SDMMC_RW_DIRECT ((uint8_t)52) /*!< For SD I/O card only, reserved for security specification. */
#define SD_CMD_SDMMC_RW_EXTENDED ((uint8_t)53) /*!< For SD I/O card only, reserved for security specification. */
/**
* @brief Following commands are SD Card Specific security commands.
* SD_CMD_APP_CMD should be sent before sending these commands.
*/
#define SD_CMD_SD_APP_GET_MKB ((uint8_t)43) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_MID ((uint8_t)44) /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RN1 ((uint8_t)45) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RN2 ((uint8_t)46) /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RES2 ((uint8_t)47) /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RES1 ((uint8_t)48) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK ((uint8_t)18) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_ERASE ((uint8_t)38) /*!< For SD card only */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA ((uint8_t)49) /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB ((uint8_t)48) /*!< For SD card only */
/**
* @brief Supported SD Memory Cards
*/
#define STD_CAPACITY_SD_CARD_V1_1 ((uint32_t)0x00000000)
#define STD_CAPACITY_SD_CARD_V2_0 ((uint32_t)0x00000001)
#define HIGH_CAPACITY_SD_CARD ((uint32_t)0x00000002)
#define MULTIMEDIA_CARD ((uint32_t)0x00000003)
#define SECURE_DIGITAL_IO_CARD ((uint32_t)0x00000004)
#define HIGH_SPEED_MULTIMEDIA_CARD ((uint32_t)0x00000005)
#define SECURE_DIGITAL_IO_COMBO_CARD ((uint32_t)0x00000006)
#define HIGH_CAPACITY_MMC_CARD ((uint32_t)0x00000007)
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup SD_Exported_macros SD Exported Macros
* @brief macros to handle interrupts and specific clock configurations
* @{
*/
/**
* @brief Enable the SD device.
* @retval None
*/
#define __HAL_SD_SDMMC_ENABLE(__HANDLE__) __SDMMC_ENABLE((__HANDLE__)->Instance)
/**
* @brief Disable the SD device.
* @retval None
*/
#define __HAL_SD_SDMMC_DISABLE(__HANDLE__) __SDMMC_DISABLE((__HANDLE__)->Instance)
/**
* @brief Enable the SDMMC DMA transfer.
* @retval None
*/
#define __HAL_SD_SDMMC_DMA_ENABLE(__HANDLE__) __SDMMC_DMA_ENABLE((__HANDLE__)->Instance)
/**
* @brief Disable the SDMMC DMA transfer.
* @retval None
*/
#define __HAL_SD_SDMMC_DMA_DISABLE(__HANDLE__) __SDMMC_DMA_DISABLE((__HANDLE__)->Instance)
/**
* @brief Enable the SD device interrupt.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDMMC interrupt sources to be enabled.
* This parameter can be one or a combination of the following values:
* @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt
* @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt
* @arg SDMMC_IT_TXACT: Data transmit in progress interrupt
* @arg SDMMC_IT_RXACT: Data receive in progress interrupt
* @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt
* @retval None
*/
#define __HAL_SD_SDMMC_ENABLE_IT(__HANDLE__, __INTERRUPT__) __SDMMC_ENABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @brief Disable the SD device interrupt.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDMMC interrupt sources to be disabled.
* This parameter can be one or a combination of the following values:
* @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt
* @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt
* @arg SDMMC_IT_TXACT: Data transmit in progress interrupt
* @arg SDMMC_IT_RXACT: Data receive in progress interrupt
* @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt
* @retval None
*/
#define __HAL_SD_SDMMC_DISABLE_IT(__HANDLE__, __INTERRUPT__) __SDMMC_DISABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @brief Check whether the specified SD flag is set or not.
* @param __HANDLE__: SD Handle
* @param __FLAG__: specifies the flag to check.
* This parameter can be one of the following values:
* @arg SDMMC_FLAG_CCRCFAIL: Command response received (CRC check failed)
* @arg SDMMC_FLAG_DCRCFAIL: Data block sent/received (CRC check failed)
* @arg SDMMC_FLAG_CTIMEOUT: Command response timeout
* @arg SDMMC_FLAG_DTIMEOUT: Data timeout
* @arg SDMMC_FLAG_TXUNDERR: Transmit FIFO underrun error
* @arg SDMMC_FLAG_RXOVERR: Received FIFO overrun error
* @arg SDMMC_FLAG_CMDREND: Command response received (CRC check passed)
* @arg SDMMC_FLAG_CMDSENT: Command sent (no response required)
* @arg SDMMC_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero)
* @arg SDMMC_FLAG_DBCKEND: Data block sent/received (CRC check passed)
* @arg SDMMC_FLAG_CMDACT: Command transfer in progress
* @arg SDMMC_FLAG_TXACT: Data transmit in progress
* @arg SDMMC_FLAG_RXACT: Data receive in progress
* @arg SDMMC_FLAG_TXFIFOHE: Transmit FIFO Half Empty
* @arg SDMMC_FLAG_RXFIFOHF: Receive FIFO Half Full
* @arg SDMMC_FLAG_TXFIFOF: Transmit FIFO full
* @arg SDMMC_FLAG_RXFIFOF: Receive FIFO full
* @arg SDMMC_FLAG_TXFIFOE: Transmit FIFO empty
* @arg SDMMC_FLAG_RXFIFOE: Receive FIFO empty
* @arg SDMMC_FLAG_TXDAVL: Data available in transmit FIFO
* @arg SDMMC_FLAG_RXDAVL: Data available in receive FIFO
* @arg SDMMC_FLAG_SDIOIT: SD I/O interrupt received
* @retval The new state of SD FLAG (SET or RESET).
*/
#define __HAL_SD_SDMMC_GET_FLAG(__HANDLE__, __FLAG__) __SDMMC_GET_FLAG((__HANDLE__)->Instance, (__FLAG__))
/**
* @brief Clear the SD's pending flags.
* @param __HANDLE__: SD Handle
* @param __FLAG__: specifies the flag to clear.
* This parameter can be one or a combination of the following values:
* @arg SDMMC_FLAG_CCRCFAIL: Command response received (CRC check failed)
* @arg SDMMC_FLAG_DCRCFAIL: Data block sent/received (CRC check failed)
* @arg SDMMC_FLAG_CTIMEOUT: Command response timeout
* @arg SDMMC_FLAG_DTIMEOUT: Data timeout
* @arg SDMMC_FLAG_TXUNDERR: Transmit FIFO underrun error
* @arg SDMMC_FLAG_RXOVERR: Received FIFO overrun error
* @arg SDMMC_FLAG_CMDREND: Command response received (CRC check passed)
* @arg SDMMC_FLAG_CMDSENT: Command sent (no response required)
* @arg SDMMC_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero)
* @arg SDMMC_FLAG_DBCKEND: Data block sent/received (CRC check passed)
* @arg SDMMC_FLAG_SDIOIT: SD I/O interrupt received
* @retval None
*/
#define __HAL_SD_SDMMC_CLEAR_FLAG(__HANDLE__, __FLAG__) __SDMMC_CLEAR_FLAG((__HANDLE__)->Instance, (__FLAG__))
/**
* @brief Check whether the specified SD interrupt has occurred or not.
* @param __HANDLE__: SD Handle
* @param __INTERRUPT__: specifies the SDMMC interrupt source to check.
* This parameter can be one of the following values:
* @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt
* @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt
* @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt
* @arg SDMMC_IT_TXACT: Data transmit in progress interrupt
* @arg SDMMC_IT_RXACT: Data receive in progress interrupt
* @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt
* @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt
* @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt
* @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt
* @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt
* @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt
* @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt
* @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt
* @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt
* @retval The new state of SD IT (SET or RESET).
*/
#define __HAL_SD_SDMMC_GET_IT(__HANDLE__, __INTERRUPT__) __SDMMC_GET_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @brief Clear the SD's interrupt pending bits.
* @param __HANDLE__ : SD Handle
* @param __INTERRUPT__: specifies the interrupt pending bit to clear.
* This parameter can be one or a combination of the following values:
* @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt
* @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt
* @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt
* @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt
* @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt
* @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt
* @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt
* @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt
* @arg SDMMC_IT_DATAEND: Data end (data counter, SDMMC_DCOUNT, is zero) interrupt
* @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt
* @retval None
*/
#define __HAL_SD_SDMMC_CLEAR_IT(__HANDLE__, __INTERRUPT__) __SDMMC_CLEAR_IT((__HANDLE__)->Instance, (__INTERRUPT__))
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup SD_Exported_Functions SD Exported Functions
* @{
*/
/** @defgroup SD_Exported_Functions_Group1 Initialization and de-initialization functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo);
HAL_StatusTypeDef HAL_SD_DeInit (SD_HandleTypeDef *hsd);
void HAL_SD_MspInit(SD_HandleTypeDef *hsd);
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd);
/**
* @}
*/
/** @defgroup SD_Exported_Functions_Group2 Input and Output operation functions
* @{
*/
/* Blocking mode: Polling */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr);
/* Non-Blocking mode: Interrupt */
void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd);
/* Callback in non blocking modes (DMA) */
void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma);
void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd);
void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd);
/* Non-Blocking mode: DMA */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
/**
* @}
*/
/** @defgroup SD_Exported_Functions_Group3 Peripheral Control functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo);
HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode);
HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd);
HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd);
/**
* @}
*/
/* Peripheral State functions ************************************************/
/** @defgroup SD_Exported_Functions_Group4 Peripheral State functions
* @{
*/
HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus);
HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus);
HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/** @defgroup SD_Private_Types SD Private Types
* @{
*/
/**
* @}
*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup SD_Private_Defines SD Private Defines
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup SD_Private_Variables SD Private Variables
* @{
*/
/**
* @}
*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup SD_Private_Constants SD Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup SD_Private_Macros SD Private Macros
* @{
*/
/**
* @}
*/
/* Private functions prototypes ----------------------------------------------*/
/** @defgroup SD_Private_Functions_Prototypes SD Private Functions Prototypes
* @{
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup SD_Private_Functions SD Private Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_SD_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,894 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* Xilinx library includes. */
#include "xparameters.h"
#include "xil_types.h"
#include "xsdps.h" /* SD device driver */
#include "xsdps_info.h" /* SD info */
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_headers.h"
#include "ff_sddisk.h"
#include "ff_sys.h"
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
#include "xil_exception.h"
#include "xscugic_hw.h"
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
#include "uncached_memory.h"
#define sdSIGNATURE 0x41404342
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (int) (sizeof(x)/sizeof(x)[0])
#endif
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
#define SD_DEVICE_ID XPAR_XSDPS_0_DEVICE_ID
#define HIGH_SPEED_SUPPORT 0x01
#define WIDTH_4_BIT_SUPPORT 0x4
#define SD_CLK_12_MHZ 12000000
#define SD_CLK_25_MHZ 25000000
#define SD_CLK_26_MHZ 26000000
#define SD_CLK_52_MHZ 52000000
#define EXT_CSD_DEVICE_TYPE_BYTE 196
#define EXT_CSD_4_BIT_WIDTH_BYTE 183
#define EXT_CSD_HIGH_SPEED_BYTE 185
#define EXT_CSD_DEVICE_TYPE_HIGH_SPEED 0x3
#define HUNDRED_64_BIT 100ULL
#define BYTES_PER_MB ( 1024ull * 1024ull )
#define SECTORS_PER_MB ( BYTES_PER_MB / 512ull )
#define XSDPS_INTR_NORMAL_ENABLE ( XSDPS_INTR_CC_MASK | XSDPS_INTR_TC_MASK | \
XSDPS_INTR_DMA_MASK | XSDPS_INTR_CARD_INSRT_MASK | XSDPS_INTR_CARD_REM_MASK | \
XSDPS_INTR_ERR_MASK )
/* Two defines used to set or clear the interrupt */
#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
/* Interupt numbers for SDIO units 0 and 1: */
#define SCUGIC_SDIO_0_INTR 0x38
#define SCUGIC_SDIO_1_INTR 0x4F
/* Define a timeout on data transfers for SDIO: */
#define sdWAIT_INT_TIME_OUT_MS 5000UL
/* Define a short timeout, used during card-detection only (CMD1): */
#define sdQUICK_WAIT_INT_TIME_OUT_MS 1000UL
/* XSdPs xSDCardInstance; */
static XSdPs *pxSDCardInstance;
static int sd_disk_status = STA_NOINIT; /* Disk status */
const int drive_nr = 0;
static SemaphoreHandle_t xPlusFATMutex;
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
/* Create a semaphore for each of the two memory-card slots. */
static SemaphoreHandle_t xSDSemaphores[ 2 ];
#endif
static int vSDMMC_Init( int iDriveNumber );
static int vSDMMC_Status( int iDriveNumber );
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
static void vInstallInterrupt( void );
#endif
struct xCACHE_MEMORY_INFO
{
/* Reserve 'uncached' memory for caching sectors, will be passed to the +FAT library. */
uint8_t pucCacheMemory[ 0x10000 ];
/* Reserve 'uncached' memory for i/o to the SD-card. */
uint8_t pucHelpMemory[ 0x40000 ];
XSdPs xSDCardInstance;
};
struct xCACHE_STATS
{
uint32_t xMemcpyReadCount;
uint32_t xMemcpyWriteCount;
uint32_t xPassReadCount;
uint32_t xPassWriteCount;
uint32_t xFailReadCount;
uint32_t xFailWriteCount;
};
struct xCACHE_STATS xCacheStats;
struct xCACHE_MEMORY_INFO *pxCacheMem = NULL;
static const uint8_t *prvStoreSDCardData( const uint8_t *pucBuffer, uint32_t ulByteCount );
static uint8_t *prvReadSDCardData( uint8_t *pucBuffer, uint32_t ulByteCount );
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
void XSdPs_IntrHandler(void *XSdPsPtr);
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode;
int iResult;
uint8_t *pucReadBuffer;
if( ( pxDisk != NULL ) && /*_RB_ Could this be changed to an assert? */
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount )
{
iResult = vSDMMC_Status( drive_nr );
if( ( iResult & STA_NODISK ) != 0 )
{
lReturnCode = FF_ERR_DRIVER_NOMEDIUM | FF_ERRFLAG;
FF_PRINTF( "prvFFRead: NOMEDIUM\n" );
}
else if( ( iResult & STA_NOINIT ) != 0 )
{
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;
FF_PRINTF( "prvFFRead: NOINIT\n" );
}
else if( ulSectorCount == 0ul )
{
lReturnCode = 0;
}
else
{
/* Convert LBA to byte address if needed */
if( pxSDCardInstance->HCS == 0 )
{
ulSectorNumber *= XSDPS_BLK_SIZE_512_MASK;
}
pucReadBuffer = prvReadSDCardData( pucBuffer, 512UL * ulSectorCount );
if( ucIsCachedMemory( pucReadBuffer ) != pdFALSE )
{
xCacheStats.xFailReadCount++;
}
iResult = XSdPs_ReadPolled( pxSDCardInstance, ulSectorNumber, ulSectorCount, pucReadBuffer );
if( pucBuffer != pucReadBuffer )
{
xCacheStats.xMemcpyReadCount++;
memcpy( pucBuffer, pucReadBuffer, 512 * ulSectorCount );
}
else
{
xCacheStats.xPassReadCount++;
}
if( iResult == XST_SUCCESS )
{
lReturnCode = 0l;
}
else
{
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;
}
}
}
else
{
memset( ( void *) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised != pdFALSE )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG;
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturnCode;
if( ( pxDisk != NULL ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
int iResult;
iResult = vSDMMC_Status(drive_nr);
if( ( iResult & STA_NODISK ) != 0 )
{
lReturnCode = FF_ERR_DRIVER_NOMEDIUM | FF_ERRFLAG;
FF_PRINTF( "prvFFWrite: NOMEDIUM\n" );
}
else if( ( iResult & STA_NOINIT ) != 0 )
{
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
FF_PRINTF( "prvFFWrite: NOINIT\n" );
}
else
{
if( ulSectorCount == 0ul )
{
lReturnCode = 0l;
}
else
{
/* Convert LBA to byte address if needed */
if (!(pxSDCardInstance->HCS)) ulSectorNumber *= XSDPS_BLK_SIZE_512_MASK;
pucBuffer = ( uint8_t * )prvStoreSDCardData( pucBuffer, 512UL * ulSectorCount );
if( ucIsCachedMemory( pucBuffer ) != pdFALSE )
{
xCacheStats.xFailWriteCount++;
}
iResult = XSdPs_WritePolled( pxSDCardInstance, ulSectorNumber, ulSectorCount, pucBuffer );
if( iResult == XST_SUCCESS )
{
lReturnCode = 0;
}
else
{
FF_PRINTF( "prvFFWrite[%d]: at 0x%X count %ld : %d\n",
(int)drive_nr, (unsigned)ulSectorNumber, ulSectorCount, iResult );
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
}
}
}
}
else
{
lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
if( pxDisk->xStatus.bIsInitialised )
{
FF_PRINTF( "prvFFWrite::read: warning: %lu + %lu > %lu\n",
ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
}
return lReturnCode;
}
/*-----------------------------------------------------------*/
void FF_SDDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
static const uint8_t *prvStoreSDCardData( const uint8_t *pucBuffer, uint32_t ulByteCount )
{
const uint8_t *pucReturn;
if( ( ucIsCachedMemory( pucBuffer ) != pdFALSE ) && ( ulByteCount <= sizeof( pxCacheMem->pucHelpMemory ) ) )
{
memcpy( pxCacheMem->pucHelpMemory, pucBuffer, ulByteCount );
pucReturn = pxCacheMem->pucHelpMemory;
xCacheStats.xMemcpyWriteCount++;
}
else
{
pucReturn = pucBuffer;
xCacheStats.xPassWriteCount++;
}
return pucReturn;
}
/*-----------------------------------------------------------*/
static uint8_t *prvReadSDCardData( uint8_t *pucBuffer, uint32_t ulByteCount )
{
uint8_t *pucReturn;
if( ( ucIsCachedMemory( pucBuffer ) != pdFALSE ) && ( ulByteCount <= sizeof( pxCacheMem->pucHelpMemory ) ) )
{
pucReturn = pxCacheMem->pucHelpMemory;
}
else
{
pucReturn = pucBuffer;
}
return pucReturn;
}
/*-----------------------------------------------------------*/
static struct xCACHE_MEMORY_INFO *pucGetSDIOCacheMemory( )
{
if( pxCacheMem == NULL )
{
pxCacheMem = ( struct xCACHE_MEMORY_INFO * ) pucGetUncachedMemory( sizeof( *pxCacheMem ) );
memset( pxCacheMem, '\0', sizeof( *pxCacheMem ) );
}
return pxCacheMem;
}
/*-----------------------------------------------------------*/
/* Initialise the SDIO driver and mount an SD card */
FF_Disk_t *FF_SDDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t * pxDisk;
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
int iIndex;
#endif
pucGetSDIOCacheMemory();
pxDisk = (FF_Disk_t *)pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk == NULL )
{
FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );
}
else if( pxCacheMem == NULL )
{
FF_PRINTF( "FF_SDDiskInit: Cached memory failed\n" );
}
else
{
pxSDCardInstance = &( pxCacheMem->xSDCardInstance );
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
{
for( iIndex = 0; iIndex < ARRAY_SIZE( xSDSemaphores ); iIndex++ )
{
if( xSDSemaphores[ iIndex ] == NULL )
{
xSDSemaphores[ iIndex ] = xSemaphoreCreateBinary();
configASSERT( xSDSemaphores[ iIndex ] != NULL );
}
}
}
#endif
vSDMMC_Init( 0 );
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
pxDisk->ulNumberOfSectors = myCSD.sd_last_block_address + 1;
if( xPlusFATMutex == NULL )
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulSignature = sdSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.pucCacheMemory = pxCacheMem->pucCacheMemory;
xParameters.ulMemorySize = sizeof( pxCacheMem->pucCacheMemory );
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be protected with
the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in the +FAT driver,
and also to avoid concurrent calls to prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) );
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SDDiskMount( pxDisk ) == 0 )
{
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );
FF_SDDiskShowPartition( pxDisk );
}
}
}
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart )
{
FF_Error_t xError;
BaseType_t xReturn = 0;
FF_SDDiskUnmount( pxDisk );
{
/* Format the drive */
xError = FF_Format( pxDisk, aPart, pdFALSE, pdFALSE); // Try FAT32 with large clusters
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
return 0;
}
else
{
FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = aPart;
xError = FF_SDDiskMount( pxDisk );
FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = 1;
FF_SDDiskShowPartition( pxDisk );
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Unmount the volume */
BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn = 1;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) )
{
pxDisk->xStatus.bIsMounted = pdFALSE;
xFFError = FF_Unmount( pxDisk );
FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError );
if( FF_isERR( xFFError ) )
{
xReturn = 0;
}
else
{
FF_PRINTF( "Drive unmounted\n" );
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk )
{
int iStatus = vSDMMC_Init( 0 ); /* Hard coded index. */
/*_RB_ parameter not used. */
( void ) pxDisk;
FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned )iStatus );
return iStatus;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn = 1;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );
xReturn = 0;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( HUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / SECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / SECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "DataSectors %8lu\n", pxIOManager->xPartition.ulDataSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
FF_PRINTF( "BeginLBA %8lu\n", pxIOManager->xPartition.ulBeginLBA );
FF_PRINTF( "FATBeginLBA %8lu\n", pxIOManager->xPartition.ulFATBeginLBA );
}
return xReturn;
}
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
static void vInstallInterrupt( void )
{
/* Install an interrupt handler for SDIO_0 */
XScuGic_RegisterHandler( INTC_BASE_ADDR, SCUGIC_SDIO_0_INTR,
( Xil_ExceptionHandler )XSdPs_IntrHandler,
( void * )pxSDCardInstance );
/* Enable this interrupt. */
XScuGic_EnableIntr( INTC_DIST_BASE_ADDR, SCUGIC_SDIO_0_INTR );
/* Choose the signals. */
XSdPs_WriteReg16(pxSDCardInstance->Config.BaseAddress,
XSDPS_NORM_INTR_SIG_EN_OFFSET,
XSDPS_INTR_NORMAL_ENABLE );
XSdPs_WriteReg16(pxSDCardInstance->Config.BaseAddress,
XSDPS_ERR_INTR_SIG_EN_OFFSET,
0x0 );
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
static int vSDMMC_Init( int iDriveNumber )
{
int iReturnCode, iStatus;
XSdPs_Config *SdConfig;
/*_RB_ Function name not following convention, parameter not used, parameter
using plain int type. */
/* Open a do {} while(0) loop to allow the use of break. */
do
{
/* Check if card is in the socket */
iStatus = vSDMMC_Status( iDriveNumber );
if( ( iStatus & STA_NODISK ) != 0 )
{
break;
}
/* Assume that the initialisation will fail: set the 'STA_NOINIT' bit. */
iStatus |= STA_NOINIT;
/* Initialize the host controller */
SdConfig = XSdPs_LookupConfig(SD_DEVICE_ID);
if( SdConfig == NULL )
{
break;
}
iReturnCode = XSdPs_CfgInitialize(pxSDCardInstance, SdConfig, SdConfig->BaseAddress);
if( iReturnCode != XST_SUCCESS )
{
break;
}
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
{
vInstallInterrupt();
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
iReturnCode = XSdPs_CardInitialize( pxSDCardInstance );
if( iReturnCode != XST_SUCCESS )
{
break;
}
/* Disk is initialized OK: clear the 'STA_NOINIT' bit. */
iStatus &= ~( STA_NOINIT );
} while( 0 );
sd_disk_status = iStatus;
return iStatus;
}
/*-----------------------------------------------------------*/
static int vSDMMC_Status( int iDriveNumber )
{
int iStatus = sd_disk_status;
u32 ulStatusReg;
/*_RB_ Function name not following convention, parameter not used, parameter
using plain int type. */
( void ) iDriveNumber;
ulStatusReg = XSdPs_GetPresentStatusReg( XPAR_XSDPS_0_BASEADDR );
if( ( ulStatusReg & XSDPS_PSR_CARD_INSRT_MASK ) == 0 )
{
iStatus = STA_NODISK | STA_NOINIT;
}
else
{
iStatus &= ~STA_NODISK;
if( ( ulStatusReg & XSDPS_PSR_WPS_PL_MASK ) != 0 )
{
iStatus &= ~STA_PROTECT;
}
else
{
iStatus |= STA_PROTECT;
}
}
sd_disk_status = iStatus;
return iStatus;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr )
{
BaseType_t xReturn;
int iStatus;
/* Check if card is in the socket */
iStatus = vSDMMC_Status( xDriveNr );
if( ( iStatus & STA_NODISK ) != 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
volatile unsigned sd_int_count = 0;
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
volatile u32 ulSDInterruptStatus[2];
void XSdPs_IntrHandler(void *XSdPsPtr)
{
XSdPs *InstancePtr = (XSdPs *)XSdPsPtr;
int iIndex = InstancePtr->Config.DeviceId;
uint32_t ulStatusReg;
configASSERT( iIndex <= 1 );
sd_int_count++;
/* Read the current status. */
ulStatusReg = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET );
/* Write to clear error bits. */
XSdPs_WriteReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET, ulStatusReg );
/* The new value must be OR-ed, if not the
Command Complete (CC) event might get overwritten
by the Transfer Complete (TC) event. */
ulSDInterruptStatus[ iIndex ] |= ulStatusReg;
if( ( ulStatusReg & ( XSDPS_INTR_CARD_INSRT_MASK | XSDPS_INTR_CARD_REM_MASK ) ) != 0 )
{
/* Could wake-up another task. */
}
if( xSDSemaphores[ iIndex ] != NULL )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR( xSDSemaphores[ iIndex ], &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken != 0 )
{
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
void XSdPs_ClearInterrupt( XSdPs *InstancePtr )
{
int iIndex = InstancePtr->Config.DeviceId;
configASSERT( iIndex <= 1 );
ulSDInterruptStatus[ iIndex ] = 0;
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
/* Wait for an interrupt and return the 32 bits of the status register.
A return value of 0 means: time-out. */
u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask, u32 ulWait )
{
u32 ulStatusReg;
int iIndex = InstancePtr->Config.DeviceId;
TickType_t xRemainingTime = pdMS_TO_TICKS( sdWAIT_INT_TIME_OUT_MS );
TimeOut_t xTimeOut;
if( ulWait == 0UL )
{
xRemainingTime = pdMS_TO_TICKS( sdQUICK_WAIT_INT_TIME_OUT_MS );
}
configASSERT( iIndex <= 1 );
configASSERT( xSDSemaphores[ iIndex ] != 0 );
vTaskSetTimeOutState( &xTimeOut );
/* Loop until:
1. Expected bit (ulMask) becomes high
2. Time-out reached (normally 2 seconds)
*/
do
{
if( xRemainingTime != 0 )
{
xSemaphoreTake( xSDSemaphores[ iIndex ], xRemainingTime );
}
ulStatusReg = ulSDInterruptStatus[ iIndex ];
if( ( ulStatusReg & XSDPS_INTR_ERR_MASK ) != 0 )
{
break;
}
}
while( ( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) == pdFALSE ) &&
( ( ulStatusReg & ulMask ) == 0 ) );
if( ( ulStatusReg & ulMask ) == 0 )
{
ulStatusReg = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET );
if( ulWait != 0UL )
{
FF_PRINTF( "XSdPs_WaitInterrupt[ %d ]: Got %08lx, expect %08lx ints: %d\n",
iIndex,
ulStatusReg,
ulMask,
sd_int_count );
}
}
return ulStatusReg;
}
#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */
/*-----------------------------------------------------------*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,221 @@
/******************************************************************************
*
* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xsdps.h
* @addtogroup sdps_v2_5
* @{
* @details
*
* This file contains the implementation of XSdPs driver.
* This driver is used initialize read from and write to the SD card.
* Features such as switching bus width to 4-bit and switching to high speed,
* changing clock frequency, block size etc. are supported.
* SD 2.0 uses 1/4 bus width and speeds of 25/50KHz. Initialization, however
* is done using 1-bit bus width and 400KHz clock frequency.
* SD commands are classified as broadcast and addressed. Commands can be
* those with response only (using only command line) or
* response + data (using command and data lines).
* Only one command can be sent at a time. During a data transfer however,
* when dsta lines are in use, certain commands (which use only the command
* line) can be sent, most often to obtain status.
* This driver does not support multi card slots at present.
*
* Intialization:
* This includes initialization on the host controller side to select
* clock frequency, bus power and default transfer related parameters.
* The default voltage is 3.3V.
* On the SD card side, the initialization and identification state diagram is
* implemented. This resets the card, gives it a unique address/ID and
* identifies key card related specifications.
*
* Data transfer:
* The SD card is put in tranfer state to read from or write to it.
* The default block size is 512 bytes and if supported,
* default bus width is 4-bit and bus speed is High speed.
* The read and write functions are implemented in polled mode using ADMA2.
*
* At any point, when key parameters such as block size or
* clock/speed or bus width are modified, this driver takes care of
* maintaining the same selection on host and card.
* All error bits in host controller are monitored by the driver and in the
* event one of them is set, driver will clear the interrupt status and
* communicate failure to the upper layer.
*
* File system use:
* This driver can be used with xilffs library to read and write files to SD.
* (Please refer to procedure in diskio.c). The file system read/write example
* in polled mode can used for reference.
*
* There is no example for using SD driver without file system at present.
* However, the driver can be used without the file system. The glue layer
* in filesytem can be used as reference for the same. The block count
* passed to the read/write function in one call is limited by the ADMA2
* descriptor table and hence care will have to be taken to call read/write
* API's in a loop for large file sizes.
*
* Interrupt mode is not supported because it offers no improvement when used
* with file system.
*
* eMMC support:
* SD driver supports SD and eMMC based on the "enable MMC" parameter in SDK.
* The features of eMMC supported by the driver will depend on those supported
* by the host controller. The current driver supports read/write on eMMC card
* using 4-bit and high speed mode currently.
*
* Features not supported include - card write protect, password setting,
* lock/unlock, interrupts, SDMA mode, programmed I/O mode and
* 64-bit addressed ADMA2, erase/pre-erase commands.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 1.00a hk/sg 10/17/13 Initial release
* 2.0 hk 03/07/14 Version number revised.
* 2.1 hk 04/18/14 Increase sleep for eMMC switch command.
* Add sleep for microblaze designs. CR# 781117.
* 2.2 hk 07/28/14 Make changes to enable use of data cache.
* 2.3 sk 09/23/14 Send command for relative card address
* when re-initialization is done.CR# 819614.
* Use XSdPs_Change_ClkFreq API whenever changing
* clock.CR# 816586.
* 2.4 sk 12/04/14 Added support for micro SD without
* WP/CD. CR# 810655.
* Checked for DAT Inhibit mask instead of CMD
* Inhibit mask in Cmd Transfer API.
* Added Support for SD Card v1.0
* 2.5 sg 07/09/15 Added SD 3.0 features
* kvn 07/15/15 Modified the code according to MISRAC-2012.
* 2.6 sk 10/12/15 Added support for SD card v1.0 CR# 840601.
*
* </pre>
*
******************************************************************************/
#ifndef SDPS_H_
#define SDPS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "xstatus.h"
#include "xsdps_hw.h"
#include <string.h>
/************************** Constant Definitions *****************************/
#define XSDPS_CT_ERROR 0x2U /**< Command timeout flag */
/**************************** Type Definitions *******************************/
/**
* This typedef contains configuration information for the device.
*/
typedef struct {
u16 DeviceId; /**< Unique ID of device */
u32 BaseAddress; /**< Base address of the device */
u32 InputClockHz; /**< Input clock frequency */
u32 CardDetect; /**< Card Detect */
u32 WriteProtect; /**< Write Protect */
} XSdPs_Config;
/* ADMA2 descriptor table */
typedef struct {
u16 Attribute; /**< Attributes of descriptor */
u16 Length; /**< Length of current dma transfer */
u32 Address; /**< Address of current dma transfer */
} XSdPs_Adma2Descriptor;
/**
* The XSdPs driver instance data. The user is required to allocate a
* variable of this type for every SD device in the system. A pointer
* to a variable of this type is then passed to the driver API functions.
*/
typedef struct {
XSdPs_Config Config; /**< Configuration structure */
u32 IsReady; /**< Device is initialized and ready */
u32 Host_Caps; /**< Capabilities of host controller */
u32 Host_CapsExt; /**< Extended Capabilities */
u32 HCS; /**< High capacity support in card */
u8 CardType; /**< Type of card - SD/MMC/eMMC */
u8 Card_Version; /**< Card version */
u8 HC_Version; /**< Host controller version */
u8 BusWidth; /**< Current operating bus width */
u32 BusSpeed; /**< Current operating bus speed */
u8 Switch1v8; /**< 1.8V Switch support */
u32 CardID[4]; /**< Card ID Register */
u32 RelCardAddr; /**< Relative Card Address */
u32 CardSpecData[4]; /**< Card Specific Data Register */
u32 SdCardConfig; /**< Sd Card Configuration Register */
/**< ADMA Descriptors */
#ifdef __ICCARM__
#pragma data_alignment = 32
XSdPs_Adma2Descriptor Adma2_DescrTbl[32];
#pragma data_alignment = 4
#else
XSdPs_Adma2Descriptor Adma2_DescrTbl[32] __attribute__ ((aligned(32)));
#endif
} XSdPs;
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
XSdPs_Config *XSdPs_LookupConfig(u16 DeviceId);
s32 XSdPs_CfgInitialize(XSdPs *InstancePtr, XSdPs_Config *ConfigPtr,
u32 EffectiveAddr);
s32 XSdPs_SdCardInitialize(XSdPs *InstancePtr);
s32 XSdPs_ReadPolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff);
s32 XSdPs_WritePolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff);
s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize);
s32 XSdPs_Select_Card (XSdPs *InstancePtr);
s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq);
s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr);
s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr);
s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR);
s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff);
s32 XSdPs_Pullup(XSdPs *InstancePtr);
s32 XSdPs_MmcCardInitialize(XSdPs *InstancePtr);
s32 XSdPs_CardInitialize(XSdPs *InstancePtr);
s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff);
/* Wait for Command/Transfer Complete. */
s32 XSdPs_Wait_For(XSdPs *InstancePtr, u32 Mask, u32 Wait);
#ifdef __cplusplus
}
#endif
#endif /* SD_H_ */
/** @} */

View file

@ -0,0 +1,69 @@
/******************************************************************************
*
* Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xsdps_g.c
*
* This file contains a configuration table that specifies the configuration of
* SD devices in the system.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 1.00a hk/sg 10/17/13 Initial release
*
* </pre>
*
******************************************************************************/
#include "xparameters.h"
#include "xsdps.h"
/*
* The configuration table for devices
*/
XSdPs_Config XSdPs_ConfigTable[] =
{
{
XPAR_XSDPS_0_DEVICE_ID,
XPAR_XSDPS_0_BASEADDR,
XPAR_XSDPS_0_SDIO_CLK_FREQ_HZ,
0,
0
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,300 @@
/******************************************************************************
*
* mmc_decode_cid() and sd_decode_csd()
*
* analyse the meta data of an SD-card to read its capacity and some other properties.
*
* CID and CSD Analysis borrowed from the Linux kernel.
*
******************************************************************************/
#include "xsdps.h"
#include "xparameters.h"
#include "xil_cache.h"
#include "ff_headers.h"
#include "xsdps_info.h"
struct mmc_cid myCID;
struct mmc_csd myCSD;
u32 UNSTUFF_BITS( u32 *ulResponse, int iFirst, int iSize )
{
const u32 ulMask = ( iSize < 32 ? ( 1 << iSize ) : 0 ) - 1;
const int iOffset = 3 - ( iFirst / 32);
const int iShiftCount = iFirst & 31;
u32 ulResult;
ulResult = ulResponse[ iOffset ] >> iShiftCount;
if( iSize + iShiftCount > 32 )
{
ulResult |= ulResponse[ iOffset - 1 ] << ( ( 32 - iShiftCount ) % 32 );
}
return ulResult & ulMask; \
}
int mmc_decode_cid( const struct mmc_csd *pxCSD, struct mmc_cid *pxCID, u32 *ulResponse )
{
int iResult = 0;
/*
* The selection of the format here is based upon published
* specs from sandisk and from what people have reported.
*/
switch( pxCSD->mmca_vsn )
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
pxCID->manfid = UNSTUFF_BITS( ulResponse, 104, 24 );
pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 );
pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 );
pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 );
pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 );
pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 );
pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 );
pxCID->prod_name[ 6 ] = UNSTUFF_BITS( ulResponse, 48, 8 );
pxCID->hwrev = UNSTUFF_BITS( ulResponse, 44, 4 );
pxCID->fwrev = UNSTUFF_BITS( ulResponse, 40, 4 );
pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 24 );
pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 );
pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997;
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
pxCID->manfid = UNSTUFF_BITS( ulResponse, 120, 8 );
pxCID->oemid = UNSTUFF_BITS( ulResponse, 104, 16 );
pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 );
pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 );
pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 );
pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 );
pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 );
pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 );
pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 32 );
pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 );
pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997;
break;
default:
FF_PRINTF ("mmc_decode_cid: card has unknown MMCA version %d\n",
pxCSD->mmca_vsn);
iResult = -1;
break;
}
if( iResult >= 0 )
{
FF_PRINTF ("CID: Manfid %lu (%-8.8s) serial %lu oem %u mon/year %u/%u rev %u fw %u\n",
pxCID->manfid,
pxCID->prod_name,
pxCID->serial,
pxCID->oemid,
pxCID->month,
pxCID->year,
pxCID->hwrev,
pxCID->fwrev);
}
return iResult;
}
static const unsigned int tran_exp[] =
{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const unsigned char tran_mant[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const unsigned int tacc_exp[] =
{
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const unsigned int tacc_mant[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
char mmc_is_block_addressed;
/* Given a 128-bit response, decode to our card CSD structure. */
static __inline unsigned tobe32( unsigned value )
{
return
( value >> 24 ) |
( ( value >> 8 ) & 0x0000ff00 ) |
( ( value << 8 ) & 0x00ff0000 ) |
( value << 24 );
}
int sd_decode_csd( struct mmc_csd *pxCSD, u32 *ulResponse )
{
unsigned int e, m, csd_struct;
int iResult = 0;
csd_struct = UNSTUFF_BITS( ulResponse, 126, 2 );
pxCSD->mmca_vsn = UNSTUFF_BITS( ulResponse, 122, 4 );
FF_PRINTF("CSD data: %08x %08x %08x %08x mmca_vsn = %u\n",
( unsigned )ulResponse[0],
( unsigned )ulResponse[1],
( unsigned )ulResponse[2],
( unsigned )ulResponse[3],
pxCSD->mmca_vsn);
// pxCSD->mmca_vsn = 2;
// CSD data: 005e0032 5f5a83cb 2db7ffbf 9680000f
// sd_decode_csd: capacity 1989120 (byte addressed)
switch (csd_struct) {
case 0:
m = UNSTUFF_BITS( ulResponse, 115, 4 );
e = UNSTUFF_BITS( ulResponse, 112, 3 );
pxCSD->tacc_ns = ( tacc_exp[ e ] * tacc_mant[ m ] + 9 ) / 10;
pxCSD->tacc_clks = UNSTUFF_BITS( ulResponse, 104, 8 ) * 100;
m = UNSTUFF_BITS( ulResponse, 99, 4 );
e = UNSTUFF_BITS( ulResponse, 96, 3 );
pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ];
pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 );
e = UNSTUFF_BITS( ulResponse, 47, 3 );
m = UNSTUFF_BITS( ulResponse, 62, 12 );
pxCSD->capacity = ( 1 + m ) << ( e + 2 );
/*
* The CSD capacity field is in units of read_blkbits.
* set_capacity takes units of 512 bytes.
*/
pxCSD->read_blkbits = UNSTUFF_BITS( ulResponse, 80, 4 );
pxCSD->read_partial = UNSTUFF_BITS( ulResponse, 79, 1 );
pxCSD->write_misalign = UNSTUFF_BITS( ulResponse, 78, 1 );
pxCSD->read_misalign = UNSTUFF_BITS( ulResponse, 77, 1 );
pxCSD->r2w_factor = UNSTUFF_BITS( ulResponse, 26, 3 );
pxCSD->write_blkbits = UNSTUFF_BITS( ulResponse, 22, 4 );
pxCSD->write_partial = UNSTUFF_BITS( ulResponse, 21, 1 );
pxCSD->capacity <<= ( pxCSD->read_blkbits - 9 );
FF_PRINTF ("Capacity: (%u + 1) << (%u + 2) = %u Rd/Wr bits %u/%u\n",
m, e,
( unsigned )pxCSD->capacity,
( unsigned )pxCSD->read_blkbits,
( unsigned )pxCSD->write_blkbits);
if( UNSTUFF_BITS( ulResponse, 46, 1 ) )
{
pxCSD->erase_size = 1;
}
else if( pxCSD->write_blkbits >= 9 )
{
pxCSD->erase_size = UNSTUFF_BITS( ulResponse, 39, 7 ) + 1;
pxCSD->erase_size <<= pxCSD->write_blkbits - 9;
}
else
{
pxCSD->erase_size = 0; // Card is not eraseble
}
break;
case 1:
/*
* This is a block-addressed SDHC card. Most
* interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards,
* we assume those fixed values ourselves.
*/
mmc_is_block_addressed = 1;
pxCSD->tacc_ns = 0; /* Unused */
pxCSD->tacc_clks = 0; /* Unused */
m = UNSTUFF_BITS( ulResponse, 99, 4 );
e = UNSTUFF_BITS( ulResponse, 96, 3 );
// max_dtr gives 25,000,000
pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ];
// cmdClass gives: 10110110101 (0x5B5)
pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 );
m = UNSTUFF_BITS( ulResponse, 48, 22 );
pxCSD->capacity = ( 1 + m ) << 10;
FF_PRINTF( "capacity: (1 + %u) << 10 DTR %u Mhz\n", m, pxCSD->max_dtr / 1000000);
pxCSD->read_blkbits = 9;
pxCSD->read_partial = 0;
pxCSD->write_misalign = 0;
pxCSD->read_misalign = 0;
pxCSD->r2w_factor = 4; /* Unused */
pxCSD->write_blkbits = 9;
pxCSD->write_partial = 0;
pxCSD->erase_size = 1;
break;
default:
FF_PRINTF ("sd_decode_csd: unrecognised CSD structure version %d\n", csd_struct);
iResult = -1;
break;
}
if( iResult >= 0 )
{
unsigned int sz;
FF_PRINTF ("sd_decode_csd: capacity %lu (%s addressed)\n",
pxCSD->capacity, mmc_is_block_addressed ? "block" : "byte");
sz = (pxCSD->capacity << (pxCSD->read_blkbits - 9)) >> 11;
if (sz < 128)
{
pxCSD->pref_erase = 512 * 1024 / 512;
}
else if (sz < 512)
{
pxCSD->pref_erase = 1024 * 1024 / 512;
}
else if (sz < 1024)
{
pxCSD->pref_erase = 2 * 1024 * 1024 / 512;
}
else
{
pxCSD->pref_erase = 4 * 1024 * 1024 / 512;
}
if (pxCSD->pref_erase < pxCSD->erase_size)
{
pxCSD->pref_erase = pxCSD->erase_size;
}
else
{
sz = ( pxCSD->pref_erase % pxCSD->erase_size );
if( sz != 0 )
{
pxCSD->pref_erase += ( pxCSD->erase_size - sz );
}
}
// compute last block addr
pxCSD->sd_last_block_address = pxCSD->capacity - 1;
// compute card capacity in bytes
pxCSD->capacity_bytes = ( ( uint64_t )XSDPS_BLK_SIZE_512_MASK ) * pxCSD->capacity;
FF_PRINTF( "sd_mmc_spi_get_capacity: Capacity %lu MB Erase %u Pref %lu\n",
( uint32_t ) ( pxCSD->capacity_bytes / ( 1024LLU * 1024LLU ) ),
pxCSD->erase_size,
pxCSD->pref_erase );
}
return iResult;
}

View file

@ -0,0 +1,56 @@
/******************************************************************************
*
* mmc_decode_cid() and sd_decode_csd()
*
* analyse the meta data of an SD-card to read its capacity and some other properties.
*
* CID and CSD Analysis borrowed from the Linux kernel.
*
******************************************************************************/
#ifndef SDPS_INFO_H_
#define SDPS_INFO_H_ 1
#include <stdint.h>
struct mmc_cid {
uint32_t manfid;
char prod_name[8];
uint32_t serial;
uint16_t oemid;
uint16_t year;
uint8_t hwrev;
uint8_t fwrev;
uint8_t month;
};
struct mmc_csd {
volatile uint64_t capacity_bytes;
uint32_t sd_last_block_address;
uint8_t mmca_vsn;
uint16_t erase_size;
uint8_t spare;
uint16_t cmdclass;
uint16_t tacc_clks;
int32_t erase_shift;
uint32_t tacc_ns;
uint32_t r2w_factor;
uint32_t max_dtr;
uint32_t read_blkbits;
uint32_t write_blkbits;
uint32_t capacity;
uint32_t pref_erase;
uint32_t read_partial : 1,
read_misalign : 1,
write_partial : 1,
write_misalign : 1;
};
extern struct mmc_cid myCID;
extern struct mmc_csd myCSD;
int mmc_decode_cid( const struct mmc_csd *pxCSD, struct mmc_cid *pxCID, uint32_t *raw_data );
int sd_decode_csd( struct mmc_csd *pxCSD, uint32_t *ulResponse );
#endif /* SDPS_INFO_H_ */

View file

@ -0,0 +1,978 @@
/******************************************************************************
*
* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xsdps_options.c
* @addtogroup sdps_v2_5
* @{
*
* Contains API's for changing the various options in host and card.
* See xsdps.h for a detailed description of the device and driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 1.00a hk/sg 10/17/13 Initial release
* 2.1 hk 04/18/14 Increase sleep for eMMC switch command.
* Add sleep for microblaze designs. CR# 781117.
* 2.3 sk 09/23/14 Use XSdPs_Change_ClkFreq API whenever changing
* clock.CR# 816586.
* 2.5 sg 07/09/15 Added SD 3.0 features
* kvn 07/15/15 Modified the code according to MISRAC-2012.
*
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xsdps.h"
#include "xil_cache.h"
/*
* The header sleep.h and API usleep() can only be used with an arm design.
* MB_Sleep() is used for microblaze design.
*/
#if defined (__arm__) || defined (__aarch64__)
#include "sleep.h"
#endif
#ifdef __MICROBLAZE__
#include "microblaze_sleep.h"
#endif
#include <FreeRTOS.h>
#include "task.h"
#include "FreeRTOSFATConfig.h"
#include "uncached_memory.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);
void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);
s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr);
s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )
/* Declared in ff_sddisk.c :
Function will sleep and get interrupted on a change of
the status register. It will loop until:
1. Expected bit (ulMask) becomes high
2. Time-out reached (normally 2 seconds)
*/
extern u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask );
/* Clear the interrupt before using it. */
extern void XSdPs_ClearInterrupt( XSdPs *InstancePtr );
#else
#error Please define ffconfigSDIO_DRIVER_USES_INTERRUPT
#endif
/*****************************************************************************/
/**
* Update Block size for read/write operations.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param BlkSize - Block size passed by the user.
*
* @return None
*
******************************************************************************/
s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize)
{
s32 Status;
u32 PresentStateReg;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_PRES_STATE_OFFSET);
if ((PresentStateReg & ((u32)XSDPS_PSR_INHIBIT_CMD_MASK |
(u32)XSDPS_PSR_INHIBIT_DAT_MASK |
(u32)XSDPS_PSR_WR_ACTIVE_MASK | (u32)XSDPS_PSR_RD_ACTIVE_MASK)) != 0U) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/* Send block write command */
Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
/* Set block size to the value passed */
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
BlkSize & XSDPS_BLK_SIZE_MASK);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to get bus width support by card.
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
* @param SCR - buffer to store SCR register returned by card.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR)
{
s32 Status;
u16 BlkCnt;
u16 BlkSize;
s32 LoopCnt;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) {
SCR[LoopCnt] = 0U;
}
/* Send block write command */
Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
InstancePtr->RelCardAddr, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
BlkCnt = XSDPS_SCR_BLKCNT;
BlkSize = XSDPS_SCR_BLKSIZE;
/* Set block size to the value passed */
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_BLK_SIZE_OFFSET, BlkSize);
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
Xil_DCacheInvalidateRange((u32)SCR, 8);
Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0U, BlkCnt);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to set bus width to 4-bit in card and host
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr)
{
s32 Status;
u32 StatusReg;
u32 Arg;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
if (InstancePtr->CardType == XSDPS_CARD_SD) {
Status = XSdPs_CmdTransfer(InstancePtr, CMD55, InstancePtr->RelCardAddr,
0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;
Arg = ((u32)InstancePtr->BusWidth);
Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
} else {
if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3)
&& (InstancePtr->CardType == XSDPS_CHIP_EMMC)) {
/* in case of eMMC data width 8-bit */
InstancePtr->BusWidth = XSDPS_8_BIT_WIDTH;
} else {
InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;
}
if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {
Arg = XSDPS_MMC_8_BIT_BUS_ARG;
} else {
Arg = XSDPS_MMC_4_BIT_BUS_ARG;
}
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/* Check for transfer complete */
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
}
#if defined (__arm__) || defined (__aarch64__)
usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
#endif
#ifdef __MICROBLAZE__
/* 2 msec delay */
MB_Sleep(2);
#endif
StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL1_OFFSET);
/* Width setting in controller */
if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {
StatusReg |= XSDPS_HC_EXT_BUS_WIDTH;
} else {
StatusReg |= XSDPS_HC_WIDTH_MASK;
}
XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL1_OFFSET,
(u8)StatusReg);
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to get bus speed supported by card.
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
* @param ReadBuff - buffer to store function group support data
* returned by card.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff)
{
s32 Status;
u32 Arg;
u16 BlkCnt;
u16 BlkSize;
s32 LoopCnt;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) {
ReadBuff[LoopCnt] = 0U;
}
BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_BLK_SIZE_OFFSET, BlkSize);
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
Arg = XSDPS_SWITCH_CMD_HS_GET;
Xil_DCacheInvalidateRange((u32)ReadBuff, 64);
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to set high speed in card and host. Changes clock in host accordingly.
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr)
{
s32 Status;
u32 StatusReg;
u32 Arg;
u16 BlkCnt;
u16 BlkSize;
u8 ReadBuff[64];
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
if (InstancePtr->CardType == XSDPS_CARD_SD) {
BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_BLK_SIZE_OFFSET, BlkSize);
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
Xil_DCacheFlushRange((u32)ReadBuff, 64);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
Arg = XSDPS_SWITCH_CMD_HS_SET;
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
/* Change the clock frequency to 50 MHz */
InstancePtr->BusSpeed = XSDPS_CLK_50_MHZ;
Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
} else if (InstancePtr->CardType == XSDPS_CARD_MMC) {
Arg = XSDPS_MMC_HIGH_SPEED_ARG;
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
/* Change the clock frequency to 52 MHz */
InstancePtr->BusSpeed = XSDPS_CLK_52_MHZ;
Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
} else {
Arg = XSDPS_MMC_HS200_ARG;
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
/* Change the clock frequency to 200 MHz */
InstancePtr->BusSpeed = XSDPS_MMC_HS200_MAX_CLK;
Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
Status = XSdPs_Execute_Tuning(InstancePtr);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
}
#if defined (__arm__) || defined (__aarch64__)
usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
#endif
#ifdef __MICROBLAZE__
/* 2 msec delay */
MB_Sleep(2);
#endif
StatusReg = (s32)XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL1_OFFSET);
StatusReg |= XSDPS_HC_SPEED_MASK;
XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL1_OFFSET, (u8)StatusReg);
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to change clock freq to given value.
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
* @param SelFreq - Clock frequency in Hz.
*
* @return None
*
* @note This API will change clock frequency to the value less than
* or equal to the given value using the permissible dividors.
*
******************************************************************************/
s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)
{
u16 ClockReg;
u16 DivCnt;
u16 Divisor = 0U;
u16 ExtDivisor;
s32 Status;
u16 ReadReg;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/* Disable clock */
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);
ClockReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET, ClockReg);
if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
/* Calculate divisor */
for (DivCnt = 0x1U; DivCnt <= XSDPS_CC_EXT_MAX_DIV_CNT;DivCnt++) {
if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {
Divisor = DivCnt >> 1;
break;
}
}
if (DivCnt > XSDPS_CC_EXT_MAX_DIV_CNT) {
/* No valid divisor found for given frequency */
Status = XST_FAILURE;
goto RETURN_PATH;
}
} else {
/* Calculate divisor */
DivCnt = 0x1U;
while (DivCnt <= XSDPS_CC_MAX_DIV_CNT) {
if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {
Divisor = DivCnt / 2U;
break;
}
DivCnt = DivCnt << 1U;
}
if (DivCnt > XSDPS_CC_MAX_DIV_CNT) {
/* No valid divisor found for given frequency */
Status = XST_FAILURE;
goto RETURN_PATH;
}
}
/* Set clock divisor */
if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);
ClockReg &= ~(XSDPS_CC_SDCLK_FREQ_SEL_MASK |
XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK);
ExtDivisor = Divisor >> 8;
ExtDivisor <<= XSDPS_CC_EXT_DIV_SHIFT;
ExtDivisor &= XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK;
Divisor <<= XSDPS_CC_DIV_SHIFT;
Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;
ClockReg |= Divisor | ExtDivisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,
ClockReg);
} else {
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);
ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK);
Divisor <<= XSDPS_CC_DIV_SHIFT;
Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;
ClockReg |= Divisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,
ClockReg);
}
/* Wait for internal clock to stabilize */
ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);
while((ReadReg & XSDPS_CC_INT_CLK_STABLE_MASK) == 0U) {
ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);;
}
/* Enable SD clock */
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_CLK_CTRL_OFFSET,
ClockReg | XSDPS_CC_SD_CLK_EN_MASK);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to send pullup command to card before using DAT line 3(using 4-bit bus)
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Pullup(XSdPs *InstancePtr)
{
s32 Status;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
InstancePtr->RelCardAddr, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0U, 0U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to get EXT_CSD register of eMMC.
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
* @param ReadBuff - buffer to store EXT_CSD
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff)
{
s32 Status;
u32 Arg = 0U;
u16 BlkCnt;
u16 BlkSize;
s32 LoopCnt;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) {
ReadBuff[LoopCnt] = 0U;
}
BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT;
BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE;
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_BLK_SIZE_OFFSET, BlkSize);
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
Xil_DCacheInvalidateRange((u32)ReadBuff, 512U);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
/* Send SEND_EXT_CSD command */
Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
XSDPS_RESP0_OFFSET);
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
/*****************************************************************************/
/**
*
* API to UHS-I mode initialization
*
*
* @param InstancePtr is a pointer to the XSdPs instance.
* @param Mode UHS-I mode
*
* @return
* - XST_SUCCESS if successful.
* - XST_FAILURE if fail.
*
* @note None.
*
******************************************************************************/
s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode)
{
s32 Status;
u16 CtrlReg;
u32 Arg;
u16 BlkCnt;
u16 BlkSize;
u8 ReadBuff[64];
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/* Drive strength */
/* Bus speed mode selection */
BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
BlkSize);
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
Xil_DCacheFlushRange((u32)ReadBuff, 64);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
switch (Mode) {
case 0U:
Arg = XSDPS_SWITCH_CMD_SDR12_SET;
InstancePtr->BusSpeed = XSDPS_SD_SDR12_MAX_CLK;
break;
case 1U:
Arg = XSDPS_SWITCH_CMD_SDR25_SET;
InstancePtr->BusSpeed = XSDPS_SD_SDR25_MAX_CLK;
break;
case 2U:
Arg = XSDPS_SWITCH_CMD_SDR50_SET;
InstancePtr->BusSpeed = XSDPS_SD_SDR50_MAX_CLK;
break;
case 3U:
Arg = XSDPS_SWITCH_CMD_SDR104_SET;
InstancePtr->BusSpeed = XSDPS_SD_SDR104_MAX_CLK;
break;
case 4U:
Arg = XSDPS_SWITCH_CMD_DDR50_SET;
InstancePtr->BusSpeed = XSDPS_SD_DDR50_MAX_CLK;
break;
default:
Status = XST_FAILURE;
goto RETURN_PATH;
break;
}
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
/* Current limit */
/* Set UHS mode in controller */
CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL2_OFFSET);
CtrlReg &= (u16)(~XSDPS_HC2_UHS_MODE_MASK);
CtrlReg |= Mode;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
XSDPS_HOST_CTRL2_OFFSET, CtrlReg);
/* Change the clock frequency */
Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
if((Mode == XSDPS_UHS_SPEED_MODE_SDR104) ||
(Mode == XSDPS_UHS_SPEED_MODE_DDR50)) {
/* Send tuning pattern */
Status = XSdPs_Execute_Tuning(InstancePtr);
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
}
Status = XST_SUCCESS;
RETURN_PATH:
return Status;
}
static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
{
s32 Status;
u16 BlkCnt;
u16 BlkSize;
s32 LoopCnt;
u8 ReadBuff[128];
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
BlkCnt = XSDPS_TUNING_CMD_BLKCNT;
BlkSize = XSDPS_TUNING_CMD_BLKSIZE;
if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH)
{
BlkSize = BlkSize*2U;
}
BlkSize &= XSDPS_BLK_SIZE_MASK;
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
BlkSize);
for (LoopCnt = 0; LoopCnt < (s32)BlkSize; LoopCnt++) {
ReadBuff[LoopCnt] = 0U;
}
XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,
XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
Xil_DCacheInvalidateRange((u32)ReadBuff, BlkSize);
if(InstancePtr->CardType == XSDPS_CARD_SD) {
Status = XSdPs_CmdTransfer(InstancePtr, CMD19, 0U, 1U);
} else {
Status = XSdPs_CmdTransfer(InstancePtr, CMD21, 0U, 1U);
}
if (Status != XST_SUCCESS) {
Status = XST_FAILURE;
goto RETURN_PATH;
}
/*
* Check for transfer complete
* Polling for response for now
*/
Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);
if (Status != XST_SUCCESS) {
goto RETURN_PATH;
}
Status = XST_SUCCESS;
RETURN_PATH: return Status;
}
/** @} */

View file

@ -0,0 +1,95 @@
/******************************************************************************
*
* Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xsdps_sinit.c
*
* The implementation of the XSdPs component's static initialization
* functionality.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 1.00a hk/sg 10/17/13 Initial release
*
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xstatus.h"
#include "xsdps.h"
#include "xparameters.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
extern XSdPs_Config XSdPs_ConfigTable[];
/*****************************************************************************/
/**
*
* Looks up the device configuration based on the unique device ID. A table
* contains the configuration info for each device in the system.
*
* @param DeviceId contains the ID of the device to look up the
* configuration for.
*
* @return
*
* A pointer to the configuration found or NULL if the specified device ID was
* not found. See xsdps.h for the definition of XSdPs_Config.
*
* @note None.
*
******************************************************************************/
XSdPs_Config *XSdPs_LookupConfig(u16 DeviceId)
{
XSdPs_Config *CfgPtr = NULL;
int Index;
for (Index = 0; Index < XPAR_XSDPS_NUM_INSTANCES; Index++) {
if (XSdPs_ConfigTable[Index].DeviceId == DeviceId) {
CfgPtr = &XSdPs_ConfigTable[Index];
break;
}
}
return CfgPtr;
}

View file

@ -0,0 +1,75 @@
//
//
//
#define SD_MMC_SPI_MEM 1
#include "ff_headers.h"
#include "logbuf.h"
#include "secCache.h"
#include "ff_flush.h"
extern BaseType_t FF_SemaphoreTaken( void *pxSemaphore );
FF_Error_t FF_FlushWrites( FF_IOManager_t *pxIOManager, BaseType_t xForced )
{
FF_Error_t xRetValue;
if( ( pxIOManager == NULL ) || ( cache_dirt_count() == 0 ) )
{
xRetValue = FF_ERR_NONE;
}
else if( ( pxIOManager->ucPreventFlush != pdFALSE ) && ( xForced == pdFALSE ) )
{
xRetValue = FF_ERR_IOMAN_PARTITION_MOUNTED | FF_ERRFLAG;
}
else
{
BaseType_t rc = 0;
if( xForced != pdFALSE )
{
FF_FlushCache( pxIOManager );
}
// if( FF_TrySemaphore( pxIOManager->pvSemaphore, xForced ? 5000 : 0 ) != pdFALSE )
if( ( xForced != pdFALSE ) || ( FF_SemaphoreTaken( pxIOManager->pvSemaphore ) == pdFALSE ) )
{
rc = cache_flush( xForced );
// FF_ReleaseSemaphore( pxIOManager->pvSemaphore );
}
xRetValue = rc;
}
return xRetValue;
}
FF_Error_t FF_StopFlush( FF_IOManager_t *pxIOManager, BaseType_t xFlag )
{
FF_Error_t xRetValue;
if( pxIOManager == NULL )
{
xRetValue = 0;
}
else
{
vTaskSuspendAll();
{
xRetValue = pxIOManager->ucPreventFlush;
if( xFlag != FLUSH_ENABLE )
{
xRetValue++;
}
else if ( xRetValue > 0 )
{
xRetValue--;
}
pxIOManager->ucPreventFlush = xRetValue;
}
xTaskResumeAll();
}
return xRetValue;
}

View file

@ -0,0 +1,48 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
#if !defined(__FF_FLUSH_H__)
#define __FF_FLUSH_H__
#ifdef __cplusplus
extern "C" {
#endif
// HT addition: call FF_FlushCache and in addition call cache_write_flush (see secCache.cpp)
FF_Error_t FF_FlushWrites( FF_IOManager_t *pxIOManager, BaseType_t xForced );
#define FLUSH_DISABLE 1
#define FLUSH_ENABLE 0
// HT addition: prevent flushing temporarily FF_StopFlush(pIoMan, true)
FF_Error_t FF_StopFlush( FF_IOManager_t *pxIOManager, BaseType_t xFlag );
#ifdef __cplusplus
} // extern "C"
#endif
#endif // !defined(__FF_FLUSH_H__)

View file

@ -0,0 +1,343 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "ff_headers.h"
#include "event_groups.h"
/* Scheduler include files. */
#ifdef __WIN32__
#include "MyMalloc.h"
#else
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "tcpLogging.h"
#endif
#include "logbuf.h"
#include <string.h>
#include "bitops.h"
#if USE_SOFT_WDT
#include "softWdt.h"
#endif
#include "thread_mutex.h"
#include "event_groups.h"
#if( FF_DO_TRACE_SEMAPHORE != 0 )
#include "eventLogging.h"
#endif
/* There are two areas which are protected with a semaphore:
Directories and the FAT area.
The masks below are used when calling Group Event functions. */
#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK )
#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK )
/* This is not a real lock: it is a bit (or semaphore) will will be given
each time when a sector buffer is released. */
#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK )
extern void myTaskDelay (unsigned aTime);
static char cMutexWasCreated = 0;
static pthread_mutex_t xFATMutex;
static void vCreateFATMutex ()
{
cMutexWasCreated = 1;
pthread_mutex_init ("FreeRTOS+FAT", &xFATMutex, 0);
}
BaseType_t FF_HasSemaphore (void *pxSemaphore)
{
// Return pdTRUE if the calling task owns the semaphore
if (!cMutexWasCreated) vCreateFATMutex ();
return pthread_has_mutex (&xFATMutex);
}
BaseType_t FF_SemaphoreTaken (void *pxSemaphore)
{
// Return pdTRUE if the calling task owns the semaphore
if (!cMutexWasCreated) vCreateFATMutex ();
return pthread_mutex_islocked (&xFATMutex);
}
#if( FF_DO_TRACE_SEMAPHORE != 0 )
static char mutex_owner[32];
#endif
BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms)
{
BaseType_t rc;
#if( FF_DO_TRACE_SEMAPHORE != 0 )
{
eventLogAdd("Pend_%s\n", pcName);
}
#endif /* FF_DO_TRACE_SEMAPHORE */
if (!cMutexWasCreated) vCreateFATMutex ();
rc = pthread_mutex_lock (&xFATMutex, ulTime_ms);
#if( FF_DO_TRACE_SEMAPHORE != 0 )
if (rc > 0) {
if(mutex_owner[0] != 0) {
logPrintf("Pend Try: %s overruled\n", mutex_owner);
}
snprintf(mutex_owner, sizeof mutex_owner, pcName);
}
#endif /* FF_DO_TRACE_SEMAPHORE */
return rc;
}
/*-----------------------------------------------------------*/
void FF_PendSemaphore( void *pxSemaphore )
{
#if( FF_DO_TRACE_SEMAPHORE != 0 )
{
eventLogAdd("Pend_%s\n", pcName);
}
#endif /* FF_DO_TRACE_SEMAPHORE */
if (!cMutexWasCreated) vCreateFATMutex ();
pthread_mutex_lock (&xFATMutex, 120000);
#if( FF_DO_TRACE_SEMAPHORE != 0 )
{
if(mutex_owner[0] != 0) {
logPrintf("Pend Enter: %s overruled by %s\n", mutex_owner, pcName);
}
snprintf(mutex_owner, sizeof mutex_owner, pcName);
}
#endif /* FF_DO_TRACE_SEMAPHORE */
}
/*-----------------------------------------------------------*/
void FF_ReleaseSemaphore( void *pxSemaphore )
{
#if( FF_DO_TRACE_SEMAPHORE != 0 )
{
if(strcmp (pcName, mutex_owner) != 0) {
// FF_GetBuffer2 != FF_GetBuffer
logPrintf("Pend Exit: %s owned by %s\n", pcName, mutex_owner);
}
eventLogAdd("Exit_%s\n", pcName);
mutex_owner[0] = '\0';
}
#endif /* FF_DO_TRACE_SEMAPHORE */
if (cMutexWasCreated) {
pthread_mutex_unlock (&xFATMutex);
}
}
/*-----------------------------------------------------------*/
void FF_Sleep( uint32_t ulTime_ms )
{
myTaskDelay (ulTime_ms);
}
/*-----------------------------------------------------------*/
BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager )
{
BaseType_t xResult;
pxIOManager->xEventGroup = xEventGroupCreate();
if( pxIOManager->xEventGroup != NULL )
{
xEventGroupSetBits( pxIOManager->xEventGroup,
FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS );
xResult = pdTRUE;
}
else
{
xResult = pdFALSE;
}
return xResult;
}
/*-----------------------------------------------------------*/
void FF_LockDirectory( FF_IOManager_t *pxIOManager )
{
EventBits_t xBits;
for( ;; )
{
/* Called when a task want to make changes to a directory.
First it waits for the desired bit to come high. */
xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
( EventBits_t )0, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
pdMS_TO_TICKS( 10000UL ) );
/* The next operation will only succeed for 1 task at a time,
because it is an atomary test & set operation: */
xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );
if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 )
{
/* This task has cleared the desired bit.
It now 'owns' the resource. */
break;
}
}
}
/*-----------------------------------------------------------*/
void FF_UnlockDirectory( FF_IOManager_t *pxIOManager )
{
configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 );
xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );
}
/*-----------------------------------------------------------*/
int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )
{
int iReturn;
void *handle = xTaskGetCurrentTaskHandle();
if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) )
{
iReturn = pdTRUE;
}
else
{
iReturn = pdFALSE;
}
}
else
{
iReturn = pdFALSE;
}
return iReturn;
}
void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits )
{
void *handle = xTaskGetCurrentTaskHandle();
if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
configASSERT( pxIOManager->pvFATLockHandle != NULL && pxIOManager->pvFATLockHandle == handle );
/* In case configASSERT() is not defined. */
( void ) pxIOManager;
( void ) handle;
}
}
void FF_LockFAT( FF_IOManager_t *pxIOManager )
{
EventBits_t xBits;
configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE );
if (FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) != pdFALSE )
{
return;
}
for( ;; )
{
/* Called when a task want to make changes to the FAT area.
First it waits for the desired bit to come high. */
xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
( EventBits_t )0, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
pdMS_TO_TICKS( 10000UL ) );
/* The next operation will only succeed for 1 task at a time,
because it is an atomary test & set operation: */
xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );
if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
/* This task has cleared the desired bit.
It now 'owns' the resource. */
pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle();
break;
}
}
}
/*-----------------------------------------------------------*/
void FF_UnlockFAT( FF_IOManager_t *pxIOManager )
{
configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 );
if (FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) != pdFALSE )
{
pxIOManager->pvFATLockHandle = NULL;
xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );
}
else
{
FF_PRINTF("FF_UnlockFAT: wasn't locked by me\n");
}
}
/*-----------------------------------------------------------*/
BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS )
{
EventBits_t xBits;
BaseType_t xReturn;
/* This function is called when a task is waiting for a sector buffer
to become available. */
xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
pdMS_TO_TICKS( xWaitMS ) );
if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void FF_BufferProceed( FF_IOManager_t *pxIOManager )
{
/* Wake-up all tasks that are waiting for a sector buffer to become available. */
xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS );
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,423 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_headers.h"
#include "ff_ramdisk.h"
#include "ff_sys.h"
#define ramHIDDEN_SECTOR_COUNT 8
#define ramPRIMARY_PARTITIONS 1
#define ramHUNDRED_64_BIT 100ULL
#define ramSECTOR_SIZE 512UL
#define ramPARTITION_NUMBER 0 /* Only a single partition is used. */
#define ramBYTES_PER_KB ( 1024ull )
#define ramSECTORS_PER_KB ( ramBYTES_PER_KB / 512ull )
/* Used as a magic number to indicate that an FF_Disk_t structure is a RAM
disk. */
#define ramSIGNATURE 0x41404342
/*-----------------------------------------------------------*/
/*
* The function that writes to the media - as this is implementing a RAM disk
* the media is just a RAM buffer.
*/
static int32_t prvWriteRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*
* The function that reads from the media - as this is implementing a RAM disk
* the media is just a RAM buffer.
*/
static int32_t prvReadRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*
* This is the driver for a RAM disk. Unlike most media types, RAM disks are
* volatile so are created anew each time the system is booted. As the disk is
* new and just created, it must also be partitioned and formatted.
*/
static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk );
/*-----------------------------------------------------------*/
/* This is the prototype of the function used to initialise the RAM disk driver.
Other media drivers do not have to have the same prototype.
In this example:
+ pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.
+ pucDataBuffer is the start of the RAM to use as the disk.
+ ulSectorCount is effectively the size of the disk, each sector is 512 bytes.
+ xIOManagerCacheSize is the size of the IO manager's cache, which must be a
multiple of the sector size, and at least twice as big as the sector size.
*/
FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize )
{
FF_Error_t xError;
FF_Disk_t *pxDisk = NULL;
FF_CreationParameters_t xParameters;
/* Check the validity of the xIOManagerCacheSize parameter. */
configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );
configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );
/* Attempt to allocated the FF_Disk_t structure. */
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );
if( pxDisk != NULL )
{
/* Start with every member of the structure set to zero. */
memset( pxDisk, '\0', sizeof( FF_Disk_t ) );
/* Clear the entire space. */
memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE );
/* The pvTag member of the FF_Disk_t structure allows the structure to be
extended to also include media specific parameters. The only media
specific data that needs to be stored in the FF_Disk_t structure for a
RAM disk is the location of the RAM buffer itself - so this is stored
directly in the FF_Disk_t's pvTag member. */
pxDisk->pvTag = ( void * ) pucDataBuffer;
/* The signature is used by the disk read and disk write functions to
ensure the disk being accessed is a RAM disk. */
pxDisk->ulSignature = ramSIGNATURE;
/* The number of sectors is recorded for bounds checking in the read and
write functions. */
pxDisk->ulNumberOfSectors = ulSectorCount;
/* Create the IO manager that will be used to control the RAM disk. */
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.pucCacheMemory = NULL;
xParameters.ulMemorySize = xIOManagerCacheSize;
xParameters.ulSectorSize = ramSECTOR_SIZE;
xParameters.fnWriteBlocks = prvWriteRAM;
xParameters.fnReadBlocks = prvReadRAM;
xParameters.pxDisk = pxDisk;
/* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.
In this case the semaphore is only used to protect FAT data
structures. */
xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();
xParameters.xBlockDeviceIsReentrant = pdFALSE;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );
if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
{
/* Record that the RAM disk has been initialised. */
pxDisk->xStatus.bIsInitialised = pdTRUE;
/* Create a partition on the RAM disk. NOTE! The disk is only
being partitioned here because it is a new RAM disk. It is
known that the disk has not been used before, and cannot already
contain any partitions. Most media drivers will not perform
this step because the media will have already been partitioned. */
xError = prvPartitionAndFormatDisk( pxDisk );
if( FF_isERR( xError ) == pdFALSE )
{
/* Record the partition number the FF_Disk_t structure is, then
mount the partition. */
pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;
/* Mount the partition. */
xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
}
if( FF_isERR( xError ) == pdFALSE )
{
/* The partition mounted successfully, add it to the virtual
file system - where it will appear as a directory off the file
system's root directory. */
FF_FS_Add( pcName, pxDisk );
}
}
else
{
FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
/* The disk structure was allocated, but the disk's IO manager could
not be allocated, so free the disk again. */
FF_RAMDiskDelete( pxDisk );
pxDisk = NULL;
}
}
else
{
FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return pdPASS;
}
/*-----------------------------------------------------------*/
static int32_t prvReadRAM( uint8_t *pucDestination, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturn;
uint8_t *pucSource;
if( pxDisk != NULL )
{
if( pxDisk->ulSignature != ramSIGNATURE )
{
/* The disk structure is not valid because it doesn't contain a
magic number written to the disk when it was created. */
lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
}
else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
{
/* The disk has not been initialised. */
lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
}
else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
{
/* The start sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
{
/* The end sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else
{
/* Obtain the pointer to the RAM buffer being used as the disk. */
pucSource = ( uint8_t * ) pxDisk->pvTag;
/* Move to the start of the sector being read. */
pucSource += ( ramSECTOR_SIZE * ulSectorNumber );
/* Copy the data from the disk. As this is a RAM disk this can be
done using memcpy(). */
memcpy( ( void * ) pucDestination,
( void * ) pucSource,
( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) );
lReturn = FF_ERR_NONE;
}
}
else
{
lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
}
return lReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvWriteRAM( uint8_t *pucSource, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t lReturn = FF_ERR_NONE;
uint8_t *pucDestination;
if( pxDisk != NULL )
{
if( pxDisk->ulSignature != ramSIGNATURE )
{
/* The disk structure is not valid because it doesn't contain a
magic number written to the disk when it was created. */
lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
}
else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
{
/* The disk has not been initialised. */
lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
}
else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
{
/* The start sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
{
/* The end sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else
{
/* Obtain the location of the RAM being used as the disk. */
pucDestination = ( uint8_t * ) pxDisk->pvTag;
/* Move to the sector being written to. */
pucDestination += ( ramSECTOR_SIZE * ulSectorNumber );
/* Write to the disk. As this is a RAM disk the write can use a
memcpy(). */
memcpy( ( void * ) pucDestination,
( void * ) pucSource,
( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE );
lReturn = FF_ERR_NONE;
}
}
else
{
lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
}
return lReturn;
}
/*-----------------------------------------------------------*/
static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk )
{
FF_PartitionParameters_t xPartition;
FF_Error_t xError;
/* Create a single partition that fills all available space on the disk. */
memset( &xPartition, '\0', sizeof( xPartition ) );
xPartition.ulSectorCount = pxDisk->ulNumberOfSectors;
xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT;
xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS;
xPartition.eSizeType = eSizeIsQuota;
/* Partition the disk */
xError = FF_Partition( pxDisk, &xPartition );
FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if( FF_isERR( xError ) == pdFALSE )
{
/* Format the partition. */
xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );
FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
}
return xError;
}
/*-----------------------------------------------------------*/
BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeKB, ulFreeSizeKB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
if( pxIOManager->xPartition.ulDataSectors == ( uint32_t )0 )
{
iPercentageFree = 0;
}
else
{
iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
}
ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB;
ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu KB\n", ulTotalSizeKB );
FF_PRINTF( "FreeSize %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
void FF_RAMDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/

View file

@ -0,0 +1,50 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
#ifndef __RAMDISK_H__
#define __RAMDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize );
/* Release all resources */
BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk );
/* Show some partition information */
BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __RAMDISK_H__ */

View file

@ -0,0 +1,76 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
#ifndef __SDDISK_H__
#define __SDDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
/* Return non-zero if the SD-card is present.
The parameter 'pxDisk' may be null, unless device locking is necessary. */
BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk );
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t *FF_SDDiskInit( const char *pcName );
BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk );
/* Unmount the volume */
BaseType_t FF_SDDiskUnmount( FF_Disk_t *pDisk );
/* Mount the volume */
BaseType_t FF_SDDiskMount( FF_Disk_t *pDisk );
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pDisk );
/* Show some partition information */
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pDisk );
/* Flush changes from the driver's buf to disk */
void FF_SDDiskFlush( FF_Disk_t *pDisk );
/* Format a given partition on an SD-card. */
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart );
/* Return non-zero if an SD-card is detected in a given slot. */
BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr );
/* _RB_ Temporary function - ideally the application would not need the IO
manageer structure, just a handle to a disk. */
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SDDISK_H__ */

View file

@ -0,0 +1,532 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* LPC18xx includes. */
#include "chip.h"
#include "board.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_sddisk.h"
#include "ff_sys.h"
#include "hr_gettime.h"
/* Misc definitions. */
#define sdSIGNATURE 0x41404342UL
#define sdHUNDRED_64_BIT ( 100ull )
#define sdBYTES_PER_MB ( 1024ull * 1024ull )
#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull )
#define sdIOMAN_MEM_SIZE 4096
#define xSDCardInfo ( sd_mmc_cards[ 0 ] )
#define sdAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
/*-----------------------------------------------------------*/
/*_RB_ Functions require comment blocks. */
static void prvSDMMCSetupWakeup( void *pvInfo );
static uint32_t prvSDMMCWait( void );
static void prvSDMMCDelay_ms( uint32_t time );
static void prvInitialiseCardInfo( void );
static int32_t prvSDMMC_Init( void );
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*-----------------------------------------------------------*/
/*_RB_ Variables require a comment block where appropriate. */
static int32_t lSDDetected = 0;
static mci_card_struct xCardInfo;
static volatile int32_t lSDIOWaitExit;
static BaseType_t xSDCardStatus;
static SemaphoreHandle_t xSDCardSemaphore;
static SemaphoreHandle_t xPlusFATMutex;
/*-----------------------------------------------------------*/
#warning Update to make read and write functions static and make use of the FF_Disk_t type.
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
/*_RB_ Many of the comments in this file apply to other functions in the file. */
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = Chip_SDMMC_ReadBlocks( LPC_SDMMC, pucBuffer, ulSectorNumber, ulSectorCount );
/*_RB_ I'm guessing 512 is a sector size, but that needs to be clear.
Is it defined in a header somewhere? If so we can do a search and
replace in files on it as it seems to be used everywhere. */
if( iReturn == ( ulSectorCount * 512 ) ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
/*_RB_ Signed number used to return bitmap (again below). */
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised != 0 )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = Chip_SDMMC_WriteBlocks( LPC_SDMMC, pucBuffer, ulSectorNumber, ulSectorCount );
if( iReturn == ( ulSectorCount * 512 ) ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = 0;
}
else
{
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
void FF_SDDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
/* Initialise the SDIO driver and mount an SD card */
FF_Disk_t *FF_SDDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t * pxDisk;
xSDCardStatus = prvSDMMC_Init();
if( xSDCardStatus == pdPASS )
{
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk != NULL )
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
if( xPlusFATMutex == NULL)
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulNumberOfSectors = xCardInfo.card_info.blocknr;
pxDisk->ulSignature = sdSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = sdIOMAN_MEM_SIZE;
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) );
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SDDiskMount( pxDisk ) == 0 )
{
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );
FF_SDDiskShowPartition( pxDisk );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
else
{
FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );
}
} /* if( xSDCardStatus == pdPASS ) */
else
{
FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\n" );
pxDisk = NULL;
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
xError = FF_SDDiskMount( pxDisk );
FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
FF_SDDiskShowPartition( pxDisk );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
void SDIO_IRQHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* All SD based register handling is done in the callback function. The SDIO
interrupt is not enabled as part of this driver and needs to be
enabled/disabled in the callbacks or application as needed. This is to allow
flexibility with IRQ handling for applications and RTOSes. */
/* Set wait exit flag to tell wait function we are ready. In an RTOS, this
would trigger wakeup of a thread waiting for the IRQ. */
NVIC_DisableIRQ( SDIO_IRQn );
xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken );
lSDIOWaitExit = 1;
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/*-----------------------------------------------------------*/
/* Sets up the SD event driven wakeup */
static void prvSDMMCSetupWakeup( void *pvInfo )
{
uint32_t *ulWaitStatus = ( uint32_t * ) pvInfo;
/* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ
based wakeup. */
/*_RB_ Don't understand why this is spinning on a block time of 0. Is it
really meant to be != pdFALSE? */
while( xSemaphoreTake( xSDCardSemaphore, 0 ) != pdFALSE )
{
}
NVIC_ClearPendingIRQ( SDIO_IRQn );
lSDIOWaitExit = 0;
Chip_SDIF_SetIntMask( LPC_SDMMC, *ulWaitStatus );
NVIC_EnableIRQ( SDIO_IRQn );
}
/*-----------------------------------------------------------*/
static uint32_t prvSDMMCWait( void )
{
uint32_t ulStatus;
/*_RB_ 2000 needs to be defined and use pdMS_TO_TICKS so the delay period
remains constant no matter how the end user sets configTICK_RATE_MS. */
xSemaphoreTake( xSDCardSemaphore, 2000 );
ulStatus = Chip_SDIF_GetIntStatus( LPC_SDMMC );
if( ( ( ulStatus & MCI_INT_CMD_DONE ) == 0 ) || ( lSDIOWaitExit == 0 ) )
{
FF_PRINTF( "Wait SD: int32_t %ld ulStatus 0x%02lX\n", lSDIOWaitExit, ulStatus );
}
return ulStatus;
}
/*-----------------------------------------------------------*/
static void prvSDMMCDelay_ms( uint32_t ulTime )
{
/* In an RTOS, the thread would sleep allowing other threads to run.
For standalone operation, just spin on a timer */
vTaskDelay( pdMS_TO_TICKS( ulTime ) );
}
/*-----------------------------------------------------------*/
static int32_t prvSDMMC_Init( void )
{
int32_t lSDCardStatus;
if( xSDCardSemaphore == NULL )
{
xSDCardSemaphore = xSemaphoreCreateBinary();
configASSERT( xSDCardSemaphore );
xSemaphoreGive( xSDCardSemaphore );
}
prvInitialiseCardInfo();
NVIC_SetPriority( SDIO_IRQn, configSD_INTERRUPT_PRIORITY );
/*_RB_ Board_SDMMC_Init() is library specific code that is also specific to
the target development board.The SDMMC peripheral should be initialised from
the application code before this code is called. */
Board_SDMMC_Init();
Chip_SDIF_Init( LPC_SDMMC );
lSDDetected = !Chip_SDIF_CardNDetect( LPC_SDMMC );
Chip_SDIF_PowerOn( LPC_SDMMC );
lSDCardStatus = Chip_SDMMC_Acquire( LPC_SDMMC, &xCardInfo );
FF_PRINTF( "Acquire: %ld\n", lSDCardStatus );
return lSDCardStatus;
}
/*-----------------------------------------------------------*/
static void prvInitialiseCardInfo( void )
{
memset( &xCardInfo, 0, sizeof( xCardInfo ) );
xCardInfo.card_info.evsetup_cb = prvSDMMCSetupWakeup;
xCardInfo.card_info.waitfunc_cb = prvSDMMCWait;
xCardInfo.card_info.msdelay_func = prvSDMMCDelay_ms;
}