📄 main.c
字号:
* Input arguments:
*
* <none>
*
* Returns:
*
* TR_OK if successful, TR_FAILURE otherwise
*
*/
int get_sd_cid(void)
{
CLEAR_ARGS(arg);
cprintf(C"-> Requesting CID (Card Identification)\r\n");
xmitcmd(CMD10_SEND_CID, arg);
if (waitForR1(rxbuf, 18) < 0) {
cprintf(C"ERROR: Timeout on CMD10_SEND_CID\r\n");
return TR_FAILURE;
}
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: CID failed internal CRC7 check\r\n");
return TR_FAILURE;
}
/* Dump human-readable Card Identification data */
decodeCID(&rxbuf[1]);
return 0;
}
/* Dump a buffer in hexadecimal and printable ASCII format to the console
*
* Input arguments:
*
* b - byte buffer to dump
* len - number of bytes to dump
*
* Returns:
*
* <none>
*
*/
void hexdump(uint8_t *b, uint16_t len)
{
int x, c;
int line;
cprintf(C"ADDR| 0 1 2 3 4 5 6 7 8 9 A B C D E F | ASCII\r\n");
cprintf(C"------------------------------------------------------------------------\r\n");
for (line = 0; line < ((len % 16) ? (len / 16) + 1 : (len / 16)); line++) {
cprintf(C"%04X| ", line * 16);
for (x = 0; x < 16; x++) {
if (x + (line * 16) < len) {
c = b[x+line*16];
cprintf(C"%02x ", c);
} else {
cprintf(C" ");
}
}
cprintf(C"| ");
for (x = 0; x < 16; x++) {
if (x + (line * 16) < len) {
c = b[x+line*16];
if ((c > 0x1f) && (c < 0x7f)) {
cprintf(C"%c", c);
} else {
cprintf(C".");
}
} else {
cprintf(C" ");
}
}
cprintf(C"\r\n");
}
cprintf(C"------------------------------------------------------------------------\r\n");
}
/* Read a block from the SD card into the block buffer
*
* Input arguments:
*
* blocknr - block address to read
*
* Returns:
*
* TR_OK if successful, TR_FAILURE otherwise
*
*/
int readblock(uint32_t blocknr)
{
int result;
/* Read a block from the card */
cprintf(C"-> Reading block %u from card\r\n", blocknr);
/* The SD card read command requires a byte address aligned on */
/* block boundaries. Compute this address from the block address */
blocknr *= blocksize;
/* This byte address is stored MSB-first in the argument buffer */
arg[0] = (blocknr & 0xff000000L) >> 24;
arg[1] = (blocknr & 0x00ff0000L) >> 16;
arg[2] = (blocknr & 0x0000ff00L) >> 8;
arg[3] = blocknr & 0x000000ffL;
/* Transmit the read command plus the byte address argument */
xmitcmd(CMD17_READ_SINGLE_BLOCK, arg);
/* We read 514 bytes as this is the blocksize (512) plus two CRC-16 bytes */
if ((result = waitForR1(rxbuf, 514)) < 0) {
switch (result) {
case TR_INVALID_ARG:
cprintf(C"Invalid argument\r\n");
break;
case TR_TIMEOUT:
cprintf(C"Data timeout\r\n");
break;
case TR_ERROR_TOKEN:
cprintf(C"Error token: 0x%02x\r\n", rxbuf[1]);
break;
case TR_NOT_IDLE:
cprintf(C"Bus not idle at end of transaction\r\n");
break;
}
return TR_FAILURE;
}
if (check_r1(rxbuf[0], R1_NOERROR) < 0) {
cprintf(C"Read failure\r\n");
return TR_FAILURE;
}
if (verifyCRC(SD_CRC16, &rxbuf[1], 512, (rxbuf[513]<<8) + rxbuf[514])
!= CRC_OK) {
cprintf(C"ERROR: Data block did not pass CRC16 check\r\n");
return TR_FAILURE;
}
/* Dump the data for the user to examine */
hexdump(rxbuf+1, 512);
return TR_OK;
}
/* Write the block buffer into the SD card at the specified address
*
* Input arguments:
*
* blocknr - block address to write
*
* Returns:
*
* TR_OK if successful, TR_FAILURE otherwise
*
*/
int writeblock(uint32_t blocknr)
{
uint8_t rxdata;
uint16_t i, crc = 0x0000;
int result;
/* Write the block buffer back to card */
cprintf(C"-> Write block %u to card\r\n", blocknr);
/* Prepare the block buffer by adding the data start token */
rxbuf[0] = 0xfe;
/* Run a CRC-16 over the 512 bytes of data and append this to the end */
for (i = 1; i < 513; i++) {
crc = crc_16(crc, rxbuf[i]);
}
crc = crc_16augment(crc);
rxbuf[513] = crc >> 8;
rxbuf[514] = crc & 0x00ff;
/* The SD card read command requires a byte address aligned on */
/* block boundaries. Compute this address from the block address */
blocknr *= blocksize;
/* This byte address is stored MSB-first in the argument buffer */
arg[0] = (blocknr & 0xff000000L) >> 24;
arg[1] = (blocknr & 0x00ff0000L) >> 16;
arg[2] = (blocknr & 0x0000ff00L) >> 8;
arg[3] = blocknr & 0x000000ffL;
/* Transmit the write command plus the byte address argument */
xmitcmd(CMD24_WRITE_BLOCK, arg);
/* The card will respond with a R1 format response indicating the */
/* validity of the command and argument before a write can begin */
if ((result = waitForR1(&rxdata, 0)) < 0) {
switch (result) {
case TR_INVALID_ARG:
cprintf(C"Invalid argument\r\n");
break;
case TR_TIMEOUT:
cprintf(C"Data timeout\r\n");
break;
case TR_NOT_IDLE:
cprintf(C"Bus not idle at end of transaction\r\n");
break;
}
return TR_FAILURE;
}
if (check_r1(rxdata, R1_NOERROR) < 0) {
return TR_FAILURE;
}
/* Send the block of data to the SD card */
for (i = 0; i < BLOCK_BUFFER_LEN; i++) {
rxdata = xferSPI(rxbuf[i]);
if (rxdata != 0xff) {
/* The bus should be idle whilst we are transmitting */
/* If this is not the case, flag it */
cprintf(C"During write, strange readback 0x%x\r\n", rxdata);
}
}
/* Wait for the data response token */
i = 0;
rxdata = xferSPI(0xff);
/* The format of the data response token is: xxx0ddd1 */
/* where x is don't-care, and ddd is the three-bit response code */
while ((rxdata & 0x10) || ((rxdata & 0x01) == 0)) {
i++;
if (i > WAIT_WRITE_TIMEOUT) {
/* After an arbitrarily large wait, give up and signal error */
/* A fully-compliant SD host would use the timeout calculated */
/* from the CSD register to time out the write transaction */
cprintf(C"Timeout\r\n");
return TR_TIMEOUT; /* Write timeout */
}
}
/* Interpret the response */
switch ((rxdata & 0x0e) >> 1) {
case 0x02:
cprintf(C"Data accepted!\r\n");
break;
case 0x05:
cprintf(C"Rejected (CRC)\r\n");
break;
case 0x06:
cprintf(C"Rejected (Write)\r\n");
break;
default:
cprintf(C"Illegal response!", rxdata);
break;
}
/* The SD card will now send a stream of idle tokens (0x00) on its DO */
/* line to indicate that it is busy writing the requested data to */
/* the non-volatile storage. We must wait until the bus returns to */
/* idle (0xff) before issuing any other commands */
i = 0;
rxdata = xferSPI(0xff);
while (rxdata != 0xff) {
/* Busy token sent back. Keep looping until timeout */
i++;
if (i > WAIT_WRITE_TIMEOUT) {
return TR_TIMEOUT;
}
rxdata = xferSPI(0xff);
}
return TR_OK;
}
int main(void)
{
uint8_t done, i, numarg, inbuf[INPUT_BUFFER_LEN];
uint16_t blocknr;
/* Set up the serial port for 115200 bps, no parity, 8 bits, 1 stop bit */
SCON0 = SCON0_REN | SCON0_SM1;
SMD0 = SMD0_SMOD0;
PR0 = 0x3afb; /* 115200 bps for 16MHz HF xtal */
/* Set up the SPI port */
SPICF = 0x00; /* Rising clock latches data, 8-bit */
SPICK = 0x28; /* div 42 sysclock == 380kHz */
SPICN |= 0x03; /* Enable SPI master */
PD5 |= 0x10; /* /SS used as an output */
PO5 |= 0x10; /* /SS = 1 */
cprintf(C"\r\nMAXQ2000 SD Card via SPI Demo Application\r\n");
done = 0;
while (!done) {
/* Output a prompt */
cprintf(C"> ");
/* Get input */
i = 0;
while ((i < INPUT_BUFFER_LEN-1) && ((inbuf[i] = readuart())!= 0x0d)) {
cprintf(C"%c", inbuf[i]);
i++;
}
cprintf(C"\r\n");
inbuf[i] = 0x00; /* Null terminate at all costs */
/* Attempt to convert to command */
if ((numarg = sscanf(inbuf, "%c %hu", &i, &blocknr)) < 1) {
cprintf(C"No command.");
} else {
switch (i) {
case 'd':
/* Dump the block buffer in a human-readable format */
hexdump(rxbuf, 1);
hexdump(rxbuf+1, 512);
hexdump(rxbuf+512, 2);
break;
case 'c':
PO5 &= ~0x10; /* Select chip */
/* Retrieve Card Identification register */
get_sd_cid();
PO5 |= 0x10; /* Deselect chip */
break;
case 's':
PO5 &= ~0x10; /* Select chip */
/* Retrieve Card Specific Data register */
get_sd_csd();
PO5 |= 0x10; /* Deselect chip */
break;
case 'i':
PO5 &= ~0x10; /* Select chip */
/* Start the SD card in SPI mode */
if (init_sd_card(10) == TR_OK) {
cprintf(C"SD card intialized OK.\r\n");
} else {
cprintf(C"Error initializing SD card.\r\n");
}
PO5 |= 0x10; /* Deselect chip */
break;
case 'r':
/* Read a block into buffer and display */
PO5 &= ~0x10; /* Select chip */
if (numarg == 2) {
if (readblock(blocknr) == TR_OK) {
cprintf(C"Read successful.\r\n");
} else {
cprintf(C"Read failed.\r\n");
}
} else {
cprintf(C"Read requires block number <arg1>\r\n");
}
PO5 |= 0x10; /* Deselect chip */
break;
case 'w':
/* Write a block from buffer */
PO5 &= ~0x10; /* Select chip */
if (numarg == 2) {
if (writeblock(blocknr) == TR_OK) {
cprintf(C"Write successful.\r\n");
} else {
cprintf(C"Write failed.\r\n");
}
} else {
cprintf(C"Write requires block number\r\n");
}
PO5 |= 0x10; /* Deselect chip */
break;
case 'e':
/* Edit block buffer */
/* for now, simply zero buffer and put "MAXQ2000 SD SPI" in buffer */
cprintf(C"Block buffer cleared and set to default\r\n");
memset(rxbuf+1, 0x00, 512);
strcpy(rxbuf+1, "MAXQ2000 SD SPI");
break;
case 'f':
/* Flush the SPI bus */
PO5 &= ~0x10; /* Select chip */
if (flush_spi(1000) == TR_TIMEOUT) {
cprintf(C"Error: Unable to flush SPI bus. Idle not detected.\r\n");
}
PO5 |= 0x10; /* Deselect chip */
break;
default:
cprintf(C"Program Usage:\r\n");
cprintf(C" i - Initialize card. MUST BE DONE FIRST AFTER ANY MEDIA CHANGE.\r\n");
cprintf(C" c - Retrieve Card Identification register\r\n");
cprintf(C" s - Retrieve Card Specific Data register\r\n");
cprintf(C" d - Dump the block buffer in hexadecimal and ASCII format\r\n");
cprintf(C" r <address> - Reads card block <address> into the block buffer\r\n");
cprintf(C" w <address> - Writes the block buffer to card at block <address>\r\n");
cprintf(C" e - Set block buffer to \"MAXQ2000 SD SPI\"\r\n");
cprintf(C" f - Flush all SPI bus bytes until 5 idle bytes are detected\r\n");
break;
}
}
}
while (1); /* jump $ */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -