Ejemplo n.º 1
0
/**
 * @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;
}
Ejemplo n.º 2
0
/**
 * @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;
  uint32_t csd[4];

  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->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)
        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, 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)
          return TRUE;
        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)
        return TRUE;
      if (++i >= MMC_CMD1_RETRY)
        return TRUE;
      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)
      return TRUE;

    /* Determine capacity.*/
    if (read_CSD(mmcp, csd))
      return TRUE;
    mmcp->capacity = mmcsdGetCapacity(csd);
    if (mmcp->capacity == 0)
      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;
}