/**
* @file   sd_drivers.c
*
* @brief  This file contains SD Card drivers that access the SPI hardware directly.
*   
* This module uses the NIOS II core in the Altera Cyclone 2 used on the DE1
* development board. It is assumed the processor core, SRAM, and SPI components
* have been initialized and programmed in the FPGA fabric.
*
* @author Dr. Pong Chu
* Revised by: David L. Kempert
*
*/
//********************************************************************************
#include <stdio.h>
#include <io.h>
#include <ctype.h>
#include "system.h"
#include "drivers.h"        ///< PIO stuff
#include "sd_drivers.h"


/*********************************************************************************
* Public Variables
**********************************************************************************/
int CardType=-1;    ///< initialize to an invalid card type

/*********************************************************************************
***
*** SPI related functions
***
**********************************************************************************/

/*********************************************************************************
* int sd_spi_is_ready(alt_u32 sd_base)
**********************************************************************************/
/**
* @brief  This function checks the ready signal of the SPI controller.
*
* While the SPI module is clocking data it is in a 'not ready' state and
* we must check this status before starting another transfer.
*
* @param sd_base - the base address of the SD card peripheral.
* @return - 1 if ready, 0 if not
*
*--------------------------------------------------------------------------------*/
int sd_spi_is_ready(alt_u32 sd_base)
{
	alt_u32 spi_reg;

	spi_reg = IORD(sd_base, SD_RD_DATA_REG);
	return((int)((spi_reg & 0x00000100) >> 8));
}

/*********************************************************************************
* void sd_spi_wr_cs(alt_u32 sd_base, alt_u32 en_bit)
**********************************************************************************/
/**
* @brief  This function enables/disables an SD card's chip select (ss).
*
* At this time there is only a single cs signal defined in the SPI hardware
* module. If more than one card can exist, a cs for each device must exist
* and a check must be added so that only one cs can be enabled at a time.
*
* @param sd_base - the base address of the SD card peripheral.
* @param en_bit - the cs state to be written.
*
*--------------------------------------------------------------------------------*/
void sd_spi_wr_cs(alt_u32 sd_base, alt_u32 en_bit)
{
	IOWR(sd_base, SD_CS_REG, en_bit);
}

/*********************************************************************************
* void sd_spi_wr_dvsr(alt_u32 sd_base, alt_u8 dvsr)
**********************************************************************************/
/**
* @brief  This function sets the SPI clock divisor.
*
* The formula to calculate the divisor is:  25,000,000 / clk rate
* 25MHz is the maximum sclk frequency.
* 
* @param sd_base - the base address of the SD card peripheral.
* @param dvsr - the divisor value to be written.
*
*--------------------------------------------------------------------------------*/
void sd_spi_wr_dvsr(alt_u32 sd_base, alt_u8 dvsr)
{
	IOWR(sd_base, SD_DVSR_REG, (alt_u32)dvsr);
}

/*********************************************************************************
* void sd_spi_delay(alt_u32 sd_base, alt_u16 loops)
**********************************************************************************/
/**
* @brief  This function is used to clock out idle bits to the SD card.
*
* To wake up an SD card, at least 74 clocks must toggle while holding the cs
* and MOSI lines high. The caller is responsible for making sure the correct
* value is sent.
* 
* @param sd_base - the base address of the SD card peripheral.
* @param loops - the number of loops to execute.
*
*--------------------------------------------------------------------------------*/
void sd_spi_delay(alt_u32 sd_base, alt_u16 loops)
{
  alt_u16 i;

	///< clock out idle bytes with data of 0xFF
  for (i=0; i<loops; i++)
		sd_spi_wr_byte(sd_base, 0xff); ///< 8 cycles per write
}


/*********************************************************************************
* void sd_spi_wr_byte(alt_u32 sd_base, alt_u8 spi_data)
**********************************************************************************/
/**
* @brief  This function writes a byte of data to the SPI xfer register.
*
* Do not leave function until the SPI transfer is complete.
*
* @param sd_base - the base address of the SD card peripheral.
* @param spi_data - a byte of data to be sent.
*
*--------------------------------------------------------------------------------*/
void sd_spi_wr_byte(alt_u32 sd_base, alt_u8 spi_data)
{
	while (!sd_spi_is_ready(sd_base)){};  ///< wait until SPI is ready
	IOWR(sd_base, SD_WR_DATA_REG, (alt_u32)spi_data);  ///< write a byte
	while (!sd_spi_is_ready(sd_base)){};  ///< wait until byte is sent
}

/*********************************************************************************
* alt_u8 sd_spi_rd_byte(alt_u32 sd_base)
**********************************************************************************/
/**
* @brief  This function reads a byte of data from the SPI recv register.
*
* Perform a dummy write to shift data into the receive register.
*
* @param sd_base - the base address of the SD card peripheral.
* @return - the received byte of data from the SD card.
*
*--------------------------------------------------------------------------------*/
alt_u8 sd_spi_rd_byte(alt_u32 sd_base)
{
	alt_u32 spi_reg;

	sd_spi_wr_byte(sd_base, 0xff);    ///< write a dummy byte to shift data in
	spi_reg = IORD(sd_base, SD_RD_DATA_REG);  ///< get the data and return
	return((alt_u8)(spi_reg & 0x000000ff));
}


/*********************************************************************************
***
*** SD card related functions
***
**********************************************************************************/

/*********************************************************************************
* alt_u8 sd_wr_cmd(alt_u32 sd_base, alt_u8 cmd, alt_u32 argument, alt_u32 *r3,
                    alt_u8 *rcode)
**********************************************************************************/
/**
* @brief  This function sends a command to the SD card.
*
* @param sd_base - the base address of the SD card peripheral.
* @param cmd - a 6-bit command.
* @param argument - a 32-bit argument.
* @param *r3 - 32-bit additional data for R3 and R5 responses.
* @param *rcode - the response code from the SD card.
* @return - 0: command failure, 1: success
*
* <pre>
* 1. Response code (Rl):
*    a. Oxff when no response
*    b. CMDO (reset) command: 0x01 for no error
*    c. other commands: 0x00 for no error; other for error conditions
* 2. 6 bytes to send: command + 4-byte argument (MSB first) + crc
*    except for the CMD0/CMD8, crc is optional (not implemented)
* 3. Command format: 01 + 6-bit value
* 4. SD card may need up to 8-byte transmission time to respond
* 5. SD card continues sending 1 when busy (or no data)
* 6. CMD8/CMD58 responds with 5 bytes
* </pre>
*--------------------------------------------------------------------------------*/
alt_u8 sd_wr_cmd(alt_u32 sd_base, alt_u8 cmd, alt_u32 argument, alt_u32 *r3,
                  alt_u8 *rcode)
{
	int i;
	alt_u8 crc, byte;
	alt_u32 ocr=0;

	///*** Set the crc for CMDO or CMD8 ***
	if (cmd==SD_CMD0_RESET)
		crc = 0x95; ///< crc for CMD0(0) = 0x95
	else
		crc = 0x87; ///< crc for CMDS(0x1aa) = 0x87

	///*** Send everything ***
	///< send the command
	sd_spi_wr_byte(sd_base, cmd | 0x40); // 2 MSBs = 01
	///< send the argument
	sd_spi_wr_byte(sd_base, (alt_u8)(argument >>24));
	sd_spi_wr_byte(sd_base, (alt_u8)(argument >>16));
	sd_spi_wr_byte(sd_base, (alt_u8)(argument >>8));
	sd_spi_wr_byte(sd_base, (alt_u8)argument);
	///< send crc; only valid for CMDO and CMD8
	sd_spi_wr_byte(sd_base, crc);
	///< wait for response , up to 8-byte delay
	for(i=0; i<100; i++) {
		/* read R1 response */
		*rcode = sd_spi_rd_byte(sd_base);
		if ((*rcode & 0x80) == 0) // once a start bit is recvd (0)
			break;
	}
	if (i >= 100)
    return(0);

	///< read 4 additional bytes for CMD8 and CMD58 response
	if (cmd==SD_CMD8_SEND_IF || cmd==SD_CMD58_RD_0CR) {
		for(i=0; i<4; i++) {
			byte = sd_spi_rd_byte(sd_base);
			ocr = (ocr <<8 | byte);
		}
		*r3 = ocr;
	}

	return(1);  ///< return success
}

/*********************************************************************************
* int sd_init(alt_u32 sd_base)
**********************************************************************************/
/**
* @brief  This function initializes the SD card in SPI mode.
*
* @param sd_base - the base address of the SD card peripheral.
* @return
* 	- status code:
* 	  -1: initialization fails
* 	  0: initialization success with standard SD card
* 	  +1: initialization success with high capacity SDHC card
* @note
* <pre>
* 	- Procedure
* 		1. send at least 74 sd.clk with sd card deselected (i.e., cs.n=l)
* 		to force the sd card to accept native command
* 		2. send CMDO w/ cs asserted (cs.n=0) to force the card
* 		to enter SPI mode and reset the card to idle state
* 		3. send CMD55 and then CMD41 to initialize the card
* 	- Different commands needed in step Z to initialize MMC or SDHC card
* 	- Initialization may take a fraction of a second
* </pre>
*--------------------------------------------------------------------------------*/
int sd_init(alt_u32 sd_base)
{
	int i, j;
	alt_u8 rcode;
	alt_u32 ocr;
	int hcs;

	///*** Set SPI clock to 200 kHz for init ***
	sd_spi_wr_dvsr(sd_base, 125);

	///*** Force the SD card to enter SPI mode ***
	sd_spi_wr_cs(sd_base, CS_DISABLE); ///< disable SD chip select
  sd_spi_delay(sd_base, 100);        ///< send at least 100 clocks with data idle
	sd_spi_wr_cs(sd_base, CS_ENABLE);  ///< enable SD chip select

	///*** Send reset command ***
  for (i=0; i<20; i++) {
	  if (sd_wr_cmd(sd_base, SD_CMD0_RESET, 0, &ocr, &rcode)==1) ///< send cmd0
			break;
	}
	if (i==20) {                            ///< retry 20 times, then bail
		printf ("CMDO command fails : R1=0x%02x \n", rcode);
		return (-1);
	}

	///*** Send interface condition check command ***
  for (i=0; i<20; i++) {
  	 sd_wr_cmd(sd_base, SD_CMD8_SEND_IF, 0x000001aa, &ocr, &rcode); ///< send cmd8
  	if (!((rcode!=0x01 || ocr!=0x000001aa) && (rcode!=05)))
			break;
	}
	if (i==20) {                            ///< retry 20 times, then bail
    printf("CMD8 command fails : R1/data=0x%02x 0x%x\n", rcode, (int)ocr);
    return (-1);
  }

  ///*** Send SD card init command and wait for 0.3 sec ***
	for(i=0; i<SD_INIT_TIME_OUT; i++) {
	  for (j=0; j<20; j++) {
	    if (sd_wr_cmd(sd_base, SD_CMD55_APP, 0, &ocr, &rcode)==1) ///< send cmd55
	      break;
	  }
	  if (j==20) {                          ///< retry 20 times, then bail
	    printf ("CMD55 command fails: R1=0x%02x \n", rcode);
	    return (-1);
	  }

    for (j=0; j<20; j++) {
      if (sd_wr_cmd(sd_base, SD_ACMD41_INIT_SD, 0x40000000, &ocr, &rcode)==1) ///< send cmd41
        break;
    }
    if (j==20) {                          ///< retry 20 times, then bail
      printf ("ACMD41 could not be sent: R1=0x%02x \n", rcode);
      return (-1);
    }

		if ((rcode & 1)==0x00) ///< break out if correct response received
			break;
	}
	if (i==SD_INIT_TIME_OUT) {       ///< if could not init, then bail
		printf ("SD Card init fails: R1=0x%02x\n", rcode);
		return (-1);
	}

	///*** Send command to read OCR register ***
  for (i=0; i<20; i++) {
  	if (sd_wr_cmd(sd_base, SD_CMD58_RD_0CR, 0x000001aa, &ocr, &rcode)==1) ///< send cmd58
      break;
  }
	if (i==20) {                            ///< retry 20 times, then bail
		printf("CMD58 command fails : R1=0x%02x \n", rcode);
		return(-1);
	}
	///*** extract HCS bit (bit 30) ***
	hcs = (ocr & 0x40000000) >> 30;

	///*** Set SPI clock to full speed ***
	sd_spi_wr_dvsr(sd_base, SD_SCLK_SET);
	return (hcs);   ///< return the HCS bit
}

/*********************************************************************************
* int sd_read_sector(alt_u32 sd_base, alt_u32 sect, alt_u8 *buf)
**********************************************************************************/
/**
* @brief  This function retrieves one sector (512 bytes) from the SD card to a buffer.
*
* @param sd_base - the base address of the SD card peripheral.
* @param sect - sector number.
* @param *buf - pointer to buffer.
* @return
*   0: read successful
*   -1: read failed
*
* @note
* <pre>
* 	- Procedure
* 		1. send read-one-sector command
* 		2. wait for SD card to send data-start token
* 		3. read 512 bytes
* 		4. read 2 dummy crc bytes
* 	- CMD17 argument
* 		* standard capacity SD card: starting byte address (sect<<9)
* 		* high capacity SDHC card: starting sector address (sect)
* 	- Calling function must allocate 512 byte buffer space
* </pre>
*--------------------------------------------------------------------------------*/
int sd_read_sector(alt_u32 sd_base, alt_u32 sect, alt_u8 *buf)
{
	int i;
	alt_u8 rcode, token;
	alt_u32 addr, ocr;

	if (CardType<0) {   ///< make sure the SD card is initialized
		printf("SD Card not yet initialized\n");
		return (-1);
	}

  sd_spi_wr_cs(sd_base, CS_ENABLE); ///< enable SD chip select

  ///*** Set the sector address ***
	if (CardType==0)
		addr = (sect<<9);  ///< byte addr for SD card
	else
		addr = sect;       ///< sector # for SDHC card

	///*** Send command to read a single block from the SD card ***
  for (i=0; i<20; i++) {
  	if (sd_wr_cmd(sd_base, SD_CMD17_READ, addr, &ocr, &rcode)==1) ///< send cmd17
      break;
  }
	if (i==20) {                            ///< retry 20 times, then bail
		printf("CMD17 command fails : R1=0x%02x \n", rcode);
		return (-1);
	}

	///*** Wait for data-start token up to 0.1 sec ***
	for(i=0; i<SD_READ_TIME_OUT; i++) {
		token = sd_spi_rd_byte(sd_base);
		if (token==SD_TOKEN_DATA_START) ///< break out if correct response received
			break;
	}
	if (token!=SD_TOKEN_DATA_START) { ///< bail if time-out
		printf("No data start token: last token=0x%02x\n", token);
  	sd_spi_wr_cs(sd_base, CS_DISABLE); // disable SD chip select
		return (-1);
	}

	///*** Got the token, read one sector (512 bytes) ***
  pio_write(LEDR_BASE, 0x7); // write LEDs to check timing with a scope
	for (i=0; i<512; i++)
		buf[i] = sd_spi_rd_byte(sd_base);
	sd_spi_rd_byte(sd_base);    ///< read and discard two crc bytes
	sd_spi_rd_byte(sd_base);
  pio_write(LEDR_BASE, 0); // clear LEDs to check timing with a scope

	sd_spi_wr_cs(sd_base, CS_DISABLE); ///< disable SD chip select

	return (0);  ///< return success
}

/*********************************************************************************
* int disk_readp(alt_u8 *buf, alt_u32 sect, alt_u16 ofs, alt_u16 cnt)
**********************************************************************************/
/**
* @brief  This function retrieves a number of bytes from the SD card to a buffer.
*
* @param *buf - pointer to buffer.
* @param sect - sector number.
* @param ofs - offset into the sector.
* @param cnt - # of bytes to read.
* @return
*   0: read successful
*   -1: read failed
*
* @note
* <pre>
* 	- procedure
* 		1. send read-one-sector command
* 		2. wait for SD card to send data-start token
* 		3. read and discard the ofs bytes
*     4. read the desired cnt bytes
*     5. read and discard any remaining bytes
* 		6. read 2 dummy crc bytes
* 	- CMD17 argument
* 		* standard capacity SD card: starting byte address (sect<<9)
* 		* high capacity SDHC card: starting sector address (sect)
* 	- calling function must allocate proper byte buffer space
*   - calling function responsible that ofs + cnt <= 512
* </pre>
*--------------------------------------------------------------------------------*/
int disk_readp(alt_u8 *buf, alt_u32 sect, alt_u16 ofs, alt_u16 cnt)
{
	int i;
	alt_u8 rcode, token;
	alt_u32 addr, ocr;
	alt_u16 bc;

	if (CardType<0) {   ///< make sure the SD card is initialized
		printf("SD Card not yet initialized\n");
		return (-1);
	}

  sd_spi_wr_cs(SD_CARD_BASE, CS_ENABLE); ///< enable SD chip select

  ///*** Set the sector address ***
	if (CardType==0)
		addr = (sect<<9);  ///< byte addr for SD card
	else
		addr = sect;       ///< sector # for SDHC card

	///*** Send command to read a single block from the SD card ***
  for (i=0; i<20; i++) {
  	if (sd_wr_cmd(SD_CARD_BASE, SD_CMD17_READ, addr, &ocr, &rcode)==1) ///< send cmd17
      break;
  }
	if (i==20) {                            ///< retry 20 times, then bail
		printf("CMD17 command fails : R1=0x%02x \n", rcode);
		return (-1);
	}

	///*** Wait for data-start token up to 0.1 sec ***
	for(i=0; i<SD_READ_TIME_OUT; i++) {
		token = sd_spi_rd_byte(SD_CARD_BASE);
		if (token==SD_TOKEN_DATA_START) ///< break out if correct response received
			break;
	}
	if (token!=SD_TOKEN_DATA_START) { ///< bail if time-out
		printf("No data start token: last token=0x%02x\n", token);
  	sd_spi_wr_cs(SD_CARD_BASE, CS_DISABLE); // disable SD chip select
		return (-1);
	}

  ///*** Get the data ***
	bc = 512 - ofs - cnt;   ///< calculate the # of trailing bytes to discard

	///< skip leading bytes (ofs bytes)
	if (ofs) {
		do sd_spi_rd_byte(SD_CARD_BASE); while (--ofs);
	}

	///< read data (cnt bytes)
	for (i=0; i<cnt; i++)
		buf[i] = sd_spi_rd_byte(SD_CARD_BASE);

	///< skip trailing bytes (bc bytes)
	if (bc) {
  	do sd_spi_rd_byte(SD_CARD_BASE); while (--bc);
  }

	sd_spi_rd_byte(SD_CARD_BASE);       ///< read and discard two crc bytes
	sd_spi_rd_byte(SD_CARD_BASE);

	sd_spi_wr_cs(SD_CARD_BASE, CS_DISABLE); ///< disable SD chip select

	return (0);  ///< return success
}

/*********************************************************************************
* int sd_write_sector(alt_u32 sd_base, alt_u32 sect, alt_u8 *buf)
**********************************************************************************/
/**
* @brief  This function writes one sector (512 bytes) from a buffer to the SD card.
*
* @param sd_base - the base address of the SD card peripheral.
* @param sect - sector number.
* @param *buf - pointer to buffer.
* @return
*   0: write successful
*   -1: write failed
*
* @note
* <pre>
* 	- procedure
* 		1. send write-one-sector command
* 		2. send data-start token
* 		3. send 512 bytes
* 		4. send 2 dummy crc bytes
*     5. check for data accept token
*     6. wait for completion
* 	- CMD24 argument
* 		* standard capacity SD card: starting byte address (sect<<9)
* 		* high capacity SDHC card: starting sector address (sect)
* </pre>
*--------------------------------------------------------------------------------*/
int sd_write_sector(alt_u32 sd_base, alt_u32 sect, alt_u8 *buf)
{
	int i;
	alt_u8 rcode, token;
	alt_u32 addr, dummy;

	if (CardType<0) {   ///< make sure the SD card is initialized
		printf("SD Card not yet initialized\n");
		return (-1);
	}

	sd_spi_wr_cs(sd_base, CS_ENABLE); ///< enable SD chip select

  ///*** Set the sector address ***
	if (CardType==0)
		addr = (sect<<9);  ///< byte addr for SD card
	else
		addr = sect;       ///< sector # for SDHC card

	///*** Send command to write a single block to the SD card ***
  for (i=0; i<20; i++) {
  	if (sd_wr_cmd(sd_base, SD_CMD24_WRITE, addr, &dummy, &rcode)==1) ///< send cmd24
      break;
  }
	if (i==20) {                            ///< retry 20 times, then bail
		printf ("CMD24 command fails : R1=0x%02x \n" , rcode);
		return (-1);
	}

	///*** Transfer the data ***
	sd_spi_wr_byte(sd_base, SD_TOKEN_DATA_START);   ///< send data-start token
	///< send 512 bytes
	for (i=0; i<512; i++) {
		sd_spi_wr_byte(sd_base, buf[i]);
	}
	///< send two dummy crc bytes
	sd_spi_wr_byte(sd_base, 0xff);
	sd_spi_wr_byte(sd_base, 0xff);

	///< wait for data acceptance token up to 0.25 sec
	for(i=0; SD_WRITE_TIME_OUT; i++) {
		token = sd_spi_rd_byte(sd_base);
		token = token & 0x1f; // only 5 LSBs used
		if (token==SD_TOKEN_DATA_ACCEPT) ///< break out if correct response received
			break;
	}
	if (token!=SD_TOKEN_DATA_ACCEPT) { ///< bail if time-out
		printf ("No data accept token: last token=0x%02x\n", token);
  	sd_spi_wr_cs(sd_base, CS_DISABLE); // disable SD chip select
		return (-1);
	}
	///< wait for write completion
	for(i=0; i<SD_WRITE_TIME_OUT; i++) {
		token = sd_spi_rd_byte(sd_base);
		if (token==0xff) ///< break out if correct response received
			break;
	}
	if (token != 0xff) { ///< bail if time-out
		printf ("Write completion timeout: last token=0x%02x\n", token);
  	sd_spi_wr_cs(sd_base, CS_DISABLE); // disable SD chip select
		return (-1);
	}
	sd_spi_wr_cs(sd_base, CS_DISABLE); ///< disable SD chip select

	return (0);  ///< return success
}


/*********************************************************************************
* int disk_writep(alt_u8 *buf, alt_u32 sect)
**********************************************************************************/
/**
* @brief  This function writes a number of bytes to the SD card.
*
* @param *buf - pointer to data to be sent. If NULL, initiate/finalize the write.
* @param sect - sector/# of bytes.
* @return
*   0: write successful
*   -1: write failed
*
* @note
* <pre>
*   sect specifies the number of bytes to send if buf is not a NULL. If buf is
*   a NULL and sect is not a zero, the function initiates a write operation to
*   the sector. If both parameters are zero, the function finalizes the current
*   sector write operation.
*
* 	Procedure
* 		1. initiate a sector write command
* 		2. send data-start token
* 		3. start to send data to the sector
*     4. send the rest of the data, unused to zero
*     5. finalize the write operation
* 		6. send 2 dummy crc bytes
*     7. check for data accept token
*     8. wait for completion
*
* 	CMD24 argument
* 		* standard capacity SD card: starting byte address (sect<<9)
* 		* high capacity SDHC card: starting sector address (sect)
* </pre>
*--------------------------------------------------------------------------------*/
int disk_writep(alt_u8 *buf, alt_u32 sect)
{
	int i;
	alt_u8 rcode, token;
	alt_u32 addr, dummy;
	alt_u16 bc;
 	static alt_u16 wc;   ///< keeps track of bytes to send

	if (CardType<0) {   ///< make sure the SD card is initialized
		printf("SD Card not yet initialized\n");
		return (-1);
	}

	if (buf) {		///< Send data bytes
		bc = (alt_u16)sect;
		while (bc && wc) {
  		sd_spi_wr_byte(SD_CARD_BASE, *buf++);
			wc--; bc--;
		}
	}
  else {
    ///Initiate sector write process --------
		if (sect) {	
    	sd_spi_wr_cs(SD_CARD_BASE, CS_ENABLE); ///< enable SD chip select

      ///*** Set the sector address ***
    	if (CardType==0)
		    addr = (sect<<9);  ///< byte addr for SD card
    	else
		    addr = sect;       ///< sector # for SDHC card

    	///*** Send command to write a single block to the SD card ***
      for (i=0; i<20; i++) {
 	      if (sd_wr_cmd(SD_CARD_BASE, SD_CMD24_WRITE, addr, &dummy, &rcode)==1)
          break;
      }
    	if (i==20) {                            ///< retry 20 times, then bail
	      printf ("CMD24 command fails : R1=0x%02x \n" , rcode);
	      return (-1);
      }
	    sd_spi_wr_byte(SD_CARD_BASE, SD_TOKEN_DATA_START);  ///< send data-start token
			wc = 512;							// Set byte counter
		}
    ///Finalize sector write process --------
    else {
			bc = wc + 2;

			while (bc--)
        sd_spi_wr_byte(SD_CARD_BASE, 0);	///< fill left over bytes and CRC with zeros

    	///< wait for data acceptance token up to 0.25 sec
	    for(i=0; SD_WRITE_TIME_OUT; i++) {
		    token = sd_spi_rd_byte(SD_CARD_BASE);
		    token = token & 0x1f; // only 5 LSBs used
		    if (token==SD_TOKEN_DATA_ACCEPT) ///< break out if correct response received
			    break;
	    }
	    if (token!=SD_TOKEN_DATA_ACCEPT) { ///< bail if time-out
		    printf ("No data accept token: last token=0x%02x\n", token);
  	    sd_spi_wr_cs(SD_CARD_BASE, CS_DISABLE); // disable SD chip select
		    return (-1);
	    }
	    /* wait for write completion */
	    for(i=0; i<SD_WRITE_TIME_OUT; i++) {
		    token = sd_spi_rd_byte(SD_CARD_BASE);
		    if (token==0xff) ///< break out if correct response received
			    break;
	    }
	    if (token != 0xff) { ///< bail if time-out
		    printf ("Write completion timeout: last token=0x%02x\n", token);
  	    sd_spi_wr_cs(SD_CARD_BASE, CS_DISABLE); // disable SD chip select
		    return (-1);
	    }
	    sd_spi_wr_cs(SD_CARD_BASE, CS_DISABLE); ///< disable SD chip select
		}
	}

	return (0);  ///< return success
}


/*********************************************************************************
* int disk_initialize(void)
**********************************************************************************/
/**
* @brief  This function initializes the SD card.
*
* The card is initialized by putting it in SPI mode and determining
* the card type. If the initialization fails, the user can decide
* to continue or quit.
*
* @return
*   -1: initialization failed
*   <>: any other value is the type of card
*
*--------------------------------------------------------------------------------*/
int disk_initialize(void)
{
	char yes[3];

  ///< Wake up SD card and determine capacity (high or low).
	printf("SD card Initialization...\n");
  while (1) {
  	CardType = sd_init(SD_CARD_BASE);
	  if (CardType==-1) {
		  printf("SD card initialization failed, Retry? (Y or N)\n");
      scanf("%s", yes);
      if (yes[0]!='y' && yes[0]!='Y') {
      	printf("Application Aborted!!\n");
        return(-1);   ///< return an error
      }
    }
    else {
    	printf("SD card Initialization...done\n");
      break;
    }
  }
  return(CardType);   ///< return the card type
}

