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";
235 printer <<
"\tReceived: " << _sd_firstByteResponse <<
'\n';
236 this->first_byte_expansion(printer);
239 printer <<
"SD Error " << relativeError <<
": Invalid response during initialization\n";
240 printer <<
"\tResponse: " << _sd_firstByteResponse <<
'\n';
243 printer <<
"SD Error " << relativeError <<
": Invalid data-start ID\n";
244 printer <<
"\tReceived: " << _sd_firstByteResponse <<
'\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 {
297 waitcnt(CLKFREQ / 10 + CNT);
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 PropWare::ErrorCode err;
335 uint32_t longWiggleRoom = 3 * MILLISECOND;
336 bool stageCleared =
false;
339 timeout = SEND_ACTIVE_TIMEOUT + CNT;
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, 0);
347 check_errors(this->get_response(RESPONSE_LEN_R1, firstByte, response));
350 if (RESPONSE_ACTIVE == firstByte)
354 if (abs(timeout - CNT) < longWiggleRoom)
358 }
while (!stageCleared);
366 inline PropWare::ErrorCode increase_throttle ()
const {
367 return this->m_spi->
set_clock(FULL_SPEED_SPI);
380 void send_command (
const uint8_t cmd,
const uint32_t arg,
const uint8_t crc)
const {
386 this->m_spi->
shift_out(16, arg & WORD_0);
403 PropWare::ErrorCode get_response (uint8_t numBytes, uint8_t &firstByte, uint8_t *dat)
const {
407 timeout = RESPONSE_TIMEOUT + CNT;
409 firstByte = (uint8_t) this->m_spi->
shift_in(8);
412 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
416 }
while (0xff == firstByte);
422 if ((RESPONSE_IDLE == firstByte) || (RESPONSE_ACTIVE == firstByte)) {
427 *dat++ = (uint8_t) this->m_spi->
shift_in(8);
429 _sd_firstByteResponse = firstByte;
435 this->m_spi->
shift_out(16, (uint32_t) -1);
436 this->m_spi->
shift_out(16, (uint32_t) -1);
437 this->m_spi->
shift_out(16, (uint32_t) -1);
438 this->m_spi->
shift_out(16, (uint32_t) -1);
453 PropWare::ErrorCode read_block (uint16_t bytes, uint8_t dat[])
const {
459 timeout = RESPONSE_TIMEOUT + CNT;
461 firstByte = (uint8_t) this->m_spi->
shift_in(8);
464 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
468 }
while (0xff == firstByte);
471 if (RESPONSE_ACTIVE == firstByte) {
473 timeout = RESPONSE_TIMEOUT + CNT;
475 dat[0] = (uint8_t) this->m_spi->
shift_in(8);
478 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
482 }
while (DATA_START_ID != dat[0]);
485 if (DATA_START_ID == *dat) {
487 if (SECTOR_SIZE == bytes)
491 *dat++ = (uint8_t) this->m_spi->
shift_in(8);
495 timeout = RESPONSE_TIMEOUT + CNT;
497 checksum = (uint8_t) this->m_spi->
shift_in(8);
500 if ((timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
504 }
while (0xff == checksum);
526 PropWare::ErrorCode write_block (uint16_t bytes,
const uint8_t dat[])
const {
531 timeout = RESPONSE_TIMEOUT + CNT;
533 firstByte = (uint8_t) this->m_spi->
shift_in(8);
536 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
540 }
while (0xff == firstByte);
543 if (RESPONSE_ACTIVE == firstByte) {
547 this->m_spi->
shift_out(8, DATA_START_ID);
550 if (SECTOR_SIZE == bytes)
558 timeout = RESPONSE_TIMEOUT + CNT;
560 firstByte = (uint8_t) this->m_spi->
shift_in(8);
563 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
567 }
while (0xff == firstByte);
568 if (RSPNS_TKN_ACCPT != (firstByte & (uint8_t) RSPNS_TKN_BITS))
575 timeout = RESPONSE_TIMEOUT + CNT;
577 temp = (char) this->m_spi->
shift_in(8);
580 if (abs(timeout - CNT) < SINGLE_BYTE_WIGGLE_ROOM)
584 }
while (0xff != temp);
589 void first_byte_expansion (
const Printer &printer) {
590 if (BIT_0 & _sd_firstByteResponse)
591 printer.
puts(
"\t0: Idle\n");
592 if (BIT_1 & _sd_firstByteResponse)
593 printer.
puts(
"\t1: Erase reset\n");
594 if (BIT_2 & _sd_firstByteResponse)
595 printer.
puts(
"\t2: Illegal command\n");
596 if (BIT_3 & _sd_firstByteResponse)
597 printer.
puts(
"\t3: Communication CRC error\n");
598 if (BIT_4 & _sd_firstByteResponse)
599 printer.
puts(
"\t4: Erase sequence error\n");
600 if (BIT_5 & _sd_firstByteResponse)
601 printer.
puts(
"\t5: Address error\n");
602 if (BIT_6 & _sd_firstByteResponse)
603 printer.
puts(
"\t6: Parameter error\n");
604 if (BIT_7 & _sd_firstByteResponse)
605 printer.
puts(
"\t7: Something is really screwed up. This should always be 0.\n");
610 static void unpack_sd_pins (uint32_t pins[]) {
612 " brw #skipVars \n\t" 614 "__cfg_sdspi_config1 \n\t" 616 "__cfg_sdspi_config2 \n\t" 618 " .compress default \n" 632 static const uint16_t SECTOR_SIZE = 512;
633 static const uint8_t SECTOR_SIZE_SHIFT = 9;
636 static const uint32_t SPI_INIT_FREQ = 200000;
638 static const uint32_t FULL_SPEED_SPI = 900000;
643 static const uint32_t RESPONSE_TIMEOUT;
644 static const uint32_t SEND_ACTIVE_TIMEOUT;
645 static const uint32_t SINGLE_BYTE_WIGGLE_ROOM;
648 static const uint8_t CMD_IDLE = 0x40 + 0;
649 static const uint8_t CMD_INTERFACE_COND = 0x40 + 8;
650 static const uint8_t CMD_RD_CSD = 0x40 + 9;
651 static const uint8_t CMD_RD_CID = 0x40 + 10;
652 static const uint8_t CMD_RD_BLOCK = 0x40 + 17;
653 static const uint8_t CMD_WR_BLOCK = 0x40 + 24;
654 static const uint8_t CMD_WR_OP = 0x40 + 41;
655 static const uint8_t CMD_APP = 0x40 + 55;
656 static const uint8_t CMD_READ_OCR = 0x40 + 58;
659 static const uint32_t HOST_VOLTAGE_3V3 = 0x01;
660 static const uint32_t R7_CHECK_PATTERN = 0xAA;
661 static const uint32_t ARG_CMD8 = ((HOST_VOLTAGE_3V3 << 8) | R7_CHECK_PATTERN);
662 static const uint32_t ARG_LEN = 5;
665 static const uint8_t CRC_IDLE = 0x95;
666 static const uint8_t CRC_CMD8 = 0x87;
667 static const uint8_t CRC_ACMD_PREP = 0x65;
668 static const uint8_t CRC_ACMD = 0x77;
669 static const uint8_t CRC_OTHER = 0x01;
672 static const uint8_t RESPONSE_IDLE = 0x01;
673 static const uint8_t RESPONSE_ACTIVE = 0x00;
674 static const uint8_t DATA_START_ID = 0xFE;
675 static const uint8_t RESPONSE_LEN_R1 = 1;
676 static const uint8_t RESPONSE_LEN_R3 = 5;
677 static const uint8_t RESPONSE_LEN_R7 = 5;
678 static const uint8_t RSPNS_TKN_BITS = 0x0f;
679 static const uint8_t RSPNS_TKN_ACCPT = (0x02 << 1) | 1;
680 static const uint8_t RSPNS_TKN_CRC = (0x05 << 1) | 1;
681 static const uint8_t RSPNS_TKN_WR = (0x06 << 1) | 1;
691 const uint32_t SD::RESPONSE_TIMEOUT = 100 * MILLISECOND;
692 const uint32_t SD::SEND_ACTIVE_TIMEOUT = 500 * MILLISECOND;
693 const uint32_t SD::SINGLE_BYTE_WIGGLE_ROOM = 150 * MICROSECOND;
void set_mask(const PropWare::Port::Mask mask)
int _cfg_sdspi_config2
Value is injected by propeller-load if set in the configuration file.
Utility class to handle general purpose I/O pins.
void write_short(const uint16_t offset, uint8_t buf[], const uint16_t value) const
Write two bytes to a buffer.
uint32_t get_long(const uint16_t offset, const uint8_t buf[]) const
Read four bytes from a buffer.
PropWare::ErrorCode read_data_block(const uint32_t address, uint8_t buf[]) const
Read a block of data from the device into RAM.
void clear() const
Clear selected output port (set it to 0)
Generic definitions and functions for the Parallax Propeller.
PropWare::ErrorCode set_clock(const int32_t frequency)
Change the SPI module's clock frequency.
void set_mosi(const Port::Mask mask)
Release the current MOSI pin as a floating input and set the new one as output.
void shift_out_block_msb_first_fast(const uint8_t buffer[], size_t numberOfBytes)
Receive an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first...
void shift_in_block_mode0_msb_first_fast(uint8_t *buffer, size_t numberOfBytes)
Receive an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first...
void shift_out(uint8_t bits, uint32_t value) const
Send a value out to a peripheral device.
Mode
Descriptor for SPI signal as defined by Motorola modes.
Container class that has formatting methods for human-readable output. This class can be constructed ...
void puts(const char string[]) const
Send a null-terminated character array.
void print_error_str(const Printer &printer, const ErrorCode err)
Create a human-readable error string.
void set_dir_out() const
Set the port for output.
Any device that uses blocks as hardware level abstraction.
void write_long(const uint16_t offset, uint8_t buf[], const uint32_t value) const
Write four bytes to a buffer.
void set_bit_mode(const BitMode bitmode)
Set the bitmode of SPI communication.
BitMode
Determine if data is communicated with the LSB or MSB sent/received first.
PropWare::ErrorCode start() const
Initialize SD card communication over SPI for 3.3V configuration.
uint16_t get_short(const uint16_t offset, const uint8_t buf[]) const
Read two bytes from a buffer.
uint16_t get_sector_size() const
Return the size of a sector (also known as a "block") for the given storage device.
int _cfg_sdspi_config1
Value is injected by propeller-load if set in the configuration file.
void set_miso(const Port::Mask mask)
Set the new pin as input.
PropWare::ErrorCode write_data_block(uint32_t address, const uint8_t dat[]) const
Write data to a storage device.
A simple SD driver communicating over the SPI protocol.
void set() const
Set selected output port high (set all pins to 1)
void set_sclk(const Port::Mask mask)
Release the current SCLK pin as a floating input and set the new one as output.
void set_mode(const Mode mode)
Set the mode of SPI communication.
SPI serial communications library; Core functionality comes from a dedicated assembly cog...
unsigned char _sd_firstByteResponse
First byte response receives special treatment to allow for verbose debugging (not for public use) ...
SD(SPI *spi, const Port::Mask mosi, const Port::Mask miso, const Port::Mask sclk, const Port::Mask cs)
Construct an SD object with the given SPI parameters.
uint8_t get_sector_size_shift() const
Determine the number of shifts required to multiply or divide a number by the sector size...
uint32_t shift_in(const unsigned int bits) const
Read a value from the MISO line.
static SPI * get_instance()
Best way to use SPI is through here, where you can get a shared instance of the SPI module (not threa...