📄 main.c
字号:
*
* Important note:
* - Must be augmented with 7 zeros!
*
*/
new_crc = old_crc;
for (x = 7; x >= 0; x--) {
new_crc <<= 1;
new_crc |= GETBIT(data,x);
if (GETBIT(new_crc, 7) == 1) {
new_crc ^= 0x89; /* XOR with poly -- this clears the top bit, too!*/
}
}
return new_crc;
}
/* Provides the zero-padding final step to CRC-7
*
* Input arguments:
*
* old_crc - value from last call to crc_7()
*
* Returns:
*
* Finalized CRC-7 checksum
*
*/
uint8_t crc_7augment(uint8_t old_crc)
{
unsigned char new_crc;
int x;
new_crc = old_crc;
for (x = 0; x < 7; x++) {
new_crc <<= 1;
if (GETBIT(new_crc, 7) == 1) {
new_crc ^= 0x89; /* XOR with poly -- this clears the top bit, too!*/
}
}
return new_crc;
}
/* CRC-16 (CCITT) as described in the Secure Digital spec
*
* Input arguments:
*
* old_crc - 0x0000 to start new CRC, or value from previous call to continue
* data - data byte to add to CRC computation
*
* Returns:
*
* CRC-16 checksum which MUST be augmented by crc_16augment() before use
*
*/
uint16_t crc_16(uint16_t old_crc, uint8_t data)
{
uint16_t new_crc;
uint8_t flipit;
int x;
/* CRC-16's polynomial is x^16 + x^12 + x^5 + 1 */
new_crc = old_crc;
for (x = 7; x >= 0; x--) {
flipit = GETBIT(new_crc, 15); /* Carry-out from shift */
new_crc <<= 1;
new_crc |= GETBIT(data,x);
if (flipit == 1) {
/* Unlike CRC-7, we leave out the x^16 term because */
/* the carry bit has left our register */
new_crc ^= 0x1021;
}
}
return new_crc;
}
/* Provides the zero-padding final step to CRC-16
*
* Input arguments:
*
* old_crc - value from last call to crc_16()
*
* Returns:
*
* Finalized CRC-16 checksum
*
*/
uint16_t crc_16augment(uint16_t old_crc)
{
uint16_t new_crc;
uint8_t flipit;
int x;
new_crc = old_crc;
for (x = 0; x < 16; x++) {
flipit = GETBIT(new_crc, 15);
new_crc <<= 1;
if (flipit == 1) {
new_crc ^= 0x1021;
}
}
return new_crc;
}
/* Verifies CRC-7 or CRC-16 against expected value
*
* Input arguments:
*
* type - SD_CRC7 or SD_CRC16
* b - pointer to character data
* len - length of data to check (must not be 0,
* which returns CRC_FAIL)
* expect - expected CRC-7 (only LSB is significant) or CRC-16 value.
*
* Returns:
*
* CRC_OK (0) - Data passes integrity check by selected CRC algorithm
* CRC_FAIL (-1) - Data fails integrity check or wrong
*/
int verifyCRC(int type, uint8_t *b, uint32_t len, uint16_t expect)
{
uint16_t crc = 0x0000;
int i;
/* Sanity check arguments */
if ((b == NULL) || (len < 1) ||
(type != SD_CRC7) && (type != SD_CRC16)) {
return CRC_FAIL;
}
for (i = 0; i < len; i++) {
if (type == SD_CRC16) {
crc = crc_16(crc, *(b+i));
} else {
crc = crc_7((uint8_t)(crc & 0x00ff), *(b+i));
}
}
if (type == SD_CRC16) {
crc = crc_16augment(crc);
} else {
crc = crc_7augment(crc);
}
if (type == SD_CRC16) {
if (crc == expect) {
return CRC_OK;
}
} else {
if ((crc & 0x00ff) == (expect & 0x00ff)) {
return CRC_OK;
}
}
/* Always error out with failure by default. */
return CRC_FAIL;
}
/* Decode Card Identification register into human-readable format
*
* Input arguments:
*
* b - pointer to data buffer holding CID
*
* Returns:
*
* <none>
*
*/
void decodeCID(uint8_t *b)
{
cprintf(C" Manufacturer ID: 0x%02x\r\n", b[0]);
cprintf(C" OEM/Application ID: %c%c\r\n", b[1], b[2]);
cprintf(C" Product Name: %c%c%c%c%c\r\n", b[3], b[4], b[5], b[6], b[7]);
cprintf(C" Product Revision: %u.%u\r\n", b[8], b[9]);
cprintf(C" Serial Number: 0x%04x%04x\r\n",
(b[10] << 8)+b[11], (b[12] <<8) + b[13]);
cprintf(C" Date Code: 0x%04x\r\n", ((b[13] & 0x0f) << 8) + b[14]);
return;
}
/* Transmit command to card. Calculates the proper CRC and handles framing
*
* Input arguments:
*
* cmd - one of the SD card commands
* arg - four bytes which hold the SD command argument
*
* Returns:
*
* <none>
*
*/
void xmitcmd(uint8_t cmd, uint8_t *arg)
{
uint8_t crcb = 0x00;
uint8_t out;
/* First byte has framing bits and command */
out = 0x40 | (cmd & 0x3f);
crcb = crc_7(crcb, out);
xferSPI(out);
/* Next five bytes hold arguments, if any */
crcb = crc_7(crcb, arg[0]);
xferSPI(arg[0]);
crcb = crc_7(crcb, arg[1]);
xferSPI(arg[1]);
crcb = crc_7(crcb, arg[2]);
xferSPI(arg[2]);
crcb = crc_7(crcb, arg[3]);
xferSPI(arg[3]);
/* Finally, crc byte is transmitted,
* shifted left by one and the stop bit added
*/
crcb = crc_7augment(crcb);
out = (crcb << 1) | 0x01;
xferSPI(out);
}
/* Initialize SD card in SPI mode
*
* Input arguments:
*
* retries - number of retries to attempt before erroring out
*
* Returns:
*
* <none>
*
*/
int init_sd_card(int retries)
{
uint8_t rxdata;
int status, errors, i;
status = -1; /* Currently in error */
errors = 0; /* Retry counter */
CLEAR_ARGS(arg);
/* Just in case the card is in some unknown state */
/* Flush out all data and attempt to get back to an idle bus */
flush_spi(516);
/* Sent the CMD0_GO_IDLE_STATE while CS is asserted */
/* This signals the SD card to fall back to SPI mode */
while ((status == -1) && (errors < retries)) {
cprintf(C"-> Send CMD0_GO_IDLE_STATE\r\n");
xmitcmd(CMD0_GO_IDLE_STATE, arg);
if ((i = waitForR1(&rxdata, 0)) < 0) {
if (i == TR_TIMEOUT) {
cprintf(C"ERROR: Timeout\r\n");
}
if (i == TR_NOT_IDLE) {
cprintf(C"ERROR: Bus not idle\r\n");
}
errors++;
continue;
}
if (rxdata != R1_IDLE) {
cprintf(C"ERROR: R1 != R1_IDLE\r\n");
errors++;
continue;
}
status = 0; /* We're talking to the card */
cprintf(C"-> Got Idle Card State\r\n");
}
if (status < 0) {
/* Failure to talk to card */
return TR_FAILURE;
}
/* Now that card is in SPI mode with IDLE bit set, we need */
/* to send the command to start its initialization process */
/* and wait for R1_IDLE to disappear before issuing other commands */
status = 1;
errors = 0;
while(status && (errors < retries)) {
cprintf(C"-> Send CMD55_APP_CMD\r\n");
xmitcmd(CMD55_APP_CMD, arg);
if (waitForR1(&rxdata, 0) < 0) {
/* If this is a MultiMediaCard (not SD), it won't respond here */
cprintf(C"ERROR: Timeout! Perhaps this is a MMC card?\r\n");
return TR_TIMEOUT;
}
check_r1(rxdata, R1_IDLE);
cprintf(C"-> Send ACMD41_SEND_OP_COND\r\n");
xmitcmd(ACMD41_SEND_OP_COND, arg);
if (waitForR1(&rxdata, 0) < 0) {
cprintf(C"ERROR: Timeout on ACMD41_SEND_OP_COND\r\n");
return TR_TIMEOUT;
}
status = rxdata & R1_IDLE;
if (status) {
/* Pause here for a bit to let the card start up */
for (i = 0; i < 10000; i++); /* busy loop */
}
}
if (status) {
/* Card never signaled ready */
return TR_FAILURE;
}
/* Enable CRC to protect against bus-induced data errors */
cprintf(C"-> Send CMD59_CRC_ON_OFF\r\n");
arg[3] = 0x01; /* LSB set to 1 enables CRC verification */
xmitcmd(CMD59_CRC_ON_OFF, arg);
CLEAR_ARGS(arg);
if (waitForR1(&rxdata, 0) < 0) {
cprintf(C"ERROR: Timeout on CMD59_CRC_ON_OFF\r\n");
return TR_TIMEOUT;
}
check_r1(rxdata, R1_NOERROR);
return TR_OK;
}
/* Retrieve the Card-specific Data register and decode
*
* Input arguments:
*
* <none>
*
* Returns:
*
* TR_OK if successful, TR_FAILURE otherwise
*
*/
int get_sd_csd(void)
{
uint8_t multiplier;
uint32_t cardsize;
CLEAR_ARGS(arg);
cprintf(C"-> Requesting CSD (Card Specific Data)\r\n");
xmitcmd(CMD9_SEND_CSD, arg);
if (waitForR1(rxbuf, 18) < 0) {
cprintf(C"ERROR: Timeout on CMD9_SEND_CSD\r\n");
return -1;
}
check_r1(rxbuf[0], R1_NOERROR);
if (verifyCRC(SD_CRC16, &rxbuf[1], 16, (rxbuf[17]<<8) + rxbuf[18])
!= CRC_OK) {
cprintf(C"ERROR: Data block did not pass CRC16 check\r\n");
return TR_FAILURE;
}
if (verifyCRC(SD_CRC7, &rxbuf[1], 15, (rxbuf[16] >> 1)) != CRC_OK) {
cprintf(C"ERROR: CSD failed internal CRC7 check\r\n");
return TR_FAILURE;
}
/* Decode Card Specific Data */
/* A couple of items are of interest to us here:
*
* - block size of card (typically 512, but may differ) from READ_BL_LEN
* - total size of card from C_SIZE, C_SIZE_MULT, and READ_BL_LEN
*
*/
/* Blocksize is easy to decode */
blocksize = 0x01 << (rxbuf[6] & 0x0f);
/* Cardsize is split over several bytes */
cardsize = ((rxbuf[7] & 0x03) << 10) | (rxbuf[8] << 2) | (rxbuf[9] & 0xc0);
/* Multiplier is also split over several bytes */
multiplier = ((rxbuf[10] & 0x03) << 1) | (rxbuf[11] >> 7);
/* Compute final card size */
cardsize <<= (multiplier + 2); /* Multiplier is 2^(m+2) */
switch (blocksize) {
case 512:
cardsize >>= 11;
break;
case 1024:
break;
case 2048:
cardsize <<= 9;
break;
default:
cprintf(C"Unsupported blocksize!\r\n");
return TR_FAILURE;
break;
}
cprintf(C"Card size: %uMB\r\n", cardsize);
return TR_OK;
}
/* Retrieve the Card Identification register and decode
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -