88 unpack_sd_pins((uint32_t *) pins);
127 PropWare::ErrorCode
start ()
const {
128 PropWare::ErrorCode err;
129 uint8_t response[16];
136 check_errors(this->reset_and_verify_v2_0(response));
138 check_errors(this->activate(response));
140 check_errors(this->increase_throttle());
154 return SECTOR_SIZE_SHIFT;
158 PropWare::ErrorCode err;
163 temp = (uint8_t) this->m_spi->
shift_in(8);
170 this->send_command(CMD_RD_BLOCK, address, CRC_OTHER);
171 err = this->read_block(SECTOR_SIZE, buf);
178 PropWare::ErrorCode err;
183 temp = (uint8_t) this->m_spi->
shift_in(8);
186 this->send_command(CMD_WR_BLOCK, address, CRC_OTHER);
188 check_errors(this->write_block(SECTOR_SIZE, dat));
194 uint16_t
get_short (
const uint16_t offset,
const uint8_t buf[])
const {
195 return (buf[offset + 1] << 8) + buf[offset];
198 uint32_t
get_long (
const uint16_t offset,
const uint8_t buf[])
const {
199 return (buf[offset + 3] << 24) + (buf[offset + 2] << 16) + (buf[offset + 1] << 8) + buf[offset];
202 void write_short (
const uint16_t offset, uint8_t buf[],
const uint16_t value)
const {
203 buf[offset + 1] = value >> 8;
207 void write_long (
const uint16_t offset, uint8_t buf[],
const uint32_t value)
const {
208 buf[offset + 3] = (uint8_t) (value >> 24);
209 buf[offset + 2] = (uint8_t) (value >> 16);
210 buf[offset + 1] = (uint8_t) (value >> 8);
211 buf[offset] = (uint8_t) value;
221 const uint8_t relativeError = err -
BEG_ERROR;
225 printer <<
"SD Error " << relativeError <<
": Invalid command\n";
228 printer <<
"SD Error " << relativeError <<
": Timed out during read\n";
231 printer <<
"SD Error " << relativeError <<
": Invalid number of bytes\n";
234 printer <<
"SD Error " << relativeError <<
": Invalid first-byte response\n";
236 SD::first_byte_expansion(printer);
239 printer <<
"SD Error " << relativeError <<
": Invalid response during initialization\n";
243 printer <<
"SD Error " << relativeError <<
": Invalid data-start ID\n";
256 inline PropWare::ErrorCode reset_and_verify_v2_0 (uint8_t response[])
const {
257 PropWare::ErrorCode err;
262 stageCleared =
false;
263 for (i = 0; i < 10 && !stageCleared; ++i) {
265 for (j = 0; j < 10 && !stageCleared; ++j) {
270 this->reset(response, stageCleared);
277 stageCleared =
false;
278 check_errors(this->verify_v2_0(response, &stageCleared));
286 if ((HOST_VOLTAGE_3V3 != response[2]) || (R7_CHECK_PATTERN != response[3]))
295 inline void power_up ()
const {
301 for (i = 0; i < 32; ++i)
302 this->m_spi->
shift_out(24, (uint32_t) -1);
305 inline void reset (uint8_t response[],
bool &isIdle)
const {
310 this->send_command(CMD_IDLE, 0, CRC_IDLE);
311 this->get_response(RESPONSE_LEN_R1, firstByte, response);
314 if (RESPONSE_IDLE == firstByte)
318 inline PropWare::ErrorCode verify_v2_0 (uint8_t response[],
bool *stageCleared)
const {
319 PropWare::ErrorCode err;
323 this->send_command(CMD_INTERFACE_COND, ARG_CMD8, CRC_CMD8);
324 check_errors(this->get_response(RESPONSE_LEN_R7, firstByte, response));
325 if (RESPONSE_IDLE == firstByte)
326 *stageCleared =
true;
331 inline PropWare::ErrorCode activate (uint8_t response[])
const {
332 const uint32_t wiggleRoom = 3 * MILLISECOND;
338 PropWare::ErrorCode err;
342 this->send_command(CMD_APP, 0, CRC_ACMD_PREP);
343 check_errors(this->get_response(RESPONSE_LEN_R1, firstByte, response));
346 this->send_command(CMD_WR_OP, BIT_30, 0x77);
347 check_errors(this->get_response(RESPONSE_LEN_R1, firstByte, response));
350 if (RESPONSE_ACTIVE == firstByte)
360 inline PropWare::ErrorCode increase_throttle ()
const {
361 return this->m_spi->
set_clock(FULL_SPEED_SPI);
374 void send_command (
const uint8_t cmd,
const uint32_t arg,
const uint8_t crc)
const {
380 this->m_spi->
shift_out(16, arg & WORD_0);
397 PropWare::ErrorCode get_response (uint8_t numBytes, uint8_t &firstByte, uint8_t *dat)
const {
403 firstByte = (uint8_t) this->m_spi->
shift_in(8);
406 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
410 }
while (0xff == firstByte);
416 if ((RESPONSE_IDLE == firstByte) || (RESPONSE_ACTIVE == firstByte)) {
421 *dat++ = (uint8_t) this->m_spi->
shift_in(8);
429 this->m_spi->
shift_out(16, (uint32_t) -1);
430 this->m_spi->
shift_out(16, (uint32_t) -1);
431 this->m_spi->
shift_out(16, (uint32_t) -1);
432 this->m_spi->
shift_out(16, (uint32_t) -1);
447 PropWare::ErrorCode read_block (uint16_t bytes, uint8_t dat[])
const {
455 firstByte = (uint8_t) this->m_spi->
shift_in(8);
458 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
462 }
while (0xff == firstByte);
465 if (RESPONSE_ACTIVE == firstByte) {
469 dat[0] = (uint8_t) this->m_spi->
shift_in(8);
472 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
476 }
while (DATA_START_ID != dat[0]);
479 if (DATA_START_ID == *dat) {
481 if (SECTOR_SIZE == bytes)
485 *dat++ = (uint8_t) this->m_spi->
shift_in(8);
491 checksum = (uint8_t) this->m_spi->
shift_in(8);
494 if ((
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
498 }
while (0xff == checksum);
520 PropWare::ErrorCode write_block (uint16_t bytes,
const uint8_t dat[])
const {
527 firstByte = (uint8_t) this->m_spi->
shift_in(8);
530 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
534 }
while (0xff == firstByte);
537 if (RESPONSE_ACTIVE == firstByte) {
541 this->m_spi->
shift_out(8, DATA_START_ID);
544 if (SECTOR_SIZE == bytes)
554 firstByte = (uint8_t) this->m_spi->
shift_in(8);
557 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
561 }
while (0xff == firstByte);
562 if (RSPNS_TKN_ACCPT != (firstByte & (uint8_t) RSPNS_TKN_BITS))
574 if (abs(
timeout -
CNT) < SINGLE_BYTE_WIGGLE_ROOM)
578 }
while (0xff != temp);
583 static void first_byte_expansion (
const Printer &printer) {
585 printer.puts(
"\t0: Idle\n");
587 printer.puts(
"\t1: Erase reset\n");
589 printer.puts(
"\t2: Illegal command\n");
591 printer.puts(
"\t3: Communication CRC error\n");
593 printer.puts(
"\t4: Erase sequence error\n");
595 printer.puts(
"\t5: Address error\n");
597 printer.puts(
"\t6: Parameter error\n");
599 printer.puts(
"\t7: Something is really screwed up. This should always be 0.\n");
604 static void unpack_sd_pins (uint32_t pins[]) {
606 #ifdef __PROPELLER_COG__
607 " jmp #skipVars \n\t"
609 " brw #skipVars \n\t"
613 "__cfg_sdspi_config1 \n\t"
615 "__cfg_sdspi_config2 \n\t"
617 " .compress default \n"
631 static const uint16_t SECTOR_SIZE = 512;
632 static const uint8_t SECTOR_SIZE_SHIFT = 9;
635 static const uint32_t SPI_INIT_FREQ = 200000;
637 static const uint32_t FULL_SPEED_SPI = 900000;
639 static const SPI::BitMode SPI_BITMODE = SPI::BitMode::MSB_FIRST;
642 static const uint32_t RESPONSE_TIMEOUT;
643 static const uint32_t SEND_ACTIVE_TIMEOUT;
644 static const uint32_t SINGLE_BYTE_WIGGLE_ROOM;
647 static const uint8_t CMD_IDLE = 0x40 + 0;
648 static const uint8_t CMD_INTERFACE_COND = 0x40 + 8;
649 static const uint8_t CMD_RD_CSD = 0x40 + 9;
650 static const uint8_t CMD_RD_CID = 0x40 + 10;
651 static const uint8_t CMD_RD_BLOCK = 0x40 + 17;
652 static const uint8_t CMD_WR_BLOCK = 0x40 + 24;
653 static const uint8_t CMD_WR_OP = 0x40 + 41;
654 static const uint8_t CMD_APP = 0x40 + 55;
655 static const uint8_t CMD_READ_OCR = 0x40 + 58;
658 static const uint32_t HOST_VOLTAGE_3V3 = 0x01;
659 static const uint32_t R7_CHECK_PATTERN = 0xAA;
660 static const uint32_t ARG_CMD8 = ((HOST_VOLTAGE_3V3 << 8U) | R7_CHECK_PATTERN);
661 static const uint32_t ARG_LEN = 5;
664 static const uint8_t CRC_IDLE = 0x95;
665 static const uint8_t CRC_CMD8 = 0x87;
666 static const uint8_t CRC_ACMD_PREP = 0x65;
667 static const uint8_t CRC_ACMD = 0x77;
668 static const uint8_t CRC_OTHER = 0x01;
671 static const uint8_t RESPONSE_IDLE = 0x01;
672 static const uint8_t RESPONSE_ACTIVE = 0x00;
673 static const uint8_t DATA_START_ID = 0xFE;
674 static const uint8_t RESPONSE_LEN_R1 = 1;
675 static const uint8_t RESPONSE_LEN_R3 = 5;
676 static const uint8_t RESPONSE_LEN_R7 = 5;
677 static const uint8_t RSPNS_TKN_BITS = 0x0f;
678 static const uint8_t RSPNS_TKN_ACCPT = (0x02U << 1U) | 1U;
679 static const uint8_t RSPNS_TKN_CRC = (0x05U << 1U) | 1U;
680 static const uint8_t RSPNS_TKN_WR = (0x06U << 1U) | 1U;
690 const uint32_t SD::RESPONSE_TIMEOUT = 100 * MILLISECOND;
691 const uint32_t SD::SEND_ACTIVE_TIMEOUT = 500 * MILLISECOND;
692 const uint32_t SD::SINGLE_BYTE_WIGGLE_ROOM = 150 * MICROSECOND;