gpio_set(mmc->chip_select);
}
-/* Wait for MMC Card to be ready.
+/* Wait for SD/MMC Card to be ready.
* return -EBUSY on timeout.
* Note : The SPI Bus mutex must be held by the calling function.
* FIXME : handle timeout with sleep()
* Note : The SPI Bus mutex must be held by the calling function.
* Return R1 or (R1 | 0x0100) on timeout.
*/
-static int sdmmc_send_command(const struct sdmmc_card* mmc, uint8_t index, uint32_t arg, uint8_t* buf, int len)
+static uint8_t sdmmc_send_command(const struct sdmmc_card* mmc, uint8_t index, uint32_t arg, uint8_t* buf, int len)
{
uint8_t mmc_command[MMC_CMD_SIZE];
int i = 0;
/* Get R1 */
for (i = 0; i < 8; i++) {
r1 = (uint8_t)spi_transfer_single_frame(mmc->ssp_bus_num, 0xFF);
- if (r1 != 0xFF) {
+ if (!(r1 & 0x80)) {
break;
}
}
}
if (len > 1) {
/* Receive response data */
+ memset(buf, 0xFF, len);
spi_transfer_multiple_frames(mmc->ssp_bus_num, NULL, buf, len, 8);
}
static int sdmmc_send_app_command(const struct sdmmc_card* mmc, uint8_t index, uint32_t arg)
{
- int r1 = 0;
+ uint8_t r1 = 0;
/* Send APP_CMD (CMD55) first */
r1 = sdmmc_send_command(mmc, MMC_APP_CMD, 0, NULL, 0);
return sdmmc_send_command(mmc, index, arg, NULL, 0);
}
-int sdmmc_reset(struct sdmmc_card* mmc)
+void sdmmc_set_card_to_spi_mode(const struct sdmmc_card* mmc)
{
- int r1 = 0, ret = 0;
+ int i = 0;
+ /* Get SPI Bus */
+ spi_get_mutex(mmc->ssp_bus_num);
+ /* Set SPI pins to GPIO mode */
+ set_pins(mmc->pin_cfg_mode_gpio);
+ /* Configure GPIOs */
config_gpio(&(mmc->chip_select), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
+ config_gpio(&(mmc->sclk), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
+ config_gpio(&(mmc->mosi), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
+
+ /* Toggle SCLK to get 74 clock cycles while holding MOSI and CS high */
+ gpio_set(mmc->chip_select);
+ gpio_set(mmc->mosi);
+ for (i = 0; i < (80 * 2); i++) {
+ gpio_toggle(mmc->sclk);
+ }
+
+ /* Set SPI pins to GPIO mode */
+ set_pins(mmc->pin_cfg_mode_spi);
+
+ /* Release SPI Bus */
+ spi_release_mutex(mmc->ssp_bus_num);
+}
+
+int sdmmc_reset(struct sdmmc_card* mmc)
+{
+ int ret = 0;
+ uint8_t r1 = 0;
+
+ /* Set SD/MMC Card to SPI mode */
+ sdmmc_set_card_to_spi_mode(mmc);
/* Get SPI Bus */
spi_get_mutex(mmc->ssp_bus_num);
ret = -EIO; /* This one should have succeded even without a card inserted ... */
}
+ /* Release SPI Bus */
sdmmc_cs_release(mmc);
spi_release_mutex(mmc->ssp_bus_num);
}
-int sdmmc_init(struct sdmmc_card* mmc)
+int sdmmc_init_start(struct sdmmc_card* mmc)
{
- int r1 = 0, ret = 0;
uint8_t buf[MMC_CMD_SIZE];
+ int ret = 0;
+ uint8_t r1 = 0;
- config_gpio(&(mmc->chip_select), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
mmc->card_type = MMC_CARDTYPE_UNKNOWN;
/* Get SPI Bus */
spi_get_mutex(mmc->ssp_bus_num);
sdmmc_cs_activate(mmc);
- /* Send CMD0 (RESET or GO_IDLE_STATE) */
- r1 = sdmmc_send_command(mmc, MMC_GO_IDLE_STATE, 0, NULL, 0);
- if (r1 > MMC_R1_IN_IDLE_STATE) {
- ret = -EIO; /* This one should have succeded even without a card inserted ... */
- goto init_release_bus;
- }
- msleep(1);
-
/* Send CMD8, check the card type
* CMD8 is the Send interface Condition Command.
* 0x01 is "2.7V to 3.6V"
int sdmmc_init_wait_card_ready(struct sdmmc_card* mmc)
{
- int r1 = 0;
+ uint8_t r1 = 0;
/* Get SPI Bus */
spi_get_mutex(mmc->ssp_bus_num);
int sdmmc_init_end(struct sdmmc_card* mmc)
{
- int r1 = 0, ret = 0;
uint8_t buf[MMC_CMD_SIZE];
+ int ret = 0;
+ uint8_t r1 = 0;
/* Get SPI Bus */
spi_get_mutex(mmc->ssp_bus_num);
}
+/* sdmmc_init_single does a single loop of initialisation steps, but allows for a
+ * user defined number of "wait" step retries (with at least one wait step).
+ * the loop is :
+ * start
+ * (wait * retries)
+ * end
+ * There is a 10ms delay before each wait step (sdmmc_init_wait_card_ready() call),
+ * including the first one.
+ * It is not possible to skip the first delay and wait step, even with a nretry of 0.
+ * The loop may stop at any of the steps, with "rstep" set to the step number (if not NULL).
+ * if step = 0 : returned value is the return value of sdmmc_init_start().
+ * if step = 1 : returned value is the return value of last sdmmc_init_wait_card_ready().
+ * if step = 2 : returned value is the return value of sdmmc_init_end().
+ * If the returned value is 0, then step should be 2.
+ * If nretries is not NULL, it is used as the number of "wait" steps, and updated
+ * with the number of retries executed.
+ */
+int sdmmc_init_single(struct sdmmc_card* mmc, uint8_t* rstep, uint8_t* nretries)
+{
+ int ret = 0, step = 0, i = 0;
+ uint8_t retries = 0;
+
+ ret = sdmmc_init_start(mmc);
+ if (ret == 0) {
+ step = 1;
+ if (nretries != NULL) {
+ retries = *nretries;
+ }
+ do {
+ msleep(10);
+ ret = sdmmc_init_wait_card_ready(mmc);
+ i++;
+ } while ((ret != 0 ) && (i < retries));
+ if (ret <= 1) {
+ step = 2;
+ ret = sdmmc_init_end(mmc);
+ }
+ }
+
+ if (rstep != NULL) {
+ *rstep = step;
+ }
+ if (nretries != NULL) {
+ *nretries = i;
+ }
+ return ret;
+}
+
/* Read one block of data.
+ * One block should be of "mmc->block_size" length, so provided buffer must be at least
+ * big enough to receive "mmc->block_size" bytes.
+ * If the attached card is of type MMC_CARDTYPE_SDV2_HC it is mandatory that we read
+ * full sector, which is MMC_MAX_SECTOR_SIZE bytes long. In this case, if the requested
+ * block size (mmc->block_size) is less than MMC_MAX_SECTOR_SIZE, this function will
+ * read the remaining data from the card and silently drop it.
* Returns -EINVAL on arguments error, -ENODEV on command error,
* -EBUSY on timeout, -EIO on CRC error,
* or 0 on success
ret = spi_transfer_multiple_frames(mmc->ssp_bus_num, NULL, buffer, mmc->block_size, 8);
/* Compute CRC of this part */
crc = crc_ccitt(0x0000, buffer, mmc->block_size);
- /* Read data, remaining part */
+ /* Read data, remaining part (need to read full sector) */
if ((mmc->card_type == MMC_CARDTYPE_SDV2_HC) && (mmc->block_size != MMC_MAX_SECTOR_SIZE)) {
char tmpbuf[TMPBUF_SIZE];
int size = (MMC_MAX_SECTOR_SIZE - mmc->block_size);
}
+/* Wait for write to be finished on SD/MMC card
+ * In some cases the write may take longer on some cards and the sdmmc_write_block()
+ * call will return -EBUSY.
+ * It is then necessary to check that the card is ready before reading or writting
+ * again.
+ * Return 0 when card is ready, or -EBUSY when card is still busy.
+ */
+int sdmmc_wait_write_end(const struct sdmmc_card* mmc)
+{
+ int ret = 0;
+
+ /* Get SPI Bus */
+ spi_get_mutex(mmc->ssp_bus_num);
+ sdmmc_cs_activate(mmc);
+
+ /* Wait for card ready */
+ ret = sdmmc_wait_for_ready(mmc, 0xFF);
+ if (ret != 0xFF) {
+ ret = -EBUSY;
+ goto wait_ready_release;
+ }
+ ret = 0;
+
+wait_ready_release:
+ /* Release SPI Bus */
+ sdmmc_cs_release(mmc);
+ spi_release_mutex(mmc->ssp_bus_num);
+ return ret;
+}
+
uint16_t block_size;
uint8_t block_shift;
struct pio chip_select;
+ struct pio sclk;
+ struct pio mosi;
+ struct pio miso;
+ struct pio_config* pin_cfg_mode_spi;
+ struct pio_config* pin_cfg_mode_gpio;
};
-int sdmmc_init(struct sdmmc_card* mmc);
+
+/* Reset the card
+ * It is mandatory to call this function before any other sd/mmc function to set
+ * the SD/MMC card to SPI mode, which is the only supported mode for the LPC112x
+ * micro-controller.
+ */
+int sdmmc_reset(struct sdmmc_card* mmc);
+
+/* The card initialisation has been split in three parts, as for some cards it may
+ * be required to iterrate many times over the middle part (waiting for the card
+ * to get ready).
+ * This splitting allows the user to perform other stuff while waiting, like
+ * feeding a watchdog.
+ */
+int sdmmc_init_start(struct sdmmc_card* mmc);
int sdmmc_init_wait_card_ready(struct sdmmc_card* mmc);
int sdmmc_init_end(struct sdmmc_card* mmc);
-int sdmmc_reset(struct sdmmc_card* mmc);
+/* sdmmc_init_single does a single loop of initialisation steps, but allows for a
+ * user defined number of "wait" step retries (with at least one wait step).
+ * the loop is :
+ * start
+ * (wait * retries)
+ * end
+ * There is a 10ms delay before each wait step (sdmmc_init_wait_card_ready() call),
+ * including the first one.
+ * It is not possible to skip the first delay and wait step, even with a nretry of 0.
+ * The loop may stop at any of the steps, with "rstep" set to the step number (if not NULL).
+ * if step = 0 : returned value is the return value of sdmmc_init_start().
+ * if step = 1 : returned value is the return value of last sdmmc_init_wait_card_ready().
+ * if step = 2 : returned value is the return value of sdmmc_init_end().
+ * If the returned value is 0, then step should be 2.
+ * If nretries is not NULL, it is used as the number of "wait" steps, and updated
+ * with the number of retries executed.
+ */
+int sdmmc_init_single(struct sdmmc_card* mmc, uint8_t* rstep, uint8_t* nretries);
+
+
/* Read one block of data.
- * Return -ENODEV on error, -EBUSY on timeout, -EIO on CRC error, or 0 on success
+ * One block should be of "mmc->block_size" length, so provided buffer must be at least
+ * big enough to receive "mmc->block_size" bytes.
+ * If the attached card is of type MMC_CARDTYPE_SDV2_HC it is mandatory that we read
+ * full sector, which is MMC_MAX_SECTOR_SIZE bytes long. In this case, if the requested
+ * block size (mmc->block_size) is less than MMC_MAX_SECTOR_SIZE, this function will
+ * read the remaining data from the card and silently drop it.
+ * Returns -EINVAL on arguments error, -ENODEV on command error,
+ * -EBUSY on timeout, -EIO on CRC error,
+ * or 0 on success
*/
int sdmmc_read_block(const struct sdmmc_card* mmc, uint32_t block_number, uint8_t *buffer);
+
+/* Write one block of data.
+ * This routine does not pre-erase the block, so if the user did not pre-erase the
+ * corresponding block then the write takes longer.
+ * Returns -EINVAL on arguments error, -ENODEV on command error,
+ * -ECOMM on response error, -EIO on CRC error, -EPERM on write error
+ * or 0 on success
+ */
int sdmmc_write_block(const struct sdmmc_card* mmc, uint32_t block_number, uint8_t *buffer);
+/* Wait for write to be finished on SD/MMC card
+ * In some cases the write may take longer on some cards and the sdmmc_write_block()
+ * call will return -EBUSY.
+ * It is then necessary to check that the card is ready before reading or writting
+ * again.
+ * Return 0 when card is ready, or -EBUSY when card is still busy.
+ */
+int sdmmc_wait_write_end(const struct sdmmc_card* mmc);
/* Card states and Operation modes */
/* Inactive operation mode */
* Response type is R1 unless specified
*/
#define MMC_GO_IDLE_STATE 0 /* CMD0 */
-#define MMC_SEND_OP_COND 1
+#define MMC_SEND_OP_COND 1 /* CMD1 or ACMD41 */
#define MMC_ALL_SEND_CID 2 /* R2 */
#define MMC_SEND_REL_ADDR 3 /* R6 */
#define MMC_SET_DSR 4