//////////////////////////////////////////////////////////////////////////////// /// @file hal_sdio.c /// @author AE TEAM /// @brief THIS FILE PROVIDES ALL THE SDIO FIRMWARE FUNCTIONS. //////////////////////////////////////////////////////////////////////////////// /// @attention /// /// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE /// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE /// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR /// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH /// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN /// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS. /// ///

© COPYRIGHT MINDMOTION

//////////////////////////////////////////////////////////////////////////////// // Define to prevent recursive inclusion #define _HAL_SDIO_C_ #include "reg_sdio.h" #include "hal_sdio.h" #include "hal_rcc.h" //////////////////////////////////////////////////////////////////////////////// /// @addtogroup MM32_Hardware_Abstract_Layer /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup SDIO_HAL /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup SDIO_Exported_Functions /// @{ //////////////////////////////////////////////////////////////////////////////// /// @brief Deinitializes the SDIO peripheral registers to their default reset /// values. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_DeInit(void) { RCC_AHBPeriphResetCmd(RCC_AHBRSTR_SDIO, ENABLE); RCC_AHBPeriphResetCmd(RCC_AHBRSTR_SDIO, DISABLE); } //////////////////////////////////////////////////////////////////////////////// /// @brief Fills each SDIO_InitStruct member with its default value. /// @param SDIO_InitStruct: pointer to an SDIO_InitTypeDef structure which /// will be initialized. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_StructInit(SDIO_InitTypeDef* SDIO_InitStruct) { // SDIO_InitStruct members default value SDIO_InitStruct->SDIO_MDEN = 0; SDIO_InitStruct->SDIO_DATWT = 0; SDIO_InitStruct->SDIO_SelPTSM = 0; SDIO_InitStruct->SDIO_CLKSP = 0; SDIO_InitStruct->SDIO_OUTM = 0; SDIO_InitStruct->SDIO_SelSM = 0; SDIO_InitStruct->SDIO_OPMSel = 0; } /// /// @brief Fills each SDIO_DataInitStruct member with its default value. /// @param SDIO_DataInitStruct: pointer to an SDIO_DataInitTypeDef structure which /// will be initialized. /// @retval None /// void SDIO_DataStructInit(SDIO_DataInitTypeDef* SDIO_DataInitStruct) { /* SDIO_DataInitStruct members default value */ SDIO_DataInitStruct->SDIO_DataTimeOut = 0xFFFFFFFF; SDIO_DataInitStruct->SDIO_DataLength = 0x00; SDIO_DataInitStruct->SDIO_DataBlockSize = SDIO_DataBlockSize_1b; SDIO_DataInitStruct->SDIO_TransferDir = SDIO_TransferDir_ToCard; // SDIO_DataInitStruct->SDIO_TransferMode = SDIO_TransferMode_Block; // SDIO_DataInitStruct->SDIO_DPSM = SDIO_DPSM_Disable; } /// /// @brief Initializes the SDIO data path according to the specified /// parameters in the SDIO_DataInitStruct. /// @param SDIO_DataInitStruct : pointer to a SDIO_DataInitTypeDef structure that /// contains the configuration information for the SDIO command. /// @retval None /// //void SDIO_DataConfig(SDIO_DataInitTypeDef* SDIO_DataInitStruct) //{ // u32 tmpreg = 0; // /*---------------------------- SDIO DTIMER Configuration ---------------------*/ // /* Set the SDIO Data TimeOut value */ // SDIO->MMC_TIMEOUTCNT = SDIO_DataInitStruct->SDIO_DataTimeOut; // /*---------------------------- SDIO DLEN Configuration -----------------------*/ // /* Set the SDIO DataLength value */ // SDIO->MMC_BYTECNTL = SDIO_DataInitStruct->SDIO_DataLength; // /*---------------------------- SDIO DCTRL Configuration ----------------------*/ // /* Get the SDIO DCTRL value */ // tmpreg = SDIO->DCTRL; // /* Clear DEN, DTMODE, DTDIR and DBCKSIZE bits */ // tmpreg &= DCTRL_CLEAR_MASK; // /* Set DEN bit according to SDIO_DPSM value */ // /* Set DTMODE bit according to SDIO_TransferMode value */ // /* Set DTDIR bit according to SDIO_TransferDir value */ // /* Set DBCKSIZE bits according to SDIO_DataBlockSize value */ // tmpreg |= (u32)SDIO_DataInitStruct->SDIO_DataBlockSize | SDIO_DataInitStruct->SDIO_TransferDir;// // //| SDIO_DataInitStruct->SDIO_TransferMode | SDIO_DataInitStruct->SDIO_DPSM; // /* Write to SDIO DCTRL */ // SDIO->DCTRL = tmpreg; //} //////////////////////////////////////////////////////////////////////////////// /// @brief The frequency division factor is configured to generate the SDIO clock. /// @param value : 1MHz = Fhclk/((mmc_cardsel[5 : 0] + 1) × 2) /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_ClockSet(u32 value) { // SDIO->MMC_CARDSEL &= ~SDIO_MMC_CARDSEL_MASK; SDIO->MMC_CARDSEL = (SDIO_MMC_CARDSEL_CTREN | SDIO_MMC_CARDSEL_ENPCLK | (value & 0x3F)); // SDIO->MMC_CARDSEL = 0xC0+0x2F;//0xdf; } //////////////////////////////////////////////////////////////////////////////// /// @brief Initializes the SDIO peripheral according to the specified /// parameters in the SDIO_InitStruct. /// @param SDIO_InitStruct : pointer to a SDIO_InitTypeDef structure /// that contains the configuration information for the SDIO peripheral. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_Init(SDIO_InitTypeDef* SDIO_InitStruct) { SDIO->MMC_CTRL &= 0x700; SDIO->MMC_CTRL |= (SDIO_InitStruct->SDIO_OPMSel | SDIO_InitStruct->SDIO_SelSM | SDIO_InitStruct->SDIO_OUTM | SDIO_InitStruct->SDIO_CLKSP | SDIO_InitStruct->SDIO_SelPTSM | SDIO_InitStruct->SDIO_DATWT | SDIO_InitStruct->SDIO_MDEN); } //////////////////////////////////////////////////////////////////////////////// /// @brief Enables or disables the SDIO interrupts. /// @param SDIO_IT: specifies the SDIO interrupt sources to be enabled or disabled. /// state : new state of the specified SDIO interrupts. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_ITConfig(u32 SDIO_IT, FunctionalState state) { (state) ? (SDIO->MMC_INT_MASK |= SDIO_IT) : (SDIO->MMC_INT_MASK &= ~SDIO_IT); } //////////////////////////////////////////////////////////////////////////////// /// @brief Enables or disables the SDIO CRC. /// @param SDIO_CRC: specifies the SDIO CRC sources to be enabled or disabled. /// state : new state of the specified SDIO CRC. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_CRCConfig(u32 SDIO_CRC, FunctionalState state) { (state) ? (SDIO->MMC_CRCCTL |= SDIO_CRC) : (SDIO->MMC_CRCCTL &= ~SDIO_CRC); } //////////////////////////////////////////////////////////////////////////////// /// @brief Port transfer speed mode. /// @param clkdiv : High/low speed. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_Clock_Set(u8 clkdiv) { SDIO->MMC_CTRL &= ~SDIO_MMC_CTRL_SelPTSM; (clkdiv) ? (SDIO->MMC_CTRL |= SDIO_MMC_CTRL_SelPTSM) : (SDIO->MMC_CTRL &= ~SDIO_MMC_CTRL_SelPTSM); } //////////////////////////////////////////////////////////////////////////////// /// @brief Turn off the SDIO switch. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// SD_Error SD_PowerOFF(void) { SDIO->MMC_CARDSEL &= ~(SDIO_MMC_CARDSEL_ENPCLK | SDIO_MMC_CARDSEL_CTREN); return SD_OK; } /// /// @brief Fills each SDIO_CmdInitStruct member with its default value. /// @param SDIO_CmdInitStruct: pointer to an SDIO_CmdInitTypeDef /// structure which will be initialized. /// @retval None /// void SDIO_CmdStructInit(SDIO_CmdInitTypeDef* SDIO_CmdInitStruct) { /* SDIO_CmdInitStruct members default value */ SDIO_CmdInitStruct->SDIO_Argument = 0x00; SDIO_CmdInitStruct->SDIO_CmdIndex = 0x00; SDIO_CmdInitStruct->SDIO_Response = SDIO_Response_No; SDIO_CmdInitStruct->SDIO_Wait = SDIO_Wait_No; // SDIO_CmdInitStruct->SDIO_CPSM = SDIO_CPSM_Disable; } //////////////////////////////////////////////////////////////////////////////// /// @brief SDIO sends command functions. /// @param cmdindex : Type the command. /// waitrsp : Expected correspondence. /// arg : parameter. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_Send_Cmd(u8 cmdindex, u8 waitrsp, u32 arg) { SDIO->CMD_BUF0 = (arg >> 0) & 0xFF; SDIO->CMD_BUF1 = (arg >> 8) & 0xFF; SDIO->CMD_BUF2 = (arg >> 16) & 0xFF; SDIO->CMD_BUF3 = (arg >> 24) & 0xFF; SDIO->CMD_BUF4 = 0x40 | cmdindex; SDIO->CLR_MMC_INT |= 0; SDIO->MMC_IO = SDIO_MMC_IO_AUTOTR; while(1) { if(SDIO->CLR_MMC_INT & SDIO_CLR_MMC_INT_CMDDMC) { SDIO->CLR_MMC_INT |= SDIO_CLR_MMC_INT_CMDDMC; break; } } if(waitrsp == SDIO_Response_Short) { SDIO->MMC_IO = SDIO_MMC_IO_AUTOCLKG | \ SDIO_MMC_IO_AUTOTR | \ SDIO_MMC_IO_RESPCMDSEL; } else if(waitrsp == SDIO_Response_Long) { SDIO->MMC_IO = SDIO_MMC_IO_AUTOCLKG | \ SDIO_MMC_IO_AUTOTR | \ SDIO_MMC_IO_RESPCMDSEL | \ SDIO_MMC_IO_CID_CSDRD; } else { } } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the execution status of CMD0. /// @param None. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdError(void) { SD_Error errorstatus = SD_OK; u32 timeout = SDIO_CMD0TIMEOUT; while (timeout--) { if(((SDIO->MMC_IO & SDIO_MMC_IO_RESPCMDSEL) == 0) && ((SDIO->MMC_IO & SDIO_MMC_IO_AUTOTR) == 0)) break; } if (timeout == 0) return SD_CMD_RSP_TIMEOUT; SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_MASK; return errorstatus; } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the error status of the R1 response. /// @param cmd : Current command. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdResp1Error(u8 cmd) { u32 status; u32 response; while(1) { status = SDIO->CLR_MMC_INT ; if(status & (SDIO_CLR_MMC_INT_CRCEMC | SDIO_CLR_MMC_INT_CRNTMC | SDIO_CLR_MMC_INT_CMDDMC)) break; } if(status & SDIO_CLR_MMC_INT_CRNTMC) { SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRNTMC; return SD_CMD_RSP_TIMEOUT; } if(status & (SDIO_CLR_MMC_INT_CRCEMC)) { SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRCEMC; return SD_CMD_CRC_FAIL; } SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_MASK; if((SDIO->CMD_BUF4 & 0x3F) != cmd) { return SD_ILLEGAL_CMD; } response = SDIO->CMD_BUF3 << 24 | SDIO->CMD_BUF2 << 16 | SDIO->CMD_BUF1 << 8 | SDIO->CMD_BUF0; return (SD_Error)(response & SD_OCR_ERRORBITS); } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the execution status of CMD2. /// @param None. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdResp2Error(void) { SD_Error errorstatus = SD_OK; u32 status; u32 timeout = SDIO_CMD0TIMEOUT; while(timeout--) { status = SDIO->CLR_MMC_INT ; if(status & (SDIO_CLR_MMC_INT_CRCEMC | SDIO_CLR_MMC_INT_CRNTMC | SDIO_CLR_MMC_INT_CMDDMC)) break; } if((timeout == 0) || (status & SDIO_CLR_MMC_INT_CRNTMC)) { errorstatus = SD_CMD_RSP_TIMEOUT; SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRNTMC; return errorstatus; } if(status & SDIO_CLR_MMC_INT_CRCEMC) { errorstatus = SD_CMD_CRC_FAIL; SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRCEMC; } SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_MASK; return errorstatus; } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the execution status of CMD3. /// @param None. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdResp3Error(void) { u32 status; while(1) { status = SDIO->CLR_MMC_INT ; if(status & (SDIO_CLR_MMC_INT_CRCEMC | SDIO_CLR_MMC_INT_CRNTMC | SDIO_CLR_MMC_INT_CMDDMC)) break; } if(status & SDIO_CLR_MMC_INT_CRNTMC) { SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRNTMC; return SD_CMD_RSP_TIMEOUT; } SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_MASK; return SD_OK; } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the execution status of CMD6. /// @param None. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdResp6Error(u8 cmd, u16* prca) { SD_Error errorstatus = SD_OK; u32 status; u32 rspr1; while(1) { status = SDIO->CLR_MMC_INT ; if(status & (SDIO_CLR_MMC_INT_CRCEMC | SDIO_CLR_MMC_INT_CRNTMC | SDIO_CLR_MMC_INT_CMDDMC)) break; } if(status & SDIO_CLR_MMC_INT_CRNTMC) { SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRNTMC; return SD_CMD_RSP_TIMEOUT; } if(status & SDIO_CLR_MMC_INT_CRCEMC) { SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRCEMC; return SD_CMD_CRC_FAIL; } if((SDIO->CMD_BUF4 & 0x3F) != cmd) { return SD_ILLEGAL_CMD; } SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_MASK; rspr1 = SDIO->CMD_BUF3 << 24 | SDIO->CMD_BUF2 << 16 | SDIO->CMD_BUF1 << 8 | SDIO->CMD_BUF0; if(SD_ALLZERO == (rspr1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED))) { *prca = (u16)(rspr1 >> 16); return errorstatus; } if(rspr1 & SD_R6_GENERAL_UNKNOWN_ERROR) { return SD_GENERAL_UNKNOWN_ERROR; } if(rspr1 & SD_R6_ILLEGAL_CMD) { return SD_ILLEGAL_CMD; } if(rspr1 & SD_R6_COM_CRC_FAILED) { return SD_COM_CRC_FAILED; } return errorstatus; } //////////////////////////////////////////////////////////////////////////////// /// @brief Check the execution status of CMD7. /// @param None. /// @retval card error code. //////////////////////////////////////////////////////////////////////////////// SD_Error CmdResp7Error(void) { SD_Error errorstatus = SD_OK; u32 status; u32 timeout = SDIO_CMD0TIMEOUT; while(timeout--) { status = SDIO->CLR_MMC_INT ; if(status & (SDIO_CLR_MMC_INT_CRCEMC | SDIO_CLR_MMC_INT_CRNTMC | SDIO_CLR_MMC_INT_CMDDMC)) break; } if((timeout == 0) || (status & SDIO_CLR_MMC_INT_CRNTMC)) { //timeout errorstatus = SD_CMD_RSP_TIMEOUT; SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CRNTMC; return errorstatus; } if(status & SDIO_CLR_MMC_INT_CMDDMC) { errorstatus = SD_OK; SDIO->CLR_MMC_INT = SDIO_CLR_MMC_INT_CMDDMC; } return errorstatus; } //////////////////////////////////////////////////////////////////////////////// /// @brief Write data direction block size configuration. /// @param datatimeout : maximum latency. /// datalen : data len /// blksize : block count. /// dir : direction /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_Send_Data_Cfg(u32 datatimeout, u32 datalen, u8 blksize, u8 dir) { u32 tmpreg, tmpreg1, tmpreg2 = 0; tmpreg = SDIO->MMC_IO_MBCTL; tmpreg1 = SDIO->MMC_IO; tmpreg &= ~(SDIO_MMC_IO_MBCTL_BTSSel | SDIO_MMC_IO_MBCTL_SPMBDTR | SDIO_MMC_IO_MBCTL_SMBDTD); if (datatimeout < 100) { SDIO->MMC_TIMEOUTCNT = datatimeout; } else if (datatimeout < 10000) { SDIO->MMC_TIMEOUTCNT = datatimeout / 100; tmpreg |= SDIO_MMC_IO_MBCTL_BTSSel; } else if (datatimeout < 1000000) { SDIO->MMC_TIMEOUTCNT = datatimeout / 10000; tmpreg |= SDIO_MMC_IO_MBCTL_BTSSel_2; } else { SDIO->MMC_TIMEOUTCNT = datatimeout / 1000000; tmpreg |= SDIO_MMC_IO_MBCTL_BTSSel; } SDIO->MMC_BYTECNTL = datalen & 0x1FFFFFF; ; SDIO->MMC_BLOCKCNT = blksize; if (dir == 0) { tmpreg |= SDIO_MMC_IO_MBCTL_SMBDTD; tmpreg1 |= SDIO_MMC_IO_TRANSFDIR; tmpreg2 |= SDIO_BUF_CTLL_SBAD; } else { tmpreg &= ~(SDIO_MMC_IO_MBCTL_SMBDTD); tmpreg1 &= ~(SDIO_MMC_IO_TRANSFDIR); tmpreg2 &= ~(SDIO_BUF_CTLL_SBAD); } SDIO->MMC_IO_MBCTL = tmpreg; SDIO->MMC_IO = tmpreg1; SDIO->BUF_CTL = tmpreg2; } //////////////////////////////////////////////////////////////////////////////// /// @brief Clears the SDIO's Flag pending bits. /// @param SDIO_IT: specifies the flag pending bit to clear. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_ClearFlag(u32 SDIO_FLAG) { SDIO->CLR_MMC_INT |= SDIO_FLAG; } //////////////////////////////////////////////////////////////////////////////// /// @brief Clears the SDIO's interrupt pending bits. /// @param SDIO_IT: specifies the interrupt pending bit to clear. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_ClearITPendingBit(u32 SDIO_IT) { SDIO->CLR_MMC_INT |= SDIO_IT; } //////////////////////////////////////////////////////////////////////////////// /// @brief Checks whether the specified SDIO flag is set or not. /// @param SDIO_FLAG: specifies the flag to check. /// @retval The new state of SDIO_FLAG (SET or RESET). //////////////////////////////////////////////////////////////////////////////// FlagStatus SDIO_GetFlagStatus(u32 SDIO_FLAG) { return ((SDIO->CLR_MMC_INT & SDIO_FLAG) ? SET : RESET); } //////////////////////////////////////////////////////////////////////////////// /// @brief Reads the value of the data transfer timeout count /// @param None. /// @retval timeout count. //////////////////////////////////////////////////////////////////////////////// u32 SDIO_GetTimeOutCounter(void) { return (SDIO->MMC_TIMEOUTCNT & 0xFF); } //////////////////////////////////////////////////////////////////////////////// /// @brief Read one data word from FIFO. /// @param None. /// @retval Data received. //////////////////////////////////////////////////////////////////////////////// u32 SDIO_ReadData(void) { return SDIO->FIFO; } //////////////////////////////////////////////////////////////////////////////// /// @brief Write one data word to FIFO. /// @param tempbuff : Write data. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_WriteData(u32 tempbuff) { SDIO->FIFO = tempbuff; } //////////////////////////////////////////////////////////////////////////////// /// @brief Returns number of remaining data bytes to be transferred. /// @param None /// @retval Number of remaining data bytes to be transferred //////////////////////////////////////////////////////////////////////////////// u32 SDIO_GetDataCounter(void) { return SDIO->MMC_BYTECNTL; } //////////////////////////////////////////////////////////////////////////////// /// @brief Enable or Dsiable DMA . /// @param tempbuff : Write data. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void SDIO_DMACmd(FunctionalState state) { (state) ? ((SDIO->BUF_CTL |= SDIO_BUF_CTLL_DMAHEN), SDIO->BUF_CTL &= (~(SDIO_BUF_CTLL_DRM))) : (SDIO->BUF_CTL &= ~SDIO_BUF_CTLL_DMAHEN); } /// @} /// @} /// @}