📄 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 + -