Exemplo n.º 1
0
/**
 * @brief   Reads the CSD.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] csd       pointer to the CSD buffer
 *
 * @return              The operation status.
 * @retval CH_SUCCESS   the operation succeeded.
 * @retval CH_FAILED    the operation failed.
 *
 * @notapi
 */
static bool_t read_CxD(MMCDriver *mmcp, uint8_t cmd, uint32_t cxd[4]) {
  unsigned i;
  uint8_t *bp, buf[16];

  spiSelect(mmcp->config->spip);
  send_hdr(mmcp, cmd, 0);
  if (recvr1(mmcp) != 0x00) {
    spiUnselect(mmcp->config->spip);
    return CH_FAILED;
  }

  /* Wait for data availability.*/
  for (i = 0; i < MMC_WAIT_DATA; i++) {
    spiReceive(mmcp->config->spip, 1, buf);
    if (buf[0] == 0xFE) {
      uint32_t *wp;

      spiReceive(mmcp->config->spip, 16, buf);
      bp = buf;
      for (wp = &cxd[3]; wp >= cxd; wp--) {
        *wp = ((uint32_t)bp[0] << 24) | ((uint32_t)bp[1] << 16) |
              ((uint32_t)bp[2] << 8)  | (uint32_t)bp[3];
        bp += 4;
      }

      /* CRC ignored then end of transaction. */
      spiIgnore(mmcp->config->spip, 2);
      spiUnselect(mmcp->config->spip);

      return CH_SUCCESS;
    }
  }
  return CH_FAILED;
}
Exemplo n.º 2
0
/**
 * @brief   Reads a block within a sequential read operation.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] buffer   pointer to the read buffer
 * @return              The operation status.
 * @retval FALSE        the operation succeeded.
 * @retval TRUE         the operation failed.
 *
 * @api
 */
bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) {
  int i;

  chDbgCheck((mmcp != NULL) && (buffer != NULL), "mmcSequentialRead");

  chSysLock();
  if (mmcp->state != MMC_READING) {
    chSysUnlock();
    return TRUE;
  }
  chSysUnlock();

  for (i = 0; i < MMC_WAIT_DATA; i++) {
    spiReceive(mmcp->spip, 1, buffer);
    if (buffer[0] == 0xFE) {
      spiReceive(mmcp->spip, MMC_SECTOR_SIZE, buffer);
      /* CRC ignored. */
      spiIgnore(mmcp->spip, 2);
      return FALSE;
    }
  }
  /* Timeout.*/
  spiUnselect(mmcp->spip);
  chSysLock();
  if (mmcp->state == MMC_READING)
    mmcp->state = MMC_READY;
  chSysUnlock();
  return TRUE;
}
Exemplo n.º 3
0
/**
 * @brief   Writes a block within a sequential write operation.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] buffer   pointer to the write buffer
 * @return              The operation status.
 * @retval FALSE        the operation succeeded.
 * @retval TRUE         the operation failed.
 *
 * @api
 */
bool_t mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) {
  static const uint8_t start[] = {0xFF, 0xFC};
  uint8_t b[1];

  chDbgCheck((mmcp != NULL) && (buffer != NULL), "mmcSequentialWrite");

  chSysLock();
  if (mmcp->state != MMC_WRITING) {
    chSysUnlock();
    return TRUE;
  }
  chSysUnlock();

  spiSend(mmcp->spip, sizeof(start), start);        /* Data prologue.       */
  spiSend(mmcp->spip, MMC_SECTOR_SIZE, buffer);     /* Data.                */
  spiIgnore(mmcp->spip, 2);                         /* CRC ignored.         */
  spiReceive(mmcp->spip, 1, b);
  if ((b[0] & 0x1F) == 0x05) {
    wait(mmcp);
    return FALSE;
  }

  /* Error.*/
  spiUnselect(mmcp->spip);
  chSysLock();
  if (mmcp->state == MMC_WRITING)
    mmcp->state = MMC_READY;
  chSysUnlock();
  return TRUE;
}
Exemplo n.º 4
0
/**
 * @brief   Writes a block within a sequential write operation.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] buffer   pointer to the write buffer
 *
 * @return              The operation status.
 * @retval HAL_SUCCESS   the operation succeeded.
 * @retval HAL_FAILED    the operation failed.
 *
 * @api
 */
bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) {
  static const uint8_t start[] = {0xFF, 0xFC};
  uint8_t b[1];

  osalDbgCheck((mmcp != NULL) && (buffer != NULL));

  if (mmcp->state != BLK_WRITING) {
    return HAL_FAILED;
  }

  spiSend(mmcp->config->spip, sizeof(start), start);    /* Data prologue.   */
  spiSend(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);/* Data.            */
  spiIgnore(mmcp->config->spip, 2);                     /* CRC ignored.     */
  spiReceive(mmcp->config->spip, 1, b);
  if ((b[0] & 0x1FU) == 0x05U) {
    wait(mmcp);
    return HAL_SUCCESS;
  }

  /* Error.*/
  spiUnselect(mmcp->config->spip);
  spiStop(mmcp->config->spip);
  mmcp->state = BLK_READY;
  return HAL_FAILED;
}
Exemplo n.º 5
0
/**
 * @brief   Reads a block within a sequential read operation.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] buffer   pointer to the read buffer
 *
 * @return              The operation status.
 * @retval CH_SUCCESS   the operation succeeded.
 * @retval CH_FAILED    the operation failed.
 *
 * @api
 */
bool_t mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) {
  int i;

  chDbgCheck((mmcp != NULL) && (buffer != NULL), "mmcSequentialRead");

  if (mmcp->state != BLK_READING)
    return CH_FAILED;

  for (i = 0; i < MMC_WAIT_DATA; i++) {
    spiReceive(mmcp->config->spip, 1, buffer);
    if (buffer[0] == 0xFE) {
      spiReceive(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);
      /* CRC ignored. */
      spiIgnore(mmcp->config->spip, 2);
      return CH_SUCCESS;
    }
  }
  /* Timeout.*/
  spiUnselect(mmcp->config->spip);
  spiStop(mmcp->config->spip);
  return CH_FAILED;
}
Exemplo n.º 6
0
/**
 * @brief   Reads a block within a sequential read operation.
 *
 * @param[in] mmcp      pointer to the @p MMCDriver object
 * @param[out] buffer   pointer to the read buffer
 *
 * @return              The operation status.
 * @retval HAL_SUCCESS   the operation succeeded.
 * @retval HAL_FAILED    the operation failed.
 *
 * @api
 */
bool mmcSequentialRead(MMCDriver *mmcp, uint8_t *buffer) {
  unsigned i;

  osalDbgCheck((mmcp != NULL) && (buffer != NULL));

  if (mmcp->state != BLK_READING) {
    return HAL_FAILED;
  }

  for (i = 0; i < MMC_WAIT_DATA; i++) {
    spiReceive(mmcp->config->spip, 1, buffer);
    if (buffer[0] == 0xFEU) {
      spiReceive(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);
      /* CRC ignored. */
      spiIgnore(mmcp->config->spip, 2);
      return HAL_SUCCESS;
    }
  }
  /* Timeout.*/
  spiUnselect(mmcp->config->spip);
  spiStop(mmcp->config->spip);
  mmcp->state = BLK_READY;
  return HAL_FAILED;
}
Exemplo n.º 7
0
/*
 * Application entry point.
 */
int main(void) {
    unsigned i;

    /*
     * System initializations.
     * - HAL initialization, this also initializes the configured device drivers
     *   and performs the board-specific initializations.
     * - Kernel initialization, the main() function becomes a thread and the
     *   RTOS is active.
     */
    halInit();
    chSysInit();

    /*
     * Prepare transmit pattern.
     */
    for (i = 0; i < sizeof(txbuf); i++)
        txbuf[i] = (uint8_t)i;

    /* Starting driver for test, DSPI_B I/O pins setup.*/
    spiStart(&SPID2, &ls_spicfg);
    SIU.PCR[102].R = PAL_MODE_OUTPUT_ALTERNATE(1);    /* SCK    */
    SIU.PCR[103].R = PAL_MODE_OUTPUT_ALTERNATE(1);    /* SIN    */
    SIU.PCR[104].R = PAL_MODE_OUTPUT_ALTERNATE(1);    /* SOUT   */
    SIU.PCR[105].R = PAL_MODE_OUTPUT_ALTERNATE(1);    /* PCS[0] */
    SIU.PCR[106].R = PAL_MODE_OUTPUT_ALTERNATE(1);    /* PCS[1] */

    /* Testing sending and receiving at the same time.*/
    spiExchange(&SPID2, 4, txbuf, rxbuf);
    spiExchange(&SPID2, 32, txbuf, rxbuf);
    spiExchange(&SPID2, 512, txbuf, rxbuf);

    /* Testing clock pulses without data buffering.*/
    spiIgnore(&SPID2, 4);
    spiIgnore(&SPID2, 32);

    /* Testing sending data ignoring incoming data.*/
    spiSend(&SPID2, 4, txbuf);
    spiSend(&SPID2, 32, txbuf);

    /* Testing receiving data while sending idle bits (high level).*/
    spiReceive(&SPID2, 4, rxbuf);
    spiReceive(&SPID2, 32, rxbuf);

    /* Testing stop procedure.*/
    spiStop(&SPID2);

    /*
     * Starting the transmitter and receiver threads.
     */
    chThdCreateStatic(spi_thread_1_wa, sizeof(spi_thread_1_wa),
                      NORMALPRIO + 1, spi_thread_1, NULL);
    chThdCreateStatic(spi_thread_2_wa, sizeof(spi_thread_2_wa),
                      NORMALPRIO + 1, spi_thread_2, NULL);

    /*
     * Normal main() thread activity, in this demo it does nothing.
     */
    while (TRUE) {
        chThdSleepMilliseconds(500);
        palTogglePad(PORT11, P11_LED2);
    }
    return 0;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
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;

  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;
}
Exemplo n.º 10
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 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;
}
Exemplo n.º 11
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 was successful and the driver is now
 *                      in the @p MMC_READY state.
 * @retval TRUE         the operation failed.
 */
bool_t mmcConnect(MMCDriver *mmcp) {
  unsigned i;
  bool_t result;

  chDbgCheck(mmcp != NULL, "mmcConnect");

  chDbgAssert((mmcp->mmc_state != MMC_UNINIT) &&
              (mmcp->mmc_state != MMC_STOP),
              "mmcConnect(), #1",
              "invalid state");

  if (mmcp->mmc_state == MMC_INSERTED) {
    /* Slow clock mode and 128 clock pulses.*/
    spiStart(mmcp->mmc_spip, mmcp->mmc_lscfg);
    spiIgnore(mmcp->mmc_spip, 16);

    /* SPI mode selection.*/
    i = 0;
    while (TRUE) {
      if (send_command(mmcp, MMC_CMDGOIDLE, 0) == 0x01)
        break;
      if (++i >= MMC_CMD0_RETRY)
        return TRUE;
      chThdSleepMilliseconds(10);
    }

    /* Initialization. */
    i = 0;
    while (TRUE) {
      uint8_t b = send_command(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->mmc_spip, mmcp->mmc_hscfg);

    /* Setting block size.*/
    if (send_command(mmcp, MMC_CMDSETBLOCKLEN, MMC_SECTOR_SIZE) != 0x00)
      return TRUE;

    /* Transition to MMC_READY state (if not extracted).*/
    chSysLock();
    if (mmcp->mmc_state == MMC_INSERTED) {
      mmcp->mmc_state = MMC_READY;
      result = FALSE;
    }
    else
      result = TRUE;
    chSysUnlock();
    return result;
  }
  if (mmcp->mmc_state == MMC_READY)
    return FALSE;
  /* Any other state is invalid.*/
  return TRUE;
}