/** * @brief Erases blocks. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[in] startblk starting block number * @param[in] endblk ending block number * * @return The operation status. * @retval CH_SUCCESS the operation succeeded. * @retval CH_FAILED the operation failed. * * @api */ bool_t mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { chDbgCheck((mmcp != NULL), "mmcErase"); /* Handling command differences between HC and normal cards.*/ if (!mmcp->block_addresses) { startblk *= MMCSD_BLOCK_SIZE; endblk *= MMCSD_BLOCK_SIZE; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk)) goto failed; if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk)) goto failed; if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0)) goto failed; return CH_SUCCESS; /* Command failed, state reset to BLK_ACTIVE.*/ failed: spiStop(mmcp->config->spip); return CH_FAILED; }
/** * @brief Erases blocks. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[in] startblk starting block number * @param[in] endblk ending block number * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { osalDbgCheck((mmcp != NULL)); /* Erase operation in progress.*/ mmcp->state = BLK_WRITING; /* Handling command differences between HC and normal cards.*/ if (!mmcp->block_addresses) { startblk *= MMCSD_BLOCK_SIZE; endblk *= MMCSD_BLOCK_SIZE; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk) != 0x00U) { goto failed; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk) != 0x00U) { goto failed; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0) != 0x00U) { goto failed; } mmcp->state = BLK_READY; return HAL_SUCCESS; /* Command failed, state reset to BLK_ACTIVE.*/ failed: spiStop(mmcp->config->spip); mmcp->state = BLK_READY; return HAL_FAILED; }
/** * @brief Performs the initialization procedure on the inserted card. * @details This function should be invoked when a card is inserted and * brings the driver in the @p MMC_READY state where it is possible * to perform read and write operations. * @note It is possible to invoke this function from the insertion event * handler. * * @param[in] mmcp pointer to the @p MMCDriver object * * @return The operation status. * @retval CH_SUCCESS the operation succeeded and the driver is now * in the @p MMC_READY state. * @retval CH_FAILED the operation failed. * * @api */ bool_t mmcConnect(MMCDriver *mmcp) { unsigned i; chDbgCheck(mmcp != NULL, "mmcConnect"); chDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), "mmcConnect(), #1", "invalid state"); /* Connection procedure in progress.*/ mmcp->state = BLK_CONNECTING; /* Slow clock mode and 128 clock pulses.*/ spiStart(mmcp->config->spip, mmcp->config->lscfg); spiIgnore(mmcp->config->spip, 16); /* SPI mode selection.*/ i = 0; while (TRUE) { if (send_command_R1(mmcp, MMCSD_CMD_GO_IDLE_STATE, 0) == 0x01) break; if (++i >= MMC_CMD0_RETRY) goto failed; chThdSleepMilliseconds(10); } /* Try to detect if this is a high capacity card and switch to block addresses if possible. This method is based on "How to support SDC Ver2 and high capacity cards" by ElmChan.*/ uint8_t r3[4]; if (send_command_R3(mmcp, MMCSD_CMD_SEND_IF_COND, MMCSD_CMD8_PATTERN, r3) != 0x05) { /* Switch to SDHC mode.*/ i = 0; while (TRUE) { if ((send_command_R1(mmcp, MMCSD_CMD_APP_CMD, 0) == 0x01) && (send_command_R3(mmcp, MMCSD_CMD_APP_OP_COND, 0x400001aa, r3) == 0x00)) break; if (++i >= MMC_ACMD41_RETRY) goto failed; chThdSleepMilliseconds(10); } /* Execute dedicated read on OCR register */ send_command_R3(mmcp, MMCSD_CMD_READ_OCR, 0, r3); /* Check if CCS is set in response. Card operates in block mode if set.*/ if (r3[0] & 0x40) mmcp->block_addresses = TRUE; } /* Initialization.*/ i = 0; while (TRUE) { uint8_t b = send_command_R1(mmcp, MMCSD_CMD_INIT, 0); if (b == 0x00) break; if (b != 0x01) goto failed; if (++i >= MMC_CMD1_RETRY) goto failed; chThdSleepMilliseconds(10); } /* Initialization complete, full speed.*/ spiStart(mmcp->config->spip, mmcp->config->hscfg); /* Setting block size.*/ if (send_command_R1(mmcp, MMCSD_CMD_SET_BLOCKLEN, MMCSD_BLOCK_SIZE) != 0x00) goto failed; /* Determine capacity.*/ if (read_CxD(mmcp, MMCSD_CMD_SEND_CSD, mmcp->csd)) goto failed; mmcp->capacity = mmcsdGetCapacity(mmcp->csd); if (mmcp->capacity == 0) goto failed; if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) goto failed; mmcp->state = BLK_READY; return CH_SUCCESS; /* Connection failed, state reset to BLK_ACTIVE.*/ failed: spiStop(mmcp->config->spip); mmcp->state = BLK_ACTIVE; return CH_FAILED; }
/** * @brief Performs the initialization procedure on the inserted card. * @details This function should be invoked when a card is inserted and * brings the driver in the @p MMC_READY state where it is possible * to perform read and write operations. * @note It is possible to invoke this function from the insertion event * handler. * * @param[in] mmcp pointer to the @p MMCDriver object * @return The operation status. * @retval FALSE the operation succeeded and the driver is now * in the @p MMC_READY state. * @retval TRUE the operation failed. * * @api */ bool_t mmcConnect(MMCDriver *mmcp) { unsigned i; bool_t result; chDbgCheck(mmcp != NULL, "mmcConnect"); chDbgAssert((mmcp->state != MMC_UNINIT) && (mmcp->state != MMC_STOP), "mmcConnect(), #1", "invalid state"); if (mmcp->state == MMC_INSERTED) { /* Slow clock mode and 128 clock pulses.*/ spiStart(mmcp->spip, mmcp->lscfg); spiIgnore(mmcp->spip, 16); /* SPI mode selection.*/ i = 0; while (TRUE) { if (send_command_R1(mmcp, MMC_CMDGOIDLE, 0) == 0x01) break; if (++i >= MMC_CMD0_RETRY) return TRUE; chThdSleepMilliseconds(10); } /* Try to detect if this is a high capacity card and switch to block * addresses if possible. * * This method is based on "How to support SDC Ver2 and high capacity cards" * by ElmChan. * * */ uint8_t r3[4]; if(send_command_R3(mmcp, MMC_CMDINTERFACE_CONDITION, 0x01AA, r3) != 0x05){ /* Switch to SDHC mode */ i = 0; while (TRUE) { if ((send_command_R1(mmcp, MMC_CMDAPP, 0) == 0x01) && (send_command_R3(mmcp, MMC_ACMDOPCONDITION, 0x400001aa, r3) == 0x00)) break; if (++i >= MMC_ACMD41_RETRY) return TRUE; chThdSleepMilliseconds(10); } /* Execute dedicated read on OCR register */ send_command_R3(mmcp, MMC_CMDREADOCR, 0, r3); /* Check if CCS is set in response. Card operates in block mode if set */ if(r3[0] & 0x40) mmcp->block_addresses = TRUE; } /* Initialization. */ i = 0; while (TRUE) { uint8_t b = send_command_R1(mmcp, MMC_CMDINIT, 0); if (b == 0x00) break; if (b != 0x01) return TRUE; if (++i >= MMC_CMD1_RETRY) return TRUE; chThdSleepMilliseconds(10); } /* Initialization complete, full speed. */ spiStart(mmcp->spip, mmcp->hscfg); /* Setting block size.*/ if (send_command_R1(mmcp, MMC_CMDSETBLOCKLEN, MMC_SECTOR_SIZE) != 0x00) return TRUE; /* Transition to MMC_READY state (if not extracted).*/ chSysLock(); if (mmcp->state == MMC_INSERTED) { mmcp->state = MMC_READY; result = FALSE; } else result = TRUE; chSysUnlock(); return result; } if (mmcp->state == MMC_READY) return FALSE; /* Any other state is invalid.*/ return TRUE; }
/** * @brief Performs the initialization procedure on the inserted card. * @details This function should be invoked when a card is inserted and * brings the driver in the @p MMC_READY state where it is possible * to perform read and write operations. * @note It is possible to invoke this function from the insertion event * handler. * * @param[in] mmcp pointer to the @p MMCDriver object * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded and the driver is now * in the @p MMC_READY state. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcConnect(MMCDriver *mmcp) { unsigned i; uint8_t r3[4]; osalDbgCheck(mmcp != NULL); osalDbgAssert((mmcp->state == BLK_ACTIVE) || (mmcp->state == BLK_READY), "invalid state"); /* Connection procedure in progress.*/ mmcp->state = BLK_CONNECTING; mmcp->block_addresses = false; /* Slow clock mode and 128 clock pulses.*/ spiStart(mmcp->config->spip, mmcp->config->lscfg); spiIgnore(mmcp->config->spip, 16); /* SPI mode selection.*/ i = 0; while (true) { if (send_command_R1(mmcp, MMCSD_CMD_GO_IDLE_STATE, 0) == 0x01U) { break; } if (++i >= MMC_CMD0_RETRY) { goto failed; } osalThreadSleepMilliseconds(10); } /* Try to detect if this is a high capacity card and switch to block addresses if possible. This method is based on "How to support SDC Ver2 and high capacity cards" by ElmChan.*/ if (send_command_R3(mmcp, MMCSD_CMD_SEND_IF_COND, MMCSD_CMD8_PATTERN, r3) != 0x05U) { /* Switch to SDHC mode.*/ i = 0; while (true) { /*lint -save -e9007 [13.5] Side effect unimportant.*/ if ((send_command_R1(mmcp, MMCSD_CMD_APP_CMD, 0) == 0x01U) && (send_command_R3(mmcp, MMCSD_CMD_APP_OP_COND, 0x400001AAU, r3) == 0x00U)) { /*lint -restore*/ break; } if (++i >= MMC_ACMD41_RETRY) { goto failed; } osalThreadSleepMilliseconds(10); } /* Execute dedicated read on OCR register */ (void) send_command_R3(mmcp, MMCSD_CMD_READ_OCR, 0, r3); /* Check if CCS is set in response. Card operates in block mode if set.*/ if ((r3[0] & 0x40U) != 0U) { mmcp->block_addresses = true; } } /* Initialization.*/ i = 0; while (true) { uint8_t b = send_command_R1(mmcp, MMCSD_CMD_INIT, 0); if (b == 0x00U) { break; } if (b != 0x01U) { goto failed; } if (++i >= MMC_CMD1_RETRY) { goto failed; } osalThreadSleepMilliseconds(10); } /* Initialization complete, full speed.*/ spiStart(mmcp->config->spip, mmcp->config->hscfg); /* Setting block size.*/ if (send_command_R1(mmcp, MMCSD_CMD_SET_BLOCKLEN, MMCSD_BLOCK_SIZE) != 0x00U) { goto failed; } /* Determine capacity.*/ if (read_CxD(mmcp, MMCSD_CMD_SEND_CSD, mmcp->csd)) { goto failed; } mmcp->capacity = _mmcsd_get_capacity(mmcp->csd); if (mmcp->capacity == 0U) { goto failed; } if (read_CxD(mmcp, MMCSD_CMD_SEND_CID, mmcp->cid)) { goto failed; } mmcp->state = BLK_READY; return HAL_SUCCESS; /* Connection failed, state reset to BLK_ACTIVE.*/ failed: spiStop(mmcp->config->spip); mmcp->state = BLK_ACTIVE; return HAL_FAILED; }