/** ################################################################### ** THIS COMPONENT MODULE IS GENERATED BY THE TOOL. DO NOT MODIFY IT. ** Filename : SDHC1.c ** Project : ProcessorExpert ** Processor : MK60DN512ZVMD10 ** Component : SDHC_LDD ** Version : Component 00.001, Driver 01.03, CPU db: 3.00.003 ** Compiler : CodeWarrior ARM C Compiler ** Date/Time : 2012-07-29, 21:43, # CodeGen: 371 ** Abstract : ** This component implements a SD host controller driver ** interface. Handles control and data transfers to/from ** SD and MMC cards. ** Settings : ** Component name : SDHC1 ** Device : SDHC ** Settings : ** Interface : 4-bit data mode ** Bus clock : 390.625 kHz ** Data timeout exponent : 20 ** DMA : ** Read watermark : 16 ** Write watermark : 16 ** Buffers : ** Transfer buffer table size : 8 ** Interrupt service/event : Enabled ** SDHC : INT_SDHC ** SDHC priority : medium priority ** Pins : 4-bit data mode ** CLK pin : PTE2/SPI1_SCK/UART1_CTS_b/SDHC0_DCLK/ADC1_SE6a ** CLK pin signal : SD_CLK ** CMD pin : PTE3/SPI1_SIN/UART1_RTS_b/SDHC0_CMD/ADC1_SE7a ** CMD pin signal : SD_CMD ** Data : ** DAT0 pin : PTE1/SPI1_SOUT/UART1_RX/SDHC0_D0/I2C1_SCL/ADC1_SE5a ** DAT0 pin signal : SD_DATA0 ** DAT1 : Enabled ** DAT1 pin : PTE0/SPI1_PCS1/UART1_TX/SDHC0_D1/I2C1_SDA/ADC1_SE4a ** DAT1 pin signal : SD_DATA1 ** DAT2 : Enabled ** DAT2 pin : PTE5/SPI1_PCS2/UART3_RX/SDHC0_D2 ** DAT2 pin signal : SD_DATA2 ** DAT3 : Enabled ** DAT3 pin : PTE4/SPI1_PCS0/UART3_TX/SDHC0_D3 ** DAT3 pin signal : SD_DATA3 ** Initialization : ** Enable device : yes ** Auto initialization : no ** Event mask : ** OnCardInserted : Enabled ** OnCardRemoved : Enabled ** OnFinished : Enabled ** CPU clock/configuration selection : ** Clock configuration 0 : This component enabled ** Clock configuration 1 : This component disabled ** Clock configuration 2 : This component disabled ** Contents : ** Init - LDD_TDeviceData* SDHC1_Init(LDD_TUserData *UserDataPtr); ** Deinit - void SDHC1_Deinit(LDD_TDeviceData *DeviceDataPtr); ** Enable - LDD_TError SDHC1_Enable(LDD_TDeviceData *DeviceDataPtr); ** Disable - LDD_TError SDHC1_Disable(LDD_TDeviceData *DeviceDataPtr); ** SetEventMask - LDD_TError SDHC1_SetEventMask(LDD_TDeviceData *DeviceDataPtr, LDD_TEventMask... ** GetEventMask - LDD_TEventMask SDHC1_GetEventMask(LDD_TDeviceData *DeviceDataPtr); ** DetectCards - LDD_TError SDHC1_DetectCards(LDD_TDeviceData *DeviceDataPtr); ** SelectCard - LDD_TError SDHC1_SelectCard(LDD_TDeviceData *DeviceDataPtr, uint8_t Id); ** GetCardInfo - LDD_TError SDHC1_GetCardInfo(LDD_TDeviceData *DeviceDataPtr,... ** TransferBlocks - LDD_TError SDHC1_TransferBlocks(LDD_TDeviceData *DeviceDataPtr,... ** EraseBlocks - LDD_TError SDHC1_EraseBlocks(LDD_TDeviceData *DeviceDataPtr, uint32_t... ** SetDataWidth - LDD_TError SDHC1_SetDataWidth(LDD_TDeviceData *DeviceDataPtr, uint8_t Width); ** SelectBusClock - LDD_TError SDHC1_SelectBusClock(LDD_TDeviceData *DeviceDataPtr,... ** SetVoltage - LDD_TError SDHC1_SetVoltage(LDD_TDeviceData *DeviceDataPtr, LDD_SDHC_TVoltage... ** SetWriteProtection - LDD_TError SDHC1_SetWriteProtection(LDD_TDeviceData *DeviceDataPtr,... ** GetWriteProtection - LDD_TError SDHC1_GetWriteProtection(LDD_TDeviceData *DeviceDataPtr, uint32_t... ** CancelOperation - LDD_TError SDHC1_CancelOperation(LDD_TDeviceData *DeviceDataPtr); ** GetStatus - LDD_SDHC_TStatus SDHC1_GetStatus(LDD_TDeviceData *DeviceDataPtr); ** GetError - LDD_SDHC_TError SDHC1_GetError(LDD_TDeviceData *DeviceDataPtr, uint32_t... ** ConnectPin - LDD_TError SDHC1_ConnectPin(LDD_TDeviceData *DeviceDataPtr, LDD_TPinMask... ** SetOperationMode - LDD_TError SDHC1_SetOperationMode(LDD_TDeviceData *DeviceDataPtr,... ** GetDriverState - LDD_TDriverState SDHC1_GetDriverState(LDD_TDeviceData *DeviceDataPtr); ** ** Copyright : 1997 - 2011 Freescale Semiconductor, Inc. All Rights Reserved. ** ** http : www.freescale.com ** mail : support@freescale.com ** ###################################################################*/ /* MODULE SDHC1 */ /*lint -save -esym(960,10.1) -e961 Disable MISRA rule (10.1,12.1) checking. */ #include #include #include #include #include "sdhc.h" #include "mk64f12.h" #include "sim.h" #include "irq.h" LDD_SDHC1_TDeviceData SDHC1_stDeviceData; /* {FreeRTOS RTOS Adapter} Global variable used for passing a parameter into ISR */ static LDD_SDHC1_TDeviceData* INT_SDHC__BAREBOARD_RTOS_ISRPARAM; /* Internal method prototypes */ static void VoltageValidation(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static void CardRegistration(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static void CardInfoRetrieval(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool CardSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool Transfer(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool Erasion(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool DataWidthSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool BusClockSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool WriteProtectionSetup(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static bool WriteProtectionRetrieval(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static void SetBusClockPrescalers(LDD_SDHC1_TDeviceData *DeviceDataPtr, SDHC1_TBusClock Frequency); static LDD_SDHC_TError GetCommandError(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response); static void SendCardStatusRequest(LDD_SDHC1_TDeviceData *DeviceDataPtr); static void EventHandler(LDD_SDHC1_TDeviceData *DeviceDataPtr); /* ** =================================================================== ** Method : SDHC1_Init (component SDHC_LDD) ** ** Description : ** Initializes the device. Allocates memory for the device data ** structure, allocates interrupt vectors and sets interrupt ** priority, sets pin routing, sets timing, etc. If the ** property <"Enable device"> is set to "yes" then the device ** is also enabled (see the description of the method). ** In this case the method is not necessary and need ** not to be generated. This method can be called only once. ** Before the second call of Init the method must be ** called first. ** Parameters : ** NAME - DESCRIPTION ** * UserDataPtr - Pointer to user data ** structure pointer. ** Returns : ** --- - Pointer to the device data structure. ** =================================================================== */ LDD_SDHC1_TDeviceData* SDHC1_Init(LDD_TUserData *UserDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv; uint8_t Id; /* {FreeRTOS RTOS Adapter} Driver memory allocation: RTOS function call is defined by FreeRTOS RTOS Adapter property */ //DeviceDataPrv = (LDD_SDHC1_TDeviceData *)pvPortMalloc(sizeof(LDD_SDHC1_TDeviceData)); DeviceDataPrv = &SDHC1_stDeviceData; #if FreeRTOS_CHECK_MEMORY_ALLOCATION_ERRORS if (DeviceDataPrv == NULL) { return (NULL); } #endif /* Initialize the device data */ DeviceDataPrv->UserDataPtr = UserDataPtr; /* Store the user data pointer */ DeviceDataPrv->CardId = SDHC1_NO_CARD; /* No card will be selected */ DeviceDataPrv->State = LDD_SDHC_RESET; /* Cards will be reseted after host initialization */ DeviceDataPrv->HighVoltage = TRUE; /* Initially set bus voltage to high */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ for (Id = 0; Id < SDHC1_MAX_CARD_NUMBER; Id++) { DeviceDataPrv->Cards[Id].Initialized = FALSE; } DeviceDataPrv->TransferTable = (SDHC1_TTransferBufferDesc*) /* Align transfer buffer table memory according to hardware requirements */ (((uint32_t)DeviceDataPrv->TransferTableMem + SDHC1_TRANSFER_TABLE_ALIGN) & (uint32_t)(~(uint32_t)(SDHC1_TRANSFER_TABLE_ALIGN - 1U))); DeviceDataPrv->CSDPtr = (uint8_t*) /* Align CSD (card specific data) card register buffer according to hardware requirements */ (((uint32_t)DeviceDataPrv->CSDMem + SDHC1_TRANSFER_BUFFER_ALIGN) & (uint32_t)(~(uint32_t)(SDHC1_TRANSFER_BUFFER_ALIGN - 1U))); DeviceDataPrv->BusTestPtr = (uint8_t*) /* Align bus test buffer according to hardware requirements */ (((uint32_t)DeviceDataPrv->BusTestMem + SDHC1_TRANSFER_BUFFER_ALIGN) & (uint32_t)(~(uint32_t)(SDHC1_TRANSFER_BUFFER_ALIGN - 1U))); DeviceDataPrv->DataWidth = LDD_SDHC_CARD_DATA_WIDTH_4_BIT; /* Set default data width */ DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->SpeedMode = CPU_CLOCK_CONFIG_0; /* Set initial clock configuration */ DeviceDataPrv->EventMask = /* Initialize the event mask */ LDD_SDHC_ON_CARD_INSERTED | LDD_SDHC_ON_CARD_REMOVED | LDD_SDHC_ON_FINISHED |0U; DeviceDataPrv->EnabledMode = TRUE; /* Enable the device clock configuration */ /* SIM_SCGC3: SDHC=1 */ SIM_vSetReg32( SIM_SCGC3, SIM_SCGC3_SDHC_MASK ); //SIM_SCGC3 |= (uint32_t)0x00020000UL; /* initialise hardware ports */ SDHC_vHWInit(); /* Configure card detection and DMA mode */ /* SDHC_PROCTL: ??=0,??=0,??=0,??=0,??=0,WECRM=0,WECINS=0,WECINT=0,??=0,??=0,??=0,??=0,IABG=0,RWCTL=0,CREQ=0,SABGREQ=0,??=0,??=0,??=0,??=0,??=0,??=0,DMAS=2,CDSS=0,CDTL=0,EMODE=2,D3CD=0,DTW=0,LCTL=0 */ SDHC_PROCTL = (uint32_t)0x0220UL; /* Set DMA watermark levels */ /* SDHC_WML: ??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,WRWML=0x10,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,RDWML=0x10 */ SDHC_WML = (uint32_t)0x00100010UL; /* SDHC_VENDOR: ??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,INTSTVAL=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,EXBLKNU=0,EXTDMAEN=0 */ SDHC_VENDOR = (uint32_t)0x00UL; /* SIM_SOPT2: SDHCSRC=0 */ SIM_vClrReg32( SIM_SOPT2, SIM_SOPT2_SDHCSRC_MASK ); //SIM_SOPT2 &= (uint32_t)~0x30000000UL; /* Set bus clock frequency and data timeout */ /* SDHC_SYSCTL: ??=0,??=0,??=0,??=0,INITA=0,RSTD=0,RSTC=0,RSTA=0,??=0,??=0,??=0,??=0,DTOCV=7,SDCLKFS=0x40,DVS=0,SDCLKEN=0,PEREN=0,HCKEN=0,IPGEN=0 */ SDHC_SYSCTL = (uint32_t)0x00074000UL; while (!SDHC_PDD_IsSDClockStable(SDHC_BASE_PTR)) {} /* Wait for clock to stabilize */ /* Set interrupt priorities */ /* NVICIP80: PRI80=0x80 */ IRQ_vEnableIRQ(SDHC_IRQn, IRQ_enPRIO_15, NULL, NULL); //NVICIP80 = (uint8_t)0x80U; /* NVICISER2: SETENA|=0x00010000 */ //NVICISER2 |= (uint32_t)0x00010000UL; /* Allocate the interrupt vector */ /* {FreeRTOS RTOS Adapter} Set interrupt vector: IVT is static, ISR parameter is passed by the global variable */ INT_SDHC__BAREBOARD_RTOS_ISRPARAM = DeviceDataPrv; /* Enable and clear status flags */ /* SDHC_IRQSTAT: ??=1,??=1,??=1,DMAE=1,??=1,??=1,??=1,AC12E=1,??=1,DEBE=1,DCE=1,DTOE=1,CIE=1,CEBE=1,CCE=1,CTOE=1,??=1,??=1,??=1,??=1,??=1,??=1,??=1,CINT=1,CRM=1,CINS=1,BRR=1,BWR=1,DINT=1,BGE=1,TC=1,CC=1 */ SDHC_IRQSTAT = (uint32_t)0xFFFFFFFFUL; /* SDHC_IRQSIGEN: ??=0,??=0,??=0,DMAEIEN=0,??=0,??=0,??=0,AC12EIEN=0,??=0,DEBEIEN=0,DCEIEN=0,DTOEIEN=0,CIEIEN=0,CEBEIEN=0,CCEIEN=0,CTOEIEN=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,CINTIEN=0,CRMIEN=0,CINSIEN=0,BRRIEN=0,BWRIEN=0,DINTIEN=0,BGEIEN=0,TCIEN=1,CCIEN=1 */ //SDHC_IRQSIGEN = (uint32_t)0x03UL; /* SDHC_IRQSTATEN: ??=1,??=1,??=1,DMAESEN=1,??=1,??=1,??=1,AC12ESEN=1,??=1,DEBESEN=1,DCESEN=1,DTOESEN=1,CIESEN=1,CEBESEN=1,CCESEN=1,CTOESEN=1,??=1,??=1,??=1,??=1,??=1,??=1,??=1,CINTSEN=1,CRMSEN=0,CINSEN=0,BRRSEN=0,BWRSEN=0,DINTSEN=1,BGESEN=1,TCSEN=1,CCSEN=1 */ SDHC_IRQSTATEN = (uint32_t)0xFFFFFF0FUL; /* Power up cards */ SDHC_PDD_InitCard(SDHC_BASE_PTR); /* SDHC_IRQSIGEN: ??=0,??=0,??=0,DMAEIEN=0,??=0,??=0,??=0,AC12EIEN=0,??=0,DEBEIEN=0,DCEIEN=0,DTOEIEN=0,CIEIEN=0,CEBEIEN=0,CCEIEN=0,CTOEIEN=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,CINTIEN=0,CRMIEN=0,CINSIEN=0,BRRIEN=0,BWRIEN=0,DINTIEN=0,BGEIEN=0,TCIEN=1,CCIEN=1 */ SDHC_IRQSIGEN = (uint32_t)0x03UL; while (!SDHC_PDD_IsCardInitComplete(SDHC_BASE_PTR)) {} /* Set transfer timeout to 7 */ SDHC_SYSCTL |= SDHC_SYSCTL_DTOCV(SDHCHA_nTransferTimeoutExponent); /* Reset cards */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD0_GO_IDLE_STATE, SDHC_PDD_NO_RESPONSE); DeviceDataPrv->Enabled = TRUE; /* Enable the component */ //MATTHEW //DeviceDataPrv->State = LDD_SDHC_IDLE; /* Registration of the device structure */ PE_LDD_RegisterDeviceStructure(PE_LDD_COMPONENT_SDHC1_ID,DeviceDataPrv); return DeviceDataPrv; } /* ** =================================================================== ** Method : SDHC1_Deinit (component SDHC_LDD) ** ** Description : ** Deinitializes the device. Switches off the device, frees the ** device data structure memory, interrupt vectors, etc. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : Nothing ** =================================================================== */ void SDHC1_Deinit(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; (void)DeviceDataPrv; /* Suppress unused variable warning if needed */ /* Disable interrupts */ SDHC_IRQSIGEN = 0x00; SDHC_IRQSTATEN = 0x00; /* {FreeRTOS RTOS Adapter} Restore interrupt vector: IVT is static, no code is generated */ /* Disable the device clock */ SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, PDD_DISABLE); /* Reset the device */ SDHC_PDD_ResetDevice(SDHC_BASE_PTR); /* Unregistration of the device structure */ //PE_LDD_UnregisterDeviceStructure(PE_LDD_COMPONENT_SDHC1_ID); /* Deallocation of the internal device data structure */ /* {FreeRTOS RTOS Adapter} Driver memory deallocation: RTOS function call is defined by FreeRTOS RTOS Adapter property */ //vPortFree(DeviceDataPrv); /* SIM_SCGC3: SDHC=0 */ SIM_vClrReg32( SIM_SCGC3, SIM_SCGC3_SDHC_MASK ); //SIM_SCGC3 &= (uint32_t)~0x00020000UL; } /* ** =================================================================== ** Method : SDHC1_Enable (component SDHC_LDD) ** ** Description : ** Enables the component. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - OK ** =================================================================== */ LDD_TError SDHC1_Enable(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; DeviceDataPrv->Enabled = TRUE; /* Enable the component */ return ERR_OK; } /* ** =================================================================== ** Method : SDHC1_Disable (component SDHC_LDD) ** ** Description : ** Disables the component. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - OK ** =================================================================== */ LDD_TError SDHC1_Disable(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; DeviceDataPrv->Enabled = FALSE; /* Disable the component */ return ERR_OK; } /* ** =================================================================== ** Method : SDHC1_SetEventMask (component SDHC_LDD) ** ** Description : ** Sets event mask. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** EventMask - Event mask ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - OK ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_PARAM_MASK - Invalid mask (one or more ** event is unmaskable) ** =================================================================== */ LDD_TError SDHC1_SetEventMask(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_TEventMask EventMask) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if ((EventMask & (LDD_TEventMask)(~(LDD_TEventMask)( LDD_SDHC_ON_CARD_INSERTED | LDD_SDHC_ON_CARD_REMOVED | LDD_SDHC_ON_FINISHED))) != 0U) { return ERR_PARAM_MASK; } DeviceDataPrv->EventMask = EventMask; return ERR_OK; } /* ** =================================================================== ** Method : SDHC1_GetEventMask (component SDHC_LDD) ** ** Description : ** Returns event mask. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - Current event mask. ** =================================================================== */ LDD_TEventMask SDHC1_GetEventMask(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; return DeviceDataPrv->EventMask; } /* ** =================================================================== ** Method : SDHC1_DetectCards (component SDHC_LDD) ** ** Description : ** Detects newly inserted and removed cards. The OnCardInserted ** event will be called for every new card and the ** OnCardRemoved event will be called for every removed card. ** This method should be used when card detection pin is not ** available. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Card detection started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_DetectCards(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->State = LDD_SDHC_VOLTAGE_VALIDATION; DeviceDataPrv->Substate = SDHC1_VV_START; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_SelectCard (component SDHC_LDD) ** ** Description : ** Selects a card by its identification number. All further ** operations will apply to this card. Special card ** identification number _NO_CARD will deselect the ** active card. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Id - Card identification number passed by the ** OnCardInserted event parameter. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Card selection started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** ERR_PARAM_ID - Invalid card ID ** =================================================================== */ LDD_TError SDHC1_SelectCard(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint8_t Id) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ uint32_t Argument; /* Card command argument */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (Id != SDHC1_NO_CARD) { if (!DeviceDataPrv->Cards[Id].Initialized) { return ERR_PARAM_ID; } } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ if (Id != DeviceDataPrv->CardId) { /* Reselecting already selected card is an illegal card operation */ /* Change card selection */ DeviceDataPrv->CardId = Id; if (Id != SDHC1_NO_CARD) { /* Select card */ DeviceDataPrv->CardType = DeviceDataPrv->Cards[Id].Type; /* Store currently selected card's type */ Argument = SDHC1_CMD_ARG_RCA((uint32_t)DeviceDataPrv->Cards[Id].RCA); /* Select card by its RCA */ } else { /* Unselect card */ Argument = 0U; /* Zero is a special RCA (relative card address) for deselecting all cards */ } DeviceDataPrv->State = LDD_SDHC_CARD_SELECTION; /* Send card selection command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, Argument); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD7_SELECT_CARD, SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); } } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_GetCardInfo (component SDHC_LDD) ** ** Description : ** Returns card information about the selected card. Method ** call starts the card information retrieval process. After ** the card information has been received, the OnFinished event ** is called (the component state changes to idle) and the ** information is stored in the specified variable. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** * InfoPtr - Pointer to a variable, where card ** information will be stored. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Card information retrieval started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_GetCardInfo(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_SDHC_TCardInfo *InfoPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->CardInfoPtr = InfoPtr; /* Store a pointer to the card info variable for later card info update */ /* Start card information retrieval */ DeviceDataPrv->State = LDD_SDHC_CARD_INFO_RETRIEVAL; DeviceDataPrv->Substate = SDHC1_CIR_START; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_TransferBlocks (component SDHC_LDD) ** ** Description : ** Initiates a data block transfer on the selected card. ** Transfer can be a read or write operation depending on the ** transfer operation parameter. Read operation reads data ** blocks from the specified address on a memory card and ** stores their content into buffers specified by the buffer ** descriptor list. Write operation writes data blocks ** specified by the buffer descriptor list to a card memory on ** the specified address. Data blocks should be the same size ** and the block size should be supported by the memory card. ** Buffer addresses should be aligned to a hardware specific ** address boundary. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Operation - Transfer operation ** Address - Card memory address. Byte address ** in case of standard capacity memory cards, ** 512 byte block number in case of high ** capacity memory cards. ** * BufferDescListPtr - Pointer to ** data block buffer descriptor list. ** BufferDescCount - Data block buffer ** descriptor list item count ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Transfer started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** ERR_PARAM_ADDRESS - Invalid buffer address ** (one or more buffer address from the list ** of buffer descriptors is misaligned) ** ERR_PARAM_BUFFER_COUNT - Buffer count ** exceeds the internal buffer table size ** =================================================================== */ LDD_TError SDHC1_TransferBlocks(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_SDHC_TTransferOperation Operation, uint32_t Address, LDD_SDHC_TBufferDesc *BufferDescListPtr, uint16_t BufferDescCount) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ uint32_t Index; /* Transfer table index */ bool Finished; /* Indicates whether transfer has finished */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if ((BufferDescCount == 0U) || (BufferDescCount > SDHC1_BUFFER_TABLE_SIZE)) { return ERR_PARAM_BUFFER_COUNT; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->TransferBlockSize = BufferDescListPtr[0].Size; /* Determine block size from first buffer size */ DeviceDataPrv->TransferBlockCount = BufferDescCount; /* Determine block count from buffer count */ /* Fill in the transfer descriptors table */ for (Index = 0U; Index < BufferDescCount; Index++) { DeviceDataPrv->TransferTable[Index].Attributes = /* Mark each transfer buffer descriptor as ready for transfer */ SDHC1_ADMA2_VALID | SDHC1_ADMA2_ATTR_ACT_TRAN; DeviceDataPrv->TransferTable[Index].Length = BufferDescListPtr[Index].Size; /* Copy transfer buffer size */ DeviceDataPrv->TransferTable[Index].Address = (uint32_t)BufferDescListPtr[Index].DataPtr; /* Copy transfer buffer address */ } DeviceDataPrv->TransferTable[BufferDescCount - 1U].Attributes |= SDHC1_ADMA2_END; /* Mark the last descriptor as last */ DeviceDataPrv->TransferOperation = Operation; /* Store the transfer operation type */ DeviceDataPrv->Address = Address; /* Store the source/destination address for the read/write operation */ /* Start data transfer */ DeviceDataPrv->State = LDD_SDHC_TRANSFER; DeviceDataPrv->CmdState = SDHC1_CMD_DATA_LEN; Finished = Transfer(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the transfer state */ (void)Finished; /* The return value is not used */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_EraseBlocks (component SDHC_LDD) ** ** Description : ** Initiates a memory area erasion on the selected card. Erase ** operation erases a memory area of the specified size from ** the specified address on a memory card. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Address - Address of the beginning of the ** erased area. Byte address in case of ** standard capacity memory card and 512 byte ** block number in case of high capacity ** memory card. ** Size - Size of the erased area. Byte size in ** case of standard capacity memory card and ** 512 byte blocks count in case of high ** capacity memory card. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Erasing started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_EraseBlocks(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Address, uint32_t Size) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ bool Finished; /* Indicates whether erasion has finished */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->ErasionStart = Address; /* Store the erasion start address */ DeviceDataPrv->ErasionEnd = (Address + Size) - 1U; /* Count the erasion end address */ /* Start data erasion */ DeviceDataPrv->State = LDD_SDHC_ERASION; DeviceDataPrv->Substate = SDHC1_E_SET_START; Finished = Erasion(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the erasion state */ (void)Finished; /* The return value is not used */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_SetDataWidth (component SDHC_LDD) ** ** Description : ** Initiates a data width setup. The card has to support the ** specified data width. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Width - Data bus bit count. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Setup started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** ERR_PARAM_WIDTH - Invalid data width ** =================================================================== */ LDD_TError SDHC1_SetDataWidth(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint8_t Width) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ bool Finished; /* Indicates whether bus width selection has finished */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } /* Check allowed data width values */ if (DeviceDataPrv->CardType == LDD_SDHC_MMC) { /* Data widths generaly supported by MMC cards */ if ((Width != LDD_SDHC_CARD_DATA_WIDTH_1_BIT) && (Width != LDD_SDHC_CARD_DATA_WIDTH_4_BIT) && (Width != LDD_SDHC_CARD_DATA_WIDTH_8_BIT)) { return ERR_PARAM_WIDTH; } } else { /* Data widths generaly supported by SD cards */ if ((Width != LDD_SDHC_CARD_DATA_WIDTH_1_BIT) && (Width != LDD_SDHC_CARD_DATA_WIDTH_4_BIT)) { return ERR_PARAM_WIDTH; } } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->DataWidth = Width; /* Store the new data width */ /* Start data width selection */ DeviceDataPrv->State = LDD_SDHC_DATA_WIDTH_SELECTION; DeviceDataPrv->CmdState = SDHC1_CMD_START; Finished = DataWidthSelection(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the data width selection state */ (void)Finished; /* The return value is not used */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_SelectBusClock (component SDHC_LDD) ** ** Description : ** Initiates a SD bus clock frequency change. If the frequency ** is for high speed mode, initiates a high speed mode setup on ** the selected card. The card has to support the specified bus ** clock frequency. This method is enabled only if a list of ** bus clock frequencies is specified. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Frequency - Bus clock frequency identifier. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Setup started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_SelectBusClock(LDD_SDHC1_TDeviceData *DeviceDataPtr, SDHC1_TBusClock Frequency) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ static const uint32_t BusClockList[] = { /* Selectable bus clock frequencies in hertz specified by the timing dialog property */ 390625u, 12500000u, 25000000u }; /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->Frequency = Frequency; /* Store the new bus clock frequency ID */ /* Start bus clock selection */ DeviceDataPrv->State = LDD_SDHC_BUS_CLOCK_SELECTION; if (((DeviceDataPrv->Cards[Id].Type == LDD_SDHC_SD) && (BusClockList[Frequency] >= 25000000U)) || ((DeviceDataPrv->Cards[Id].Type == LDD_SDHC_MMC) && (BusClockList[Frequency] >= 20000000U))) { /* Card needs speed mode switch */ DeviceDataPrv->CmdState = SDHC1_CMD_START; } else { /* Card doesn't need speed mode switch */ DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; } if (BusClockSelection(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE)) { DeviceDataPrv->State = LDD_SDHC_IDLE; if (DeviceDataPrv->EventMask & LDD_SDHC_ON_FINISHED) { SDHC1_OnFinished(DeviceDataPrv->UserDataPtr); /* Call the user event */ } } } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_SetVoltage (component SDHC_LDD) ** ** Description : ** Initiates a bus voltage change. The card has to support the ** specified voltage. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Voltage - Voltage identifier. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Setup started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_SetVoltage(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_SDHC_TVoltage Voltage) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ uint8_t Id; /* Card ID storage */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ /* Start a new voltage validation */ DeviceDataPrv->State = LDD_SDHC_VOLTAGE_VALIDATION; DeviceDataPrv->Substate = SDHC1_VV_START; DeviceDataPrv->HighVoltage = (Voltage == LDD_SDHC_HIGH_VOLTAGE) ? TRUE : FALSE; /* Store the new voltage configuration */ /* Remove cards from the device data structure */ for (Id = 0U; Id < SDHC1_MAX_CARD_NUMBER; Id++) { if (DeviceDataPrv->Cards[Id].Initialized) { DeviceDataPrv->Cards[Id].Initialized = FALSE; if (DeviceDataPrv->EventMask & LDD_SDHC_ON_CARD_REMOVED) { SDHC1_OnCardRemoved(DeviceDataPrv->UserDataPtr, Id); /* Call the user event */ } } } DeviceDataPrv->CardId = SDHC1_NO_CARD; /* No card will be selected */ /* Send reset command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD0_GO_IDLE_STATE, SDHC_PDD_NO_RESPONSE); } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_SetWriteProtection (component SDHC_LDD) ** ** Description : ** Initiates a write protection setup for the selected card. If ** the write protection type is LDD_SDHC_GROUP, write ** protection will be set for the addressed write protection ** group. Write protection group size is contained within the ** card information structure. If the write protection type is ** LDD_SDHC_CARD, write protection will be set for the whole ** card and the address parameter will be ignored. Only a whole ** card write protection clear can remove this protection. The ** card has to support write protection. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Type - Write protection type. ** Address - Address of the write protection ** group, if the write protection type is ** LDD_SDHC_GROUP. Byte address in case of ** standard capacity memory card and 512 byte ** block number in case of high capacity ** memory card. ** Protected - Indicates whether the ** addressed write protection group or card ** should be write protected or not. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Setup started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_SetWriteProtection(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_SDHC_TWriteProtectType Type, uint32_t Address, bool Protected) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ bool Finished; /* Indicates whether write protection setup has finished */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->WriteProtType = Type; /* Store the write protection type to be set */ DeviceDataPrv->Address = Address; /* Store the write protection group address */ DeviceDataPrv->WriteProtFlag = Protected; /* Store whether to clear or set write protection */ /* Start write protection setup */ DeviceDataPrv->State = LDD_SDHC_WRITE_PROTECTION_SETUP; if (Type == LDD_SDHC_GROUP) { /* Change sector group write protection */ DeviceDataPrv->CmdState = SDHC1_CMD_START; } else { /* Change the whole card write protection */ if (Protected) { DeviceDataPrv->Cards[Id].CSD[0] |= SDHC1_R2_TMP_WRITE_PROTECT_MASK; /* Set the temporary write protection bit in the CSD (card specific data) register */ } else { DeviceDataPrv->Cards[Id].CSD[0] &= (uint32_t)(~(uint32_t)SDHC1_R2_TMP_WRITE_PROTECT_MASK); /* Clear the temporary write protection bit in the CSD (card specific data) register */ } DeviceDataPrv->CmdState = SDHC1_CMD_START; } Finished = WriteProtectionSetup(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the write protection setup state */ (void)Finished; /* The return value is not used */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_GetWriteProtection (component SDHC_LDD) ** ** Description : ** Initiates a write protection mask retrieval for the selected ** card. After the mask has been received, the OnFinished event ** is called and the mask is stored in the specified variable. ** The returned mask contains a bit mask of write protected ** write protection groups starting at the specified address. ** The least significant bit represents the status of the first ** write protection group. Bits of write protection groups out ** of range are cleared. The card has to support write ** protection. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Address - Address of the write protection ** group. Byte address in case of standard ** capacity memory card and 512 byte block ** number in case of high capacity memory card. ** * MaskPtr - Pointer to a variable, where the ** write protection groups status mask will be ** stored. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Write protection mask retrieval ** started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_BUSY - Another card operation is in ** progress ** =================================================================== */ LDD_TError SDHC1_GetWriteProtection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Address, uint32_t *MaskPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ bool Finished; /* Indicates whether write protection retrieval has finished */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State == LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = FALSE; /* Clear the cancel flag */ DeviceDataPrv->LastError = LDD_SDHC_ERR_OK; /* Clear the error code */ DeviceDataPrv->LastErrorAddress = 0U; /* Clear the error address */ DeviceDataPrv->Address = Address; /* Store the write protection group address */ DeviceDataPrv->WriteProtMaskPtr = MaskPtr; /* Store a pointer to the write protection mask variable for later update */ /* Start write protection retrieval */ DeviceDataPrv->State = LDD_SDHC_WRITE_PROTECTION_RETRIEVAL; DeviceDataPrv->CmdState = SDHC1_CMD_START; Finished = WriteProtectionRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the write protection retrieval state */ (void)Finished; /* The return value is not used */ } else { Result = ERR_BUSY; /* Another operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_CancelOperation (component SDHC_LDD) ** ** Description : ** Initiates a cancelation of the ongoing operation. The ** OnFinished event will be called for the stopped operation. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - Operation cancelation started ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_NOTAVAIL - No operation is in progress ** =================================================================== */ LDD_TError SDHC1_CancelOperation(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TError Result = ERR_OK; /* Error code storage */ /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State != LDD_SDHC_IDLE) { DeviceDataPrv->Cancel = TRUE; /* Set the cancel flag */ if (DeviceDataPrv->CmdState == SDHC1_CMD_DATA) { /* Send stop transmission command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD12_STOP_TRANSMISSION, SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); } } else { Result = ERR_NOTAVAIL; /* No operation is in progress */ } return Result; } /* ** =================================================================== ** Method : SDHC1_GetStatus (component SDHC_LDD) ** ** Description : ** Returns the current component status, specifying the ongoing ** operation. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** Returns : ** --- - Component status. ** =================================================================== */ LDD_SDHC_TStatus SDHC1_GetStatus(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; return DeviceDataPrv->State; } /* ** =================================================================== ** Method : SDHC1_GetError (component SDHC_LDD) ** ** Description : ** Returns the last error code and the memory address where the ** error occurred (if applicable). ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to the device ** data structure. ** * AddressPtr - Pointer to a variable, where ** the error address will be stored. ** Returns : ** --- - The last error code. ** =================================================================== */ LDD_SDHC_TError SDHC1_GetError(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t *AddressPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_SDHC_TError Error; /* Error code storage */ Error = DeviceDataPrv->LastError; if (AddressPtr) { *AddressPtr = DeviceDataPrv->LastErrorAddress; } return Error; } /* ** =================================================================== ** Method : SDHC1_ConnectPin (component SDHC_LDD) ** ** Description : ** This method reconnects the requested pins associated with ** the selected peripheral in the component. This method is ** only available for CPU derivatives and peripherals that ** support the runtime pin sharing with other internal on-chip ** peripherals. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Pointer to device data ** structure. ** PinMask - Mask for the requested pins. The ** peripheral pins are reconnected according ** to this mask. ** Returns : ** --- - ** Error code, possible values: ** ERR_OK - OK ** ERR_PARAM_MASK - Invalid pin mask ** =================================================================== */ LDD_TError SDHC1_ConnectPin(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_TPinMask PinMask) { // (void)DeviceDataPtr; /* Parameter is not used, suppress unused argument warning */ // if (PinMask & (LDD_TPinMask)(~(LDD_TPinMask)( // LDD_SDHC_CLK_PIN | // LDD_SDHC_CMD_PIN | // LDD_SDHC_DAT0_PIN | // LDD_SDHC_DAT1_PIN | // LDD_SDHC_DAT2_PIN | // LDD_SDHC_DAT3_PIN |0U))) { // return ERR_PARAM_MASK; // } // if (PinMask & LDD_SDHC_CLK_PIN) { // clrSetReg32Bits(PORTE_PCR2, 0x01000300U, 0x0400U); /* MUX=0x04U */ // } // if (PinMask & LDD_SDHC_CMD_PIN) { // clrSetReg32Bits(PORTE_PCR3, 0x01000300U, 0x0400U); /* MUX=0x04U */ // PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, SDHC1_PIN_CMD_PORT_INDEX, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, SDHC1_PIN_CMD_PORT_INDEX, PORT_PDD_PULL_ENABLE); // PORT_PDD_SetPinDriveStrength(PORTE_BASE_PTR, SDHC1_PIN_CMD_PORT_INDEX, PORT_PDD_DRIVE_STRENGTH_HIGH); // } // if (PinMask & LDD_SDHC_DAT0_PIN) { // clrSetReg32Bits(PORTE_PCR1, 0x01000300U, 0x0400U); /* MUX=0x04U */ // PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, SDHC1_PIN_DAT0_PORT_INDEX, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, SDHC1_PIN_DAT0_PORT_INDEX, PORT_PDD_PULL_ENABLE); // PORT_PDD_SetPinDriveStrength(PORTE_BASE_PTR, SDHC1_PIN_DAT0_PORT_INDEX, PORT_PDD_DRIVE_STRENGTH_HIGH); // } // if (PinMask & LDD_SDHC_DAT1_PIN) { // clrSetReg32Bits(PORTE_PCR0, 0x01000300U, 0x0400U); /* MUX=0x04U */ // PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, SDHC1_PIN_DAT1_PORT_INDEX, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, SDHC1_PIN_DAT1_PORT_INDEX, PORT_PDD_PULL_ENABLE); // PORT_PDD_SetPinDriveStrength(PORTE_BASE_PTR, SDHC1_PIN_DAT1_PORT_INDEX, PORT_PDD_DRIVE_STRENGTH_HIGH); // } // if (PinMask & LDD_SDHC_DAT2_PIN) { // clrSetReg32Bits(PORTE_PCR5, 0x01000300U, 0x0400U); /* MUX=0x04U */ // PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, SDHC1_PIN_DAT2_PORT_INDEX, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, SDHC1_PIN_DAT2_PORT_INDEX, PORT_PDD_PULL_ENABLE); // PORT_PDD_SetPinDriveStrength(PORTE_BASE_PTR, SDHC1_PIN_DAT2_PORT_INDEX, PORT_PDD_DRIVE_STRENGTH_HIGH); // } // if (PinMask & LDD_SDHC_DAT3_PIN) { // clrSetReg32Bits(PORTE_PCR4, 0x01000300U, 0x0400U); /* MUX=0x04U */ // PORT_PDD_SetPinPullSelect(PORTE_BASE_PTR, SDHC1_PIN_DAT3_PORT_INDEX, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTE_BASE_PTR, SDHC1_PIN_DAT3_PORT_INDEX, PORT_PDD_PULL_ENABLE); // PORT_PDD_SetPinDriveStrength(PORTE_BASE_PTR, SDHC1_PIN_DAT3_PORT_INDEX, PORT_PDD_DRIVE_STRENGTH_HIGH); // } return ERR_OK; } /* ** =================================================================== ** Method : SDHC1_SetOperationMode (component SDHC_LDD) ** ** Description : ** This method requests to change the component's operation ** mode. Upon a request to change the operation mode, the ** component will finish a pending job first and then notify a ** caller that an operation mode has been changed. When no job ** is pending (ERR_OK), the component changes an operation mode ** immediately and notify a caller about this change. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Device data structure ** pointer returned by Init method. ** OperationMode - Requested driver ** operation mode. ** ModeChangeCallback - Callback to ** notify the upper layer once a mode has been ** changed. ** * ModeChangeCallbackParamPtr ** - Pointer to callback parameter to notify ** the upper layer once a mode has been ** changed. ** Returns : ** --- - Error code, possible codes: ** ERR_OK - OK ** ERR_DISABLED - The component is disabled ** ERR_SPEED - The component does not work in ** the active clock configuration ** ERR_PARAM_MODE - Invalid operation mode ** ERR_BUSY - A job is pending ** =================================================================== */ LDD_TError SDHC1_SetOperationMode(LDD_SDHC1_TDeviceData *DeviceDataPtr, LDD_TDriverOperationMode OperationMode, LDD_TCallback ModeChangeCallback, LDD_TCallbackParam *ModeChangeCallbackParamPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; /* Device state test - this test can be disabled by setting the "Ignore enable test" property to the "yes" value in the "Configuration inspector" */ if (!DeviceDataPrv->Enabled) { return ERR_DISABLED; } if (DeviceDataPrv->State != LDD_SDHC_IDLE) { return ERR_BUSY; } switch (OperationMode) { case DOM_RUN: /* SIM_SCGC3: SDHC=1 */ SIM_vSetReg32( SIM_SCGC3, SIM_SCGC3_SDHC_MASK ); //SIM_SCGC3 |= (uint32_t)0x00020000UL; SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, PDD_ENABLE); break; case DOM_WAIT: case DOM_SLEEP: SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, PDD_DISABLE); break; case DOM_STOP: SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, PDD_DISABLE); /* SIM_SCGC3: SDHC=0 */ SIM_vClrReg32( SIM_SCGC3, SIM_SCGC3_SDHC_MASK ); //SIM_SCGC3 &= (uint32_t)~0x00020000UL; break; default: return ERR_PARAM_MODE; /* Invalid operation mode parameter */ } if (ModeChangeCallback != NULL) { ModeChangeCallback(ModeChangeCallbackParamPtr); } return ERR_OK; } /* ** =================================================================== ** Method : SDHC1_GetDriverState (component SDHC_LDD) ** ** Description : ** This method returns the current driver status. ** Parameters : ** NAME - DESCRIPTION ** * DeviceDataPtr - Device data structure ** pointer returned by Init method. ** Returns : ** --- - ** The current driver status mask. The ** following status masks defined in PE_LDD.h ** can be used to check the current driver ** status: ** PE_LDD_DRIVER_DISABLED_IN_CLOCK_CONFIGURATION - ** Driver is disabled in the current speed ** mode ** PE_LDD_DRIVER_DISABLED_BY_USER - Driver is ** disabled by the user ** PE_LDD_DRIVER_BUSY - Driver is in the BUSY ** state ** =================================================================== */ LDD_TDriverState SDHC1_GetDriverState(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_TDriverState DriverState = 0U; /* Driver state storage */ if (!DeviceDataPrv->EnabledMode) { DriverState |= LDD_DRIVER_DISABLED_IN_CLOCK_CONFIGURATION; } if (!DeviceDataPrv->Enabled) { DriverState |= LDD_DRIVER_DISABLED_BY_USER; } if (DeviceDataPrv->State != LDD_SDHC_IDLE) { DriverState |= LDD_DRIVER_BUSY; } return DriverState; } /* ** =================================================================== ** Method : SDHC1_VoltageValidation (component SDHC_LDD) ** ** Description : ** Voltage validation state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void VoltageValidation(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ switch (DeviceDataPrv->Substate) { case SDHC1_VV_START: DeviceDataPrv->CardsVoltages = 0; /* Start with SD card version 2.0 or later interface conditions check */ DeviceDataPrv->Substate = SDHC1_VV_SDHC_CHECK; DeviceDataPrv->CmdState = SDHC1_CMD_START; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ break; case SDHC1_VV_SDHC_CHECK: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Send interface conditions request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, ((DeviceDataPrv->HighVoltage == TRUE) ? /* Propose bus voltage configuration */ SDHC1_IF_COND_HIGH_VOLTAGE_MASK : SDHC1_IF_COND_LOW_VOLTAGE_MASK) | SDHC1_IF_COND_CHECK_PATTERN); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD8_SEND_EXT_CSD, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->HighCapacity = TRUE; /* Card is an SD card version 2.0 or later (possibly high capacity) */ } else if (Error == LDD_SDHC_ERR_TIMEOUT) { DeviceDataPrv->HighCapacity = FALSE; /* Card is a normal SD or other type of card */ } else { DeviceDataPrv->LastError = Error; } /* Continue with SD card interface conditions check */ DeviceDataPrv->Substate = SDHC1_VV_SD_CHECK; DeviceDataPrv->CmdState = SDHC1_CMD_START; DeviceDataPrv->RetryCounter = SDHC1_VOLT_VALID_RETRY_COUNT; /* Limit the interface conditions request number */ VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ break; default: break; } break; case SDHC1_VV_SD_CHECK: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_ACMD; /* Start application specific command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD55_APP_CMD, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_ACMD: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) || (Error == LDD_SDHC_ERR_INTERNAL_FAILURE)) { DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Send OCR (operation conditions register) request */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, ((DeviceDataPrv->HighCapacity == TRUE) ? SDHC1_OCR_HIGH_CAPACITY_MASK : 0U) | ((DeviceDataPrv->HighVoltage == TRUE) ? /* Propose bus voltage configuration */ SDHC1_OCR_HIGH_VOLTAGE_MASK : SDHC1_OCR_LOW_VOLTAGE_MASK)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_ACMD41_SD_APP_OP_COND, SDHC_PDD_RESPONSE_LENGTH_48); } else { if (Error == LDD_SDHC_ERR_COMMAND_CRC) { DeviceDataPrv->LastError = Error; } /* No more SD card, check MMC cards */ DeviceDataPrv->Substate = SDHC1_VV_MMC_CHECK; DeviceDataPrv->CmdState = SDHC1_CMD_START; DeviceDataPrv->RetryCounter = SDHC1_VOLT_VALID_RETRY_COUNT; /* Limit the interface conditions request number */ VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R3_OCR_IS_CARD_POWER_UP(Response)) { /* Card is powered up, start the registration */ DeviceDataPrv->CardType = LDD_SDHC_SD; DeviceDataPrv->CardsVoltages |= *Response & /* Save card voltage capabilities */ (SDHC1_OCR_HIGH_VOLTAGE_MASK | SDHC1_OCR_LOW_VOLTAGE_MASK); DeviceDataPrv->HighCapacity = (SDHC1_R3_OCR_IS_CARD_HIGH_CAPACITY(Response)) ? TRUE : FALSE; DeviceDataPrv->State = LDD_SDHC_CARD_REGISTRATION; DeviceDataPrv->Substate = SDHC1_CR_START; CardRegistration(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card registration state */ } else if (DeviceDataPrv->RetryCounter--) { /* Card is not powered up yet, resend request */ DeviceDataPrv->CmdState = SDHC1_CMD_START; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } else { /* Power up reached timeout, check MMC cards */ DeviceDataPrv->LastError = LDD_SDHC_ERR_TIMEOUT; DeviceDataPrv->Substate = SDHC1_VV_MMC_CHECK; DeviceDataPrv->CmdState = SDHC1_CMD_START; } } else { if (Error == LDD_SDHC_ERR_COMMAND_CRC) { DeviceDataPrv->LastError = Error; } /* No response for ACMD41, check MMC cards */ DeviceDataPrv->Substate = SDHC1_VV_MMC_CHECK; DeviceDataPrv->CmdState = SDHC1_CMD_START; } if (DeviceDataPrv->Substate == SDHC1_VV_MMC_CHECK) { DeviceDataPrv->RetryCounter = SDHC1_VOLT_VALID_RETRY_COUNT; /* Limit the interface conditions request number */ /* Send reset command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD0_GO_IDLE_STATE, SDHC_PDD_NO_RESPONSE); } break; default: break; } break; case SDHC1_VV_MMC_CHECK: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Send OCR (operation conditions register) request */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, ((DeviceDataPrv->HighVoltage == TRUE) ? /* Propose bus voltage configuration */ SDHC1_OCR_HIGH_VOLTAGE_MASK : SDHC1_OCR_LOW_VOLTAGE_MASK) | SDHC1_OCR_HIGH_CAPACITY_MASK); /* Indicate high capacity card support by the host */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD1_SEND_OP_COND, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R3_OCR_IS_CARD_POWER_UP(Response)) { /* Card is powered up, start the registration */ DeviceDataPrv->CardType = LDD_SDHC_MMC; DeviceDataPrv->CardsVoltages |= *Response & /* Save card voltage capabilities */ (SDHC1_OCR_HIGH_VOLTAGE_MASK | SDHC1_OCR_LOW_VOLTAGE_MASK); DeviceDataPrv->HighCapacity = (SDHC1_R3_OCR_IS_CARD_HIGH_CAPACITY(Response)) ? TRUE : FALSE; DeviceDataPrv->State = LDD_SDHC_CARD_REGISTRATION; DeviceDataPrv->Substate = SDHC1_CR_START; CardRegistration(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card registration state */ } else if (DeviceDataPrv->RetryCounter--) { /* Card is not powered up yet, resend request */ DeviceDataPrv->CmdState = SDHC1_CMD_START; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } else { /* Power up reached timeout, finish */ DeviceDataPrv->LastError = LDD_SDHC_ERR_TIMEOUT; DeviceDataPrv->Substate = SDHC1_VV_FINISH; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } } else { if (Error == LDD_SDHC_ERR_COMMAND_CRC) { DeviceDataPrv->LastError = Error; } /* No more MMC card, finish */ DeviceDataPrv->Substate = SDHC1_VV_FINISH; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ } break; default: break; } break; case SDHC1_VV_FINISH: DeviceDataPrv->State = LDD_SDHC_IDLE; if (DeviceDataPrv->EventMask & LDD_SDHC_ON_FINISHED) { SDHC1_OnFinished(DeviceDataPrv->UserDataPtr); /* Call the user event */ } break; default: break; } } /* ** =================================================================== ** Method : CardRegistration (component SDHC_LDD) ** ** Description : ** Card registration state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void CardRegistration(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint8_t Id; /* Card ID storage */ uint32_t Index; /* Array index */ switch (DeviceDataPrv->Substate) { case SDHC1_CR_START: switch (DeviceDataPrv->CardType) { case LDD_SDHC_SD: case LDD_SDHC_MMC: /* Send CID register request */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD2_ALL_SEND_CID, SDHC_PDD_RESPONSE_LENGTH_136); DeviceDataPrv->Substate = SDHC1_CR_GET_CID; break; default: break; } break; case SDHC1_CR_GET_CID: switch (DeviceDataPrv->CardType) { case LDD_SDHC_SD: case LDD_SDHC_MMC: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { /* Assign a free data structure to the card */ for (Id = 0U; Id < SDHC1_MAX_CARD_NUMBER; Id++) { if (!DeviceDataPrv->Cards[Id].Initialized) { /* Initialize the data structure */ DeviceDataPrv->NewCardId = Id; /* Assign a component related ID to the card */ DeviceDataPrv->Cards[Id].Initialized = TRUE; /* Mark the data structure as used */ DeviceDataPrv->Cards[Id].Type = DeviceDataPrv->CardType; DeviceDataPrv->Cards[Id].CID[0] = Response[0]; /* Store the received card ID */ DeviceDataPrv->Cards[Id].CID[1] = Response[1]; DeviceDataPrv->Cards[Id].CID[2] = Response[2]; DeviceDataPrv->Cards[Id].CID[3] = Response[3]; for (Index = 0U; Index < sizeof(DeviceDataPrv->Cards[Id].Block); Index++) { DeviceDataPrv->Cards[Id].Block[Index] = 0U; /* Clear the card info block */ } DeviceDataPrv->Cards[Id].HighCapacity = DeviceDataPrv->HighCapacity; DeviceDataPrv->Cards[Id].DataWidths = LDD_SDHC_CARD_DATA_WIDTH_1_BIT; /* Initialize supported data widths */ if (DeviceDataPrv->CardType == LDD_SDHC_SD) { /* Request an RCA (relative card address) from the card */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); } else { /* Create a new RCA (relative card address) */ DeviceDataPrv->Cards[Id].RCA = (uint16_t)((uint16_t)Id + 2U); /* MMC RCAs must start from 2 */ /* Send the RCA (relative card address) to the card */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, (uint32_t)((uint32_t)Id + 2U) << 16); } SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD3_SET_RELATIVE_ADDR, SDHC_PDD_RESPONSE_LENGTH_48); DeviceDataPrv->Substate = SDHC1_CR_GET_RCA; } } } else { if (Error != LDD_SDHC_ERR_TIMEOUT) { DeviceDataPrv->LastError = Error; } /* No more card for registration */ DeviceDataPrv->Substate = SDHC1_CR_FINISH; CardRegistration(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card registration state */ } break; default: break; } break; case SDHC1_CR_GET_RCA: switch (DeviceDataPrv->CardType) { case LDD_SDHC_SD: case LDD_SDHC_MMC: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { Id = DeviceDataPrv->NewCardId; if (DeviceDataPrv->CardType == LDD_SDHC_SD) { DeviceDataPrv->Cards[Id].RCA = SDHC1_R6_GET_RCA(Response); /* Store the received RCA (relative card address) */ } if (DeviceDataPrv->EventMask & LDD_SDHC_ON_CARD_INSERTED) { SDHC1_OnCardInserted(DeviceDataPrv->UserDataPtr, Id); /* Call the user event */ } } else { DeviceDataPrv->LastError = Error; } DeviceDataPrv->State = LDD_SDHC_CARD_REGISTRATION; DeviceDataPrv->Substate = SDHC1_CR_FINISH; CardRegistration(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card registration state */ break; default: break; } break; case SDHC1_CR_FINISH: switch (DeviceDataPrv->CardType) { case LDD_SDHC_SD: /* An SD card is registered, finish the voltage validation */ case LDD_SDHC_MMC: /* MMC cards are checked as the last, finish the voltage validation */ DeviceDataPrv->State = LDD_SDHC_VOLTAGE_VALIDATION; DeviceDataPrv->Substate = SDHC1_VV_FINISH; VoltageValidation(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the voltage validation state */ break; default: break; } break; default: break; } } /* ** =================================================================== ** Method : CardInfoRetrieval (component SDHC_LDD) ** ** Description : ** Card info retrieval state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void CardInfoRetrieval(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates card info retrieval end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ LDD_SDHC_TCardInfo *InfoPtr; /* Card info pointer storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ uint8_t BusWidths; /* Supported bus widths storage */ uint32_t Index; /* Array index */ switch (DeviceDataPrv->Substate) { case SDHC1_CIR_START: if (DeviceDataPrv->CardState != SDHC1_STAND_BY) { /* Change card state to stand-by */ DeviceDataPrv->Substate = SDHC1_CIR_STAND_BY_STATE; /* Send unselect card command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); /* Set 0 as command argument to unselect card */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD7_SELECT_CARD, SDHC_PDD_RESPONSE_LENGTH_48); } else { DeviceDataPrv->Substate = SDHC1_CIR_GET_CSD; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } break; case SDHC1_CIR_STAND_BY_STATE: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error != LDD_SDHC_ERR_TIMEOUT) { DeviceDataPrv->LastError = Error; } DeviceDataPrv->CardState = SDHC1_STAND_BY; DeviceDataPrv->Substate = SDHC1_CIR_GET_CSD; /* Send CSD (card specific data) request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_CMD_ARG_RCA((uint32_t)DeviceDataPrv->Cards[Id].RCA)); /* Set the card RCA (relative card address) as command argument */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD9_SEND_CSD, SDHC_PDD_RESPONSE_LENGTH_136); break; case SDHC1_CIR_GET_CSD: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { /* Store the CSD (card specific data) register contained in the response */ DeviceDataPrv->Cards[Id].CSD[0] = Response[0]; DeviceDataPrv->Cards[Id].CSD[1] = Response[1]; DeviceDataPrv->Cards[Id].CSD[2] = Response[2]; DeviceDataPrv->Cards[Id].CSD[3] = Response[3]; /* Change card state to transfer */ DeviceDataPrv->Substate = SDHC1_CIR_TRANSFER_STATE; /* Send card selection command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_CMD_ARG_RCA((uint32_t)DeviceDataPrv->Cards[Id].RCA)); /* Set the card RCA (relative card address) as command argument */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD7_SELECT_CARD, SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CIR_TRANSFER_STATE: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { DeviceDataPrv->CardState = SDHC1_TRANSFER; if (DeviceDataPrv->CardType == LDD_SDHC_MMC) { if (SDHC1_R2_MMC_GET_SPEC_VERS(Response) >= SDHC1_MMC_CSD_SPEC_VERS_4_X) { DeviceDataPrv->Substate = SDHC1_CIR_GET_EXT_CSD; DeviceDataPrv->CmdState = SDHC1_CMD_START; } else { DeviceDataPrv->Substate = SDHC1_CIR_FINISH; } //CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->Substate = SDHC1_CIR_GET_SCR; DeviceDataPrv->CmdState = SDHC1_CMD_START; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } } else { /* Send status request command */ SendCardStatusRequest(DeviceDataPrv); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CIR_GET_EXT_CSD: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Set data transfer size */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, SDHC1_EXT_CSD_SIZE); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = SDHC1_EXT_CSD_SIZE; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->Cards[Id].Block; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send extended CSD (card specific data) request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD8_SEND_EXT_CSD, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_READ | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error == LDD_SDHC_ERR_OK) { /* Start the bus testing procedure */ DeviceDataPrv->Substate = SDHC1_CIR_BUS_TEST_4_BIT_WRITE; DeviceDataPrv->CmdState = SDHC1_CMD_START; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } break; default: break; } break; case SDHC1_CIR_BUS_TEST_4_BIT_WRITE: case SDHC1_CIR_BUS_TEST_8_BIT_WRITE: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Clear the bus test buffer */ for (Index = 0U; Index < 8U; Index++) { DeviceDataPrv->BusTestPtr[Index] = 0U; } /* Create the bus test pattern */ if (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_WRITE) { DeviceDataPrv->BusTestPtr[0] = 0x5AU; } else { DeviceDataPrv->BusTestPtr[0] = 0x55U; DeviceDataPrv->BusTestPtr[1] = 0xAAU; } SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_WRITE) ? SDHC_PDD_4_BIT_MODE : SDHC_PDD_8_BIT_MODE); /* Set data transfer size */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_WRITE) ? 4U : 8U); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_WRITE) ? 4U : 8U; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->BusTestPtr; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send bus testing pattern write command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD19_BUS_TEST_WRITE, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_WRITE | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) || (Error == LDD_SDHC_ERR_DATA_CRC)) { DeviceDataPrv->Substate = (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_WRITE) ? SDHC1_CIR_BUS_TEST_4_BIT_READ : SDHC1_CIR_BUS_TEST_8_BIT_READ; DeviceDataPrv->CmdState = SDHC1_CMD_START; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } break; default: break; } break; case SDHC1_CIR_BUS_TEST_4_BIT_READ: case SDHC1_CIR_BUS_TEST_8_BIT_READ: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Set data transfer size */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_READ) ? 4U : 8U); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_READ) ? 4U : 8U; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->BusTestPtr; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send bus testing pattern write command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD14_BUS_TEST_READ, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_READ | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if ((Error == LDD_SDHC_ERR_OK) || (Error == LDD_SDHC_ERR_DATA_CRC)) { if (DeviceDataPrv->Substate == SDHC1_CIR_BUS_TEST_4_BIT_READ) { /* XNOR the written bus test pattern with the read bus test result */ DeviceDataPrv->BusTestPtr[0] = (DeviceDataPrv->BusTestPtr[0] & 0x5AU) | ((uint8_t)(~DeviceDataPrv->BusTestPtr[0]) & (uint8_t)(~0x5AU)); if (DeviceDataPrv->BusTestPtr[0] == 0U) { /* 4-bit data bus test succeeded */ DeviceDataPrv->Substate = SDHC1_CIR_BUS_TEST_8_BIT_WRITE; DeviceDataPrv->CmdState = SDHC1_CMD_START; DeviceDataPrv->Cards[Id].DataWidths |= LDD_SDHC_CARD_DATA_WIDTH_4_BIT; } else { DeviceDataPrv->Substate = SDHC1_CIR_FINISH; } } else { /* XNOR the written bus test pattern with the read bus test result */ DeviceDataPrv->BusTestPtr[0] = (DeviceDataPrv->BusTestPtr[0] & 0x55U) | ((uint8_t)(~DeviceDataPrv->BusTestPtr[0]) & (uint8_t)(~0x55U)); DeviceDataPrv->BusTestPtr[1] = (DeviceDataPrv->BusTestPtr[1] & 0xAAU) | ((uint8_t)(~DeviceDataPrv->BusTestPtr[1]) & (uint8_t)(~0xAAU)); if ((DeviceDataPrv->BusTestPtr[0] == 0U) && (DeviceDataPrv->BusTestPtr[1] == 0U)) { /* 8-bit data bus test succeeded */ DeviceDataPrv->Cards[Id].DataWidths |= LDD_SDHC_CARD_DATA_WIDTH_8_BIT; } DeviceDataPrv->Substate = SDHC1_CIR_FINISH; } } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } if ((DeviceDataPrv->Substate == SDHC1_CIR_FINISH) || Finished) { /* Restore the data width */ switch (DeviceDataPrv->DataWidth) { case LDD_SDHC_CARD_DATA_WIDTH_1_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_1_BIT_MODE); break; case LDD_SDHC_CARD_DATA_WIDTH_4_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_4_BIT_MODE); break; case LDD_SDHC_CARD_DATA_WIDTH_8_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_8_BIT_MODE); break; default: break; } } if (!Finished) { CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } break; default: break; } break; case SDHC1_CIR_GET_SCR: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_ACMD; /* Start application specific command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_CMD_ARG_RCA((uint32_t)DeviceDataPrv->Cards[Id].RCA)); /* Set the card RCA (relative card address) as command argument */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD55_APP_CMD, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_ACMD: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Set data transfer size */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, SDHC1_SCR_SIZE); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ /* Configure card detection and DMA mode */ /* SDHC_PROCTL: ??=0,??=0,??=0,??=0,??=0,WECRM=0,WECINS=0,WECINT=0,??=0,??=0,??=0,??=0,IABG=0,RWCTL=0,CREQ=0,SABGREQ=0,??=0,??=0,??=0,??=0,??=0,??=0,DMAS=2,CDSS=0,CDTL=0,EMODE=2,D3CD=0,DTW=0,LCTL=0 */ SDHC_PROCTL = (uint32_t)0x0220UL; DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = SDHC1_SCR_SIZE; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->Cards[Id].Block; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send SCR (SD card configuration register) request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_ACMD51_SEND_SCR, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_READ | SDHC_PDD_RESPONSE_LENGTH_48); } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; //CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error == LDD_SDHC_ERR_OK) { if (SDHC1_SCR_GET_SD_SPEC((uint32_t)DeviceDataPrv->Cards[Id].Block) != SDHC1_SCR_SD_SPEC_VERS_1_0X) { /* Check high speed support */ DeviceDataPrv->Substate = SDHC1_CIR_GET_FUNC_STATUS; DeviceDataPrv->CmdState = SDHC1_CMD_START; } else { DeviceDataPrv->Substate = SDHC1_CIR_FINISH; } CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } break; default: break; } break; case SDHC1_CIR_GET_FUNC_STATUS: switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Set data transfer size */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, SDHC1_SFS_SIZE); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = SDHC1_SFS_SIZE; DeviceDataPrv->TransferTable[0].Address = (uint32_t)&DeviceDataPrv->Cards[Id].Block[SDHC1_SFS_BLOCK_START]; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send function check command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_SD_CMD6_ARG_MODE(SDHC1_SD_CMD6_CHECK_FUNC) | SDHC1_SD_CMD6_ARG_GROUP_1(SDHC1_SD_CMD6_GROUP_1_HIGH_SPEED)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD6_SWITCH, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_READ | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; //CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->Substate = SDHC1_CIR_FINISH; CardInfoRetrieval(DeviceDataPrv, 0U, SDHC1_NO_RESPONSE); /* Handle the card info retrieval state */ } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } break; default: break; } break; case SDHC1_CIR_FINISH: Response = DeviceDataPrv->Cards[Id].CSD; /* Get a pointer to card specific data */ InfoPtr = DeviceDataPrv->CardInfoPtr; /* Get a pointer to the user card info variable */ InfoPtr->Type = DeviceDataPrv->CardType; /* Get card type from selected card type */ /* Extract card information from card registers */ InfoPtr->BlockLength = (uint16_t)((uint16_t)1U << SDHC1_R2_GET_READ_BL_LEN(Response)); /* Block length = 2^READ_BL_LEN */ if ((DeviceDataPrv->CardType != LDD_SDHC_SD) || (SDHC1_R2_GET_CSD_STRUCTURE(Response) == SDHC1_SD_CSD_VERS_1_0)) { /* CSD (card specific data) version 1.0 */ /* Block count = (C_SIZE + 1) * (2^(C_SIZE_MULT + 2)) */ InfoPtr->BlockCount = (uint16_t)(SDHC1_R2_CSD_V1_GET_C_SIZE(Response) + 1U) * (uint16_t)((uint16_t)1U << (SDHC1_R2_CSD_V1_GET_C_SIZE_MULT(Response) + 2U)); } else { /* CSD (card specific data) version 2.0 */ /* Block count = (C_SIZE + 1) * 1k */ InfoPtr->BlockCount = (SDHC1_R2_CSD_V2_GET_C_SIZE(Response) + 1U) * 1024U; } InfoPtr->Caps.Operations = (uint8_t)(SDHC1_R2_GET_CCC(Response) >> 2); /* Shift card command classes to fit into a byte (omitting mandatory classes) */ InfoPtr->Caps.HighCapacity = DeviceDataPrv->Cards[Id].HighCapacity; /* Get high capacity flag acquired during voltage validation */ InfoPtr->Caps.LowVoltage = (DeviceDataPrv->CardsVoltages & SDHC1_OCR_LOW_VOLTAGE_MASK) ? TRUE : FALSE; /* Get low voltage support flag acquired during voltage validation */ InfoPtr->Caps.Read.MaxBlockLength = (uint16_t)((uint16_t)1U << SDHC1_R2_GET_READ_BL_LEN(Response)); /* Max. read block length = 2^READ_BL_LEN */ InfoPtr->Caps.Read.MisalignBlock = (SDHC1_R2_GET_READ_BLK_MISALIGN(Response)) ? TRUE : FALSE; InfoPtr->Caps.Read.PartialBlock = (SDHC1_R2_GET_READ_BL_PARTIAL(Response)) ? TRUE : FALSE; InfoPtr->Caps.Write.MaxBlockLength = (uint16_t)((uint16_t)1U << SDHC1_R2_GET_WRITE_BL_LEN(Response)); /* Max. write block length = 2^WRITE_BL_LEN */ InfoPtr->Caps.Write.MisalignBlock = (SDHC1_R2_GET_WRITE_BLK_MISALIGN(Response)) ? TRUE : FALSE; InfoPtr->Caps.Write.PartialBlock = (SDHC1_R2_GET_WRITE_BL_PARTIAL(Response)) ? TRUE : FALSE; InfoPtr->Caps.WriteProtect.Permanent = (SDHC1_R2_GET_PERM_WRITE_PROTECT(Response)) ? TRUE : FALSE; if (DeviceDataPrv->CardType == LDD_SDHC_MMC) { InfoPtr->Caps.DataWidths = DeviceDataPrv->Cards[Id].DataWidths; /* Get data widths acquired during bus testing procedure */ InfoPtr->Caps.HighSpeed = (SDHC1_R2_MMC_GET_SPEC_VERS(Response) == SDHC1_MMC_CSD_SPEC_VERS_4_X) ? TRUE : FALSE; /* High speed supported by MMC cards from version 4.0 */ /* Erase sector size = (ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULT + 1) */ InfoPtr->Caps.Erase.SectorSize = (uint16_t)((SDHC1_R2_MMC_GET_ERASE_GRP_SIZE(Response) + 1U) * (SDHC1_R2_MMC_GET_ERASE_GRP_MULT(Response) + 1U)); /* Get erased memory byte content from the extended CSD (card specific data) register */ InfoPtr->Caps.Erase.Pattern = DeviceDataPrv->Cards[Id].Block[SDHC1_EXT_CSD_ERASED_MEM_CONT_INDEX]; /* Write protection group size = WP_GRP_SIZE + 1 */ InfoPtr->Caps.WriteProtect.GroupSize = (uint16_t)((SDHC1_R2_GET_WP_GRP_ENABLE(Response)) ? (SDHC1_R2_MMC_GET_WP_GRP_SIZE(Response) + 1U) : 0U); } else { BusWidths = (uint8_t)SDHC1_SCR_GET_SD_BUS_WIDTHS((uint32_t)DeviceDataPrv->Cards[Id].Block); InfoPtr->Caps.DataWidths = (uint8_t) /* Map SCR (SD card configuration register) values to component constants */ (((BusWidths & SDHC1_SCR_SD_BUS_WIDTH_1_BIT_MASK) ? LDD_SDHC_CARD_DATA_WIDTH_1_BIT : 0U) | ((BusWidths & SDHC1_SCR_SD_BUS_WIDTH_4_BIT_MASK) ? LDD_SDHC_CARD_DATA_WIDTH_4_BIT : 0U)); if (SDHC1_SCR_GET_SD_SPEC((uint32_t)DeviceDataPrv->Cards[Id].Block) == SDHC1_SCR_SD_SPEC_VERS_1_0X) { /* High speed is not supported in this version of SD card specification */ InfoPtr->Caps.HighSpeed = FALSE; } else { /* Get high speed support flag acquired during high speed function check */ InfoPtr->Caps.HighSpeed = (SDHC1_SFS_IS_FUNC_SUPPORTED( (uint32_t)&DeviceDataPrv->Cards[Id].Block[SDHC1_SFS_BLOCK_START], SDHC1_SFS_HIGH_SPEED_FUNC_GROUP, SDHC1_SFS_HIGH_SPEED_FUNC_INDEX)) ? TRUE : FALSE; } InfoPtr->Caps.Erase.SectorSize = (uint16_t)(SDHC1_R2_SD_GET_SECTOR_SIZE(Response) + 1U); InfoPtr->Caps.Erase.Pattern = (uint8_t) /* Erase memory byte content is defined by a data status flag */ ((SDHC1_SCR_GET_DATA_STAT_AFTER_ERASE((uint32_t)DeviceDataPrv->Cards[Id].Block)) ? 0xFFU : 0x00U); if (SDHC1_R2_GET_CSD_STRUCTURE(Response) == SDHC1_SD_CSD_VERS_2_0) { /* CSD (card specific data) structure version 2.0 */ InfoPtr->Caps.WriteProtect.GroupSize = (uint16_t)0U; } else { /* CSD (card specific data) structure version 1.0 */ InfoPtr->Caps.WriteProtect.GroupSize = (uint16_t)((SDHC1_R2_GET_WP_GRP_ENABLE(Response)) ? (SDHC1_R2_SD_GET_WP_GRP_SIZE(Response) + 1U) : 0U); } } Finished = TRUE; break; default: break; } if (Finished) { DeviceDataPrv->State = LDD_SDHC_IDLE; if (DeviceDataPrv->EventMask & LDD_SDHC_ON_FINISHED) { SDHC1_OnFinished(DeviceDataPrv->UserDataPtr); /* Call the user event */ } } } /* ** =================================================================== ** Method : CardSelection (component SDHC_LDD) ** ** Description : ** Card selection state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool CardSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates card selection end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { /* By card selection card has changed its state to transfer */ DeviceDataPrv->CardState = SDHC1_TRANSFER; Finished = TRUE; } else { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); } } else { if (Id != SDHC1_NO_CARD) { DeviceDataPrv->LastError = Error; DeviceDataPrv->Cards[Id].Initialized = FALSE; DeviceDataPrv->CardId = SDHC1_NO_CARD; /* Card has been removed */ if (DeviceDataPrv->EventMask & LDD_SDHC_ON_CARD_REMOVED) { SDHC1_OnCardRemoved(DeviceDataPrv->UserDataPtr, Id); /* Call the user event */ } } else { if (Error != LDD_SDHC_ERR_TIMEOUT) { DeviceDataPrv->LastError = Error; } } Finished = TRUE; } return Finished; } /* ** =================================================================== ** Method : Transfer (component SDHC_LDD) ** ** Description : ** Transfer state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool Transfer(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates transfer end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_DATA_LEN: DeviceDataPrv->CmdState = SDHC1_CMD_START; /* Send block length */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->TransferBlockSize); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD16_SET_BLOCKLEN, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_START: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { if (DeviceDataPrv->Cancel) { Finished = TRUE; } else { DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Set block attributes */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, DeviceDataPrv->TransferBlockSize); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, DeviceDataPrv->TransferBlockCount); /* Send transfer command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->Address); SDHC_PDD_SendCommand(SDHC_BASE_PTR, ((DeviceDataPrv->TransferOperation == LDD_SDHC_READ) ? (uint32_t)((DeviceDataPrv->TransferBlockCount > 1U) ? SDHC_PDD_CMD18_READ_MULTIPLE_BLOCK : SDHC_PDD_CMD17_READ_SINGLE_BLOCK) : (uint32_t)((DeviceDataPrv->TransferBlockCount > 1U) ? SDHC_PDD_CMD25_WRITE_MULTIPLE_BLOCK : SDHC_PDD_CMD24_WRITE_BLOCK)), ((DeviceDataPrv->TransferBlockCount > 1U) ? (SDHC_PDD_ENABLE_BLOCK_COUNT | SDHC_PDD_ENABLE_AUTO_CMD12 | SDHC_PDD_MULTIPLE_BLOCK) : 0U) | SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_RESPONSE_LENGTH_48 | ((DeviceDataPrv->TransferOperation == LDD_SDHC_READ) ? SDHC_PDD_DATA_READ : SDHC_PDD_DATA_WRITE)); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_ERROR; SendCardStatusRequest(DeviceDataPrv); } else { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); Finished = TRUE; } break; case SDHC1_CMD_ERROR: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { Finished = TRUE; } else { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; default: break; } return Finished; } /* ** =================================================================== ** Method : Erasion (component SDHC_LDD) ** ** Description : ** Erasion state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool Erasion(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates erasion end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ switch (DeviceDataPrv->Substate) { case SDHC1_E_SET_START: DeviceDataPrv->Substate = SDHC1_E_SET_END; /* Send tag erase start command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->ErasionStart); SDHC_PDD_SendCommand(SDHC_BASE_PTR, ((DeviceDataPrv->CardType == LDD_SDHC_MMC) ? /* Handle different command indices for different card types */ SDHC_PDD_CMD35_TAG_ERASE_GROUP_START : SDHC_PDD_CMD32_TAG_SECTOR_START), SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_E_SET_END: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->Substate = SDHC1_E_EXECUTE; /* Send tag erase end command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->ErasionEnd); SDHC_PDD_SendCommand(SDHC_BASE_PTR, ((DeviceDataPrv->CardType == LDD_SDHC_MMC) ? /* Handle different command indices for different card types */ SDHC_PDD_CMD36_TAG_ERASE_GROUP_END : SDHC_PDD_CMD33_TAG_SECTOR_END), SDHC_PDD_RESPONSE_LENGTH_48); } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_E_EXECUTE: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->Substate = SDHC1_E_FINISH; /* Send erase command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD38_ERASE, SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_E_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { /* Check whether erasion has finished */ if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { Finished = TRUE; } else { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; default: break; } return Finished; } /* ** =================================================================== ** Method : DataWidthSelection (component SDHC_LDD) ** ** Description : ** Data width selection state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool DataWidthSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates data width selection end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ uint8_t Argument = 0U; /* Command argument */ if (DeviceDataPrv->CardType == LDD_SDHC_MMC) { switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Map data width to an extended CSD (card specific data) register field value */ switch (DeviceDataPrv->DataWidth) { case LDD_SDHC_CARD_DATA_WIDTH_1_BIT: Argument = 0U; break; case LDD_SDHC_CARD_DATA_WIDTH_4_BIT: Argument = 1U; break; case LDD_SDHC_CARD_DATA_WIDTH_8_BIT: Argument = 2U; break; default: break; } /* Send switch command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_MMC_CMD6_ARG_ACCESS(SDHC1_MMC_CMD6_WRITE_BYTES) | SDHC1_MMC_CMD6_ARG_INDEX(SDHC1_EXT_CSD_BUS_WIDTH_INDEX) | SDHC1_MMC_CMD6_ARG_VALUE(Argument)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD6_SWITCH, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { /* Map data widths to host register field values */ switch (DeviceDataPrv->DataWidth) { case LDD_SDHC_CARD_DATA_WIDTH_1_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_1_BIT_MODE); break; case LDD_SDHC_CARD_DATA_WIDTH_4_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_4_BIT_MODE); break; case LDD_SDHC_CARD_DATA_WIDTH_8_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_8_BIT_MODE); break; default: break; } Finished = TRUE; } else { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; default: break; } } else { switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_ACMD; /* Start application specific command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_CMD_ARG_RCA(DeviceDataPrv->Cards[Id].RCA)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD55_APP_CMD, SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_ACMD: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Map data widths to card register field values */ switch (DeviceDataPrv->DataWidth) { case LDD_SDHC_CARD_DATA_WIDTH_1_BIT: SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); break; case LDD_SDHC_CARD_DATA_WIDTH_4_BIT: SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 2U); break; default: break; } /* Send bus width set command */ SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_ACMD6_SET_BUS_WIDTH, SDHC_PDD_RESPONSE_LENGTH_48); } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { /* Map data widths to host register field values */ switch (DeviceDataPrv->DataWidth) { case LDD_SDHC_CARD_DATA_WIDTH_1_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_1_BIT_MODE); break; case LDD_SDHC_CARD_DATA_WIDTH_4_BIT: SDHC_PDD_SetDataTransferWidth(SDHC_BASE_PTR, SDHC_PDD_4_BIT_MODE); break; default: break; } } else { DeviceDataPrv->LastError = Error; } Finished = TRUE; break; default: break; } } return Finished; } /* ** =================================================================== ** Method : BusClockSelection (component SDHC_LDD) ** ** Description : ** Bus clock selection state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool BusClockSelection(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates bus clock selection end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; if (DeviceDataPrv->Cards[Id].Type == LDD_SDHC_MMC) { /* Send switch command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_MMC_CMD6_ARG_ACCESS(SDHC1_MMC_CMD6_WRITE_BYTES) | SDHC1_MMC_CMD6_ARG_INDEX(SDHC1_EXT_CSD_HS_TIMING_INDEX) | SDHC1_MMC_CMD6_ARG_VALUE(1)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD6_SWITCH, SDHC_PDD_RESPONSE_LENGTH_48); } else { /* Send function switch command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_SD_CMD6_ARG_MODE(SDHC1_SD_CMD6_SWITCH_FUNC) | SDHC1_SD_CMD6_ARG_GROUP_1(SDHC1_SD_CMD6_GROUP_1_HIGH_SPEED)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD6_SWITCH, SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); } break; case SDHC1_CMD_FINISH: Finished = TRUE; Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (DeviceDataPrv->CardType == LDD_SDHC_MMC) { if (!SDHC1_R1_IS_READY_FOR_DATA(Response)) { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); Finished = FALSE; } } } if (Finished) { SetBusClockPrescalers(DeviceDataPrv, DeviceDataPrv->Frequency); } break; default: break; } return Finished; } /* ** =================================================================== ** Method : WriteProtectionSetup (component SDHC_LDD) ** ** Description : ** Write protection setup state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool WriteProtectionSetup(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates write protection setup end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ uint32_t Index; /* Array index */ if (DeviceDataPrv->WriteProtType == LDD_SDHC_GROUP) { switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Send write protection set/clear command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->Address); SDHC_PDD_SendCommand(SDHC_BASE_PTR, (DeviceDataPrv->WriteProtFlag ? /* Choose write protection set or clear command */ SDHC_PDD_CMD28_SET_WRITE_PROT : SDHC_PDD_CMD29_CLR_WRITE_PROT), SDHC_PDD_RESPONSE_LENGTH_48_BUSY_CHECK); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if ((Error == LDD_SDHC_ERR_OK) && Response) { if (SDHC1_R1_IS_READY_FOR_DATA(Response)) { Finished = TRUE; } else { /* Send status request command again */ SendCardStatusRequest(DeviceDataPrv); } } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; default: break; } } else { switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Order CSD (card specific data) register bytes from MSB to LSB */ for (Index = 0U; Index < (SDHC1_CSD_SIZE - 1U); Index++) { DeviceDataPrv->CSDPtr[(SDHC1_CSD_SIZE - 1U) - (Index + 1U)] = (uint8_t)((uint32_t)DeviceDataPrv->Cards[Id].CSD[Index / 4U] >> (8 * ((int32_t)Index % 4))) & 0xFFU; } /* Set block attributes */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, SDHC1_CSD_SIZE); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = SDHC1_CSD_SIZE; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->CSDPtr; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Program CSD (card specific data) register */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, 0U); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD27_PROGRAM_CSD, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_WRITE | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error != LDD_SDHC_ERR_OK) { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); } Finished = TRUE; break; default: break; } } return Finished; } /* ** =================================================================== ** Method : WriteProtectionRetrieval (component SDHC_LDD) ** ** Description : ** Write protection retrieval state handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static bool WriteProtectionRetrieval(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; bool Finished = FALSE; /* Indicates write protection retrieval end */ LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ switch (DeviceDataPrv->CmdState) { case SDHC1_CMD_START: DeviceDataPrv->CmdState = SDHC1_CMD_FINISH; /* Set block attributes */ SDHC_PDD_SetBlockSize(SDHC_BASE_PTR, SDHC1_WRITE_PROTECT_MASK_SIZE); SDHC_PDD_SetBlockCount(SDHC_BASE_PTR, 1U); /* Set DMA transfer properties */ DeviceDataPrv->TransferTable[0].Attributes = SDHC1_SINGLE_BLOCK_TRANS_ATTRS; DeviceDataPrv->TransferTable[0].Length = SDHC1_WRITE_PROTECT_MASK_SIZE; DeviceDataPrv->TransferTable[0].Address = (uint32_t)DeviceDataPrv->WriteProtMaskPtr; SDHC_PDD_SetADMAAddress(SDHC_BASE_PTR, DeviceDataPrv->TransferTable); /* Send write protection mask request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, DeviceDataPrv->Address); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD30_SEND_WRITE_PROT, SDHC_PDD_ENABLE_DMA | SDHC_PDD_DATA_PRESENT | SDHC_PDD_DATA_READ | SDHC_PDD_RESPONSE_LENGTH_48); break; case SDHC1_CMD_FINISH: Error = GetCommandError(DeviceDataPrv, Flags, Response); /* Check host and card error flags */ if (Error == LDD_SDHC_ERR_OK) { DeviceDataPrv->CmdState = SDHC1_CMD_DATA; } else { DeviceDataPrv->LastError = Error; Finished = TRUE; } break; case SDHC1_CMD_DATA: Error = GetCommandError(DeviceDataPrv, Flags, SDHC1_NO_RESPONSE); /* Check host error flags */ if (Error != LDD_SDHC_ERR_OK) { DeviceDataPrv->LastError = Error; DeviceDataPrv->LastErrorAddress = SDHC_PDD_GetDMAAddress(SDHC_BASE_PTR); } Finished = TRUE; break; default: break; } return Finished; } /* ** =================================================================== ** Method : SetBusClockPrescalers (component SDHC_LDD) ** ** Description : ** Bus clock prescalers setup. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void SetBusClockPrescalers(LDD_SDHC1_TDeviceData *DeviceDataPtr, SDHC1_TBusClock Frequency) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; static const uint8_t PrescalerValues[][1][2] = { /* Frequency select and divisor values for bus clock frequencies selected by property */ {{ 64u, 0u }}, {{ 2u, 0u }}, {{ 1u, 0u }} }; SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, FALSE); SDHC_PDD_SetSDHCClockFrequency(SDHC_BASE_PTR, PrescalerValues[Frequency][DeviceDataPrv->SpeedMode][0]); SDHC_PDD_SetSDHCClockDivisor(SDHC_BASE_PTR, PrescalerValues[Frequency][DeviceDataPrv->SpeedMode][1]); while (!SDHC_PDD_IsSDClockStable(SDHC_BASE_PTR)) {} /* Wait for clock to stabilize */ SDHC_PDD_EnableSDHCClock(SDHC_BASE_PTR, TRUE); } /* ** =================================================================== ** Method : GetCommandError (component SDHC_LDD) ** ** Description : ** Extracts error code from the device error flags and the card ** status response. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static LDD_SDHC_TError GetCommandError(LDD_SDHC1_TDeviceData *DeviceDataPtr, uint32_t Flags, uint32_t *Response) { LDD_SDHC_TError Error = LDD_SDHC_ERR_OK; /* Error code storage */ uint32_t AutoCMD12ErrorFlags = SDHC_PDD_GetAutoCMD12ErrorFlags(SDHC_BASE_PTR); /* Auto CMD12 error flags */ (void)DeviceDataPtr; /* Suppress unused parameter warning */ /* Map host error flags to component error codes */ if ((Flags & (SDHC_PDD_COMMAND_TIMEOUT_ERROR_INT | SDHC_PDD_DATA_TIMEOUT_ERROR_INT)) || ((Flags & SDHC_PDD_AUTO_CMD12_ERROR_INT) && (AutoCMD12ErrorFlags & SDHC_PDD_AUTO_CMD12_TIMEOUT_ERROR))) { Error = LDD_SDHC_ERR_TIMEOUT; } else if ((Flags & (SDHC_PDD_COMMAND_CRC_ERROR_INT | SDHC_PDD_COMMAND_END_BIT_ERROR_INT | SDHC_PDD_COMMAND_INDEX_ERROR_INT)) || ((Flags & SDHC_PDD_AUTO_CMD12_ERROR_INT) && (AutoCMD12ErrorFlags & (SDHC_PDD_AUTO_CMD12_CRC_ERROR | SDHC_PDD_AUTO_CMD12_END_BIT_ERROR | SDHC_PDD_AUTO_CMD12_INDEX_ERROR)))) { Error = LDD_SDHC_ERR_COMMAND_CRC; } else if (Flags & (SDHC_PDD_DATA_CRC_ERROR_INT | SDHC_PDD_DATA_END_BIT_ERROR_INT)) { Error = LDD_SDHC_ERR_DATA_CRC; } else if (Flags & SDHC_PDD_DMA_ERROR_INT) { Error = LDD_SDHC_ERR_DMA; } else { Error = LDD_SDHC_ERR_OK; } if ((Error == LDD_SDHC_ERR_OK) && Response) { /* Map card error flags to component error codes */ if (SDHC1_R1_IS_ERASE_RESET(Response) || SDHC1_R1_IS_CSD_OVERWRITE(Response) || SDHC1_R1_IS_ERASE_SEQ_ERROR(Response) || SDHC1_R1_IS_ILLEGAL_COMMAND(Response)) { Error = LDD_SDHC_ERR_INTERNAL_FAILURE; } else if (SDHC1_R1_IS_WP_ERASE_SKIP(Response)) { Error = LDD_SDHC_ERR_WP_ERASE_SKIP; } else if (SDHC1_R1_MMC_IS_OVERRUN(Response) || SDHC1_R1_MMC_IS_UNDERRUN(Response) || SDHC1_R1_IS_ERROR(Response) || SDHC1_R1_IS_CC_ERROR(Response) || SDHC1_R1_IS_CARD_ECC_FAILED(Response)) { Error = LDD_SDHC_ERR_CARD_FAILURE; } else if (SDHC1_R1_IS_COM_CRC_ERROR(Response)) { Error = LDD_SDHC_ERR_COMMAND_CRC; } else if (SDHC1_R1_IS_CARD_IS_LOCKED(Response)) { Error = LDD_SDHC_ERR_CARD_IS_LOCKED; } else if (SDHC1_R1_IS_WP_VIOLATION(Response)) { Error = LDD_SDHC_ERR_WP_VIOLATION; } else if (SDHC1_R1_IS_ERASE_PARAM(Response) || SDHC1_R1_IS_ADDRESS_MISALIGN(Response)) { Error = LDD_SDHC_ERR_ADDRESS_MISALIGN; } else if (SDHC1_R1_IS_BLOCK_LEN_ERROR(Response)) { Error = LDD_SDHC_ERR_BLOCK_LEN_ERROR; } else if (SDHC1_R1_IS_ADDRESS_OUT_OF_RANGE(Response)) { Error = LDD_SDHC_ERR_ADDRESS_OUT_OF_RANGE; } else { Error = LDD_SDHC_ERR_OK; } } return Error; } /* ** =================================================================== ** Method : SendCardStatusRequest (component SDHC_LDD) ** ** Description : ** Sends a card status request. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void SendCardStatusRequest(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; uint8_t Id = DeviceDataPrv->CardId; /* Card ID storage */ /* Send status request command */ SDHC_PDD_SetCommandArgument(SDHC_BASE_PTR, SDHC1_CMD_ARG_RCA(DeviceDataPrv->Cards[Id].RCA)); SDHC_PDD_SendCommand(SDHC_BASE_PTR, SDHC_PDD_CMD13_SEND_STATUS, SDHC_PDD_RESPONSE_LENGTH_48); } /* ** =================================================================== ** Method : SDHC1_Interrupt (component SDHC_LDD) ** ** Description : ** The method services the interrupt of the selected peripheral(s) ** and eventually invokes event(s) of the component. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ //PE_ISR(SDHC1_Interrupt) void SDHC1_Interrupt( void ) { /* {FreeRTOS RTOS Adapter} ISR parameter is passed through the global variable */ LDD_SDHC1_TDeviceData* DeviceDataPrv = INT_SDHC__BAREBOARD_RTOS_ISRPARAM; EventHandler(DeviceDataPrv); } /* ** =================================================================== ** Method : EventHandler (component SDHC_LDD) ** ** Description : ** Hardware event handler. ** This method is internal. It is used by Processor Expert only. ** =================================================================== */ static void EventHandler(LDD_SDHC1_TDeviceData *DeviceDataPtr) { LDD_SDHC1_TDeviceData *DeviceDataPrv = (LDD_SDHC1_TDeviceData*)DeviceDataPtr; uint32_t IntFlags = SDHC_PDD_GetInterruptFlags(SDHC_BASE_PTR); /* Store interrupt flags */ const uint32_t CompletionFlags = SDHC_PDD_COMMAND_COMPLETE_INT | SDHC_PDD_TRANSFER_COMPLETE_INT | SDHC_PDD_BUFFER_READ_READY_INT | SDHC_PDD_BUFFER_WRITE_READY_INT; const uint32_t CommandErrorFlags = SDHC_PDD_COMMAND_TIMEOUT_ERROR_INT | /* Command error interrupt flags mask */ SDHC_PDD_COMMAND_CRC_ERROR_INT | SDHC_PDD_COMMAND_INDEX_ERROR_INT | //MATTHEW 0; //SDHC_PDD_AUTO_CMD12_ERROR_INT; const uint32_t DataErrorFlags = SDHC_PDD_DATA_TIMEOUT_ERROR_INT | /* Data transfer error interrupt flags mask */ SDHC_PDD_DATA_CRC_ERROR_INT | SDHC_PDD_DATA_END_BIT_ERROR_INT | SDHC_PDD_DMA_ERROR_INT; const uint32_t ErrorFlags = CommandErrorFlags | DataErrorFlags; /* Error interrupt flags mask */ bool Finished = FALSE; /* Indicates operation end */ uint32_t Buffer[4]; /* Response buffer */ uint32_t *Response = SDHC1_NO_RESPONSE; /* Response buffer pointer */ if (IntFlags & (CompletionFlags | ErrorFlags)) { if (IntFlags & SDHC_PDD_COMMAND_COMPLETE_INT) { SDHC_PDD_ClearInterruptFlags(SDHC_BASE_PTR, SDHC_PDD_COMMAND_COMPLETE_INT); /* Check command completion errors */ if (IntFlags & CommandErrorFlags) { SDHC_PDD_ClearInterruptFlags(SDHC_BASE_PTR, CommandErrorFlags); Response = SDHC1_NO_RESPONSE; /* No valid response has been received */ } else { SDHC_PDD_GetCommandResponse(SDHC_BASE_PTR, Buffer); Response = Buffer; /* Assign the response pointer */ } } else { if (IntFlags & SDHC_PDD_TRANSFER_COMPLETE_INT) { SDHC_PDD_ClearInterruptFlags(SDHC_BASE_PTR, SDHC_PDD_TRANSFER_COMPLETE_INT | DataErrorFlags); } } switch (DeviceDataPrv->State) { case LDD_SDHC_RESET: Finished = TRUE; break; case LDD_SDHC_VOLTAGE_VALIDATION: VoltageValidation(DeviceDataPrv, IntFlags, Response); /* Handle the voltage validation state */ break; case LDD_SDHC_CARD_REGISTRATION: CardRegistration(DeviceDataPrv, IntFlags, Response); /* Handle the card registration state */ break; case LDD_SDHC_CARD_INFO_RETRIEVAL: CardInfoRetrieval(DeviceDataPrv, IntFlags, Response); /* Handle the card info retrieval state */ break; case LDD_SDHC_CARD_SELECTION: Finished = CardSelection(DeviceDataPrv, IntFlags, Response); /* Handle the card selection state */ break; case LDD_SDHC_TRANSFER: Finished = Transfer(DeviceDataPrv, IntFlags, Response); /* Handle the transfer state */ break; case LDD_SDHC_ERASION: Finished = Erasion(DeviceDataPrv, IntFlags, Response); /* Handle the erasion state */ break; case LDD_SDHC_DATA_WIDTH_SELECTION: Finished = DataWidthSelection(DeviceDataPrv, IntFlags, Response); /* Handle the data width selection state */ break; case LDD_SDHC_BUS_CLOCK_SELECTION: Finished = BusClockSelection(DeviceDataPrv, IntFlags, Response); /* Handle the bus clock selection state */ break; case LDD_SDHC_WRITE_PROTECTION_SETUP: Finished = WriteProtectionSetup(DeviceDataPrv, IntFlags, Response); /* Handle the write protection setup state */ break; case LDD_SDHC_WRITE_PROTECTION_RETRIEVAL: Finished = WriteProtectionRetrieval(DeviceDataPrv, IntFlags, Response); /* Handle the write protection retrieval state */ break; default: break; } } if (Finished) { DeviceDataPrv->State = LDD_SDHC_IDLE; if (DeviceDataPrv->EventMask & LDD_SDHC_ON_FINISHED) { SDHC1_OnFinished(DeviceDataPrv->UserDataPtr); /* Call the user event */ } } } /*lint -restore +esym(960,10.1) Enable MISRA rule (10.1,12.1) checking. */ /* END SDHC1 */ /* ** ################################################################### ** ** This file was created by Processor Expert 5.3 [05.01] ** for the Freescale Kinetis series of microcontrollers. ** ** ################################################################### */