/**
* @file         mm_card.c
* @brief        emmc卡驱动
* @details      emmc卡驱动
* @author       涂龙
* @date         2022-01-25 09:18
* @version      V0.0
* @copyright    Copyright (c) 2017-2022  SpaceTouch Inc.
*/
#include "platform.h"
#include "hal_mm_card.h"
#include "hal_memory_card.h"


/**
* @brief        设置存储卡的工作时钟
* @details
* @param        @arg div ：时钟的分频数
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         无
*/
uint32_t hal_mmc_set_clock(uint32_t div, uint64_t mcycle_ms_freq)
{
    return hal_memory_card_clock(div, mcycle_ms_freq);
#if 0
    uint32_t cmd_cnt = 0;
    uint32_t ret = 0;
    //等待空闲
#if DEV_MMC_TIME_OUT_CHECK == 1UL
    uint64_t time_out_value;
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->STATUS & (DEV_MMC_STATUS_DATA_BUSY | DEV_MMC_STATUS_DATA_STATE_MC_BUSY)) != 0)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1UL

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    cmd_cnt = 0;

    do
    {
        if (cmd_cnt <= 100UL)
        {
            cmd_cnt++;
        }
        else
        {
            return 1;
        }

        DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;//写1清除所有标志
        DEV_MMC->CLKENA = 0;
        DEV_MMC->CMD = DEV_MMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY//只发时钟
                       | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                       ;

        while ((DEV_MMC->CMD & DEV_MMC_CMD_START_CMD) != 0) //等待上一个命令发送
        {
            ;
        }
    }
    while (DEV_MMC->RINTSTS != 0);

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
    DEV_CMU->SDCCLK = DEV_CMU_SDCCLK_SEL_OSC_DEV | ((div - 1) << 4UL);
    cmd_cnt = 0;

    do
    {
        if (cmd_cnt <= 100UL)
        {
            cmd_cnt++;
        }
        else
        {
            return 3;
        }

        DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;//写1清除所有标志
        DEV_MMC->CLKENA = 1;
        DEV_MMC->CMD = DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE//等待前面的数据转换完成在发送此命令
                       | DEV_MMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY //只发时钟
                       | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                       ;

        while ((DEV_MMC->CMD & DEV_MMC_CMD_START_CMD) != 0) //等待上一个命令发送
        {
            ;
        }
    }
    while (DEV_MMC->RINTSTS != 0);

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
    return ret;
#endif
}


/**
* @brief        向卡发送命令
* @details      向卡发送命令，并将相应返回
* @param        @arg cmd: 对应命令号
*               @arg arg: 命令对应参数
*               @arg response: 命令对应相应的存放数组，大小为4word
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CARD_ErrorCodeEnum
* @note
*/
uint32_t hal_mmc_send_cmd(uint32_t cmd, uint32_t arg, uint32_t *response, uint64_t mcycle_ms_freq)
{
    return hal_memory_card_send_cmd(cmd, arg, response, mcycle_ms_freq);
#if 0
    uint32_t ret = 0;
#if DEV_MMC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->CMD & DEV_MMC_CMD_START_CMD) != 0) //等待上一个命令完成
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
    DEV_MMC->CMDARG = arg;//cmd携带参数
    DEV_MMC->CMD = cmd | DEV_MMC_CMD_USE_HOLD_REG;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->RINTSTS & DEV_MMC_RINTSTS_CD) != DEV_MMC_RINTSTS_CD)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_CD;

    if ((DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_RE | DEV_MMC_RINTSTS_RCRC | DEV_MMC_RINTSTS_DCRC
                             | DEV_MMC_RINTSTS_RTO_BAR | DEV_MMC_RINTSTS_DRTO_BDS | DEV_MMC_RINTSTS_FRUN
                             | DEV_MMC_RINTSTS_HLE | DEV_MMC_RINTSTS_SBE_BCI | DEV_MMC_RINTSTS_EBE)) != 0)
    {
        ret = DEV_MMC->RINTSTS;
    }

    response[0] = DEV_MMC->RESP0;
    response[1] = DEV_MMC->RESP1;
    response[2] = DEV_MMC->RESP2;
    response[3] = DEV_MMC->RESP3;
    return ret;
#endif
}

/**
* @brief        发送cmd0使卡复位
* @details
* @param        @arg argument ：cmd的参数
*                       0：reset idle
*                       0xf0f0f0f0：pre idle
*                       0xfffffffa:boot operation
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         cmd0 参数为0 ，无响应
*/
uint32_t hal_mmc_go_idle(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(0)
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_SEND_INITIALIZATION //发送初始化80个时钟
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}

/**
* @brief        发送cmd1使卡初始匹配
* @details
* @param        @arg argument ：cmd的参数
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         函数需要一段时间，直到响应为非busy为止
*/
uint32_t hal_mmc_send_operating_condition(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    uint64_t time_out_value = read_mcycle() + mcycle_ms_freq * 10 * DEV_MMC_TIME_OUT_TIME;

    do
    {
        if (read_mcycle() >= time_out_value)
        {
            return ERR_CARD_READ_CARD_READY_TIMEOUT;
        }

        arg = argument;
        cmd = MMC_CMD(1)
              | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
              | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
              | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
              ;
        ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            return ret | ERR_CARD_INVALID_CARD;
        }
    }
    while ((mmc_response[0] & (0x1UL << 31)) == 0);

    return ret;
}

/**
* @brief        发送cmd2获取卡cid寄存器信息
* @details
* @param        @arg argument ：cmd的参数
*                       0
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_mmc_send_CID(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(2)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_RESPONSE_LENGTH //长响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}

/**
* @brief        发送cmd3设置卡相对地址
* @details
* @param        @arg argument ：cmd的参数
*                       低十六位为零，高十六位大于等于1
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_mmc_set_RCA(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(3)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}

/**
* @brief        发送cmd9获取卡csd寄存器信息
* @details
* @param        @arg argument ：cmd的参数
*                       卡的相对地址
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_mmc_send_CSD(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(9)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_RESPONSE_LENGTH //长响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}
/**
* @brief        发送cmd7获取卡将卡状态切换在standby和transfer之间
* @details
* @param        @arg argument ：cmd的参数
*                       卡的相对地址
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note
*/
uint32_t hal_mmc_toggle_standby_transfer(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(7)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}

uint32_t hal_mmc_set_blocklen(uint32_t argument, uint32_t *mmc_response, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    arg = argument;
    cmd = MMC_CMD(16)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);
    return ret;
}
/**
* @brief        发送cmd8获取卡的extcsd寄存器信息
* @details
* @param        @arg argument ：cmd的参数
*                   卡的相对地址
*               @arg sd_response ：cmd的响应存放
*               @arg mcycle_ms_freq ：mcycle每毫秒的cycle数
* @return       @arg ret: 错误码 @ MEMORY_CAED_ErrorCodeEnum
* @note         cmd8 与读书命令相似
*/
uint32_t hal_mmc_sed_EXTCSD(uint32_t *ext_csd, uint64_t mcycle_ms_freq)
{
    uint32_t cmd, arg;
    uint32_t ret = 0;
    uint32_t mmc_response[4];
    DEV_MMC->BYTCNT = CARD_MMC_EXTCSD_LEN;//512bit ext_csd
    DEV_MMC->BLKSIZ = 0x200UL;
    DEV_MMC->FIFOTH = (2UL << 28UL) | (7UL << 16UL);
    arg = 0;
    cmd = MMC_CMD(8)
          | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
          | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
          | DEV_MMC_CMD_DATA_EXPECTED
          | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
          | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
          ;
    ret = hal_mmc_send_cmd(cmd, arg, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        goto read_extcsd_fail;
    }

    uint32_t cnt = 0;
    uint64_t time_out_value = read_mcycle() + mcycle_ms_freq * 10 * DEV_MMC_TIME_OUT_TIME;

    while (!(DEV_MMC->RINTSTS & DEV_MMC_RINTSTS_DTO))
    {
        if (read_mcycle() >= time_out_value)
        {
            ret = DEV_MMC->RINTSTS;
            goto read_extcsd_fail;
        }

        uint64_t time_out_value1 = read_mcycle() + mcycle_ms_freq * 10 * DEV_MMC_TIME_OUT_TIME;

        while (!(DEV_MMC->RINTSTS & DEV_MMC_RINTSTS_RXDR)) //接收fifo达到阈值
        {
            if (read_mcycle() >= time_out_value1)
            {
                ret = DEV_MMC->RINTSTS;
                goto read_extcsd_fail;
            }

            if ((DEV_MMC->RINTSTS & DEV_MMC_RINTSTS_DTO) == DEV_MMC_RINTSTS_DTO) //等待中途数据传输完成（剩余数据读取小于阈值）
            {
                break;
            }
        }

        if ((DEV_MMC->RINTSTS & DEV_MMC_RINTSTS_DTO) == DEV_MMC_RINTSTS_DTO) //不是阈值产生的中止，也就不需要读取数据
        {
            break;
        }

        for (int j = 0; j < 8; j++)
        {
            ext_csd[cnt++] = DEV_MMC->DATA;
        }

        DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_RXDR;
    }

    while (cnt < 16)
    {
        ext_csd[cnt++] = DEV_MMC->DATA;
    }

    if ((DEV_MMC->RINTSTS & (1UL << 11UL)) != 0)
    {
        ret = DEV_MMC->RINTSTS;//接受fifo溢出
    }

read_extcsd_fail:
    DEV_MMC->RINTSTS = 0xffffUL;
    DEV_MMC->CTRL = 2UL;

    while ((DEV_MMC->CTRL & 2UL) == 2UL)
    {
        ;
    }

    return ret;
}
/**
* @brief        初始化emmc卡
* @details      对s卡的初始化
* @param        @arg bus_width sdc通信的数据线
*               @arg clk 通信的时钟频率
*               @arg mmc_info 用于保留卡信息参数
* @return       @arg ret: 错误码 @ MEMORY_CARD_ErrorCodeEnum
* @note         目前只有低速一线
*/
uint32_t hal_mmc_init(uint32_t bus_width, uint32_t clk, MMC_Info mmc_info)
{
    uint32_t mmc_response[4];
    uint32_t ret = 0;
    uint64_t mcycle_ms_freq = mmc_info->mcycle_ms_freq;
    DEV_GPIO->CTL[mmc_info->clk_gpio] = 7;//clk
    DEV_GPIO->CTL[mmc_info->cmd_gpio] = 7;//cmd
    DEV_GPIO->CTL[mmc_info->d0_gpio] = 7;//d0

    if (bus_width == 4)
    {
        DEV_GPIO->CTL[mmc_info->d1_gpio] = 7;//d1
        DEV_GPIO->CTL[mmc_info->d2_gpio] = 7;//d2
        DEV_GPIO->CTL[mmc_info->d3_gpio] = 7;//d3
    }

    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_SDC;
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_SDC;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_SDC;
    DEV_CMU->SDCCLK = DEV_CMU_SDCCLK_SEL_PLL_CORE | DEV_CMU_SDCCLK_DIV_MASK;
    DEV_MMC->CTRL = DEV_MMC_CTRL_ENABLE_OD_PULLUP;//mmc需要
    DEV_MMC->PWREN = 1;
    DEV_MMC->CTYPE = 0;
    DEV_MMC->UHSREGEXT = (0x10UL << 23UL) | (0x10UL << 16UL) | (1UL << 21UL);
    ret = hal_mmc_set_clock(96UL, mcycle_ms_freq); //时钟到400khz以下

    if (ret != 0)
    {
        return ERR_CARD_SET_CLOCK_FAIL;
    }

    //cmd0
    ret = hal_mmc_go_idle(0, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_HARDWARE_ERROR;;
    }

    //cmd1
    ret = hal_mmc_send_operating_condition((0x40ff8000UL), mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret;
    }

    if ((mmc_response[0] & 0x60000000UL) == 0X40000000UL)
    {
        mmc_info->capacity = 1;//sector mode, more than 2G
    }
    else
    {
        mmc_info->capacity = 0;//byte mode
    }

    //cmd2
    ret = hal_mmc_send_CID(0, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_READ_CID_FAIL;
    }

    for (int i = 0; i < CARD_CID_LEN; i++)
    {
        mmc_info->cid[i] = mmc_response[i / 4] >> (8 * (i % 4));
    }

    //cmd3 地址分配从1开始 高十六位
    ret = hal_mmc_set_RCA(0x10000UL, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_ASK_RELATIVE_ADDR_FAIL;
    }

    mmc_info->relative_addr = 0x10000UL;
    DEV_MMC->CTRL = 0;//mmc需要 返回推挽
    //cmd9
    ret = hal_mmc_send_CSD(mmc_info->relative_addr, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_READ_CSD_FAIL;
    }

    for (int i = 0; i < CARD_CSD_LEN; i++)
    {
        mmc_info->csd[i] = mmc_response[i / 4] >> (8 * (i % 4));
    }

    //cmd7
    ret = hal_mmc_toggle_standby_transfer(mmc_info->relative_addr, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_TOGGLES_CARD_STATES_FAIL;
    }

    //cmd16
    ret = hal_mmc_set_blocklen(0x200, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_SET_BLOCKLEN_FAIL;
    }

    //此模块最大20M（高速模式最大52M）
    // todo 暂定12M
    ret = hal_mmc_set_clock(1, mcycle_ms_freq); //时钟到400khz以下
    DEV_MMC->TMOUT = 0xffffff64UL;
    //cmd8
    ret = hal_mmc_sed_EXTCSD((uint32_t *)mmc_info->ext_csd, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret | ERR_CARD_READ_EXTCSD_FAIL;
    }

    return ret;
}

#if 0
uint32_t hal_mmc_send_stop(uint64_t mcycle_ms_freq)
{
    return hal_memory_card_send_stop(mcycle_ms_freq);
    uint32_t mmc_cmd, mmc_arg;
    uint32_t mmc_response[4];
    uint32_t ret = 0;
#if DEV_MMC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    do
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        mmc_arg = 0;
        mmc_cmd = MMC_CMD(12)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_STOP_ABORT_CMD
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);
//      if(ret != 0)
//      {
//          return ret;
//      }
    }
    while (ret);

    return 0;
}



uint32_t hal_mmc_read_data(uint8_t *buffer, uint32_t mmc_addr, uint32_t len, uint32_t dma_ch, MMC_Info mmc_info)
{
    ;
    uint32_t *out_addr;
    uint32_t mmc_cmd, mmc_arg;
    uint32_t mmc_response[4];
    uint32_t ret = 0;
    uint64_t mcycle_ms_freq = mmc_info->mcycle_ms_freq;
    out_addr = (uint32_t *)buffer;
    //等待空闲
#if DEV_MMC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->STATUS & (DEV_MMC_STATUS_DATA_BUSY | DEV_MMC_STATUS_DATA_STATE_MC_BUSY)) != 0)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    mmc_arg = mmc_info->relative_addr;
    mmc_cmd = MMC_CMD(13)
              | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
              | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
              | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
              | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
              ;
    ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret;
    }

    uint32_t current_card_state;
    current_card_state = (mmc_response[0] >> 9) & 0XF;

    if (current_card_state == 3)
    {
        mmc_arg = (mmc_info->relative_addr);//cmd携带参数
        mmc_cmd = MMC_CMD(7)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            return ret;
        }

        current_card_state = (mmc_response[0] >> 9) & 0XF;
    }

    DEV_MMC->BYTCNT = len;
    DEV_MMC->BLKSIZ = 0x200;
    DEV_MMC->FIFOTH = (2UL << 28UL) | (7UL << 16UL);
    DEV_MMC->CTRL = DEV_MMC_CTRL_DMA_ENABLE;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while (DMA_GetCmdStatus(dma_ch) == ENABLE) //确定dma空闲
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    DMA_SetDestinationAddr(dma_ch, (uint32_t)out_addr);
    DMA_SetByteNum(dma_ch, len);
    DMA_Cmd(dma_ch, ENABLE);

    if (len == 512)
    {
        mmc_arg = mmc_addr;
        mmc_cmd = MMC_CMD(17)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_DATA_EXPECTED //数据期望
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            ret = ret;
            goto read_over;
        }
    }
    else
    {
        mmc_arg = mmc_addr;
        mmc_cmd = MMC_CMD(18)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_DATA_EXPECTED //数据期望
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  | DEV_MMC_CMD_SEND_AUTO_STOP; //自动发送停止命令
        ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            ret = ret;
            goto read_over;
        }
    }

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while (DMA_GetITStatus(dma_ch, DMA_TRANSFER_END) == RESET)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            ret = 1;
            break;
        }

#endif

        if ((DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_DCRC
                                 | DEV_MMC_RINTSTS_DRTO_BDS
                                 | DEV_MMC_RINTSTS_FRUN
                                 | DEV_MMC_RINTSTS_SBE_BCI
                                 | DEV_MMC_RINTSTS_EBE)) != 0)
        {
            ret = DEV_MMC->RINTSTS;

            if (len != 512)
            {
                //这些中断需要软件停止发送
                uint32_t temp_ret = hal_mmc_send_stop(mcycle_ms_freq);

                if (temp_ret)
                {
                    ret = temp_ret;//软件发送cmd12失败，超时或者响应错误
                }

                goto read_over;
            }
            else
            {
                break;
            }
        }
    }

    //若响应出错，这里查的是硬件发送cmd12的状态，
    //发现存在sd卡，硬件自动发送cmd12,sd卡不响应，此处应该重新软件发送cmd12
    //若是前面的cmd12是软件发送，不存在此问题。（因为软件发送cmd12会发送到正确，或超时为止）
    //也就是说，进入此判断语句，一定是硬件发送cmd12sd卡灭有响应出错
    if (DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_RTO_BAR | DEV_MMC_RINTSTS_RE))
    {
        uint32_t temp_ret = hal_mmc_send_stop(mcycle_ms_freq);

        if (temp_ret)
        {
            ret =  temp_ret;//软件发送cmd12失败，超时或者响应错误
            goto read_over;
        }
    }

    if (len != 512)
    {
        //自动发送cmd12或软件发送cmd12后的状态记录再RINTSTS中
        //若是通信出错，软件发送cmd12之前的错误状态已记录再ret变量中
        //此处必须等待dto和acd
#if DEV_MMC_TIME_OUT_CHECK == 1
        time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

        while ((DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_DTO | DEV_MMC_RINTSTS_ACD)) != (DEV_MMC_RINTSTS_DTO | DEV_MMC_RINTSTS_ACD))
        {
#if DEV_MMC_TIME_OUT_CHECK == 1

            if (read_mcycle() >= time_out_value)
            {
                ret = 1;//等待硬件cmd12完成超时
                goto read_over;
            }

#endif
        }
    }

read_over:
    DMA_Cmd(dma_ch, DISABLE);
    DMA_ClearITPendingBit(dma_ch, DMA_TRANSFER_END);
    DEV_MMC->CTRL &= ~DEV_MMC_CTRL_DMA_ENABLE;
    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
    DEV_MMC->CTRL |= DEV_MMC_CTRL_FIFO_RESET;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->CTRL & DEV_MMC_CTRL_FIFO_RESET) == DEV_MMC_CTRL_FIFO_RESET)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    return ret;
}






uint32_t hal_mmc_write_data(uint8_t *buffer, uint32_t mmc_addr, uint32_t len, uint32_t dma_ch, MMC_Info mmc_info)
{
    uint32_t *in_addr;
    uint32_t mmc_cmd, mmc_arg;
    uint32_t mmc_response[4];
    uint32_t ret = 0;
    uint64_t mcycle_ms_freq = mmc_info->mcycle_ms_freq;
    in_addr = (uint32_t *)buffer;
#if DEV_MMC_TIME_OUT_CHECK == 1
    uint64_t time_out_value;
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->STATUS & (DEV_MMC_STATUS_DATA_BUSY | DEV_MMC_STATUS_DATA_STATE_MC_BUSY)) != 0)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    mmc_arg = (mmc_info->relative_addr) | (0UL << 15);
    mmc_cmd = MMC_CMD(13)
              | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
              | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
              | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
              | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
              ;
    ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

    if (ret != 0)
    {
        return ret;
    }

    uint32_t current_card_state;
    current_card_state = (mmc_response[0] >> 9UL) & 0XFUL;

    if (current_card_state == 3UL)
    {
        mmc_arg = (mmc_info->relative_addr);//cmd携带参数
        mmc_cmd = MMC_CMD(7)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            return ret;
        }

        current_card_state = (mmc_response[0] >> 9UL) & 0XFUL;
    }

    DEV_MMC->BYTCNT = len;
    DEV_MMC->BLKSIZ = 0x200UL;
    DEV_MMC->FIFOTH = (2UL << 28UL) | (8UL << 0); //Msize rx_wmark设置
    DEV_MMC->CTRL = DEV_MMC_CTRL_DMA_ENABLE;//dma_enable
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while (DMA_GetCmdStatus(dma_ch) == ENABLE) //确定dma空闲
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    DMA_SetSourceAddr(dma_ch, (uint32_t)in_addr);
    DMA_SetByteNum(dma_ch, len);
    DMA_Cmd(dma_ch, ENABLE);

    if (len == 512)
    {
        mmc_arg = mmc_addr;
        mmc_cmd = MMC_CMD(24)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_DATA_EXPECTED //数据期望
                  | DEV_MMC_CMD_READ_WRITE //写数据
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            ret = ret;
            goto write_over;
        }
    }
    else
    {
        mmc_arg = mmc_addr;
        mmc_cmd = MMC_CMD(25)
                  | DEV_MMC_CMD_RESPONSE_EXPECT //期望响应
                  | DEV_MMC_CMD_CHECK_RESPONSE_CRC //检测响应crc
                  | DEV_MMC_CMD_DATA_EXPECTED //数据期望
                  | DEV_MMC_CMD_READ_WRITE //写数据
                  | DEV_MMC_CMD_WAIT_PRVDATA_COMPLETE //等待前面的数据转换完成在发送此命令
                  | DEV_MMC_CMD_START_CMD //开始发送命令，命令发送后硬件清零
                  | DEV_MMC_CMD_SEND_AUTO_STOP; //自动发送停止命令
        ;
        ret = hal_mmc_send_cmd(mmc_cmd, mmc_arg, mmc_response, mcycle_ms_freq);

        if (ret != 0)
        {
            ret = ret;
            goto write_over;
        }
    }

    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while (DMA_GetITStatus(dma_ch, DMA_TRANSFER_END) == RESET)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            ret = 1;
            break;
        }

#endif

        if ((DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_DCRC
                                 | DEV_MMC_RINTSTS_DRTO_BDS
                                 | DEV_MMC_RINTSTS_FRUN
                                 | DEV_MMC_RINTSTS_EBE)) != 0)
        {
            ret = DEV_MMC->RINTSTS;

            if (len != 512)
            {
                //这些中断需要软件停止发送
                uint32_t temp_ret = hal_mmc_send_stop(mcycle_ms_freq);

                if (temp_ret)
                {
                    ret =  temp_ret;//软件发送cmd12失败，超时或者响应错误
                }

                goto write_over;
            }
            else
            {
                break;
            }
        }
    }

    if (len != 512)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1
        time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

        while ((DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_DTO | DEV_MMC_RINTSTS_ACD)) != (DEV_MMC_RINTSTS_DTO | DEV_MMC_RINTSTS_ACD))
        {
#if DEV_MMC_TIME_OUT_CHECK == 1

            if (read_mcycle() >= time_out_value)
            {
                ret = 1;//等待硬件cmd12发送完成超时
                goto write_over;
            }

#endif
        }
    }

    if (DEV_MMC->RINTSTS & (DEV_MMC_RINTSTS_RTO_BAR | DEV_MMC_RINTSTS_RE))
    {
        uint32_t temp_ret = hal_mmc_send_stop(mcycle_ms_freq);

        if (temp_ret)
        {
            ret =  temp_ret;//软件发送cmd12失败，超时或者响应错误
            goto write_over;
        }
    }

write_over:
    DMA_Cmd(dma_ch, DISABLE);
    DMA_ClearITPendingBit(dma_ch, DMA_TRANSFER_END);
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->STATUS & (DEV_MMC_STATUS_DATA_BUSY | DEV_MMC_STATUS_DATA_STATE_MC_BUSY)) != 0)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    DEV_MMC->CTRL &= ~DEV_MMC_CTRL_DMA_ENABLE;
    DEV_MMC->RINTSTS = DEV_MMC_RINTSTS_INT_STATUS_MASK;
    DEV_MMC->CTRL |= DEV_MMC_CTRL_FIFO_RESET;
#if DEV_MMC_TIME_OUT_CHECK == 1
    time_out_value = read_mcycle() + mcycle_ms_freq * DEV_MMC_TIME_OUT_TIME;
#endif

    while ((DEV_MMC->CTRL & DEV_MMC_CTRL_FIFO_RESET) == DEV_MMC_CTRL_FIFO_RESET)
    {
#if DEV_MMC_TIME_OUT_CHECK == 1

        if (read_mcycle() >= time_out_value)
        {
            return 1;
        }

#endif
        ;
    }

    return ret;
}
#endif
