#include "emmc_driver.h" #include #define DEBUG 1 #if DEBUG #define DBG(...) printf(__VA_ARGS__) #define DBGNOIRQ(...) { __disable_irq(); printf(__VA_ARGS__); __enable_irq(); } while (0) #define TRACE do { __disable_irq(); printf("%s:%d\n", __PRETTY_FUNCTION__, __LINE__); __enable_irq(); } while (0) #define TRACE1(x) do { __disable_irq(); printf("%s:%d %s\n", __PRETTY_FUNCTION__, __LINE__,x); __enable_irq(); } while (0) const char *sd_strerror[] = { "SD OK", "CMD_CRC_FAIL", "DATA_CRC_FAIL", "CMD_RSP_TIMEOUT", "DATA_TIMEOUT", "TX_UNDERRUN", "RX_OVERRUN", "START_BIT_ERR", "CMD_OUT_OF_RANGE", "ADDR_MISALIGNED", "BLOCK_LEN_ERR", "ERASE_SEQ_ERR", "BAD_ERASE_PARAM", "WRITE_PROT_VIOLATION", "LOCK_UNLOCK_FAILED", "COM_CRC_FAILED", "ILLEGAL_CMD", "CARD_ECC_FAILED", "CC_ERROR", "GENERAL_UNKNOWN_ERROR", "STREAM_READ_UNDERRUN", "STREAM_WRITE_OVERRUN", "CID_CSD_OVERWRITE", "WP_ERASE_SKIP", "CARD_ECC_DISABLED", "ERASE_RESET", "AKE_SEQ_ERROR", "INVALID_VOLTRANGE", "ADDR_OUT_OF_RANGE", "SWITCH_ERROR", "SDIO_DISABLED", "SDIO_FUNCTION_BUSY", "SDIO_FUNCTION_FAILED", "SDIO_UNKNOWN_FUNCTION", "INTERNAL_ERROR", "NOT_CONFIGURED", "REQUEST_PENDING", "REQUEST_NOT_APPLICABLE", "INVALID_PARAMETER", "UNSUPPORTED_FEATURE", "UNSUPPORTED_HW", "ERROR", }; #else #define DBG(...) #define TRACE do { ; } while (0) #define TRACE1(x) do { ; } while (0) #endif typedef struct { uint8_t SuppCmdSet; uint8_t IntTimeoutAp; uint8_t Pwr_CL_DDR_52_360; uint8_t Pwr_CL_DDR_52_195; uint8_t MinPerf_DDR_W_8_52; uint8_t MinPerf_DDR_R_8_52; uint8_t TrimMult; uint8_t SecFeatureSupp; uint8_t SecEraseMult; uint8_t SecTrimMult; uint8_t BootInfo; uint8_t BootSizeMulti; uint8_t AccSize; uint8_t HC_EraseGrpSize; uint8_t EraseTimeoutMult; uint8_t RelWrSecCnt; uint8_t HC_WpGrpSize; uint8_t SlpCurrVCC; uint8_t SlpCurrVCCQ; uint8_t SA_Timeout; uint32_t SecCount; uint8_t MinPerf_W_8_52; uint8_t MinPerf_R_8_52; uint8_t MinPerf_W_8_26; uint8_t MinPerf_R_8_26; uint8_t MinPerf_W_4_26; uint8_t MinPerf_R_4_26; uint8_t PwrCl_26_360; uint8_t PwrCl_52_360; uint8_t PwrCl_26_195; uint8_t PwrCl_52_195; uint8_t CardType; uint8_t CsdStructVersion; uint8_t ExtCsdRev; uint8_t CmdSet; uint8_t CmdSetRev; uint8_t PwrCl; uint8_t HsTiming; uint8_t BusWidth; uint8_t ErasedMemCont; uint8_t PartitionConf; uint8_t BootConfigProt; uint8_t BootBusWidth; uint8_t EraseGroupDef; uint8_t BootWp; uint8_t UserWp; uint8_t FwConfig; uint8_t RpmbSizeMult; uint8_t RST_n_Function; uint8_t PartSupport; uint32_t MaxEnhSizeMult; uint8_t PartitionsAttr; uint8_t PartSettingCompl; uint8_t GpSizeMult[12]; uint32_t EnhSizeMult; uint32_t EnhStartAddr; uint8_t SecBadBlkMgmnt; } HAL_SD_Ext_CSDTypedef; /* SDMMC Initialization Frequency (f = 48M / (div+2) => 400KHz max) */ #define MMC_INIT_CLK_DIV ((uint8_t)0x76) /* SDMMC Data Transfer Frequency (f = 48M / (div+2) => 12MHz max) */ //#define MMC_TRANSFER_CLK_DIV ((uint8_t)0x2) /* SDMMC Data Transfer Frequency (f = 48M / (div+2) => 12MHz max) */ #define MMC_TRANSFER_CLK_DIV ((uint8_t)0x76) #define SD_CMD_SD_ERASE_GRP_START_CURRENT ((uint8_t)0x35) #define SD_CMD_SD_ERASE_GRP_END_CURRENT ((uint8_t)0x36) #define SDMMC_CMD0TIMEOUT ((uint32_t)0x00010000) #define SD_ALLZERO ((uint32_t)0x00000000) #define SD_OCR_ADDR_OUT_OF_RANGE ((uint32_t)0x80000000) #define SD_OCR_ADDR_MISALIGNED ((uint32_t)0x40000000) #define SD_OCR_BLOCK_LEN_ERR ((uint32_t)0x20000000) #define SD_OCR_ERASE_SEQ_ERR ((uint32_t)0x10000000) #define SD_OCR_BAD_ERASE_PARAM ((uint32_t)0x08000000) #define SD_OCR_WRITE_PROT_VIOLATION ((uint32_t)0x04000000) #define SD_OCR_LOCK_UNLOCK_FAILED ((uint32_t)0x01000000) #define SD_OCR_COM_CRC_FAILED ((uint32_t)0x00800000) #define SD_OCR_ILLEGAL_CMD ((uint32_t)0x00400000) #define SD_OCR_CARD_ECC_FAILED ((uint32_t)0x00200000) #define SD_OCR_CC_ERROR ((uint32_t)0x00100000) #define SD_OCR_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00080000) #define SD_OCR_STREAM_READ_UNDERRUN ((uint32_t)0x00040000) #define SD_OCR_STREAM_WRITE_OVERRUN ((uint32_t)0x00020000) #define SD_OCR_CID_CSD_OVERWRITE ((uint32_t)0x00010000) #define SD_OCR_WP_ERASE_SKIP ((uint32_t)0x00008000) #define SD_OCR_CARD_ECC_DISABLED ((uint32_t)0x00004000) #define SD_OCR_ERASE_RESET ((uint32_t)0x00002000) #define SD_OCR_AKE_SEQ_ERROR ((uint32_t)0x00000008) #define SD_OCR_ERRORBITS ((uint32_t)0xFDFFE008) #define SDMMC_STATIC_FLAGS ((uint32_t)(SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_CTIMEOUT |\ SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_RXOVERR |\ SDMMC_FLAG_CMDREND | SDMMC_FLAG_CMDSENT | SDMMC_FLAG_DATAEND |\ SDMMC_FLAG_DBCKEND)) const char* emmc_state(uint32_t state); static void emmc_check_cmd_error(const char *cmd, HAL_SD_ErrorTypedef return_value, const char* resp_str); static uint8_t emmc_card_init(void); static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd); static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD); static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd); static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd); static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus); static void EMMC_SD_Get_CardInfo(const uint8_t ExtCsdBuf[512], HAL_SD_Ext_CSDTypedef *sExtCSD); SD_HandleTypeDef mmcHandle; static HAL_SD_CardInfoTypedef mmcCardInfo; static HAL_SD_Ext_CSDTypedef mmcExtCSD; /** * @brief Initializes the emmc device. * @retval emmc status */ uint8_t emmc_init(void) { uint8_t sd_state = MSD_OK; // emmc device interface configuration mmcHandle.Instance = SDMMC1; mmcHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; mmcHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; mmcHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; mmcHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; mmcHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; mmcHandle.Init.ClockDiv = SDMMC_INIT_CLK_DIV; // Msp emmc initialization emmc_msp_init(&mmcHandle, NULL); SDMMC_PowerState_OFF(mmcHandle.Instance); SDMMC_Init(mmcHandle.Instance, mmcHandle.Init); SDMMC_PowerState_ON(mmcHandle.Instance); __SDMMC_ENABLE(mmcHandle.Instance); HAL_Delay(2); // HAL emmc initialization if(emmc_card_init() == SD_OK) { sd_state = MSD_OK; } else { sd_state = MSD_ERROR; } return sd_state; } /** * @brief DeInitializes the emmc device * @retval emmc status */ uint8_t emmc_deinit(void) { uint8_t sd_state = MSD_OK; mmcHandle.Instance = SDMMC1; // HAL MMC deinitialization if(HAL_SD_DeInit(&mmcHandle) != HAL_OK) { sd_state = MSD_ERROR; } // Msp MMC deinitialization mmcHandle.Instance = SDMMC1; emmc_msp_deinit(&mmcHandle, NULL); return sd_state; } /** * @brief Reads block(s) from a specified address in an SD card, in polling mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param ReadAddr: Address from where data is to be read * @param BlockSize: SD card data block size, that should be 512 * @param NumOfBlocks: Number of SD blocks to read * @retval SD status */ uint8_t emmc_read_blocks(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks) { if(HAL_SD_ReadBlocks(&mmcHandle, pData, ReadAddr, BlockSize, NumOfBlocks) != SD_OK) { return MSD_ERROR; } else { return MSD_OK; } } /** * @brief Writes block(s) to a specified address in polling mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param WriteAddr: Address from where data is to be written * @param BlockSize: data block size, that should be 512 * @param NumOfBlocks: Number of blocks to write * @retval SD status */ uint8_t emmc_write_blocks(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks) { if(HAL_SD_WriteBlocks(&mmcHandle, pData, WriteAddr, BlockSize, NumOfBlocks) != SD_OK) { return MSD_ERROR; } else { return MSD_OK; } } /** * @brief Reads block(s) from a specified address in DMA mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param ReadAddr: Address from where data is to be read * @param BlockSize: data block size, that should be 512 * @param NumOfBlocks: Number of blocks to read * @retval SD status */ uint8_t emmc_read_blocks_dma(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks) { uint8_t sd_state = MSD_OK; // Read block(s) in DMA transfer mode if(HAL_SD_ReadBlocks_DMA(&mmcHandle, pData, ReadAddr, BlockSize, NumOfBlocks) != SD_OK) { sd_state = MSD_ERROR; } // Wait until transfer is complete if(sd_state == MSD_OK) { if(HAL_SD_CheckReadOperation(&mmcHandle, (uint32_t)SD_DATATIMEOUT) != SD_OK) { sd_state = MSD_ERROR; } else { sd_state = MSD_OK; } } return sd_state; } /** * @brief Writes block(s) to a specified address in DMA mode. * @param pData: Pointer to the buffer that will contain the data to transmit * @param WriteAddr: Address from where data is to be written * @param BlockSize: data block size, that should be 512 * @param NumOfBlocks: Number of blocks to write * @retval SD status */ uint8_t emmc_write_blocks_dma(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks) { uint8_t sd_state = MSD_OK; // Write block(s) in DMA transfer mode if(HAL_SD_WriteBlocks_DMA(&mmcHandle, pData, WriteAddr, BlockSize, NumOfBlocks) != SD_OK) { sd_state = MSD_ERROR; } // Wait until transfer is complete if(sd_state == MSD_OK) { if(HAL_SD_CheckWriteOperation(&mmcHandle, (uint32_t)SD_DATATIMEOUT) != SD_OK) { sd_state = MSD_ERROR; } else { sd_state = MSD_OK; } } return sd_state; } /** * @brief Erases the specified memory area * @param StartAddr: Start byte address * @param EndAddr: End byte address * @retval SD status */ uint8_t emmc_erase(uint64_t StartAddr, uint64_t EndAddr) { HAL_SD_ErrorTypedef errorstate = SD_OK; SDMMC_CmdInitTypeDef sd_cmd; return HAL_SD_Erase(&mmcHandle, StartAddr, EndAddr); uint32_t delay = 0; __IO uint32_t maxdelay = 0; uint8_t cardstate = 0; /* Get max delay value */ maxdelay = 120000 / (((mmcHandle.Instance->CLKCR) & 0xFF) + 2); if ((SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) { errorstate = SD_LOCK_UNLOCK_FAILED; return errorstate; } /* Get start and end block for high capacity cards */ if (mmcHandle.CardType == HIGH_CAPACITY_SD_CARD) { StartAddr /= 512; EndAddr /= 512; } TRACE; /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */ if ((mmcHandle.CardType == STD_CAPACITY_SD_CARD_V1_1) || (mmcHandle.CardType == STD_CAPACITY_SD_CARD_V2_0) || (mmcHandle.CardType == HIGH_CAPACITY_SD_CARD)) { /* Send CMD32 SD_ERASE_GRP_START with argument as addr */ sd_cmd.Argument = (uint32_t) StartAddr; sd_cmd.CmdIndex = SD_CMD_SD_ERASE_GRP_START_CURRENT; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); /* Check for error conditions */ errorstate = SD_CmdResp1Error(&mmcHandle, SD_CMD_SD_ERASE_GRP_START_CURRENT); if (errorstate != SD_OK) { TRACE1("SD_ERASE_GRP_START_CURRENT"); return errorstate; } /* Send CMD33 SD_ERASE_GRP_END with argument as addr */ sd_cmd.Argument = (uint32_t) EndAddr; sd_cmd.CmdIndex = SD_CMD_SD_ERASE_GRP_END_CURRENT; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); /* Check for error conditions */ errorstate = SD_CmdResp1Error(&mmcHandle, SD_CMD_SD_ERASE_GRP_END_CURRENT); if (errorstate != SD_OK) { TRACE1("SD_ERASE_GRP_END_CURRENT"); return errorstate; } /* Send CMD38 ERASE */ sd_cmd.Argument = 0; sd_cmd.CmdIndex = SD_CMD_ERASE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); /* Check for error conditions */ errorstate = SD_CmdResp1Error(&mmcHandle, SD_CMD_ERASE); if (errorstate != SD_OK) { TRACE; return errorstate; } for (delay=0; delay <= maxdelay; delay++) { } /* Wait until the card is in programming state */ errorstate = SD_IsCardProgramming(&mmcHandle, &cardstate); delay = SD_DATATIMEOUT; while ((delay > 0) && (errorstate == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))) { errorstate = SD_IsCardProgramming(&mmcHandle, &cardstate); delay--; } TRACE; return errorstate; } else { return SD_UNSUPPORTED_FEATURE; } } /** * @brief Initializes the SD MSP. * @param hsd: SD handle * @param Params * @retval None */ void emmc_msp_init(SD_HandleTypeDef *hsd, void *Params) { static DMA_HandleTypeDef dma_rx_handle; static DMA_HandleTypeDef dma_tx_handle; GPIO_InitTypeDef gpio_init_structure; __HAL_RCC_CLK48_CONFIG(RCC_CLK48SOURCE_PLL); __HAL_RCC_SDMMC1_CONFIG(RCC_SDMMC1CLKSOURCE_CLK48); // Enable clock __HAL_RCC_SDMMC1_CLK_ENABLE(); // Enable DMA2 clocks __DMAx_TxRx_CLK_ENABLE(); // Enable GPIOs clock __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); // reset SDMMC1 __HAL_RCC_SDMMC1_FORCE_RESET(); __HAL_RCC_SDMMC1_RELEASE_RESET(); // PORT B #define EMMC__D4 GPIO_PIN_8 #define EMMC__D5 GPIO_PIN_9 // PORT C #define EMMC__D0 GPIO_PIN_8 #define EMMC__D1 GPIO_PIN_9 #define EMMC__D2 GPIO_PIN_10 #define EMMC__D3 GPIO_PIN_11 #define EMMC__D6 GPIO_PIN_6 #define EMMC__D7 GPIO_PIN_7 #define EMMC__CLK GPIO_PIN_12 // PORT D #define EMMC__CMD GPIO_PIN_2 // Common GPIO configuration gpio_init_structure.Mode = GPIO_MODE_AF_PP; gpio_init_structure.Pull = GPIO_PULLUP; gpio_init_structure.Speed = GPIO_SPEED_HIGH; gpio_init_structure.Alternate = GPIO_AF12_SDMMC1; // GPIO B configuration gpio_init_structure.Pin = EMMC__D4 | EMMC__D5; HAL_GPIO_Init(GPIOB, &gpio_init_structure); // GPIO C configuration gpio_init_structure.Pin = EMMC__D0 | EMMC__D1 | EMMC__D2 | EMMC__D3 | EMMC__D6 | EMMC__D7 | EMMC__CLK; HAL_GPIO_Init(GPIOC, &gpio_init_structure); // GPIO D configuration gpio_init_structure.Pin = EMMC__CMD; HAL_GPIO_Init(GPIOD, &gpio_init_structure); DBG("MMC and GPIO clocks enabled\n"); /* NVIC configuration for SDIO interrupts */ HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); HAL_NVIC_EnableIRQ(SDMMC1_IRQn); /* Configure DMA Rx parameters */ dma_rx_handle.Init.Channel = SD_DMAx_Rx_CHANNEL; dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; dma_rx_handle.Init.Mode = DMA_PFCTRL; dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; dma_rx_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; // DMA_PBURST_INC4; dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; /* Associate the DMA handle */ __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); /* Deinitialize the stream for new transfer */ HAL_DMA_DeInit(&dma_rx_handle); /* Configure the DMA stream */ HAL_DMA_Init(&dma_rx_handle); /* Configure DMA Tx parameters */ dma_tx_handle.Init.Channel = SD_DMAx_Tx_CHANNEL; dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; dma_tx_handle.Init.Mode = DMA_PFCTRL; dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; /* Associate the DMA handle */ __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); /* Deinitialize the stream for new transfer */ HAL_DMA_DeInit(&dma_tx_handle); /* Configure the DMA stream */ HAL_DMA_Init(&dma_tx_handle); /* NVIC configuration for DMA transfer complete interrupt */ HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 6, 0); HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); /* NVIC configuration for DMA transfer complete interrupt */ HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 6, 0); HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); DBG("emmc_msp_init done\n"); } /** * @brief DeInitializes the SD MSP. * @param hsd: SD handle * @param Params * @retval None */ __weak void emmc_msp_deinit(SD_HandleTypeDef *hsd, void *Params) { static DMA_HandleTypeDef dma_rx_handle; static DMA_HandleTypeDef dma_tx_handle; /* Disable NVIC for DMA transfer complete interrupts */ HAL_NVIC_DisableIRQ(SD_DMAx_Rx_IRQn); HAL_NVIC_DisableIRQ(SD_DMAx_Tx_IRQn); /* Deinitialize the stream for new transfer */ dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; HAL_DMA_DeInit(&dma_rx_handle); /* Deinitialize the stream for new transfer */ dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; HAL_DMA_DeInit(&dma_tx_handle); /* Disable NVIC for SDIO interrupts */ HAL_NVIC_DisableIRQ(SDMMC1_IRQn); /* DeInit GPIO pins can be done in the application (by surcharging this __weak function) */ /* Disable SDMMC1 clock */ __HAL_RCC_SDMMC1_CLK_DISABLE(); } /** * @brief Handles DMA Tx transfer interrupt request. * @retval None */ void SD_DMAx_Tx_IRQHandler(void) { //printf("T\n"); HAL_DMA_IRQHandler(mmcHandle.hdmatx); } /** * @brief Handles DMA Rx transfer interrupt request. * @retval None */ void SD_DMAx_Rx_IRQHandler(void) { //printf("R\n"); HAL_DMA_IRQHandler(mmcHandle.hdmarx); } /** * @brief This function handles SDIO interrupt request. * @param None * @retval None */ void SDMMC1_IRQHandler(void) { //printf("M\n"); HAL_SD_IRQHandler(&mmcHandle); } /** * @brief Gets the current data status. * @retval Data transfer state. * This value can be one of the following values: * @arg SD_TRANSFER_OK: No data transfer is acting * @arg SD_TRANSFER_BUSY: Data transfer is acting * @arg SD_TRANSFER_ERROR: Data transfer error */ HAL_SD_TransferStateTypedef emmc_get_status(void) { return(HAL_SD_GetStatus(&mmcHandle)); } /** * @brief Get information about specific mmc device * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure * @retval None */ HAL_SD_ErrorTypedef emmc_get_info(HAL_SD_CardInfoTypedef *CardInfo) { HAL_SD_ErrorTypedef rv = HAL_SD_Get_CardInfo(&mmcHandle, CardInfo); CardInfo->CardCapacity = mmcExtCSD.SecCount * 512; return rv; } /** * @brief Initializes the emmc device. * @retval emmc status */ static uint8_t emmc_card_init(void) { SDMMC_CmdInitTypeDef sd_cmd; SDMMC_DataInitTypeDef sd_data; HAL_SD_ErrorTypedef rv; uint8_t ExtCsdBuf[512]; // CMD0: GO_IDLE_STATE ---------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_GO_IDLE_STATE; sd_cmd.Argument = 0; sd_cmd.Response = SDMMC_RESPONSE_NO; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdError(&mmcHandle); emmc_check_cmd_error("CMD0 (GO_IDLE_STATE)", rv, 0); mmcHandle.RCA = 3; HAL_Delay(1); do { // CMD1: SEND_OP_COND --------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEND_OP_COND; sd_cmd.Argument = 0x40FF8080; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp3Error(&mmcHandle); emmc_check_cmd_error("CMD1 (SEND_OP_COND)", rv, 0); HAL_Delay(1); } while (!(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1) & OCR_READY)); // CMD2: ALL_SEND_CID ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_ALL_SEND_CID; sd_cmd.Argument = 0; sd_cmd.Response = SDMMC_RESPONSE_LONG; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp2Error(&mmcHandle); emmc_check_cmd_error("CMD2 (ALL_SEND_CID)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); mmcHandle.CID[0] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1); mmcHandle.CID[1] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP2); mmcHandle.CID[2] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP3); mmcHandle.CID[3] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP4); // CMD3: SET_REL_ADDR ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SET_REL_ADDR; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; //0x00; // sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, sd_cmd.CmdIndex); emmc_check_cmd_error("CMD3 (SET_REL_ADDR)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); // CMD9: SEND_CSD ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEND_CSD; sd_cmd.Argument = (mmcHandle.RCA << 16); sd_cmd.Response = SDMMC_RESPONSE_LONG; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp2Error(&mmcHandle); emmc_check_cmd_error("CMD9 (SEND_CSD)", rv, 0); /* Get Card Specific Data */ mmcHandle.CSD[0] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1); mmcHandle.CSD[1] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP2); mmcHandle.CSD[2] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP3); mmcHandle.CSD[3] = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP4); // CMD7: SEL_DESEL_CARD --------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEL_DESEL_CARD; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp2Error(&mmcHandle); emmc_check_cmd_error("CMD7 (*SEL*_DESEL_CARD)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); // CMD8: SEND_EXT_CSD ----------------------------------------------------- /* clear error flags */ __HAL_SD_SDMMC_CLEAR_FLAG(&mmcHandle, SDMMC_STATIC_FLAGS); sd_data.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; sd_data.DataLength = 512; sd_data.DataTimeOut = (512 + 128) * 8; sd_data.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; sd_data.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; sd_data.DPSM = SDMMC_DPSM_ENABLE; sd_cmd.CmdIndex = SD_CMD_HS_SEND_EXT_CSD; sd_cmd.Argument = 0; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_DataConfig(mmcHandle.Instance, &sd_data); SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, sd_cmd.CmdIndex); emmc_check_cmd_error("CMD8 (SEND_EXT_CSD)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); DBG("reading EXT CSD START "); for (unsigned count = 0; count < (512 >> 2); count++) { if ((count & 0x31) == 0) DBG("."); while (mmcHandle.Instance->STA & SDMMC_STA_RXFIFOE) { if (mmcHandle.Instance->STA & (SDMMC_STA_DATAEND | SDMMC_STA_RXOVERR | SDMMC_STA_DTIMEOUT | SDMMC_STA_DCRCFAIL)) { DBG("SD STATUS: pos:%d 0x%08x\n", count, (unsigned)mmcHandle.Instance->STA); while (1) ; } } ((uint32_t*) ExtCsdBuf)[count] = mmcHandle.Instance->FIFO; } DBG(" DONE\n"); // CMD13: SEND_STATUS ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEND_STATUS; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, sd_cmd.CmdIndex); emmc_check_cmd_error("CMD13 (SEND_STATUS)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); HAL_SD_Get_CardInfo(&mmcHandle, &mmcCardInfo); EMMC_SD_Get_CardInfo(ExtCsdBuf, &mmcExtCSD); mmcHandle.CardType = HIGH_CAPACITY_SD_CARD; mmcCardInfo.CardCapacity = mmcExtCSD.SecCount * 512; #if 0 emmc_debug_csd(&sSdCardInfo.SD_csd); emmc_debug_ext_csd(&sExtCSD); emmd_debug_cid(&sSdCardInfo.SD_cid); #endif #if 0 // CMD7: SEL_DESEL_CARD --------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEL_DESEL_CARD; sd_cmd.Argument = 0 | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp2Error(&mmcHandle); __HAL_SD_SDMMC_CLEAR_FLAG(&mmcHandle, SDMMC_STATIC_FLAGS); emmc_check_cmd_error("CMD7 (SEL_*DESEL*_CARD)", SD_OK, emmc_state(SDMMC_GetResponse(SDMMC_RESP1))); // CMD7: SEL_DESEL_CARD --------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEL_DESEL_CARD; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp2Error(&mmcHandle); emmc_check_cmd_error("CMD7 (*SEL*_DESEL_CARD)", rv, emmc_state(SDMMC_GetResponse(SDMMC_RESP1))); // CMD13: SEND_STATUS ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEND_STATUS; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, sd_cmd.CmdIndex); emmc_check_cmd_error("CMD13 (SEND_STATUS)", rv, emmc_state(SDMMC_GetResponse(SDMMC_RESP1))); #endif #if 1 // not use 8 bit WO DMA => overrun // CMD6: SWITCH ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SWITCH; sd_cmd.Argument = (SD_CMD_SWITCH_WRITE_BYTE << 24) | (SD_ECSD_BUS_WIDTH << 16) | (SD_ECSD_BUS_WIDTH_8B << 8); sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, SD_CMD_SWITCH); emmc_check_cmd_error("CMD6 (SWITCH)", rv, emmc_state(SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1))); // set interface bus width to 8 b mmcHandle.Init.BusWide = SDMMC_BUS_WIDE_8B; // " 2 to set MMC clk to 24 MHz (=48MHz / 2) mmcHandle.Init.ClockDiv = MMC_TRANSFER_CLK_DIV; #if 0 uint32_t tmpreg = ( mmcHandle.Init.ClockEdge |\ mmcHandle.Init.ClockBypass |\ mmcHandle.Init.ClockPowerSave |\ mmcHandle.Init.BusWide |\ mmcHandle.Init.HardwareFlowControl |\ mmcHandle.Init.ClockDiv); DBG("CLKCR: 0x%08x\n", tmpreg); #endif SDMMC_PowerState_OFF(mmcHandle.Instance); SDMMC_Init(mmcHandle.Instance, mmcHandle.Init); SDMMC_PowerState_ON(mmcHandle.Instance); __SDMMC_ENABLE(mmcHandle.Instance); #endif // CMD13: SEND_STATUS ----------------------------------------------------- sd_cmd.CmdIndex = SD_CMD_SEND_STATUS; sd_cmd.Argument = (mmcHandle.RCA << 16) | 0xFFFF; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); rv = SD_CmdResp1Error(&mmcHandle, sd_cmd.CmdIndex); emmc_check_cmd_error("CMD13 (SEND_STATUS)", rv, 0); rv = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1); DBG("SDMMC SEND_STATUS: 0x%x\n", rv); #if 0 if (res != TRANSFER_AND_READY) { TRACE; DBG("Error: SEND_STATUS != TRANSFER_AND_READY\n"); return 1; } #endif DBG("eMMC INIT OK\n"); return 0; } const char* emmc_state(uint32_t state) { static const char *state_map[] = { "Idle", "Ready", "Ident", "Stby", "Tran", "Data", "Rcv", "Prg", "Dis", "Btst", "Smp", "undef", "undef", "undef", "undef", "undef" }; static char rv[128]; sprintf(rv, "%s, rdy:%c, swe:%c", state_map[(state>>9) & 0xf], (state & (1<<8)) ? 'y' : 'n', (state & (1<<7)) ? 'y' : 'n'); return rv; } static void emmc_check_cmd_error(const char *cmd, HAL_SD_ErrorTypedef return_value, const char* resp_str) { if (return_value != SD_OK) { DBG("%s: ERROR %d (%s)", cmd, return_value, sd_strerror[return_value]); if (resp_str) DBG(" [%s]", resp_str); DBG("\n"); while(1); } else { DBG("%s: SUCCESS", cmd); if (resp_str) DBG(" [%s]", resp_str); DBG("\n"); } } /** * @brief Checks for error conditions for CMD0. * @param hsd: SD handle * @retval SD Card error state */ static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd) { HAL_SD_ErrorTypedef errorstate = SD_OK; uint32_t timeout, tmp; timeout = SDMMC_CMD0TIMEOUT; tmp = __HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CMDSENT); while((timeout > 0) && (!tmp)) { tmp = __HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CMDSENT); timeout--; } if(timeout == 0) { errorstate = SD_CMD_RSP_TIMEOUT; return errorstate; } /* Clear all the static flags */ __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); return errorstate; } /** * @brief Checks for error conditions for R1 response. * @param hsd: SD handle * @param SD_CMD: The sent command index * @retval SD Card error state */ static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD) { HAL_SD_ErrorTypedef errorstate = SD_OK; uint32_t response_r1; while (!__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) { } if (__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CTIMEOUT)) { errorstate = SD_CMD_RSP_TIMEOUT; __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_FLAG_CTIMEOUT); return errorstate; } else if (__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CCRCFAIL)) { errorstate = SD_CMD_CRC_FAIL; __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_FLAG_CCRCFAIL); return errorstate; } /* Check response received is of desired command */ if (SDMMC_GetCommandResponse(hsd->Instance) != SD_CMD) { errorstate = SD_ILLEGAL_CMD; return errorstate; } /* Clear all the static flags */ __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); /* We have received response, retrieve it for analysis */ response_r1 = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); if ((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO) { return errorstate; } if ((response_r1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) { return (SD_ADDR_OUT_OF_RANGE); } if ((response_r1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) { return (SD_ADDR_MISALIGNED); } if ((response_r1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) { return (SD_BLOCK_LEN_ERR); } if ((response_r1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) { return (SD_ERASE_SEQ_ERR); } if ((response_r1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) { return (SD_BAD_ERASE_PARAM); } if ((response_r1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) { return (SD_WRITE_PROT_VIOLATION); } if ((response_r1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) { return (SD_LOCK_UNLOCK_FAILED); } if ((response_r1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) { return (SD_COM_CRC_FAILED); } if ((response_r1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) { return (SD_ILLEGAL_CMD); } if ((response_r1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) { return (SD_CARD_ECC_FAILED); } if ((response_r1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) { return (SD_CC_ERROR); } if ((response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) { return (SD_GENERAL_UNKNOWN_ERROR); } if ((response_r1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) { return (SD_STREAM_READ_UNDERRUN); } if ((response_r1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) { return (SD_STREAM_WRITE_OVERRUN); } if ((response_r1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) { return (SD_CID_CSD_OVERWRITE); } if ((response_r1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) { return (SD_WP_ERASE_SKIP); } if ((response_r1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) { return (SD_CARD_ECC_DISABLED); } if ((response_r1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) { return (SD_ERASE_RESET); } if ((response_r1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) { return (SD_AKE_SEQ_ERROR); } return errorstate; } /** * @brief Checks for error conditions for R2 (CID or CSD) response. * @param hsd: SD handle * @retval SD Card error state */ static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd) { HAL_SD_ErrorTypedef errorstate = SD_OK; while (!__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) { } if (__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CTIMEOUT)) { errorstate = SD_CMD_RSP_TIMEOUT; __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_FLAG_CTIMEOUT); return errorstate; } else if (__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CCRCFAIL)) { errorstate = SD_CMD_CRC_FAIL; __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_FLAG_CCRCFAIL); return errorstate; } else { /* No error flag set */ } /* Clear all the static flags */ __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); return errorstate; } /** * @brief Checks for error conditions for R3 (OCR) response. * @param hsd: SD handle * @retval SD Card error state */ static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd) { HAL_SD_ErrorTypedef errorstate = SD_OK; while (!__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) { } if (__HAL_SD_SDMMC_GET_FLAG(hsd, SDMMC_FLAG_CTIMEOUT)) { errorstate = SD_CMD_RSP_TIMEOUT; __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_FLAG_CTIMEOUT); return errorstate; } /* Clear all the static flags */ __HAL_SD_SDMMC_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); return errorstate; } /** * @brief Checks if the SD card is in programming state. * @param hsd: SD handle * @param pStatus: pointer to the variable that will contain the SD card state * @retval SD Card error state */ static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus) { SDMMC_CmdInitTypeDef sd_cmd; HAL_SD_ErrorTypedef errorstate = SD_OK; __IO uint32_t responseR1 = 0; sd_cmd.Argument = (uint32_t)(hsd->RCA << 16); sd_cmd.CmdIndex = SD_CMD_SEND_STATUS; sd_cmd.Response = SDMMC_RESPONSE_SHORT; sd_cmd.WaitForInterrupt = SDMMC_WAIT_NO; sd_cmd.CPSM = SDMMC_CPSM_ENABLE; SDMMC_SendCommand(mmcHandle.Instance, &sd_cmd); while (!__HAL_SD_SDMMC_GET_FLAG(&mmcHandle, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT)) { } if (__HAL_SD_SDMMC_GET_FLAG(&mmcHandle, SDMMC_FLAG_CTIMEOUT)) { errorstate = SD_CMD_RSP_TIMEOUT; __HAL_SD_SDMMC_CLEAR_FLAG(&mmcHandle, SDMMC_FLAG_CTIMEOUT); return errorstate; } else if (__HAL_SD_SDMMC_GET_FLAG(&mmcHandle, SDMMC_FLAG_CCRCFAIL)) { errorstate = SD_CMD_CRC_FAIL; __HAL_SD_SDMMC_CLEAR_FLAG(&mmcHandle, SDMMC_FLAG_CCRCFAIL); return errorstate; } else { /* No error flag set */ } /* Check response received is of desired command */ if ((uint32_t) SDMMC_GetCommandResponse(mmcHandle.Instance) != SD_CMD_SEND_STATUS) { errorstate = SD_ILLEGAL_CMD; return errorstate; } /* Clear all the static flags */ __HAL_SD_SDMMC_CLEAR_FLAG(&mmcHandle, SDMMC_STATIC_FLAGS); /* We have received response, retrieve it for analysis */ responseR1 = SDMMC_GetResponse(mmcHandle.Instance, SDMMC_RESP1); /* Find out card status */ *pStatus = (uint8_t)((responseR1 >> 9) & 0x0000000F); if ((responseR1 & SD_OCR_ERRORBITS) == SD_ALLZERO) { return errorstate; } if ((responseR1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) { return (SD_ADDR_OUT_OF_RANGE); } if ((responseR1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) { return (SD_ADDR_MISALIGNED); } if ((responseR1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) { return (SD_BLOCK_LEN_ERR); } if ((responseR1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) { return (SD_ERASE_SEQ_ERR); } if ((responseR1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) { return (SD_BAD_ERASE_PARAM); } if ((responseR1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) { return (SD_WRITE_PROT_VIOLATION); } if ((responseR1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) { return (SD_LOCK_UNLOCK_FAILED); } if ((responseR1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) { return (SD_COM_CRC_FAILED); } if ((responseR1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) { return (SD_ILLEGAL_CMD); } if ((responseR1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) { return (SD_CARD_ECC_FAILED); } if ((responseR1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) { return (SD_CC_ERROR); } if ((responseR1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) { return (SD_GENERAL_UNKNOWN_ERROR); } if ((responseR1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) { return (SD_STREAM_READ_UNDERRUN); } if ((responseR1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) { return (SD_STREAM_WRITE_OVERRUN); } if ((responseR1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) { return (SD_CID_CSD_OVERWRITE); } if ((responseR1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) { return (SD_WP_ERASE_SKIP); } if ((responseR1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) { return (SD_CARD_ECC_DISABLED); } if ((responseR1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) { return (SD_ERASE_RESET); } if ((responseR1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) { return (SD_AKE_SEQ_ERROR); } return errorstate; } /** * @brief Process ExtCSD * @param ExtCsdBuf: ExtCSD RAW Data (src) * @param sExtCSD: ExtCSD Target Data (dst) * @retval SD Card error state */ static void EMMC_SD_Get_CardInfo(const uint8_t ExtCsdBuf[512], HAL_SD_Ext_CSDTypedef *sExtCSD) { /* Get Extended Card Specific Data */ sExtCSD->SuppCmdSet = ExtCsdBuf[504]; sExtCSD->IntTimeoutAp = ExtCsdBuf[241]; sExtCSD->Pwr_CL_DDR_52_360 = ExtCsdBuf[239]; sExtCSD->Pwr_CL_DDR_52_195 = ExtCsdBuf[238]; sExtCSD->MinPerf_DDR_W_8_52 = ExtCsdBuf[235]; sExtCSD->MinPerf_DDR_R_8_52 = ExtCsdBuf[234]; sExtCSD->TrimMult = ExtCsdBuf[232]; sExtCSD->SecFeatureSupp = ExtCsdBuf[231]; sExtCSD->SecEraseMult = ExtCsdBuf[230]; sExtCSD->SecTrimMult = ExtCsdBuf[229]; sExtCSD->BootInfo = ExtCsdBuf[228]; sExtCSD->BootSizeMulti = ExtCsdBuf[226]; sExtCSD->AccSize = ExtCsdBuf[225]; sExtCSD->HC_EraseGrpSize = ExtCsdBuf[224]; sExtCSD->EraseTimeoutMult = ExtCsdBuf[223]; sExtCSD->RelWrSecCnt = ExtCsdBuf[222]; sExtCSD->HC_WpGrpSize = ExtCsdBuf[221]; sExtCSD->SlpCurrVCC = ExtCsdBuf[220]; sExtCSD->SlpCurrVCCQ = ExtCsdBuf[219]; sExtCSD->SA_Timeout = ExtCsdBuf[217]; for (int tmp_i=0; tmp_i<4; ((uint8_t*)&sExtCSD->SecCount)[tmp_i] = ExtCsdBuf[212+tmp_i], ++tmp_i); // TODO: check endianess sExtCSD->MinPerf_W_8_52 = ExtCsdBuf[210]; sExtCSD->MinPerf_R_8_52 = ExtCsdBuf[209]; sExtCSD->MinPerf_W_8_26 = ExtCsdBuf[208]; sExtCSD->MinPerf_R_8_26 = ExtCsdBuf[207]; sExtCSD->MinPerf_W_4_26 = ExtCsdBuf[206]; sExtCSD->MinPerf_R_4_26 = ExtCsdBuf[205]; sExtCSD->PwrCl_26_360 = ExtCsdBuf[203]; sExtCSD->PwrCl_52_360 = ExtCsdBuf[202]; sExtCSD->PwrCl_26_195 = ExtCsdBuf[201]; sExtCSD->PwrCl_52_195 = ExtCsdBuf[200]; sExtCSD->CardType = ExtCsdBuf[196]; sExtCSD->CsdStructVersion = ExtCsdBuf[194]; sExtCSD->ExtCsdRev = ExtCsdBuf[192]; sExtCSD->CmdSet = ExtCsdBuf[191]; sExtCSD->CmdSetRev = ExtCsdBuf[189]; sExtCSD->PwrCl = ExtCsdBuf[187]; sExtCSD->HsTiming = ExtCsdBuf[185]; sExtCSD->BusWidth = ExtCsdBuf[183]; sExtCSD->ErasedMemCont = ExtCsdBuf[181]; sExtCSD->PartitionConf = ExtCsdBuf[179]; sExtCSD->BootConfigProt = ExtCsdBuf[178]; sExtCSD->BootBusWidth = ExtCsdBuf[177]; sExtCSD->EraseGroupDef = ExtCsdBuf[175]; sExtCSD->BootWp = ExtCsdBuf[173]; sExtCSD->UserWp = ExtCsdBuf[171]; sExtCSD->FwConfig = ExtCsdBuf[169]; sExtCSD->RpmbSizeMult = ExtCsdBuf[168]; sExtCSD->RST_n_Function = ExtCsdBuf[162]; sExtCSD->PartSupport = ExtCsdBuf[160]; for (int tmp_i=0; tmp_i<3; ((uint8_t*)&sExtCSD->MaxEnhSizeMult)[tmp_i] = ExtCsdBuf[157+tmp_i], ++tmp_i); // TODO: check endianess sExtCSD->PartitionsAttr = ExtCsdBuf[156]; sExtCSD->PartSettingCompl = ExtCsdBuf[155]; for (int tmp_i=0; tmp_i<12; sExtCSD->GpSizeMult[tmp_i] = ExtCsdBuf[143+tmp_i], ++tmp_i); for (int tmp_i=0; tmp_i<3; ((uint8_t*)&sExtCSD->EnhSizeMult)[tmp_i] = ExtCsdBuf[140+tmp_i], ++tmp_i); // TODO: check endianess for (int tmp_i=0; tmp_i<4; ((uint8_t*)&sExtCSD->EnhStartAddr)[tmp_i] = ExtCsdBuf[136+tmp_i], ++tmp_i); // TODO: check endianess sExtCSD->SecBadBlkMgmnt = ExtCsdBuf[134]; }