/* * This function synchronously waits any pending block transfers * are finished. If your program needs to ensure a block has finished * transferring, call this function. * * Note that sd_read_block() and sd_write_block() already call this * function internally before attempting a new transfer, so there are * only two times when a user would need to use this function. * * 1) When the processor will be shutting down. All pending * writes should be finished first. * 2) When the user needs the result of an sd_read_block() call * right away. */ void sd_wait_notbusy(sd_context_t *sdc) { /* Just twiddle our thumbs until the transfer's done */ while ((DMA0CTL & DMAEN) != 0); /* Reset the DMA controller */ DMACTL0 = 0; /* Ignore the checksum */ sd_delay(4); /* Check for the busy flag (set on write block) */ if (sdc->busyflag == 1) { while (spi_recv_byte() != 0xFF); sdc->busyflag = 0; } /* Deassert CS */ spi_cs_deassert(); /* * Send some extra clocks so the card can resynchronize * on next transfer */ sd_delay(2); }
//**********************************************************************************// // Function Name: spi_recv_data // // Arguments : U8 *data, U16 no_bytes // // Return Types : NONE // // Description : Function to receive no of bytes from slave specified by // // "U16 no_byte" the argument & are stored in "U8 *data" // //**********************************************************************************// void spi_recv_data(U8 *data, U16 no_byte) { U16 temp_count; for(temp_count = 0; temp_count < no_byte; temp_count++) { *data = spi_recv_byte(); data++; } }
/* * This function writes a single block to the SD card at block * blockaddr. Returns 1 if the command was successful, zero * otherwise. * * This is an ASYNCHRONOUS call. The transfer will not be complete * when the function returns. If you want to explicity wait until * any pending transfer are finished, use the function * sd_wait_notbusy(sdc) * * sd_context_t *sdc -- A pointer to an sd device context structure, * populated by the function sd_initialize() * u32 blockaddr -- The block address to write to the card. * This is a block address, not a linear address. * unsigned char *data -- The data, a pointer to an array of unsigned * chars. */ int sd_write_block(sd_context_t *sdc, u32 blockaddr, unsigned char *data) { /* Adjust the block address to a linear address */ blockaddr <<= SD_BLOCKSIZE_NBITS; /* Wait until any old transfers are finished */ sd_wait_notbusy(sdc); /* Pack the address */ sd_packarg(argument, blockaddr); if (sd_send_command(sdc, CMD24, CMD24_R, response, argument) == 0) return 0; /* Check for an error, like a misaligned write */ if (response[0] != 0) return 0; /* Re-assert CS to continue transfer */ spi_cs_assert(); /* * The write command need an addition 8 lock cycles before the * block write is started */ spi_recv_byte(); /* Clear any pending flags */ IFG1 &= ~(URXIFG0 | UTXIFG0); /* Get the block */ /* Source DMA address: receive register */ DMA0SA = (unsigned int)data; /* Destination DMA address: the user data buffer */ DMA0DA = U0TXBUF_; /* The size of the block to be transfered */ DMA0SZ = SD_BLOCKSIZE; /* Configure the DMA transfer */ DMA0CTL = DMADT_0 | /* Single transfer mode */ DMASBDB | /* Byte mode */ DMAEN | /* Enable DMA */ DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */ /* DMA trigger UART send */ DMACTL0 = DMA0TSEL_3; /* Kick off transfer by sending the first byte */ U0TXBUF = SD_TOK_WRITE_STARTBLOCK; /* * Signal that the card may be busy, so any subsequent commands * should wait for the busy signalling to end (indicated by a * nonzero response) */ sdc->busyflag = 1; return 1; }
/* * This function reads a single block from the SD card at block * blockaddr. The buffer must be preallocated. Returns 1 if the * command was successful, zero otherwise. * * This is an ASYNCHRONOUS call. The transfer will not be complete * when the function returns. If you want to explicity wait until * any pending transfer are finished, use the function * sd_wait_notbusy(sdc) * * sd_context_t *sdc -- A pointer to an sd device context structure, * populated by the function sd_initialize() * u32 blockaddr -- The block address to read from the card. * This is a block address, not a linear address. * unsigned char *data -- The data, a pointer to an array of unsigned * chars. */ int sd_read_block(sd_context_t *sdc, u32 blockaddr, unsigned char *data) { u32 i = 0; unsigned char tmp; /* Adjust the block address to a linear address */ /* blockaddr <<= SD_BLOCKSIZE_NBITS; */ /* Wait until any old transfers are finished */ sd_wait_notbusy(sdc); /* Pack the address */ sd_packarg(argument, blockaddr); /* Need to add size checking */ if (sd_send_command(sdc, CMD17, CMD17_R, response, argument) == 0) return 0; /* Check for an error, like a misaligned read */ if (response[0] != 0) return 0; /* Re-assert CS to continue the transfer */ spi_cs_assert(); /* Wait for the token */ i = 0; do { tmp = spi_recv_byte(); i++; } while ((tmp == 0xFF) && i < sdc->timeout_read); if ((tmp & MSK_TOK_DATAERROR) == 0) { /* Clock out a byte before returning */ spi_send_byte(0xFF); /* The card returned an error response. Ball and return 0 */ return 0; } IFG1 &= ~URXIFG0; IFG1 &= ~UTXIFG0; /* Get the block */ /* Source DMA address: receive register */ DMA0SA = U0RXBUF_; /* Destination DMA address: the user data buffer */ DMA0DA = (unsigned int)data; /* The size of the block to be transfered */ DMA0SZ = SD_BLOCKSIZE; /* Configure the DMA transfer */ DMA0CTL = DMADT_0 | /* Single transfer mode */ DMASBDB | /* Byte mode */ DMAEN | /* Enable DMA */ DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */ /* * We depend on the DMA priorities here. Both triggers occur at * the same time, sine the source is identical. DMA0 is handled * first, and retrieves the byte. DMA1 is triggered next, and * sends the next byte. */ /* Source DMA address: constant 0xFF (don't increment) */ DMA1SA = (unsigned int)␣ /* Destination DMA address: the transmit buffer */ DMA1DA = U0TXBUF_; /* Increment the destination address */ /* The size of the block to be transfered */ DMA0SZ = SD_BLOCKSIZE - 1; /* Configure the DMA transfer */ DMA1CTL = DMADT_0 | /* Single transfer mode */ DMASBDB | /* Byte mode */ DMAEN; /* Enable DMA */ /* DMA trigger UART receive for both DMA0 and DMA1 */ DMACTL0 = DMA0TSEL_3 | DMA1TSEL_3; /* Kick off transfer by sending the first byte */ U0TXBUF = 0xFF; return 1; }