// Sends ACMD41 / SD_SEND_OP_COND // hcs = 0 -> Initialize without HCS // hcs != 0 -> Initialize with HCS SDErr sd_send_op_cond_cmd(uint8_t hcs) { int i = 0; hcs = hcs == 0 ? 0x00 : 0x40; // Adjust parameter for (i = 0; i < ACMD41_MAX_TRIES; i++) { sd_res.r1 = sd_cmd(55, 0, 0, 0, 0, 0xFF); // APP_CMD sd_res.r1 = sd_cmd(41, hcs, 0, 0, 0, 0xFF); // ACMD41 (SD_SEND_OP_COND) if (sd_res.r1 == 0) { // Success. Card initialized. /* printf("ACMD41 successful after %d tries %s HCS\n", i, hcs ? "with" : "without"); */ return SD_SUCCESS; } else if (sd_res.r1 != 0x01) { // Bad response. /* printf("Error: %02X (%d)\n", res, i); sd_print_r1(res); */ return SD_SENDOPCOND_BADRES; } } return SD_SENDOPCOND_UNABLE; }
uint8_t sd_read_block(uint32_t block_offset, uint8_t block[512]) { int r; uint16_t i; if(sd_channel==1) sd_select(1); else sd_select(0); if (sd_type == SD_TYPE_SDHC) { r = sd_cmd(CMD_READ_SINGLE_BLOCK, block_offset); } else { r = sd_cmd(CMD_READ_SINGLE_BLOCK, block_offset << 9); } if (r != 0) { uart_puts("CMD_READ_SINGLE_BLOCK command failed for offset"); uart_puthex32(block_offset); uart_puts("\r\n"); if(sd_channel == 1) sd_deselect(1); else sd_deselect(0); sdok = 0; return r; } while (sd_recv() != 0xfe); // TODO: use timeout? //UART_TxStr("Block:\r\n"); for (i = 0; i < 512; i++) { uint8_t c = sd_recv(); block[i] = c; //UART_TxUint8(c); } //UART_TxStr("\r\n"); sd_recv(); sd_recv(); // skip CRC if(sd_channel == 1) sd_deselect(1); else sd_deselect(0); sd_recv(); return 0; }
static int sd_generic_write(struct sd_host *host, u8 opcode, u32 arg, void *data, size_t len, int token) { struct sd_command *cmd = &host->cmd; int retval; /* build raw command */ sd_cmd(cmd, opcode, arg); /* select card, send command and wait for response */ retval = sd_start_command(host, cmd); if (retval < 0) goto out; if (retval != 0x00) { retval = -EIO; goto out; } /* send data token, data and crc, get data response */ retval = sd_write_data(host, data, len, token); if (retval < 0) goto out; retval = 0; out: /* burn extra cycles and deselect card */ sd_end_command(host); if (retval < 0) DBG("write, offset=%d, len=%d\n", arg, len); return retval; }
static int sd_generic_read(struct sd_host *host, u8 opcode, u32 arg, void *data, size_t len, int token) { struct sd_command *cmd = &host->cmd; u16 crc, calc_crc = 0xffff; u8 *d; size_t l; int retval; /* build raw command */ sd_cmd(cmd, opcode, arg); /* select card, send command and wait for response */ retval = sd_start_command(host, cmd); if (retval < 0) goto out; if (retval != 0x00) { retval = -EIO; goto out; } /* wait for read token, then read data */ retval = sd_read_data(host, data, len, token); if (retval < 0) goto out; /* read trailing crc */ spi_read(host, &crc, sizeof(crc)); retval = 0; /* FIXME, rewrite this a bit */ { calc_crc = 0; d = data; l = len; while (l-- > 0) calc_crc = crc_xmodem_update(calc_crc, *d++); if (calc_crc != crc) retval = -EIO; } out: /* burn extra cycles and deselect card */ sd_end_command(host); if (retval < 0) { DBG("read, offset=%u, len=%d\n", arg, len); DBG("crc=%04x, calc_crc=%04x, %s\n", crc, calc_crc, (retval < 0) ? "failed" : "ok"); } return retval; }
static int sd_read_ocr(struct sd_host *host) { struct sd_command *cmd = &host->cmd; int retval; memset(&host->ocr, 0, sizeof(host->ocr)); sd_cmd(cmd, MMC_READ_OCR, 0); /* select card, send command and wait for response */ retval = sd_start_command(host, cmd); if (retval < 0) goto out; /* the OCR contents come immediately after the card response */ spi_read(host, &host->ocr, sizeof(host->ocr)); retval = 0; out: /* burn extra cycles and deselect card */ sd_end_command(host); return retval; }
int sd_init() { uint8_t i; int k; uint8_t r; uint8_t mmc = 0; sdok = 0; sd_deselect(); /* 74 cycles to start up the card */ for (i = 0; i < 10; i++) { sd_recv(); } sd_select(); /* enter idle mode */ for (k = 0; ; k++) { r = sd_cmd(CMD_GO_IDLE_STATE, 0); if (r == (1 << R1_IDLE_STATE)) { uart_puts("sd: entered IDLE state\r\n"); break; } if (k == 0x1ff) { uart_puts("sd: failed to enter IDLE state\r\n"); break; //sd_deselect(); //return 0; } } /* check SD card specification version */ char sdhc = 0; r = sd_cmd(CMD_SEND_IF_COND, 0x100 | 0xaa); /* 2.7V..3.6V */ if ((r & (1 << R1_ILL_COMMAND)) == 0) { uart_puts("sd: SD SPEC 2 (or SDHC)\r\n"); //sd_type = SD_TYPE_SPEC2; sd_type = SD_TYPE_SPEC2; sdhc = 1; sd_recv(); sd_recv(); r = sd_recv(); if (r & 1 == 0) { uart_puts("sd: voltage range mismatch\r\n"); } r = sd_recv(); if (r != 0xaa) { uart_puts("sd: wrong test pattern\r\n"); } } else { sd_cmd(CMD_APP, 0); r = sd_cmd(CMD_SD_SEND_OP_COND, 0); if ((r & (1 << R1_ILL_COMMAND)) == 0) { uart_puts("sd: SD SPEC 1\r\n"); sdhc = 0; sd_type = SD_TYPE_SPEC1; } else { uart_puts("sd: MMC\r\n"); mmc = 1; sd_type = SD_TYPE_MMC; } } uart_puts("sd: wait for card to get ready\r\n"); /* wait for the card to get ready */ for (k = 0; ; k++) { if (sd_type == SD_TYPE_SPEC1 || sd_type == SD_TYPE_SPEC2) { // if not mmc uint32_t arg = 0; if (sd_type == SD_TYPE_SPEC2) { arg = 0x40000000; } sd_cmd(CMD_APP, 0); r = sd_cmd(CMD_SD_SEND_OP_COND, arg); } else { r = sd_cmd(CMD_SEND_OP_COND, 0); } if ((r & (1 << R1_IDLE_STATE)) == 0) { uart_puts("sd: entered IDLE state (ready)\r\n"); break; } if (k == 0x7fff) { uart_puts("sd: card didn't enter IDLE state (not ready)\r\n"); //sd_deselect(); //return 1; break; } } if (sd_type == SD_TYPE_SPEC2) { r = sd_cmd(CMD_READ_OCR, 0); if (r) { uart_puts("sd: OCR command failed\r\n"); sd_deselect(); return 1; } else { if (sd_recv() & 0x40) { uart_puts("sd: card mode - SDHC\r\n"); sd_type = SD_TYPE_SDHC; } sd_recv(); sd_recv(); sd_recv(); } } if (sd_cmd(CMD_SET_BLOCKLEN, 512) != 0) { uart_puts("sd: failed to set block length to 512 bytes\r\n"); sd_deselect(); return 1; } uart_puts("sd: done\r\n"); sd_deselect(); sdok = 1; return 0; }
SDErr sd_init() { int i; // Set clock rate to 400kHz SDErr errsv = spi_set_clockrate(400000); // Save so available for printing if (errsv != SD_SUCCESS) { return errsv; } // Set CS high for wake-up phase *sd_cs_ptr = 1; // Send 80 dummy bits == 10 dummy bytes for (i = 0; i < 10; i++) { spi_send(0xFF); } // Set CS low to begin sending commands *sd_cs_ptr = 0; // Send GO_IDLE //printf("Initializing card\n"); sd_res.r1 = sd_cmd(0, 0, 0, 0, 0, 0x94); // GO_IDLE if (sd_res.r1 != 1) { //printf("Error: %02X\n", sd_res.r1); return SD_GOIDLE; } //printf("Card entered SPI Mode\n"); // Send CMD8 (SEND_IF_COND) const uint8_t volt_range = 0x01; // 0x01 = 2.7V - 3.6V const uint8_t check_pattern = 0xAA; // Constant //printf("Sending CMD8\n"); sd_res.r7[0] = sd_cmd(8, 0, 0, volt_range, check_pattern, 0x86); //printf("Initial: "); //sd_print_r1(sd_res.r7[0]); for (i = 0; i < 4; i++) { sd_res.r7[1 + i] = spi_send(0xFF); //printf("%02X ", sd_res.r7[1 + i]); } //printf("\n"); // Verify response if (sd_res.r7[0] != 0x01 || sd_res.r7[1] != 0x00 || sd_res.r7[2] != 0x00 || sd_res.r7[3] != volt_range || sd_res.r7[4] != check_pattern) { /* printf("Invalid R7 response to CMD8: "); for (i = 0; i < 5; i++) { printf("%02X ", sd_res.r7[i]); } printf("\n"); */ return SD_SENDIFCOND_BADRES; } // Send ACMD41 (SD_SEND_OP_COND) //printf("Sending ACMD41\n"); // First try with HCS if (SD_SUCCESS != sd_send_op_cond_cmd(1)) { errsv = sd_send_op_cond_cmd(0); // On failure, try without if (SD_SUCCESS != errsv) { //printf("Unable to initialize card\n"); return errsv; } } //printf("Card initialized to Data Transfer Mode\n"); // Disable CRC - CMD59 /* printf("Disabling CRC\n"); sd_res.r1 = sd_cmd(59, 0, 0, 0, 0, 0xFF); if (sd_res.r1 != 0) { printf("Unable to disable CRC: "); sd_print_r1(sd_res.r1); printf("\n"); return SD_CRC_BADRES; } */ // TODO: Read OCR of card (CMD58) // Set block length - CMD16 //printf("Setting block length to 512 bytes\n"); sd_res.r1 = sd_cmd(16, 0, 0, 0x02, 0, 0xFF); // Block Length = 512 bytes = 0x0200 if (sd_res.r1 != 0) { /* printf("Unable to set block length: "); sd_print_r1(res); printf("\n"); */ return SD_BLKLEN_BADRES; } sd_global_info.block_sz = 512; // Increase clock rate to maximum errsv = spi_set_clockrate(20000000); // 20MHz if (errsv != SD_SUCCESS) { //printf("Unable to increase clock rate"); return errsv; } return SD_SUCCESS; }
static int sd_reset_sequence(struct sd_host *host) { struct sd_command *cmd = &host->cmd; u8 d; int i; int retval = 0; u32 cmd_ret = 0; host->card.state = 0; /* * Wait at least 80 dummy clock cycles with the card deselected * and with the MOSI line continuously high. */ exi_dev_take(host->exi_device); exi_dev_deselect(host->exi_device); for (i = 0; i < SD_IDLE_CYCLES; i++) { d = 0xff; exi_dev_write(host->exi_device, &d, sizeof(d)); } exi_dev_give(host->exi_device); /* * Send a CMD0, card must ack with "idle state" (0x01). * This puts the card into SPI mode and soft resets it. * CRC checking is disabled by default. */ for (i = 0; i < 255; i++) { /* CMD0 */ sd_cmd_go_idle_state(cmd); retval = sd_run_no_data_command(host, cmd); if (retval < 0) { retval = -ENODEV; goto out; } if (retval == R1_SPI_IDLE) { break; } } if (retval != R1_SPI_IDLE) { retval = -ENODEV; goto out; } /* * Send CMD8 and CMD58 for SDHC support */ for (i = 0; i < 8; i++) { sd_cmd_crc(cmd, SD_SEND_IF_COND, 0x01AA, 0x87); //CMD8 + Check and CRC retval = sd_start_command(host, cmd); if(retval==0x01) { memset(&cmd_ret, 0, sizeof(cmd_ret)); spi_read(host, &cmd_ret, sizeof(cmd_ret)); sd_end_command(host); if (cmd_ret == 0x01AA) { //Check if CMD8 is alright sd_cmd(cmd, MMC_SPI_READ_OCR, 0);//CMD58 retval = sd_start_command(host, cmd); memset(&cmd_ret, 0, sizeof(cmd_ret)); spi_read(host, &cmd_ret, sizeof(cmd_ret)); sd_end_command(host); if(retval==0x01) { //Everything is alright break; } } break; } else if(retval==0x05) { //NO SDHC-Card break; } } /* * Send a ACMD41 to activate card initialization process. * SD card must ack with "ok" (0x00). * MMC card will report "invalid command" (0x04). */ for (i = 0; i < 65535; i++) { /* ACMD41 = CMD55 + CMD41 */ sd_cmd(cmd, MMC_APP_CMD, 0); retval = sd_run_no_data_command(host, cmd); if (retval < 0) { retval = -ENODEV; goto out; } sd_cmd(cmd, SD_APP_OP_COND, (1<<30)|0x100000); retval = sd_run_no_data_command(host, cmd); if (retval < 0) { retval = -ENODEV; goto out; } if (retval == 0x00) { /* we found a SD card */ mmc_card_set_present(&host->card); host->card.type = MMC_TYPE_SD; break; } else if(retval != 0x01) { DBG("ACMD41 return: %d\n", retval); } if ((retval & R1_SPI_ILLEGAL_COMMAND)) { /* this looks like a MMC card */ break; } } /* * MMC cards require CMD1 to activate card initialization process. * MMC card must ack with "ok" (0x00) */ if (!mmc_card_sd(&host->card)) { for (i = 0; i < 65535; i++) { sd_cmd(cmd, MMC_SEND_OP_COND, 0); retval = sd_run_no_data_command(host, cmd); if (retval < 0) { retval = -ENODEV; goto out; } if (retval == 0x00) { /* we found a MMC card */ mmc_card_set_present(&host->card); break; } } if (retval != 0x00) { DBG("MMC card, bad, retval=%02x\n", retval); sd_card_set_bad(host); } } out: return retval; }