#include "sdcard.h"

#include "sysctl.h"

#include "gpiohs.h"

#include "fpioa.h"

#include "dmac.h"

#include "spi.h"

#include <stdio.h>

#include "gpiohs.h"

#include "sleep.h"

#include "syslog.h"

#include "utils.h"

#include "global_config.h"



#define MAIX_SDCARD_DEBUG 0

#if MAIX_SDCARD_DEBUG == 1

#include "printf.h"

#define debug_print(x, arg...) printk(x, ##arg)

#else

#define debug_print(x, arg...)

#endif



/*

 * @brief  Start Data tokens:

 *         Tokens (necessary because at nop/idle (and CS active) only 0xff is

 *         on the data/command line)

 */

#define SD_START_DATA_SINGLE_BLOCK_READ 0xFE    /*!< Data token start byte, Start Single Block Read */

#define SD_START_DATA_MULTIPLE_BLOCK_READ 0xFE  /*!< Data token start byte, Start Multiple Block Read */

#define SD_START_DATA_SINGLE_BLOCK_WRITE 0xFE   /*!< Data token start byte, Start Single Block Write */

#define SD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFC /*!< Data token start byte, Start Multiple Block Write */



/*

 * @brief  Commands: CMDxx = CMD-number | 0x40

 */

#define SD_CMD0 0    /*!< CMD0 = 0x40 */

#define SD_CMD8 8    /*!< CMD8 = 0x48 */

#define SD_CMD9 9    /*!< CMD9 = 0x49 */

#define SD_CMD10 10  /*!< CMD10 = 0x4A */

#define SD_CMD12 12  /*!< CMD12 = 0x4C */

#define SD_CMD16 16  /*!< CMD16 = 0x50 */

#define SD_CMD17 17  /*!< CMD17 = 0x51 */

#define SD_CMD18 18  /*!< CMD18 = 0x52 */

#define SD_ACMD23 23 /*!< CMD23 = 0x57 */

#define SD_CMD24 24  /*!< CMD24 = 0x58 */

#define SD_CMD25 25  /*!< CMD25 = 0x59 */

#define SD_ACMD41 41 /*!< ACMD41 = 0x41 */

#define SD_CMD55 55  /*!< CMD55 = 0x55 */

#define SD_CMD58 58  /*!< CMD58 = 0x58 */

#define SD_CMD59 59  /*!< CMD59 = 0x59 */



sdcard_config_t config = { // see struct sdcard_config_t

#ifdef CONFIG_BOARD_M5STICK

    33, 31, 30, 32, SD_CS_PIN,

#else

    28, 26, 27, 29, SD_CS_PIN,

#endif

};



SD_CardInfo cardinfo;

int sd_version = 0;



void SD_CS_HIGH(void)

{

    gpiohs_set_pin(config.cs_gpio_num, GPIO_PV_HIGH);

}



void SD_CS_LOW(void)

{

    gpiohs_set_pin(config.cs_gpio_num, GPIO_PV_LOW);

}



void SD_HIGH_SPEED_ENABLE(void)

{

    spi_set_clk_rate(SD_SPI_DEVICE, 25000000);

}



void SD_LOW_SPEED_ENABLE(void)

{

    spi_set_clk_rate(SD_SPI_DEVICE, 400000);

}



static void sd_lowlevel_init(uint8_t spi_index)

{

    gpiohs_set_drive_mode(config.cs_gpio_num, GPIO_DM_OUTPUT);

    spi_set_clk_rate(SD_SPI_DEVICE, 200000); /*set clk rate*/

}



static void sd_write_data(uint8_t *data_buff, uint32_t length)

{

    spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);

    spi_send_data_standard(SD_SPI_DEVICE, SD_SS, NULL, 0, data_buff, length);

}



static void sd_read_data(uint8_t *data_buff, uint32_t length)

{



    spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);

    spi_receive_data_standard(SD_SPI_DEVICE, SD_SS, NULL, 0, data_buff, length);

}



static void sd_write_data_dma(uint8_t *data_buff)

{

    // spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 32, 1); misaligned error

    spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);

    spi_send_data_standard_dma(SD_DMA_CH, SD_SPI_DEVICE, SD_SS, NULL, 0, (uint8_t *)(data_buff), 128 * 4);

}



static void sd_read_data_dma(uint8_t *data_buff)

{

    // spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 32, 1); misaligned error

    spi_init(SD_SPI_DEVICE, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);

    spi_receive_data_standard_dma(-1, SD_DMA_CH, SD_SPI_DEVICE, SD_SS, NULL, 0, data_buff, 128 * 4);

}



/*

 * @brief  Send 5 bytes command to the SD card.

 * @param  Cmd: The user expected command to send to SD card.

 * @param  Arg: The command argument.

 * @param  Crc: The CRC.

 * @retval None

 */

static void sd_send_cmd(uint8_t cmd, uint32_t arg, uint8_t crc)

{

    uint8_t frame[6];

    /*!< Construct byte 1 */

    frame[0] = (cmd | 0x40);

    /*!< Construct byte 2 */

    frame[1] = (uint8_t)(arg >> 24);

    /*!< Construct byte 3 */

    frame[2] = (uint8_t)(arg >> 16);

    /*!< Construct byte 4 */

    frame[3] = (uint8_t)(arg >> 8);

    /*!< Construct byte 5 */

    frame[4] = (uint8_t)(arg);

    /*!< Construct CRC: byte 6 */

    frame[5] = (crc);

    /*!< SD chip select low */

    SD_CS_LOW();

    /*!< Send the Cmd bytes */

    sd_write_data(frame, 6);

}



/*

 * @brief  Send 5 bytes command to the SD card.

 * @param  Cmd: The user expected command to send to SD card.

 * @param  Arg: The command argument.

 * @param  Crc: The CRC.

 * @retval None

 */

static void sd_end_cmd(void)

{

    uint8_t frame[1] = {0xFF};

    /*!< SD chip select high */

    SD_CS_HIGH();

    /*!< Send the Cmd bytes */

    sd_write_data(frame, 1);

}



/*

 * @brief  Returns the SD response.

 * @param  None

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

static uint8_t sd_get_response(void)

{

    uint8_t result;

    uint16_t timeout = 0xFFFF; // min: 0x5f

    /*!< Check if response is got or a timeout is happen */

    while (timeout--)

    {

        sd_read_data(&result, 1);

        /*!< Right response got */

        if (result != 0xFF)

            return result;

    }

    /*!< After time out */

    return 0xFF;

}



/*

 * @brief  Get SD card data response.

 * @param  None

 * @retval The SD status: Read data response xxx0<status>1

 *         - status 010: Data accecpted

 *         - status 101: Data rejected due to a crc error

 *         - status 110: Data rejected due to a Write error.

 *         - status 111: Data rejected due to other error.

 */

static uint8_t sd_get_dataresponse(void)

{

    uint8_t response;

    /*!< Read resonse */

    sd_read_data(&response, 1);

    /*!< Mask unused bits */

    response &= 0x1F;

    if (response != 0x05)

        return 0xFF;

    /*!< Wait null data */

    sd_read_data(&response, 1);

    while (response == 0)

        sd_read_data(&response, 1);

    /*!< Return response */

    return 0;

}



/*

 * @brief  Read the CSD card register

 *         Reading the contents of the CSD register in SPI mode is a simple

 *         read-block transaction.

 * @param  SD_csd: pointer on an SCD register structure

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

static uint8_t sd_get_csdregister(SD_CSD *SD_csd)

{

    uint8_t csd_tab[18];

    /*!< Send CMD9 (CSD register) or CMD10(CSD register) */

    sd_send_cmd(SD_CMD9, 0, 1);

    /*!< Wait for response in the R1 format (0x00 is no errors) */

    uint8_t resp = sd_get_response();

    debug_print("[MaixPy] %s | resp = %x \r\n", __func__, resp);

    if (resp != 0x00)

    {

        sd_end_cmd();

        return 0xFF;

    }

    resp = sd_get_response();

    debug_print("[MaixPy] %s | resp = %x \r\n", __func__, resp);

    if (resp != SD_START_DATA_SINGLE_BLOCK_READ)

    {

        sd_end_cmd();

        return 0xFF;

    }

    /*!< Store CSD register value on csd_tab */

    /*!< Get CRC bytes (not really needed by us, but required by SD) */

    sd_read_data(csd_tab, 18);

    sd_end_cmd();

    /*!< Byte 0 */

    SD_csd->CSDStruct = (csd_tab[0] & 0xC0) >> 6;

    SD_csd->SysSpecVersion = (csd_tab[0] & 0x3C) >> 2;

    SD_csd->Reserved1 = csd_tab[0] & 0x03;

    /*!< Byte 1 */

    SD_csd->TAAC = csd_tab[1];

    /*!< Byte 2 */

    SD_csd->NSAC = csd_tab[2];

    /*!< Byte 3 */

    SD_csd->MaxBusClkFrec = csd_tab[3];

    /*!< Byte 4 */

    SD_csd->CardComdClasses = csd_tab[4] << 4;

    /*!< Byte 5 */

    SD_csd->CardComdClasses |= (csd_tab[5] & 0xF0) >> 4;

    SD_csd->RdBlockLen = csd_tab[5] & 0x0F;

    /*!< Byte 6 */

    SD_csd->PartBlockRead = (csd_tab[6] & 0x80) >> 7;

    SD_csd->WrBlockMisalign = (csd_tab[6] & 0x40) >> 6;

    SD_csd->RdBlockMisalign = (csd_tab[6] & 0x20) >> 5;

    SD_csd->DSRImpl = (csd_tab[6] & 0x10) >> 4;

    SD_csd->Reserved2 = 0; /*!< Reserved */

    if (2 == sd_version)

    {

        SD_csd->DeviceSize = (csd_tab[6] & 0x03) << 10;

        /*!< Byte 7 */

        SD_csd->DeviceSize = (csd_tab[7] & 0x3F) << 16;

        /*!< Byte 8 */

        SD_csd->DeviceSize |= csd_tab[8] << 8;

        /*!< Byte 9 */

        SD_csd->DeviceSize |= csd_tab[9];

    }

    else if (1 == sd_version)

    {

        SD_csd->DeviceSize |= (csd_tab[6] & 0x03) << 10;

        /*!< Byte 7 */

        SD_csd->DeviceSize |= csd_tab[7] << 2;

        /*!< Byte 8 */

        SD_csd->DeviceSize |= ((csd_tab[8] & 0xC0) >> 6);

        /*!< Byte 9 10*/

        SD_csd->CSizeMlut = ((csd_tab[10] & 128) >> 7) + ((csd_tab[9] & 0x03) << 1);

    }

    /*!< Byte 10 */

    SD_csd->EraseGrSize = (csd_tab[10] & 0x40) >> 6;

    SD_csd->EraseGrMul = (csd_tab[10] & 0x3F) << 1;

    /*!< Byte 11 */

    SD_csd->EraseGrMul |= (csd_tab[11] & 0x80) >> 7;

    SD_csd->WrProtectGrSize = (csd_tab[11] & 0x7F);

    /*!< Byte 12 */

    SD_csd->WrProtectGrEnable = (csd_tab[12] & 0x80) >> 7;

    SD_csd->ManDeflECC = (csd_tab[12] & 0x60) >> 5;

    SD_csd->WrSpeedFact = (csd_tab[12] & 0x1C) >> 2;

    SD_csd->MaxWrBlockLen = (csd_tab[12] & 0x03) << 2;

    /*!< Byte 13 */

    SD_csd->MaxWrBlockLen |= (csd_tab[13] & 0xC0) >> 6;

    SD_csd->WriteBlockPaPartial = (csd_tab[13] & 0x20) >> 5;

    SD_csd->Reserved3 = 0;

    SD_csd->ContentProtectAppli = (csd_tab[13] & 0x01);

    /*!< Byte 14 */

    SD_csd->FileFormatGrouop = (csd_tab[14] & 0x80) >> 7;

    SD_csd->CopyFlag = (csd_tab[14] & 0x40) >> 6;

    SD_csd->PermWrProtect = (csd_tab[14] & 0x20) >> 5;

    SD_csd->TempWrProtect = (csd_tab[14] & 0x10) >> 4;

    SD_csd->FileFormat = (csd_tab[14] & 0x0C) >> 2;

    SD_csd->ECC = (csd_tab[14] & 0x03);

    /*!< Byte 15 */

    SD_csd->CSD_CRC = (csd_tab[15] & 0xFE) >> 1;

    SD_csd->Reserved4 = 1;

    /*!< Return the reponse */

    return 0;

}



/*

 * @brief  Read the CID card register.

 *         Reading the contents of the CID register in SPI mode is a simple

 *         read-block transaction.

 * @param  SD_cid: pointer on an CID register structure

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

static uint8_t sd_get_cidregister(SD_CID *SD_cid)

{

    uint8_t cid_tab[18];

    /*!< Send CMD10 (CID register) */

    sd_send_cmd(SD_CMD10, 0, 1);

    /*!< Wait for response in the R1 format (0x00 is no errors) */

    if (sd_get_response() != 0x00)

    {

        sd_end_cmd();

        return 0xFF;

    }

    if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ)

    {

        sd_end_cmd();

        return 0xFF;

    }

    /*!< Store CID register value on cid_tab */

    /*!< Get CRC bytes (not really needed by us, but required by SD) */

    sd_read_data(cid_tab, 18);

    sd_end_cmd();

    /*!< Byte 0 */

    SD_cid->ManufacturerID = cid_tab[0];

    /*!< Byte 1 */

    SD_cid->OEM_AppliID = cid_tab[1] << 8;

    /*!< Byte 2 */

    SD_cid->OEM_AppliID |= cid_tab[2];

    /*!< Byte 3 */

    SD_cid->ProdName1 = cid_tab[3] << 24;

    /*!< Byte 4 */

    SD_cid->ProdName1 |= cid_tab[4] << 16;

    /*!< Byte 5 */

    SD_cid->ProdName1 |= cid_tab[5] << 8;

    /*!< Byte 6 */

    SD_cid->ProdName1 |= cid_tab[6];

    /*!< Byte 7 */

    SD_cid->ProdName2 = cid_tab[7];

    /*!< Byte 8 */

    SD_cid->ProdRev = cid_tab[8];

    /*!< Byte 9 */

    SD_cid->ProdSN = cid_tab[9] << 24;

    /*!< Byte 10 */

    SD_cid->ProdSN |= cid_tab[10] << 16;

    /*!< Byte 11 */

    SD_cid->ProdSN |= cid_tab[11] << 8;

    /*!< Byte 12 */

    SD_cid->ProdSN |= cid_tab[12];

    /*!< Byte 13 */

    SD_cid->Reserved1 |= (cid_tab[13] & 0xF0) >> 4;

    SD_cid->ManufactDate = (cid_tab[13] & 0x0F) << 8;

    /*!< Byte 14 */

    SD_cid->ManufactDate |= cid_tab[14];

    /*!< Byte 15 */

    SD_cid->CID_CRC = (cid_tab[15] & 0xFE) >> 1;

    SD_cid->Reserved2 = 1;

    /*!< Return the reponse */

    return 0;

}



/*

 * @brief  Returns information about specific card.

 * @param  cardinfo: pointer to a SD_CardInfo structure that contains all SD

 *         card information.

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

static uint8_t sd_get_cardinfo(SD_CardInfo *cardinfo)

{

    if (sd_get_csdregister(&(cardinfo->SD_csd)))

    {

        debug_print("[MaixPy] %s | sd_get_csdregister failed\r\n",__func__);

        return 0xFF;

    }

    if (sd_get_cidregister(&(cardinfo->SD_cid)))

    {

        debug_print("[MaixPy] %s | sd_get_cidregister failed\r\n",__func__);

        return 0xFF;

    }

    if (2 == sd_version)

    {

        cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 1024;

        cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);

        cardinfo->CardCapacity *= cardinfo->CardBlockSize;

    }

    else if (1 == sd_version)

    {

        cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);

        cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) << (cardinfo->SD_csd.CSizeMlut + 2 + cardinfo->SD_csd.RdBlockLen);

    }

    /*!< Returns the reponse */

    return 0;

}



/*

 * @brief  Initializes the SD/SD communication.

 * @param  None

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

uint8_t sd_init(void)

{

    uint8_t frame[10], index, result;

    cardinfo.active = 0;



    fpioa_set_function(config.sclk_pin, FUNC_SPI1_SCLK);

    fpioa_set_function(config.mosi_pin, FUNC_SPI1_D0);

    fpioa_set_function(config.miso_pin, FUNC_SPI1_D1);

    fpioa_set_function(config.cs_pin, FUNC_GPIOHS0 + config.cs_gpio_num);



    /*!< Initialize SD_SPI */

    sd_lowlevel_init(0);

    /*!< SD chip select high */

    SD_CS_HIGH();

    /*!< Send dummy byte 0xFF, 10 times with CS high */

    /*!< Rise CS and MOSI for 80 clocks cycles */

    /*!< Send dummy byte 0xFF */

    for (index = 0; index < 10; index++)

        frame[index] = 0xFF;

    sd_write_data(frame, 10);

    /*------------Put SD in SPI mode--------------*/

    /*!< SD initialized and set to SPI mode properly */



    sd_send_cmd(SD_CMD0, 0, 0x95);

    result = sd_get_response();

    sd_end_cmd();

    if (result != 0x01)

    {

        debug_print("[MaixPy] %s | SD_CMD0 is %X\r\n",__func__,result);

        return 0xFF;

    }



    sd_send_cmd(SD_CMD8, 0x01AA, 0x87);

    /*!< 0x01 or 0x05 */

    result = sd_get_response();

    sd_read_data(frame, 4);

    sd_end_cmd();

    if (result != 0x01)

    {

        debug_print("[MaixPy] %s | SD_CMD8 is %X\r\n",__func__,result);

        return 0xFF;

    }

    index = 0xFF;

    while (index--)

    {

        sd_send_cmd(SD_CMD55, 0, 1);

        result = sd_get_response();

        sd_end_cmd();

        if (result != 0x01)

        {

            debug_print("SD_CMD55 ack %X\r\n", result);

            return 0xFF;

        }

        sd_send_cmd(SD_ACMD41, 0x40000000, 1);

        result = sd_get_response();

        sd_end_cmd();

        if (result == 0x00)

            break;

    }

    if (index == 0)

    {

        debug_print("SD_CMD55 is %X\r\n", result);

        return 0xFF;

    }

    index = 255;

    while (index--)

    {

        sd_send_cmd(SD_CMD58, 0, 1);

        result = sd_get_response();

        sd_read_data(frame, 4);

        sd_end_cmd();

        debug_print("[MaixPy] %s |  frame[0] = %x \r\n", __func__, frame[0]);

        debug_print("[MaixPy] %s |  frame[1] = %x \r\n", __func__, frame[1]);

        debug_print("[MaixPy] %s |  frame[2] = %x \r\n", __func__, frame[2]);

        debug_print("[MaixPy] %s |  frame[3] = %x \r\n", __func__, frame[3]);

        debug_print("[MaixPy] %s |  result = %d \r\n", __func__, result);

        debug_print("[MaixPy] %s |  index = %d \r\n", __func__, index);

        if (result == 0)

        {

            break;

        }

    }

    if (index == 0)

    {

        debug_print("[MaixPy] %s | SD_CMD58 is %X\r\n",__func__,result);

        return 0xFF;

    }

    if ((frame[0] & 0x40) == 0)

    {

#if CONFIG_SPI_SD_CARD_FORCE_HIGH_SPEED

        SD_HIGH_SPEED_ENABLE();

#endif

        sd_version = 1;

    }

    else

    {

        sd_version = 2;

        SD_HIGH_SPEED_ENABLE();

    }

    if (1 == sd_version)

    {

        sd_send_cmd(SD_CMD16, 512, 1);

        if (sd_get_response() != 0x00)

        {

            sd_end_cmd();

            return 0xFF;

        }

    }

    if (0 == sd_get_cardinfo(&cardinfo))

    {

        cardinfo.active = 1;

        return 0;

    }

    return 0xFF;

}



/*

 * @brief  Reads a block of data from the SD.

 * @param  data_buff: pointer to the buffer that receives the data read from the

 *                  SD.

 * @param  sector: SD's internal address to read from.

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

uint8_t sd_read_sector(uint8_t *data_buff, uint32_t sector, uint32_t count)

{

    uint8_t frame[2], flag;

    /*!< Send CMD17 (SD_CMD17) to read one block */

    if (count == 1)

    {

        flag = 0;

        sd_send_cmd(SD_CMD17, sector, 1);

    }

    else

    {

        flag = 1;

        sd_send_cmd(SD_CMD18, sector, 1);

    }

    /*!< Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */

    if (sd_get_response() != 0x00)

    {

        sd_end_cmd();

        return 0xFF;

    }

    while (count)

    {

        if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ)

            break;

        /*!< Read the SD block data : read NumByteToRead data */

        sd_read_data(data_buff, 512);

        /*!< Get CRC bytes (not really needed by us, but required by SD) */

        sd_read_data(frame, 2);

        data_buff += 512;

        count--;

    }

    sd_end_cmd();

    if (flag)

    {

        sd_send_cmd(SD_CMD12, 0, 1);

        sd_get_response();

        sd_end_cmd();

        sd_end_cmd();

    }

    /*!< Returns the reponse */

    return count > 0 ? 0xFF : 0;

}



/*

 * @brief  Writes a block on the SD

 * @param  data_buff: pointer to the buffer containing the data to be written on

 *                  the SD.

 * @param  sector: address to write on.

 * @retval The SD Response:

 *         - 0xFF: Sequence failed

 *         - 0: Sequence succeed

 */

uint8_t sd_write_sector(uint8_t *data_buff, uint32_t sector, uint32_t count)

{

    configASSERT(((uint32_t)data_buff) % 4 == 0);

    uint8_t frame[2] = {0xFF};

    if (count == 1)

    {

        frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE;

        sd_send_cmd(SD_CMD24, sector, 1);

    }

    else

    {

        frame[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE;

        sd_send_cmd(SD_ACMD23, count, 1);

        sd_get_response();

        sd_end_cmd();

        sd_send_cmd(SD_CMD25, sector, 1);

    }

    /*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */

    if (sd_get_response() != 0x00)

    {

        sd_end_cmd();

        return 0xFF;

    }

    while (count--)

    {

        /*!< Send the data token to signify the start of the data */

        sd_write_data(frame, 2);

        /*!< Write the block data to SD : write count data by block */

        sd_write_data(data_buff, 512);

        /*!< Put CRC bytes (not really needed by us, but required by SD) */

        sd_write_data(frame, 2);

        data_buff += 512;

        /*!< Read data response */

        if (sd_get_dataresponse() != 0x00)

        {

            sd_end_cmd();

            return 0xFF;

        }

    }

    sd_end_cmd();

    sd_end_cmd();

    /*!< Returns the reponse */

    return 0;

}



uint8_t sd_read_sector_dma(uint8_t *data_buff, uint32_t sector, uint32_t count)

{

    uint8_t frame[2], flag;

    if (1 == sd_version)

        sector = sector << 9;

    /*!< Send CMD17 (SD_CMD17) to read one block */

    if (count == 1)

    {

        flag = 0;

        sd_send_cmd(SD_CMD17, sector, 1);

    }

    else

    {

        flag = 1;

        sd_send_cmd(SD_CMD18, sector, 1);

    }

    /*!< Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */

    if (sd_get_response() != 0x00)

    {

        sd_end_cmd();

        debug_print("%s sd_get_response() != 0x00 %d\r\n", __func__, flag);

        return 0xFF;

    }

    while (count)

    {

        if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ)

            break;

        /*!< Read the SD block data : read NumByteToRead data */

        sd_read_data_dma(data_buff); // close recv dma

        /*!< Get CRC bytes (not really needed by us, but required by SD) */

        sd_read_data(frame, 2);

        data_buff += 512;

        count--;

    }

    sd_end_cmd();

    if (flag)

    {

        sd_send_cmd(SD_CMD12, 0, 1);

        sd_get_response();

        sd_end_cmd();

        sd_end_cmd();

    }

    /*!< Returns the reponse */

    return count > 0 ? 0xFF : 0;

}



uint8_t sd_write_sector_dma(uint8_t *data_buff, uint32_t sector, uint32_t count)

{

    uint8_t frame[2] = {0xFF};

    uint32_t shift = 0;

    frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE;

    uint32_t i = 0;

    if (1 == sd_version)

        sector = sector << 9;

    while (count--)

    {

        if (1 == sd_version)

            shift = i << 9;

        else

            shift = i;

        sd_send_cmd(SD_CMD24, sector + shift, 1);

        /*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */

        if (sd_get_response() != 0x00)

        {

            sd_end_cmd();

            return 0xFF;

        }



        /*!< Send the data token to signify the start of the data */

        sd_write_data(frame, 2);

        /*!< Write the block data to SD : write count data by block */

        sd_write_data_dma(data_buff);

        /*!< Put CRC bytes (not really needed by us, but required by SD) */

        sd_write_data(frame, 2);

        data_buff += 512;

        /*!< Read data response */

        if (sd_get_dataresponse() != 0x00)

        {

            sd_end_cmd();

            return 0xFF;

        }

        i++;

    }

    sd_end_cmd();

    sd_end_cmd();

    /*!< Returns the reponse */

    return 0;

}