// read a size Byte big block beginning at the address. char mmcReadBlock(const unsigned long address, const unsigned long count, unsigned char *pBuffer) { char rvalue = MMC_RESPONSE_ERROR; // Set the block length to read if (mmcSetBlockLength (count) == MMC_SUCCESS) { // Attempt to set block length MMC_CS_LOW (); // send read command MMC_READ_SINGLE_BLOCK=CMD17 mmcSendCmd (MMC_READ_SINGLE_BLOCK,address, 0xFF); // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { // Look for the data token to signify the start of data if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN) { // Clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block spiReadFrame(pBuffer, count); // Get CRC bytes (not really needed by us, but required by MMC) spiSendByte(DUMMY_CHAR); spiSendByte(DUMMY_CHAR); rvalue = MMC_SUCCESS; } else { // The data token was never received rvalue = MMC_DATA_TOKEN_ERROR; // 3 } } else { // The MMC never acknowledge the read command rvalue = MMC_RESPONSE_ERROR; // 2 } } else { // The block length was not set correctly rvalue = MMC_BLOCK_SET_ERROR; // 1 } MMC_CS_HIGH (); spiSendByte(DUMMY_CHAR); return rvalue; }// mmc_read_block
void main(void) { //Turn off the watchdog timer WDTCTL = WDTPW + WDTHOLD; P1DIR |= LED; P1OUT &= ~LED; //16MHz //Set DCO to 16 MHz calibrated DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; //Reset SD card by cycling power //Credit to Boris Cherkasskiy and his blog post on Launchpad+MMC P2DIR |= BIT2; P2OUT &= ~BIT2; __delay_cycles(1600000); // 100ms @ 16MHz P2OUT |= BIT2; __delay_cycles(1600000); // 100ms @ 16MHz //Initialize MMC library while (MMC_SUCCESS != mmcInit()); //Verify card ready while (MMC_SUCCESS != mmcPing()); //Check the memory card size volatile unsigned long size = mmcReadCardSize(); //Toggle the LED to indicate that reading was successful P1OUT ^= LED; //Test that the SD card is working //Read in the OEM name and version in bytes 3-10 volatile unsigned char block[64] = {0}; // Read in a 512 byte sector // This is a multipart process. // First you must mount the block, telling the SD card the relative offset // of your subsequent reads. Then you read the block in multiple frames. // We do this so we don't need to allocate a full 512 byte buffer in the // MSP430's memory. Instead we'll use smaller 64 byte buffers. This // means that an entire block will take 8 reads. The spiReadFrame command // reads in the given number of bytes into the byte array passed to it. // After reading all of the data in the block it should be unmounted. //volatile char result = mmcReadBlock(0, 64, block); //volatile char result = mmcMountBlock(0, 512); volatile char result = mmcMountBlock(0, 512); //My FAT partition apparently starts at block 129 (0x81) //If you have a FAT16 filesystem you could read data from that point //Read in the block 64 bytes at a time if (result == MMC_SUCCESS) { volatile int i = 0; //8 blocks of 64 to read for (i = 0; i < 8; ++i) { //If you set a breakpoint here you can examine the memory in the card. spiReadFrame((void*)block, 64); } mmcUnmountBlock(); } while (1); }