STM32 接收串口数据并且存储 SD,Python 读取 SD 验证

在我们使用 STM32 或者 FPGA 采集数据的时候,需要将数据存储到SD卡中,因为数据是按照地址存储的,并且没有文件结构,所以不能直接用电脑的文件管理器读取,下面是一种读取数据的办法

0. 实验平台

正点原子 STM32F407ZG 探索者

1. Python生成写入的数据

# %%
# 定义生成文件的大小(字节数)
file_size = 512

# 递增数据的起始值
start_value = 1

# 打开文件并写入递增数据
with open('output.bin', 'wb') as file:
    # 递增循环直到达到文件大小
    for i in range(file_size):
        # 将递增数据写入文件(使用小端字节序)
        file.write(start_value.to_bytes(1, byteorder='little'))
        # 递增起始值
        start_value += 1
        # 如果起始值超过255,则回到0
        if start_value > 10:
            start_value = 0

运行完此代码后,将会在当前文件夹里面生成一个 output.bin 的二进制文件,我们可以使用十六进制的文本阅读器打开查看里面的内容
STM32 接收串口数据并且存储 SD,Python 读取 SD 验证_第1张图片

2. STM32源码

注意:数据需要以0x66aa结尾,这里是自定义的,具体的结尾标志可以自己设定。完整代码可以查看本文章顶部的资源
当然也可以不设定结尾标志,在中断中可以直接把接收到的字节给存入接收缓存

2.1 接收串口中断函数

下面的逻辑为,如果接收到了 0x66 ,那么就判断下一个字节是不是 0xaa,如果是 0xaa,那么就认为接收完成,标记接收完成的标志位。如果不是 0xaa,那么就代表之前的 0x66 是数据,所以还需要把 0x66 进行存储,并且让接收长度 +1。这样做的好处是,可以很好的判断每次收到的数据是否完整,比如发送了 100 个字节,然后以 0x66aa 为结尾符(不计入长度),但是发现接收到的长度只有 99 个字节,那么就说明出现了丟数,方便进行问题定位

void USART_UX_IRQHandler(void)
{
    uint8_t rxdata;
#if SYS_SUPPORT_OS  /* 如果SYS_SUPPORT_OS为真,则需要支持OS. */
    OSIntEnter();
#endif

    if (USART_UX->SR & (1 << 5))                /* 接收到数据 */
    {
        rxdata = USART_UX->DR;

        if ((g_usart_rx_sta & 0x8000) == 0)     /* 接收未完成? */
        {
            if (g_usart_rx_sta & 0x4000)        /* 接收到了0x66? */
            {
                if (rxdata != 0xaa)             /* 接收到了0xaa? (必须先接收到到0x66,才检查0xaa) */
                {
                    g_usart_rx_sta &= ~0x4000;
                    g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = 0x66;   /* 存储数据到 g_usart_rx_buf */
                    g_usart_rx_sta++;
                    
                    if (rxdata == 0x66)
                    {
                        g_usart_rx_sta |= 0x4000;   /* 标记接收到了 0x66 */
                    }
                    else
                    {
                        g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = rxdata;   /* 存储数据到 g_usart_rx_buf */
                        g_usart_rx_sta++;
                        if (g_usart_rx_sta > (USART_REC_LEN - 1))g_usart_rx_sta = 0;/* 接收数据溢出, 重新开始接收 */
                    }
                }
                else
                {
                    g_usart_rx_sta |= 0x8000;   /* 收到了0x0a,标记接收完成了 */
                }
            }
            else      /* 还没收到0x0d */
            {
                if (rxdata == 0x66)
                {
                    g_usart_rx_sta |= 0x4000;   /* 标记接收到了 0x66 */
                }
                else
                {
                    g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = rxdata;   /* 存储数据到 g_usart_rx_buf */
                    g_usart_rx_sta++;
                    if (g_usart_rx_sta > (USART_REC_LEN - 1))g_usart_rx_sta = 0;/* 接收数据溢出, 重新开始接收 */
                }
            }
        }
    }
    #if SYS_SUPPORT_OS  /* 如果SYS_SUPPORT_OS为真,则需要支持OS. */
    OSIntExit();
#endif
}

2.2 SD卡驱动函数 (建议从正点原子 SD 卡例程中获取)

2.2.1 sdio_sdcard.h
#ifndef __SDMMC_SDCARD_H
#define __SDMMC_SDCARD_H

#include "./SYSTEM/sys/sys.h"

/* 用户配置区
 * SDIO时钟计算公式: SDIO_CK 时钟 = SDIOCLK / [clkdiv + 2]; 其中, SDIOCLK 一般为48Mhz
 * 如果出现驱动错误, 请尝试将 SDIO_TRANSFER_CLK_DIV 改大, 降低SD卡时钟频率
 */
#define SDIO_INIT_CLK_DIV        118        /* SDIO初始化频率, 48M / (118 + 2) = 400Khz, 最大400Kh */
#define SDIO_TRANSFER_CLK_DIV    0          /* SDIO传输频率 48M / (0 + 2) = 24M ,该值太小可能会导致读写文件出错 */

/******************************************************************************************/
/* SDIO的信号线: SD_D0 ~ SD_D3/SD_CLK/SD_CMD 引脚 定义 
 * 如果你使用了其他引脚做SDIO的信号线,修改这里写定义即可适配.
 */

#define SD_D0_GPIO_PORT                 GPIOC
#define SD_D0_GPIO_PIN                  SYS_GPIO_PIN8
#define SD_D0_GPIO_AF                   12
#define SD_D0_GPIO_CLK_ENABLE()         do{ RCC->AHB1ENR |= 1 << 2; }while(0)   /* 所在IO口时钟使能 */

#define SD_D1_GPIO_PORT                 GPIOC
#define SD_D1_GPIO_PIN                  SYS_GPIO_PIN9
#define SD_D1_GPIO_AF                   12
#define SD_D1_GPIO_CLK_ENABLE()         do{ RCC->AHB1ENR |= 1 << 2; }while(0)   /* 所在IO口时钟使能 */

#define SD_D2_GPIO_PORT                 GPIOC
#define SD_D2_GPIO_PIN                  SYS_GPIO_PIN10
#define SD_D2_GPIO_AF                   12
#define SD_D2_GPIO_CLK_ENABLE()         do{ RCC->AHB1ENR |= 1 << 2; }while(0)   /* 所在IO口时钟使能 */

#define SD_D3_GPIO_PORT                 GPIOC
#define SD_D3_GPIO_PIN                  SYS_GPIO_PIN11
#define SD_D3_GPIO_AF                   12
#define SD_D3_GPIO_CLK_ENABLE()         do{ RCC->AHB1ENR |= 1 << 2; }while(0)   /* 所在IO口时钟使能 */

#define SD_CLK_GPIO_PORT                GPIOC
#define SD_CLK_GPIO_PIN                 SYS_GPIO_PIN12
#define SD_CLK_GPIO_AF                  12
#define SD_CLK_GPIO_CLK_ENABLE()        do{ RCC->AHB1ENR |= 1 << 2; }while(0)   /* 所在IO口时钟使能 */

#define SD_CMD_GPIO_PORT                GPIOD
#define SD_CMD_GPIO_PIN                 SYS_GPIO_PIN2
#define SD_CMD_GPIO_AF                  12
#define SD_CMD_GPIO_CLK_ENABLE()        do{ RCC->AHB1ENR |= 1 << 3; }while(0)   /* 所在IO口时钟使能 */

/******************************************************************************************/

/* SD卡操作 各种错误枚举定义 */
typedef enum
{
    /* 特殊错误定义 */
    SD_CMD_CRC_FAIL                    = (1),   /*!< Command response received (but CRC check failed)              */
    SD_DATA_CRC_FAIL                   = (2),   /*!< Data block sent/received (CRC check failed)                   */
    SD_CMD_RSP_TIMEOUT                 = (3),   /*!< Command response timeout                                      */
    SD_DATA_TIMEOUT                    = (4),   /*!< Data timeout                                                  */
    SD_TX_UNDERRUN                     = (5),   /*!< Transmit FIFO underrun                                        */
    SD_RX_OVERRUN                      = (6),   /*!< Receive FIFO overrun                                          */
    SD_START_BIT_ERR                   = (7),   /*!< Start bit not detected on all data signals in wide bus mode   */
    SD_CMD_OUT_OF_RANGE                = (8),   /*!< Command's argument was out of range.                          */
    SD_ADDR_MISALIGNED                 = (9),   /*!< Misaligned address                                            */
    SD_BLOCK_LEN_ERR                   = (10),  /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */
    SD_ERASE_SEQ_ERR                   = (11),  /*!< An error in the sequence of erase command occurs.            */
    SD_BAD_ERASE_PARAM                 = (12),  /*!< An invalid selection for erase groups                        */
    SD_WRITE_PROT_VIOLATION            = (13),  /*!< Attempt to program a write protect block                     */
    SD_LOCK_UNLOCK_FAILED              = (14),  /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */
    SD_COM_CRC_FAILED                  = (15),  /*!< CRC check of the previous command failed                     */
    SD_ILLEGAL_CMD                     = (16),  /*!< Command is not legal for the card state                      */
    SD_CARD_ECC_FAILED                 = (17),  /*!< Card internal ECC was applied but failed to correct the data */
    SD_CC_ERROR                        = (18),  /*!< Internal card controller error                               */
    SD_GENERAL_UNKNOWN_ERROR           = (19),  /*!< General or unknown error                                     */
    SD_STREAM_READ_UNDERRUN            = (20),  /*!< The card could not sustain data transfer in stream read operation. */
    SD_STREAM_WRITE_OVERRUN            = (21),  /*!< The card could not sustain data programming in stream mode   */
    SD_CID_CSD_OVERWRITE               = (22),  /*!< CID/CSD overwrite error                                      */
    SD_WP_ERASE_SKIP                   = (23),  /*!< Only partial address space was erased                        */
    SD_CARD_ECC_DISABLED               = (24),  /*!< Command has been executed without using internal ECC         */
    SD_ERASE_RESET                     = (25),  /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */
    SD_AKE_SEQ_ERROR                   = (26),  /*!< Error in sequence of authentication.                         */
    SD_INVALID_VOLTRANGE               = (27),
    SD_ADDR_OUT_OF_RANGE               = (28),
    SD_SWITCH_ERROR                    = (29),
    SD_SDMMC_DISABLED                  = (30),
    SD_SDMMC_FUNCTION_BUSY             = (31),
    SD_SDMMC_FUNCTION_FAILED           = (32),
    SD_SDMMC_UNKNOWN_FUNCTION          = (33),
    /* 标准错误定义 */
    SD_INTERNAL_ERROR                  = (34),
    SD_NOT_CONFIGURED                  = (35),
    SD_REQUEST_PENDING                 = (36),
    SD_REQUEST_NOT_APPLICABLE          = (37),
    SD_INVALID_PARAMETER               = (38),
    SD_UNSUPPORTED_FEATURE             = (39),
    SD_UNSUPPORTED_HW                  = (40),
    SD_ERROR                           = (41),
    SD_OK                              = (0)
} SD_Error;

/* SD卡CSD寄存器数据 */
typedef struct
{
    uint8_t  CSDStruct;            /*!< CSD structure */
    uint8_t  SysSpecVersion;       /*!< System specification version */
    uint8_t  Reserved1;            /*!< Reserved */
    uint8_t  TAAC;                 /*!< Data read access-time 1 */
    uint8_t  NSAC;                 /*!< Data read access-time 2 in CLK cycles */
    uint8_t  MaxBusClkFrec;        /*!< Max. bus clock frequency */
    uint16_t CardComdClasses;      /*!< Card command classes */
    uint8_t  RdBlockLen;           /*!< Max. read data block length */
    uint8_t  PartBlockRead;        /*!< Partial blocks for read allowed */
    uint8_t  WrBlockMisalign;      /*!< Write block misalignment */
    uint8_t  RdBlockMisalign;      /*!< Read block misalignment */
    uint8_t  DSRImpl;              /*!< DSR implemented */
    uint8_t  Reserved2;            /*!< Reserved */
    uint32_t DeviceSize;           /*!< Device Size */
    uint8_t  MaxRdCurrentVDDMin;   /*!< Max. read current @ VDD min */
    uint8_t  MaxRdCurrentVDDMax;   /*!< Max. read current @ VDD max */
    uint8_t  MaxWrCurrentVDDMin;   /*!< Max. write current @ VDD min */
    uint8_t  MaxWrCurrentVDDMax;   /*!< Max. write current @ VDD max */
    uint8_t  DeviceSizeMul;        /*!< Device size multiplier */
    uint8_t  EraseGrSize;          /*!< Erase group size */
    uint8_t  EraseGrMul;           /*!< Erase group size multiplier */
    uint8_t  WrProtectGrSize;      /*!< Write protect group size */
    uint8_t  WrProtectGrEnable;    /*!< Write protect group enable */
    uint8_t  ManDeflECC;           /*!< Manufacturer default ECC */
    uint8_t  WrSpeedFact;          /*!< Write speed factor */
    uint8_t  MaxWrBlockLen;        /*!< Max. write data block length */
    uint8_t  WriteBlockPaPartial;  /*!< Partial blocks for write allowed */
    uint8_t  Reserved3;            /*!< Reserded */
    uint8_t  ContentProtectAppli;  /*!< Content protection application */
    uint8_t  FileFormatGrouop;     /*!< File format group */
    uint8_t  CopyFlag;             /*!< Copy flag (OTP) */
    uint8_t  PermWrProtect;        /*!< Permanent write protection */
    uint8_t  TempWrProtect;        /*!< Temporary write protection */
    uint8_t  FileFormat;           /*!< File Format */
    uint8_t  ECC;                  /*!< ECC code */
    uint8_t  CSD_CRC;              /*!< CSD CRC */
    uint8_t  Reserved4;            /*!< always 1*/
} SD_CSD;

/* SD卡CID寄存器数据 */
typedef struct
{
    uint8_t  ManufacturerID;       /*!< ManufacturerID */
    uint16_t OEM_AppliID;          /*!< OEM/Application ID */
    uint32_t ProdName1;            /*!< Product Name part1 */
    uint8_t  ProdName2;            /*!< Product Name part2*/
    uint8_t  ProdRev;              /*!< Product Revision */
    uint32_t ProdSN;               /*!< Product Serial Number */
    uint8_t  Reserved1;            /*!< Reserved1 */
    uint16_t ManufactDate;         /*!< Manufacturing Date */
    uint8_t  CID_CRC;              /*!< CID CRC */
    uint8_t  Reserved2;            /*!< always 1 */
} SD_CID;

/* SD卡状态 */
typedef enum
{
    SD_CARD_READY                  = ((uint32_t)0x00000001),
    SD_CARD_IDENTIFICATION         = ((uint32_t)0x00000002),
    SD_CARD_STANDBY                = ((uint32_t)0x00000003),
    SD_CARD_TRANSFER               = ((uint32_t)0x00000004),
    SD_CARD_SENDING                = ((uint32_t)0x00000005),
    SD_CARD_RECEIVING              = ((uint32_t)0x00000006),
    SD_CARD_PROGRAMMING            = ((uint32_t)0x00000007),
    SD_CARD_DISCONNECTED           = ((uint32_t)0x00000008),
    SD_CARD_ERROR                  = ((uint32_t)0x000000FF)
}SDCardState;

/* SD卡信息,包括CSD,CID等数据 */
typedef struct
{
  SD_CSD SD_csd;
  SD_CID SD_cid;
  long long CardCapacity;       /* SD卡容量,单位:字节,最大支持2^64字节大小的卡. */
  uint32_t CardBlockSize;       /* SD卡块大小 */
  uint16_t RCA;                 /* 卡相对地址 */
  uint8_t CardType;             /* 卡类型 */
} SD_CardInfo;

extern SD_CardInfo g_sd_card_info;  /* SD卡信息 */

/******************************************************************************************/
/* SDMMC卡 指令集 */
/* 拷贝自:stm32f7xx_hal_sd.h */
#define SD_CMD_GO_IDLE_STATE                       ((uint8_t)0U)   /*!< Resets the SD memory card.                                                               */
#define SD_CMD_SEND_OP_COND                        ((uint8_t)1U)   /*!< Sends host capacity support information and activates the card's initialization process. */
#define SD_CMD_ALL_SEND_CID                        ((uint8_t)2U)   /*!< Asks any card connected to the host to send the CID numbers on the CMD line.             */
#define SD_CMD_SET_REL_ADDR                        ((uint8_t)3U)   /*!< Asks the card to publish a new relative address (RCA).                                   */
#define SD_CMD_SET_DSR                             ((uint8_t)4U)   /*!< Programs the DSR of all cards.                                                           */
#define SD_CMD_SDMMC_SEN_OP_COND                   ((uint8_t)5U)   /*!< Sends host capacity support information (HCS) and asks the accessed card to send its 
                                                                       operating condition register (OCR) content in the response on the CMD line.              */
#define SD_CMD_HS_SWITCH                           ((uint8_t)6U)   /*!< Checks switchable function (mode 0) and switch card function (mode 1).                   */
#define SD_CMD_SEL_DESEL_CARD                      ((uint8_t)7U)   /*!< Selects the card by its own relative address and gets deselected by any other address    */
#define SD_CMD_HS_SEND_EXT_CSD                     ((uint8_t)8U)   /*!< Sends SD Memory Card interface condition, which includes host supply voltage information 
                                                                       and asks the card whether card supports voltage.                                         */
#define SD_CMD_SEND_CSD                            ((uint8_t)9U)   /*!< Addressed card sends its card specific data (CSD) on the CMD line.                       */
#define SD_CMD_SEND_CID                            ((uint8_t)10U)  /*!< Addressed card sends its card identification (CID) on the CMD line.                      */
#define SD_CMD_READ_DAT_UNTIL_STOP                 ((uint8_t)11U)  /*!< SD card doesn't support it.                                                              */
#define SD_CMD_STOP_TRANSMISSION                   ((uint8_t)12U)  /*!< Forces the card to stop transmission.                                                    */
#define SD_CMD_SEND_STATUS                         ((uint8_t)13U)  /*!< Addressed card sends its status register.                                                */
#define SD_CMD_HS_BUSTEST_READ                     ((uint8_t)14U)
#define SD_CMD_GO_INACTIVE_STATE                   ((uint8_t)15U)  /*!< Sends an addressed card into the inactive state.                                         */
#define SD_CMD_SET_BLOCKLEN                        ((uint8_t)16U)  /*!< Sets the block length (in bytes for SDSC) for all following block commands 
                                                                       (read, write, lock). Default block length is fixed to 512 Bytes. Not effective 
                                                                       for SDHS and SDXC.                                                                       */
#define SD_CMD_READ_SINGLE_BLOCK                   ((uint8_t)17U)  /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of 
                                                                       fixed 512 bytes in case of SDHC and SDXC.                                                */
#define SD_CMD_READ_MULT_BLOCK                     ((uint8_t)18U)  /*!< Continuously transfers data blocks from card to host until interrupted by 
                                                                       STOP_TRANSMISSION command.                                                               */
#define SD_CMD_HS_BUSTEST_WRITE                    ((uint8_t)19U)  /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104.                                    */
#define SD_CMD_WRITE_DAT_UNTIL_STOP                ((uint8_t)20U)  /*!< Speed class control command.                                                             */
#define SD_CMD_SET_BLOCK_COUNT                     ((uint8_t)23U)  /*!< Specify block count for CMD18 and CMD25.                                                 */
#define SD_CMD_WRITE_SINGLE_BLOCK                  ((uint8_t)24U)  /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of 
                                                                       fixed 512 bytes in case of SDHC and SDXC.                                                */
#define SD_CMD_WRITE_MULT_BLOCK                    ((uint8_t)25U)  /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows.                    */
#define SD_CMD_PROG_CID                            ((uint8_t)26U)  /*!< Reserved for manufacturers.                                                              */
#define SD_CMD_PROG_CSD                            ((uint8_t)27U)  /*!< Programming of the programmable bits of the CSD.                                         */
#define SD_CMD_SET_WRITE_PROT                      ((uint8_t)28U)  /*!< Sets the write protection bit of the addressed group.                                    */
#define SD_CMD_CLR_WRITE_PROT                      ((uint8_t)29U)  /*!< Clears the write protection bit of the addressed group.                                  */
#define SD_CMD_SEND_WRITE_PROT                     ((uint8_t)30U)  /*!< Asks the card to send the status of the write protection bits.                           */
#define SD_CMD_SD_ERASE_GRP_START                  ((uint8_t)32U)  /*!< Sets the address of the first write block to be erased. (For SD card only).              */
#define SD_CMD_SD_ERASE_GRP_END                    ((uint8_t)33U)  /*!< Sets the address of the last write block of the continuous range to be erased.           */
#define SD_CMD_ERASE_GRP_START                     ((uint8_t)35U)  /*!< Sets the address of the first write block to be erased. Reserved for each command 
                                                                       system set by switch function command (CMD6).                                            */
#define SD_CMD_ERASE_GRP_END                       ((uint8_t)36U)  /*!< Sets the address of the last write block of the continuous range to be erased. 
                                                                       Reserved for each command system set by switch function command (CMD6).                  */
#define SD_CMD_ERASE                               ((uint8_t)38U)  /*!< Reserved for SD security applications.                                                   */
#define SD_CMD_FAST_IO                             ((uint8_t)39U)  /*!< SD card doesn't support it (Reserved).                                                   */
#define SD_CMD_GO_IRQ_STATE                        ((uint8_t)40U)  /*!< SD card doesn't support it (Reserved).                                                   */
#define SD_CMD_LOCK_UNLOCK                         ((uint8_t)42U)  /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by 
                                                                       the SET_BLOCK_LEN command.                                                               */
#define SD_CMD_APP_CMD                             ((uint8_t)55U)  /*!< Indicates to the card that the next command is an application specific command rather 
                                                                       than a standard command.                                                                 */
#define SD_CMD_GEN_CMD                             ((uint8_t)56U)  /*!< Used either to transfer a data block to the card or to get a data block from the card 
                                                                       for general purpose/application specific commands.                                       */
#define SD_CMD_NO_CMD                              ((uint8_t)64U)

/**
  * @brief Following commands are SD Card Specific commands.
  *        SDMMC_APP_CMD should be sent before sending these commands.
  */
#define SD_CMD_APP_SD_SET_BUSWIDTH                 ((uint8_t)6U)   /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus 
                                                                       widths are given in SCR register.                                                          */
#define SD_CMD_SD_APP_STATUS                       ((uint8_t)13U)  /*!< (ACMD13) Sends the SD status.                                                              */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS        ((uint8_t)22U)  /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with 
                                                                       32bit+CRC data block.                                                                      */
#define SD_CMD_SD_APP_OP_COND                      ((uint8_t)41U)  /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to 
                                                                       send its operating condition register (OCR) content in the response on the CMD line.       */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT          ((uint8_t)42U)  /*!< (ACMD42) Connects/Disconnects the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card. */
#define SD_CMD_SD_APP_SEND_SCR                     ((uint8_t)51U)  /*!< Reads the SD Configuration Register (SCR).                                                 */
#define SD_CMD_SDMMC_RW_DIRECT                     ((uint8_t)52U)  /*!< For SD I/O card only, reserved for security specification.                                 */
#define SD_CMD_SDMMC_RW_EXTENDED                   ((uint8_t)53U)  /*!< For SD I/O card only, reserved for security specification.                                 */

/**
  * @brief Following commands are SD Card Specific security commands.
  *        SD_CMD_APP_CMD should be sent before sending these commands.
  */
#define SD_CMD_SD_APP_GET_MKB                      ((uint8_t)43U)  /*!< For SD card only */
#define SD_CMD_SD_APP_GET_MID                      ((uint8_t)44U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RN1                  ((uint8_t)45U)  /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RN2                  ((uint8_t)46U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SET_CER_RES2                 ((uint8_t)47U)  /*!< For SD card only */
#define SD_CMD_SD_APP_GET_CER_RES1                 ((uint8_t)48U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK   ((uint8_t)18U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK  ((uint8_t)25U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_ERASE                 ((uint8_t)38U)  /*!< For SD card only */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA           ((uint8_t)49U)  /*!< For SD card only */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB             ((uint8_t)48U)  /*!< For SD card only */

/* CMD8指令 */
#define SD_SDMMC_SEND_IF_COND                      ((uint32_t)SD_CMD_HS_SEND_EXT_CSD)
/******************************************************************************************/

/* 支持的SD卡定义 */
#define STD_CAPACITY_SD_CARD_V1_1       ((uint32_t)0x00000000U)
#define STD_CAPACITY_SD_CARD_V2_0       ((uint32_t)0x00000001U)
#define HIGH_CAPACITY_SD_CARD           ((uint32_t)0x00000002U)
#define MULTIMEDIA_CARD                 ((uint32_t)0x00000003U)
#define SECURE_DIGITAL_IO_CARD          ((uint32_t)0x00000004U)
#define HIGH_SPEED_MULTIMEDIA_CARD      ((uint32_t)0x00000005U)
#define SECURE_DIGITAL_IO_COMBO_CARD    ((uint32_t)0x00000006U)
#define HIGH_CAPACITY_MMC_CARD          ((uint32_t)0x00000007U)

/* SDMMC相关参数定义 */
#define NULL 0
#define SDMMC_STATIC_FLAGS              ((uint32_t)0x000205FF)
#define SDMMC_CMD0TIMEOUT               ((uint32_t)0x00010000)
#define SDMMC_CMD1TIMEOUT               ((uint32_t)0x00FFFFFF)
#define SDMMC_DATATIMEOUT               ((uint32_t)0X00FFFFFF)

/* Mask for errors Card Status R1 (OCR Register) */
#define SD_OCR_ADDR_OUT_OF_RANGE        ((uint32_t)0x80000000)
#define SD_OCR_ADDR_MISALIGNED          ((uint32_t)0x40000000)
#define SD_OCR_BLOCK_LEN_ERR            ((uint32_t)0x20000000)
#define SD_OCR_ERASE_SEQ_ERR            ((uint32_t)0x10000000)
#define SD_OCR_BAD_ERASE_PARAM          ((uint32_t)0x08000000)
#define SD_OCR_WRITE_PROT_VIOLATION     ((uint32_t)0x04000000)
#define SD_OCR_LOCK_UNLOCK_FAILED       ((uint32_t)0x01000000)
#define SD_OCR_COM_CRC_FAILED           ((uint32_t)0x00800000)
#define SD_OCR_ILLEGAL_CMD              ((uint32_t)0x00400000)
#define SD_OCR_CARD_ECC_FAILED          ((uint32_t)0x00200000)
#define SD_OCR_CC_ERROR                 ((uint32_t)0x00100000)
#define SD_OCR_GENERAL_UNKNOWN_ERROR    ((uint32_t)0x00080000)
#define SD_OCR_STREAM_READ_UNDERRUN     ((uint32_t)0x00040000)
#define SD_OCR_STREAM_WRITE_OVERRUN     ((uint32_t)0x00020000)
#define SD_OCR_CID_CSD_OVERWRIETE       ((uint32_t)0x00010000)
#define SD_OCR_WP_ERASE_SKIP            ((uint32_t)0x00008000)
#define SD_OCR_CARD_ECC_DISABLED        ((uint32_t)0x00004000)
#define SD_OCR_ERASE_RESET              ((uint32_t)0x00002000)
#define SD_OCR_AKE_SEQ_ERROR            ((uint32_t)0x00000008)
#define SD_OCR_ERRORBITS                ((uint32_t)0xFDFFE008)

/* Masks for R6 Response */
#define SD_R6_GENERAL_UNKNOWN_ERROR     ((uint32_t)0x00002000)
#define SD_R6_ILLEGAL_CMD               ((uint32_t)0x00004000)
#define SD_R6_COM_CRC_FAILED            ((uint32_t)0x00008000)

#define SD_VOLTAGE_WINDOW_SD            ((uint32_t)0x80100000)
#define SD_HIGH_CAPACITY                ((uint32_t)0x40000000)
#define SD_STD_CAPACITY                 ((uint32_t)0x00000000)
#define SD_CHECK_PATTERN                ((uint32_t)0x000001AA)
#define SD_VOLTAGE_WINDOW_MMC           ((uint32_t)0x80FF8000)

#define SD_MAX_VOLT_TRIAL               ((uint32_t)0x0000FFFF)
#define SD_ALLZERO                      ((uint32_t)0x00000000)

#define SD_WIDE_BUS_SUPPORT             ((uint32_t)0x00040000)
#define SD_SINGLE_BUS_SUPPORT           ((uint32_t)0x00010000)
#define SD_CARD_LOCKED                  ((uint32_t)0x02000000)
#define SD_CARD_PROGRAMMING             ((uint32_t)0x00000007)
#define SD_CARD_RECEIVING               ((uint32_t)0x00000006)
#define SD_DATATIMEOUT                  ((uint32_t)0xFFFFFFFF)
#define SD_0TO7BITS                     ((uint32_t)0x000000FF)
#define SD_8TO15BITS                    ((uint32_t)0x0000FF00)
#define SD_16TO23BITS                   ((uint32_t)0x00FF0000)
#define SD_24TO31BITS                   ((uint32_t)0xFF000000)
#define SD_MAX_DATA_LENGTH              ((uint32_t)0x01FFFFFF)

#define SD_HALFFIFO                     ((uint32_t)0x00000008)
#define SD_HALFFIFOBYTES                ((uint32_t)0x00000020)

/* Command Class Supported */
#define SD_CCCC_LOCK_UNLOCK             ((uint32_t)0x00000080)
#define SD_CCCC_WRITE_PROT              ((uint32_t)0x00000040)
#define SD_CCCC_ERASE                   ((uint32_t)0x00000020)

/******************************************************************************************/

/* 静态函数, 仅sdmmc_sdcard.c内部使用 */
static SD_Error sdmmc_cmd_error(void);
static SD_Error sdmmc_cmd_resp1_error(uint8_t cmd);
static SD_Error sdmmc_cmd_resp2_error(void);
static SD_Error sdmmc_cmd_resp3_error(void);
static SD_Error sdmmc_cmd_resp6_error(uint8_t cmd, uint16_t *prca);
static SD_Error sdmmc_cmd_resp7_error(void);

static SD_Error sdmmc_wide_bus_enable(uint8_t enx);
static SD_Error sdmmc_wide_bus_operation(uint32_t bwide);
static SD_Error sdmmc_is_card_programming(uint8_t *pstatus);

static SD_Error sdmmc_send_status(uint32_t *pstatus);
static SD_Error sdmmc_find_scr(uint16_t rca, uint32_t *pscr);

static SD_Error sdmmc_power_on(void);
static void sdmmc_clock_set(uint16_t clkdiv);
static SD_Error sdmmc_initialize_cards(void);
static SD_Error sdmmc_select_deselect(uint32_t addr);
static SD_Error sdmmc_get_card_info(SD_CardInfo *cardinfo);
static void sdmmc_send_cmd(uint8_t cmdindex, uint8_t waitrsp, uint32_t arg);
static void sdmmc_send_data_cfg(uint32_t datatimeout, uint32_t datalen, uint8_t blksize, uint8_t dir);

static SD_Error sdmmc_read_blocks(uint8_t *pbuf, long long addr, uint16_t blksize, uint32_t nblks);
static SD_Error sdmmc_write_blocks(uint8_t *pbuf, long long addr, uint16_t blksize, uint32_t nblks);


/* 接口函数定义 */
SD_Error sd_init(void);
SDCardState sdmmc_get_status(void);

uint8_t  sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt);
uint8_t  sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt);

#endif

2.2.2 sdio_sdcard.c
#include "string.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/SDIO/sdio_sdcard.h"

/* 仅在本.c文件使用的全局变量, 不加前缀 g_,
 * 另外, 为了兼容老版本, 这几个全局变量不做名字改动
 */
static uint8_t CardType = STD_CAPACITY_SD_CARD_V1_1;    /* SD卡类型(默认为1.x卡) */
static uint32_t CSD_Tab[4], CID_Tab[4], RCA = 0;        /* SD卡CSD,CID以及相对地址(RCA)数据 */

/* SD卡信息 */
SD_CardInfo g_sd_card_info;

/**
 * @brief       初始化SD卡
 * @param       无
 * @retval      无
 */
SD_Error sd_init(void)
{
    SD_Error errorstatus = SD_OK;
    uint8_t clkdiv = 0;
    /* SDIO IO口初始化 */
    RCC->APB2ENR |= 1 << 11;    /* SDIO 时钟使能 */
    SD_D0_GPIO_CLK_ENABLE();   /* D0引脚IO时钟使能 */
    SD_D1_GPIO_CLK_ENABLE();   /* D1引脚IO时钟使能 */
    SD_D2_GPIO_CLK_ENABLE();   /* D2引脚IO时钟使能 */
    SD_D3_GPIO_CLK_ENABLE();   /* D3引脚IO时钟使能 */
    SD_CLK_GPIO_CLK_ENABLE();  /* CLK引脚IO时钟使能 */
    SD_CMD_GPIO_CLK_ENABLE();  /* CMD引脚IO时钟使能 */

    sys_gpio_set(SD_D0_GPIO_PORT, SD_D0_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_D0引脚模式设置 */

    sys_gpio_set(SD_D1_GPIO_PORT, SD_D1_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_D1引脚模式设置 */

    sys_gpio_set(SD_D2_GPIO_PORT, SD_D2_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_D2引脚模式设置 */

    sys_gpio_set(SD_D3_GPIO_PORT, SD_D3_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_D3引脚模式设置 */

    sys_gpio_set(SD_CLK_GPIO_PORT, SD_CLK_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_CLK引脚模式设置 */

    sys_gpio_set(SD_CMD_GPIO_PORT, SD_CMD_GPIO_PIN,
                 SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   /* SD_CMD引脚模式设置 */

    sys_gpio_af_set(SD_D0_GPIO_PORT, SD_D0_GPIO_PIN, SD_D0_GPIO_AF);    /* SD_D0 脚, 复用功能设置 */
    sys_gpio_af_set(SD_D1_GPIO_PORT, SD_D1_GPIO_PIN, SD_D1_GPIO_AF);    /* SD_D1 脚, 复用功能设置 */
    sys_gpio_af_set(SD_D2_GPIO_PORT, SD_D2_GPIO_PIN, SD_D2_GPIO_AF);    /* SD_D2 脚, 复用功能设置 */
    sys_gpio_af_set(SD_D3_GPIO_PORT, SD_D3_GPIO_PIN, SD_D3_GPIO_AF);    /* SD_D3 脚, 复用功能设置 */
    sys_gpio_af_set(SD_CLK_GPIO_PORT, SD_CLK_GPIO_PIN, SD_CLK_GPIO_AF); /* SD_CLK 脚, 复用功能设置 */
    sys_gpio_af_set(SD_CMD_GPIO_PORT, SD_CMD_GPIO_PIN, SD_CMD_GPIO_AF); /* SD_CMD 脚, 复用功能设置 */

    /* SDMMC外设寄存器设置为默认值 */
    SDIO->POWER = 0x00000000;
    SDIO->CLKCR = 0x00000000;
    SDIO->ARG = 0x00000000;
    SDIO->CMD = 0x00000000;
    SDIO->DTIMER = 0x00000000;
    SDIO->DLEN = 0x00000000;
    SDIO->DCTRL = 0x00000000;
    SDIO->ICR = 0X1FE00FFF;
    SDIO->MASK = 0x00000000;

    errorstatus = sdmmc_power_on(); /* SD卡上电 */

    if (errorstatus == SD_OK)
    {
        errorstatus = sdmmc_initialize_cards(); /* 初始化SD卡 */
    }

    if (errorstatus == SD_OK)
    {
        errorstatus = sdmmc_get_card_info(&g_sd_card_info);  /* 获取卡信息 */
    }

    if (errorstatus == SD_OK)
    {
        errorstatus = sdmmc_select_deselect((uint32_t)(g_sd_card_info.RCA << 16));  /* 选中SD卡 */
    }

    if (errorstatus == SD_OK)
    {
        errorstatus = sdmmc_wide_bus_operation(1);  /* 4位宽度,如果是MMC卡,则不能用4位模式 */
    }

    if ((errorstatus == SD_OK) || (MULTIMEDIA_CARD == CardType))
    {
        if (g_sd_card_info.CardType == STD_CAPACITY_SD_CARD_V1_1 || g_sd_card_info.CardType == STD_CAPACITY_SD_CARD_V2_0)
        {
            clkdiv = SDIO_TRANSFER_CLK_DIV + 2;     /* V1.1/V2.0卡,设置最高 48 / 4 = 12Mhz */
        }
        else
        {
            clkdiv = SDIO_TRANSFER_CLK_DIV;         /* SDHC等其他卡,设置最高 48 / (0 + 2) = 24Mhz */
        }

        /* 设置时钟频率,SDMMC时钟计算公式: SDIO_CK 时钟 = SDIOCLK / [2 + clkdiv]; 其中, SDIOCLK 一般为48Mhz */
        sdmmc_clock_set(clkdiv);
    }

    return errorstatus;
}

/**
 * @brief       SDMMC 时钟设置
 * @param       clkdiv : 时钟分频系数
 *   @note      CK时钟 =  SDIOCLK / [2 * clkdiv]; (SDIOCLK 钟一般为72Mhz)
 * @retval      无
 */
static void sdmmc_clock_set(uint16_t clkdiv)
{
    uint32_t tmpreg = SDIO->CLKCR;
    tmpreg &= 0XFFFFFF00;
    tmpreg |= clkdiv;
    SDIO->CLKCR = tmpreg;
}

/**
 * @brief       SDMMC 发送命令函数
 * @param       cmdindex : 命令索引,低六位有效
 * @param       waitrsp  : 期待的响应.
 *   @arg       00/10, 无响应
 *   @arg       01   , 短响应
 *   @arg       11   , 长响应
 * @param       arg      : 命令参数
 * @retval      无
 */
static void sdmmc_send_cmd(uint8_t cmdindex, uint8_t waitrsp, uint32_t arg)
{
    uint32_t tmpreg = 0;
    SDIO->ARG = arg;
    tmpreg |= cmdindex & 0X3F;          /* 设置新的index */
    tmpreg |= (uint32_t)waitrsp << 6;   /* 设置新的wait rsp */
    tmpreg |= 0 << 8;                   /* 无等待 */
    tmpreg |= 1 << 10;                  /* 命令通道状态机使能 */
    SDIO->CMD = tmpreg;
}

/**
 * @brief       SDMMC 发送数据配置函数
 * @param       datatimeout : 超时时间设置
 * @param       datalen     : 传输数据长度,低25位有效,必须为块大小的整数倍
 * @param       blksize     : 块大小. 实际大小为: 2^blksize字节
 * @param       dir         : 数据传输方向: 0, 控制器到卡; 1, 卡到控制器;
 * @retval      无
 */
static void sdmmc_send_data_cfg(uint32_t datatimeout, uint32_t datalen, uint8_t blksize, uint8_t dir)
{
    uint32_t tmpreg;
    SDIO->DTIMER = datatimeout;
    SDIO->DLEN = datalen & 0X1FFFFFF; /* 低25位有效 */
    tmpreg = SDIO->DCTRL;
    tmpreg &= 0xFFFFFF00;               /* 清除之前的设置. */
    tmpreg |= blksize << 4;             /* 设置块大小 */
    tmpreg |= 0 << 2;                   /* 块数据传输 */
    tmpreg |= (dir & 0X01) << 1;        /* 方向控制 */
    tmpreg |= 1 << 0;                   /* 数据传输使能,DPSM状态机 */
    SDIO->DCTRL = tmpreg;
}

/**
 * @brief       卡上电
 *   @note      查询所有SDMMC接口上的卡设备,并查询其电压和配置时钟
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_power_on(void)
{
    uint8_t i = 0;
    uint32_t tempreg = 0;
    SD_Error errorstatus = SD_OK;
    uint32_t response = 0, count = 0, validvoltage = 0;
    uint32_t SDType = SD_STD_CAPACITY;
    /* 配置CLKCR寄存器 */
    tempreg |= 0 << 9;      /* PWRSAV=0,非省电模式 */
    tempreg |= 0 << 11;     /* WIDBUS[1:0]=0,1位数据宽度 */
    tempreg |= 0 << 13;     /* NEGEDGE=0,SDMMCCK下降沿更改命令和数据 */
    tempreg |= 0 << 14;     /* HWFC_EN=0,关闭硬件流控制 */
    SDIO->CLKCR = tempreg;

    sdmmc_clock_set(SDIO_INIT_CLK_DIV); /* 设置时钟频率(初始化的时候,不能超过400Khz) */
    SDIO->POWER = 0X03;     /* 上电状态,开启卡时钟 */
    SDIO->CLKCR |= 1 << 8;  /* SDIOCK使能 */

    for (i = 0; i < 74; i++)
    {
        sdmmc_send_cmd(SD_CMD_GO_IDLE_STATE, 0, 0); /* 发送CMD0进入IDLE STAGE模式命令. */
        errorstatus = sdmmc_cmd_error();

        if (errorstatus == SD_OK)break;
    }

    if (errorstatus)return errorstatus; /* 返回错误状态 */

    /* 发送CMD8,短响应,检查SD卡接口特性.
     * arg[11:8]:01,支持电压范围,2.7~3.6V
     * arg[7:0]:默认0XAA
     * 返回响应7
     */
    sdmmc_send_cmd(SD_SDMMC_SEND_IF_COND, 1, SD_CHECK_PATTERN);

    errorstatus = sdmmc_cmd_resp7_error();      /* 等待R7响应 */

    if (errorstatus == SD_OK)                   /* R7响应正常 */
    {
        CardType = STD_CAPACITY_SD_CARD_V2_0;   /* SD 2.0卡 */
        SDType = SD_HIGH_CAPACITY;              /* 高容量卡 */
    }

    sdmmc_send_cmd(SD_CMD_APP_CMD, 1, 0);       /* 发送CMD55,短响应 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_CMD);/* 等待R1响应 */

    if (errorstatus == SD_OK)   /* SD2.0/SD 1.1,否则为MMC卡 */
    {
        /* SD卡,发送ACMD41 SD_APP_OP_COND,参数为:0x80100000 */
        while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
        {
            sdmmc_send_cmd(SD_CMD_APP_CMD, 1, 0);   /* 发送CMD55,短响应 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_CMD);/* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;    /* 响应错误 */

            sdmmc_send_cmd(SD_CMD_SD_APP_OP_COND, 1, SD_VOLTAGE_WINDOW_SD | SDType);    /* 发送ACMD41,短响应 */
            errorstatus = sdmmc_cmd_resp3_error();  /* 等待R3响应 */

            if (errorstatus != SD_OK)return errorstatus;    /* 响应错误 */

            response = SDIO->RESP1;   /* 得到响应 */
            validvoltage = (((response >> 31) == 1) ? 1 : 0);   /* 判断SD卡上电是否完成 */
            count++;
        }

        if (count >= SD_MAX_VOLT_TRIAL)
        {
            errorstatus = SD_INVALID_VOLTRANGE;
            return errorstatus;
        }

        if (response &= SD_HIGH_CAPACITY)
        {
            CardType = HIGH_CAPACITY_SD_CARD;
        }
    }
    else    /* MMC卡 */
    {
        /* MMC卡,发送CMD1 SDMMC_SEND_OP_COND,参数为:0x80FF8000 */
        while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
        {
            sdmmc_send_cmd(SD_CMD_SEND_OP_COND, 1, SD_VOLTAGE_WINDOW_MMC);  /* 发送CMD1,短响应 */
            errorstatus = sdmmc_cmd_resp3_error();  /* 等待R3响应 */

            if (errorstatus != SD_OK)return errorstatus;    /* 响应错误 */

            response = SDIO->RESP1;;  /* 得到响应 */
            validvoltage = (((response >> 31) == 1) ? 1 : 0);
            count++;
        }

        if (count >= SD_MAX_VOLT_TRIAL)
        {
            errorstatus = SD_INVALID_VOLTRANGE;
            return errorstatus;
        }

        CardType = MULTIMEDIA_CARD;
    }

    return (errorstatus);
}

/**
 * @brief       初始化所有的卡,并让卡进入就绪状态
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_initialize_cards(void)
{
    SD_Error errorstatus = SD_OK;
    uint16_t rca = 0x01;

    if ((SDIO->POWER & 0X03) == 0)
    {
        return SD_REQUEST_NOT_APPLICABLE;           /* 检查电源状态,确保为上电状态 */
    }

    if (SECURE_DIGITAL_IO_CARD != CardType)         /* 非SECURE_DIGITAL_IO_CARD */
    {
        sdmmc_send_cmd(SD_CMD_ALL_SEND_CID, 3, 0);  /* 发送CMD2,取得CID,长响应 */
        errorstatus = sdmmc_cmd_resp2_error();      /* 等待R2响应 */

        if (errorstatus != SD_OK)return errorstatus;/* 响应错误 */

        CID_Tab[0] = SDIO->RESP1;
        CID_Tab[1] = SDIO->RESP2;
        CID_Tab[2] = SDIO->RESP3;
        CID_Tab[3] = SDIO->RESP4;
    }

    /* 判断卡类型 */
    if ((STD_CAPACITY_SD_CARD_V1_1 == CardType) || (STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SECURE_DIGITAL_IO_COMBO_CARD == CardType) || (HIGH_CAPACITY_SD_CARD == CardType))
    {
        sdmmc_send_cmd(SD_CMD_SET_REL_ADDR, 1, 0);  /* 发送CMD3,短响应 */
        errorstatus = sdmmc_cmd_resp6_error(SD_CMD_SET_REL_ADDR, &rca); /* 等待R6响应 */

        if (errorstatus != SD_OK)return errorstatus;/* 响应错误 */
    }

    if (MULTIMEDIA_CARD == CardType)
    {
        sdmmc_send_cmd(SD_CMD_SET_REL_ADDR, 1, (uint32_t)(rca << 16)); /* 发送CMD3,短响应 */
        errorstatus = sdmmc_cmd_resp2_error();      /* 等待R2响应 */

        if (errorstatus != SD_OK)return errorstatus;/* 响应错误 */
    }

    if (SECURE_DIGITAL_IO_CARD != CardType)         /* 非SECURE_DIGITAL_IO_CARD */
    {
        RCA = rca;
        sdmmc_send_cmd(SD_CMD_SEND_CSD, 3, (uint32_t)(rca << 16));  /* 发送CMD9+卡RCA,取得CSD,长响应 */
        errorstatus = sdmmc_cmd_resp2_error();      /* 等待R2响应 */

        if (errorstatus != SD_OK)return errorstatus;/* 响应错误 */

        CSD_Tab[0] = SDIO->RESP1;
        CSD_Tab[1] = SDIO->RESP2;
        CSD_Tab[2] = SDIO->RESP3;
        CSD_Tab[3] = SDIO->RESP4;
    }

    return SD_OK;   /* 卡初始化成功 */
}

/**
 * @brief       得到卡信息
 * @param       cardinfo : 卡信息存储结构体指针
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_get_card_info(SD_CardInfo *cardinfo)
{
    SD_Error errorstatus = SD_OK;
    uint8_t tmp = 0;
    cardinfo->CardType = (uint8_t)CardType;             /* 卡类型 */
    cardinfo->RCA = (uint16_t)RCA;                      /* 卡RCA值 */
    tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);
    cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;     /* CSD结构 */
    cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;/* 2.0协议还没定义这部分(为保留),应该是后续协议定义的 */
    cardinfo->SD_csd.Reserved1 = tmp & 0x03;            /* 2个保留位 */
    tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);   /* 第1个字节 */
    cardinfo->SD_csd.TAAC = tmp;                        /* 数据读时间1 */
    tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);    /* 第2个字节 */
    cardinfo->SD_csd.NSAC = tmp;                        /* 数据读时间2 */
    tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);           /* 第3个字节 */
    cardinfo->SD_csd.MaxBusClkFrec = tmp;               /* 传输速度 */
    tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);   /* 第4个字节 */
    cardinfo->SD_csd.CardComdClasses = tmp << 4;        /* 卡指令类高四位 */
    tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);   /* 第5个字节 */
    cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;  /* 卡指令类低四位 */
    cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;           /* 最大读取数据长度 */
    tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);    /* 第6个字节 */
    cardinfo->SD_csd.PartBlockRead = (tmp & 0x80) >> 7; /* 允许分块读 */
    cardinfo->SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;   /* 写块错位 */
    cardinfo->SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;   /* 读块错位 */
    cardinfo->SD_csd.DSRImpl = (tmp & 0x10) >> 4;
    cardinfo->SD_csd.Reserved2 = 0;                     /* 保留 */

    /* 标准1.1/2.0卡/MMC卡 */
    if ((CardType == STD_CAPACITY_SD_CARD_V1_1) || (CardType == STD_CAPACITY_SD_CARD_V2_0) || (MULTIMEDIA_CARD == CardType))
    {
        cardinfo->SD_csd.DeviceSize = (tmp & 0x03) << 10;   /* C_SIZE(12位) */
        tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);           /* 第7个字节 */
        cardinfo->SD_csd.DeviceSize |= (tmp) << 2;
        tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);   /* 第8个字节 */
        cardinfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;
        cardinfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;
        cardinfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);
        tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);   /* 第9个字节 */
        cardinfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;
        cardinfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;
        cardinfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1; /* C_SIZE_MULT */
        tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);    /* 第10个字节 */
        cardinfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;
        cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1);     /* 计算卡容量 */
        cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
        cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);   /* 块大小 */
        cardinfo->CardCapacity *= cardinfo->CardBlockSize;
    }
    else if (CardType == HIGH_CAPACITY_SD_CARD) /* 高容量卡 */
    {
        tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);           /* 第7个字节 */
        cardinfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16;   /* C_SIZE */
        tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);   /* 第8个字节 */
        cardinfo->SD_csd.DeviceSize |= (tmp << 8);
        tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);   /* 第9个字节 */
        cardinfo->SD_csd.DeviceSize |= (tmp);
        tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);    /* 第10个字节 */
        cardinfo->CardCapacity = (long long)(cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024; /* 计算卡容量 */
        cardinfo->CardBlockSize = 512;                      /* 块大小固定为512字节 */
    }

    cardinfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6;
    cardinfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1;
    tmp = (uint8_t)(CSD_Tab[2] & 0x000000FF);               /* 第11个字节 */
    cardinfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;
    cardinfo->SD_csd.WrProtectGrSize = (tmp & 0x7F);
    tmp = (uint8_t)((CSD_Tab[3] & 0xFF000000) >> 24);       /* 第12个字节 */
    cardinfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7;
    cardinfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5;
    cardinfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2;
    cardinfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2;
    tmp = (uint8_t)((CSD_Tab[3] & 0x00FF0000) >> 16);       /* 第13个字节 */
    cardinfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6;
    cardinfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5;
    cardinfo->SD_csd.Reserved3 = 0;
    cardinfo->SD_csd.ContentProtectAppli = (tmp & 0x01);
    tmp = (uint8_t)((CSD_Tab[3] & 0x0000FF00) >> 8);        /* 第14个字节 */
    cardinfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7;
    cardinfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6;
    cardinfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5;
    cardinfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4;
    cardinfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2;
    cardinfo->SD_csd.ECC = (tmp & 0x03);
    tmp = (uint8_t)(CSD_Tab[3] & 0x000000FF);               /* 第15个字节 */
    cardinfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1;
    cardinfo->SD_csd.Reserved4 = 1;
    tmp = (uint8_t)((CID_Tab[0] & 0xFF000000) >> 24);       /* 第0个字节 */
    cardinfo->SD_cid.ManufacturerID = tmp;
    tmp = (uint8_t)((CID_Tab[0] & 0x00FF0000) >> 16);       /* 第1个字节 */
    cardinfo->SD_cid.OEM_AppliID = tmp << 8;
    tmp = (uint8_t)((CID_Tab[0] & 0x000000FF00) >> 8);      /* 第2个字节 */
    cardinfo->SD_cid.OEM_AppliID |= tmp;
    tmp = (uint8_t)(CID_Tab[0] & 0x000000FF);               /* 第3个字节 */
    cardinfo->SD_cid.ProdName1 = tmp << 24;
    tmp = (uint8_t)((CID_Tab[1] & 0xFF000000) >> 24);       /* 第4个字节 */
    cardinfo->SD_cid.ProdName1 |= tmp << 16;
    tmp = (uint8_t)((CID_Tab[1] & 0x00FF0000) >> 16);       /* 第5个字节 */
    cardinfo->SD_cid.ProdName1 |= tmp << 8;
    tmp = (uint8_t)((CID_Tab[1] & 0x0000FF00) >> 8);        /* 第6个字节 */
    cardinfo->SD_cid.ProdName1 |= tmp;
    tmp = (uint8_t)(CID_Tab[1] & 0x000000FF);               /* 第7个字节 */
    cardinfo->SD_cid.ProdName2 = tmp;
    tmp = (uint8_t)((CID_Tab[2] & 0xFF000000) >> 24);       /* 第8个字节 */
    cardinfo->SD_cid.ProdRev = tmp;
    tmp = (uint8_t)((CID_Tab[2] & 0x00FF0000) >> 16);       /* 第9个字节 */
    cardinfo->SD_cid.ProdSN = tmp << 24;
    tmp = (uint8_t)((CID_Tab[2] & 0x0000FF00) >> 8);        /* 第10个字节 */
    cardinfo->SD_cid.ProdSN |= tmp << 16;
    tmp = (uint8_t)(CID_Tab[2] & 0x000000FF);               /* 第11个字节 */
    cardinfo->SD_cid.ProdSN |= tmp << 8;
    tmp = (uint8_t)((CID_Tab[3] & 0xFF000000) >> 24);       /* 第12个字节 */
    cardinfo->SD_cid.ProdSN |= tmp;
    tmp = (uint8_t)((CID_Tab[3] & 0x00FF0000) >> 16);       /* 第13个字节 */
    cardinfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;
    cardinfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8;
    tmp = (uint8_t)((CID_Tab[3] & 0x0000FF00) >> 8);        /* 第14个字节 */
    cardinfo->SD_cid.ManufactDate |= tmp;
    tmp = (uint8_t)(CID_Tab[3] & 0x000000FF);               /* 第15个字节 */
    cardinfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1;
    cardinfo->SD_cid.Reserved2 = 1;
    return errorstatus;
}

/**
 * @brief       设置SDMMC总线宽度(MMC卡不支持4bit模式)
 * @param       wmode  : 位宽模式
 *   @arg       0, 1位数据宽度;
 *   @arg       1, 4位数据宽度;
 *   @arg       2, 8位数据宽度
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_wide_bus_operation(uint32_t wmode)
{
    SD_Error errorstatus = SD_OK;
    uint16_t clkcr = 0;

    if (MULTIMEDIA_CARD == CardType)
    {
        return SD_UNSUPPORTED_FEATURE;      /* MMC卡不支持 */
    }
    else if ((STD_CAPACITY_SD_CARD_V1_1 == CardType) || (STD_CAPACITY_SD_CARD_V2_0 == CardType) || (HIGH_CAPACITY_SD_CARD == CardType))
    {
        if (wmode >= 2)
        {
            return SD_UNSUPPORTED_FEATURE;  /* 不支持8位模式 */
        }
        else
        {
            errorstatus = sdmmc_wide_bus_enable(wmode);

            if (SD_OK == errorstatus)
            {
                clkcr = SDIO->CLKCR;    /* 读取CLKCR的值 */
                clkcr &= ~(3 << 11);    /* 清除之前的位宽设置 */
                clkcr |= (uint32_t)wmode << 11; /* 1位/4位总线宽度 */
                clkcr |= 0 << 14;       /* 不开启硬件流控制 */
                SDIO->CLKCR = clkcr;    /* 重新设置CLKCR值 */
            }
        }
    }

    return errorstatus;
}

/**
 * @brief       卡选中
 *   @note      发送CMD7,选择相对地址(rca)为addr的卡,取消其他卡.如果为0,则都不选择.
 * @param       addr : 卡的RCA地址
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_select_deselect(uint32_t addr)
{
    sdmmc_send_cmd(SD_CMD_SEL_DESEL_CARD, 1, addr); /* 发送CMD7,选择卡,短响应 */
    return sdmmc_cmd_resp1_error(SD_CMD_SEL_DESEL_CARD);
}

/**
 * @brief       SDMMC 读取单个/多个块
 * @param       pbuf    : 读数据缓存区
 * @param       addr    : 读地址
 * @param       blksize : 块大小
 * @param       nblks   : 要读的块数, 1,表示读单个块
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_read_blocks(uint8_t *pbuf, long long addr, uint16_t blksize, uint32_t nblks)
{
    SD_Error errorstatus = SD_OK;
    uint32_t count = 0;
    uint32_t timeout = SDMMC_DATATIMEOUT;
    volatile uint32_t data;     /* 临时存储用 */ 
    uint8_t *tempbuff = pbuf;   /* 指向pbuf */
    
    SDIO->DCTRL = 0x0;                      /* 数据控制寄存器清零(关DMA) */

    if (CardType == HIGH_CAPACITY_SD_CARD)  /* 大容量卡 */
    {
        blksize = 512;
        addr >>= 9;
    }

    sdmmc_send_cmd(SD_CMD_SET_BLOCKLEN, 1, blksize);            /* 发送CMD16+设置数据长度为blksize,短响应 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SET_BLOCKLEN);   /* 等待R1响应 */

    if (errorstatus != SD_OK)return errorstatus;                /* 响应错误 */

    sdmmc_send_data_cfg(SD_DATATIMEOUT, nblks * blksize, 9, 1); /* nblks*blksize,块大小恒为512,卡到控制器 */

    if (nblks > 1)  /* 多块读 */
    {
        sdmmc_send_cmd(SD_CMD_READ_MULT_BLOCK, 1, addr);        /* 发送CMD18+从addr地址出读取数据,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_READ_MULT_BLOCK);    /* 等待R1响应 */

        if (errorstatus != SD_OK)
        {
            printf("SD_CMD_READ_MULT_BLOCK Error\r\n");
            return errorstatus; /* 响应错误 */
        }
    }
    else    /* 单块读 */
    {
        sdmmc_send_cmd(SD_CMD_READ_SINGLE_BLOCK, 1, addr);      /* 发送CMD17+从addr地址出读取数据,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_READ_SINGLE_BLOCK);  /* 等待R1响应 */

        if (errorstatus != SD_OK)return errorstatus;            /* 响应错误 */
    }

    sys_intx_disable();/* 关闭总中断(POLLING模式,严禁中断打断SDMMC读写操作!!!) */

    while (!(SDIO->STA & ((1 << 5) | (1 << 1) | (1 << 3) | (1 << 8))))    /* 无上溢/CRC/超时/完成(标志) */
    {
        if (SDIO->STA & (1 << 15))              /* 接收区半满,表示至少存了8个字 */
        {
            for (count = 0; count < 8; count++) /* 循环读取数据 */
            {
                data = SDIO->FIFO;              /* 读取FIFO 32bit */
                *tempbuff = (uint8_t)(data & 0xFFU);
                tempbuff++;
                *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
                tempbuff++;
                *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
                tempbuff++;
                *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
                tempbuff++;
            }

            timeout = SDMMC_DATATIMEOUT;    /* 读数据溢出时间 */
        }
        else    /* 处理超时 */
        {
            if (timeout == 0)
            {
                //printf("r fifo time out\r\n");
                SDIO->ICR = 0X1FE00FFF;     /* 清除所有标记 */
                sys_intx_enable();          /* 开启总中断 */
                return SD_DATA_TIMEOUT;
            }

            timeout--;
        }
    }

    sys_intx_enable();              /* 开启总中断 */

    if (SDIO->STA & (1 << 3))       /* 数据超时错误 */
    {
        SDIO->ICR |= 1 << 3;        /* 清错误标志 */
        return SD_DATA_TIMEOUT;
    }
    else if (SDIO->STA & (1 << 1))  /* 数据块CRC错误 */
    {
        SDIO->ICR |= 1 << 1;        /* 清错误标志 */

        if (nblks > 1)              /* 针对可能出现的CRC错误,如果是多块读取,必须发送结束传输命令! */
        {
            sdmmc_send_cmd(SD_CMD_STOP_TRANSMISSION, 1, 0); /* 发送CMD12+结束传输 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_STOP_TRANSMISSION);  /* 等待R1响应 */
        }

        return SD_DATA_CRC_FAIL;
    }
    else if (SDIO->STA & (1 << 5))  /* 接收fifo上溢错误 */
    {
        SDIO->ICR |= 1 << 5;        /* 清错误标志 */
        return SD_RX_OVERRUN;
    }

    if ((SDIO->STA & (1 << 8)) && (nblks > 1))    /* 多块接收结束,发送结束指令 */
    {
        if ((STD_CAPACITY_SD_CARD_V1_1 == CardType) || (STD_CAPACITY_SD_CARD_V2_0 == CardType) || (HIGH_CAPACITY_SD_CARD == CardType))
        {
            sdmmc_send_cmd(SD_CMD_STOP_TRANSMISSION, 1, 0); /* 发送CMD12+结束传输 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_STOP_TRANSMISSION);  /* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;
        }
    }

    SDIO->ICR = 0X1FE00FFF;       /* 清除所有标记 */
    return errorstatus;
}

/**
 * @brief       SDMMC 写单个/多个块
 * @param       pbuf    : 写数据缓存区
 * @param       addr    : 写地址
 * @param       blksize : 块大小
 * @param       nblks   : 要写的块数, 1,表示写单个块
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_write_blocks(uint8_t *pbuf, long long addr, uint16_t blksize, uint32_t nblks)
{
    SD_Error errorstatus = SD_OK;
    uint8_t  cardstate = 0;
    uint32_t timeout = 0;
    uint32_t cardstatus = 0, count = 0;
    volatile uint32_t data;     /* 临时存储用 */ 
    uint8_t *tempbuff = pbuf;   /* 指向pbuf */

    if (pbuf == NULL)return SD_INVALID_PARAMETER;   /* 参数错误 */

    SDIO->DCTRL = 0x0;                              /* 数据控制寄存器清零(关DMA) */

    if (CardType == HIGH_CAPACITY_SD_CARD)          /* 大容量卡 */
    {
        blksize = 512;
        addr >>= 9;
    }

    sdmmc_send_cmd(SD_CMD_SET_BLOCKLEN, 1, blksize);/* 发送CMD16+设置数据长度为blksize,短响应 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SET_BLOCKLEN);   /* 等待R1响应 */

    if (errorstatus != SD_OK)return errorstatus;    /* 响应错误 */

    if (nblks > 1)  /* 多块写 */
    {
        if (nblks * blksize > SD_MAX_DATA_LENGTH)return SD_INVALID_PARAMETER;

        if ((STD_CAPACITY_SD_CARD_V1_1 == CardType) || (STD_CAPACITY_SD_CARD_V2_0 == CardType) || (HIGH_CAPACITY_SD_CARD == CardType))
        {
            /* 提高性能*/
            sdmmc_send_cmd(SD_CMD_APP_CMD, 1, (uint32_t)RCA << 16); /* 发送ACMD55,短响应 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_CMD);    /* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;

            sdmmc_send_cmd(SD_CMD_SET_BLOCK_COUNT, 1, nblks);       /* 发送CMD23,设置块数量,短响应 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SET_BLOCK_COUNT);    /* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;
        }

        sdmmc_send_cmd(SD_CMD_WRITE_MULT_BLOCK, 1, addr);   /* 发送CMD25,多块写指令,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_WRITE_MULT_BLOCK);   /* 等待R1响应 */
    }
    else    /* 单块写 */
    {
        sdmmc_send_cmd(SD_CMD_SEND_STATUS, 1, (uint32_t)RCA << 16); /* 发送CMD13,查询卡的状态,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SEND_STATUS);    /* 等待R1响应 */

        if (errorstatus != SD_OK)return errorstatus;

        cardstatus = SDIO->RESP1;
        timeout = SD_DATATIMEOUT;

        while (((cardstatus & 0x00000100) == 0) && (timeout > 0))   /* 检查READY_FOR_DATA位是否置位 */
        {
            timeout--;
            sdmmc_send_cmd(SD_CMD_SEND_STATUS, 1, (uint32_t)RCA << 16); /* 发送CMD13,查询卡的状态,短响应 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SEND_STATUS);    /* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;

            cardstatus = SDIO->RESP1;
        }

        if (timeout == 0)return SD_ERROR;

        sdmmc_send_cmd(SD_CMD_WRITE_SINGLE_BLOCK, 1, addr);             /* 发送CMD24,写单块指令,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_WRITE_SINGLE_BLOCK); /* 等待R1响应 */
    }

    if (errorstatus != SD_OK)return errorstatus;

    sdmmc_send_data_cfg(SD_DATATIMEOUT, nblks * blksize, 9, 0); /* blksize,块大小恒为512字节,控制器到卡 */
    timeout = SDMMC_DATATIMEOUT;
    sys_intx_disable(); /* 关闭总中断(POLLING模式,严禁中断打断SDMMC读写操作!!!) */

    while (!(SDIO->STA & ((1 << 4) | (1 << 1) | (1 << 8) | (1 << 3))))    /* 下溢/CRC/数据结束/超时 */
    {
        if (SDIO->STA & (1 << 14))              /* 发送区半空,表示至少存了8字(32字节) */
        {
            for (count = 0; count < 8; count++) /* 循环写入数据 */
            {
                data = (uint32_t)(*tempbuff);
                tempbuff++;
                data |= ((uint32_t)(*tempbuff) << 8U);
                tempbuff++;
                data |= ((uint32_t)(*tempbuff) << 16U);
                tempbuff++;
                data |= ((uint32_t)(*tempbuff) << 24U);
                tempbuff++;

                SDIO->FIFO = data;
            }

            timeout = SDMMC_DATATIMEOUT;    /* 写数据溢出时间 */
        }
        else
        {
            if (timeout == 0)
            {
                //printf("w fifo time out\r\n");
                SDIO->ICR = 0X1FE00FFF; /* 清除所有标记 */
                sys_intx_enable();      /* 开启总中断 */
                return SD_DATA_TIMEOUT;
            }

            timeout--;
        }
    }

    sys_intx_enable();              /* 开启总中断 */

    if (SDIO->STA & (1 << 3))       /* 数据超时错误 */
    {
        SDIO->ICR |= 1 << 3;        /* 清错误标志 */
        return SD_DATA_TIMEOUT;
    }
    else if (SDIO->STA & (1 << 1))  /* 数据块CRC错误 */
    {
        SDIO->ICR |= 1 << 1;        /* 清错误标志 */

        if (nblks > 1)              /* 针对可能出现的CRC错误,如果是多块读取,必须发送结束传输命令! */
        {
            sdmmc_send_cmd(SD_CMD_STOP_TRANSMISSION, 1, 0); /* 发送CMD12+结束传输 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_STOP_TRANSMISSION);  /* 等待R1响应 */
        }

        return SD_DATA_CRC_FAIL;
    }
    else if (SDIO->STA & (1 << 4))    /* 接收fifo下溢错误 */
    {
        SDIO->ICR |= 1 << 4;          /* 清错误标志 */
        return SD_TX_UNDERRUN;
    }

    if ((SDIO->STA & (1 << 8)) && (nblks > 1))    /* 多块发送结束,发送结束指令 */
    {
        if ((STD_CAPACITY_SD_CARD_V1_1 == CardType) || (STD_CAPACITY_SD_CARD_V2_0 == CardType) || (HIGH_CAPACITY_SD_CARD == CardType))
        {
            sdmmc_send_cmd(SD_CMD_STOP_TRANSMISSION, 1, 0); /* 发送CMD12+结束传输 */
            errorstatus = sdmmc_cmd_resp1_error(SD_CMD_STOP_TRANSMISSION);  /* 等待R1响应 */

            if (errorstatus != SD_OK)return errorstatus;
        }
    }

    SDIO->ICR = 0X1FE00FFF;           /* 清除所有标记 */
    errorstatus = sdmmc_is_card_programming(&cardstate);

    while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)))
    {
        errorstatus = sdmmc_is_card_programming(&cardstate);
    }

    return errorstatus;
}

/**
 * @brief       检查CMD0的执行状态
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_error(void)
{
    SD_Error errorstatus = SD_OK;
    uint32_t timeout = SDMMC_CMD0TIMEOUT;

    while (timeout--)
    {
        if (SDIO->STA & (1 << 7))
        {
            break;  /* 命令已发送(无需响应) */
        }
    }

    if (timeout == 0)return SD_CMD_RSP_TIMEOUT;

    SDIO->ICR = 0X1FE00FFF;   /* 清除标记 */
    return errorstatus;
}

/**
 * @brief       检查R1响应的错误状态
 * @param       cmd : 当前命令
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_resp1_error(uint8_t cmd)
{
    uint32_t status;
    uint32_t timeout = SDMMC_CMD1TIMEOUT;

    while (timeout--)
    {
        status = SDIO->STA;

        if (status & ((1 << 0) | (1 << 2) | (1 << 6)))
        {
            break;      /* CRC错误/命令响应超时/已经收到响应(CRC校验成功) */
        }
    }

    if ((timeout == 0) || (status & (1 << 2)))  /* 响应超时 */
    {
        SDIO->ICR = 1 << 2;         /* 清除命令响应超时标志 */
        SDIO->ICR = 0X1FE00FFF;     /* 清除标记 */
        return SD_CMD_RSP_TIMEOUT;
    }

    if (status & (1 << 0))          /* CRC错误 */
    {
        SDIO->ICR = 1 << 0;         /* 清除标志 */
        return SD_CMD_CRC_FAIL;
    }

    if (SDIO->RESPCMD != cmd)
    {
        SDIO->ICR = 0X1FE00FFF;     /* 清除标记 */
        return SD_ILLEGAL_CMD;      /* 命令不匹配 */
    }

    SDIO->ICR = 0X1FE00FFF;         /* 清除标记 */
    return (SD_Error)(SDIO->RESP1 & SD_OCR_ERRORBITS);    /* 返回卡响应 */
}

/**
 * @brief       检查R2响应的错误状态
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_resp2_error(void)
{
    SD_Error errorstatus = SD_OK;
    uint32_t status;
    uint32_t timeout = SDMMC_CMD1TIMEOUT;

    while (timeout--)
    {
        status = SDIO->STA;

        if (status & ((1 << 0) | (1 << 2) | (1 << 6)))
        {
            break;      /* CRC错误/命令响应超时/已经收到响应(CRC校验成功) */
        }
    }

    if ((timeout == 0) || (status & (1 << 2)))  /* 响应超时 */
    {
        errorstatus = SD_CMD_RSP_TIMEOUT;
        SDIO->ICR |= 1 << 2;  /* 清除命令响应超时标志 */
        return errorstatus;
    }

    if (status & 1 << 0)        /* CRC错误 */
    {
        errorstatus = SD_CMD_CRC_FAIL;
        SDIO->ICR |= 1 << 0;    /* 清除响应标志 */
    }

    SDIO->ICR = 0X1FE00FFF;     /* 清除标记 */
    return errorstatus;
}

/**
 * @brief       检查R3响应的错误状态
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_resp3_error(void)
{
    uint32_t status;
    uint32_t timeout = SDMMC_CMD1TIMEOUT;

    while (timeout--)
    {
        status = SDIO->STA;

        if (status & ((1 << 0) | (1 << 2) | (1 << 6)))
        {
            break;  /* CRC错误/命令响应超时/已经收到响应(CRC校验成功) */
        }
    }

    if ((timeout == 0) || (status & (1 << 2)))  /* 响应超时 */
    {
        SDIO->ICR |= 1 << 2;    /* 清除命令响应超时标志 */
        return SD_CMD_RSP_TIMEOUT;
    }

    SDIO->ICR = 0X1FE00FFF;     /* 清除标记 */
    return SD_OK;
}

/**
 * @brief       检查R6响应的错误状态
 * @param       cmd : 当前命令
 * @param       prca: 卡返回的RCA地址
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_resp6_error(uint8_t cmd, uint16_t *prca)
{
    SD_Error errorstatus = SD_OK;
    uint32_t status;
    uint32_t rspr1;
    uint32_t timeout = SDMMC_CMD1TIMEOUT;

    while (timeout--)
    {
        status = SDIO->STA;

        if (status & ((1 << 0) | (1 << 2) | (1 << 6)))
        {
            break;      /* CRC错误/命令响应超时/已经收到响应(CRC校验成功) */
        }
    }

    if (status & (1 << 2))      /* 响应超时 */
    {
        SDIO->ICR |= 1 << 2;    /* 清除命令响应超时标志 */
        return SD_CMD_RSP_TIMEOUT;
    }

    if ((timeout == 0) || (status & (1 << 2)))  /* CRC错误 */
    {
        SDIO->ICR |= 1 << 0;    /* 清除响应标志 */
        return SD_CMD_CRC_FAIL;
    }

    if (SDIO->RESPCMD != cmd)   /* 判断是否响应cmd命令 */
    {
        return SD_ILLEGAL_CMD;
    }

    SDIO->ICR = 0X1FE00FFF;     /* 清除所有标记 */
    rspr1 = SDIO->RESP1;        /* 得到响应 */

    if (SD_ALLZERO == (rspr1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
    {
        *prca = (uint16_t)(rspr1 >> 16);    /* 右移16位得到,rca */
        return errorstatus;
    }

    if (rspr1 & SD_R6_GENERAL_UNKNOWN_ERROR)return SD_GENERAL_UNKNOWN_ERROR;

    if (rspr1 & SD_R6_ILLEGAL_CMD)return SD_ILLEGAL_CMD;

    if (rspr1 & SD_R6_COM_CRC_FAILED)return SD_COM_CRC_FAILED;

    return errorstatus;
}

/**
 * @brief       检查R7响应的错误状态
 * @param       无
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_cmd_resp7_error(void)
{
    SD_Error errorstatus = SD_OK;
    uint32_t status;
    uint32_t timeout = SDMMC_CMD0TIMEOUT;

    while (timeout--)
    {
        status = SDIO->STA;

        if (status & ((1 << 0) | (1 << 2) | (1 << 6)))
        {
            break;      /* CRC错误/命令响应超时/已经收到响应(CRC校验成功) */
        }
    }

    if ((timeout == 0) || (status & (1 << 2)))  /* 响应超时 */
    {
        errorstatus = SD_CMD_RSP_TIMEOUT;       /* 当前卡不是2.0兼容卡,或者不支持设定的电压范围 */
        SDIO->ICR |= 1 << 2;    /* 清除命令响应超时标志 */
        return errorstatus;
    }

    if (status & 1 << 6)        /* 成功接收到响应 */
    {
        errorstatus = SD_OK;
        SDIO->ICR |= 1 << 6;    /* 清除响应标志 */
    }

    return errorstatus;
}

/**
 * @brief       SDMMC 使能宽总线模式
 * @param       enx : 0, 不使能; 1, 使能;
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_wide_bus_enable(uint8_t enx)
{
    SD_Error errorstatus = SD_OK;
    uint32_t scr[2] = {0, 0};
    uint8_t arg = 0X00;

    if (enx)arg = 0X02;
    else arg = 0X00;

    if (SDIO->RESP1 & SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;    /* SD卡处于LOCKED状态 */

    errorstatus = sdmmc_find_scr(RCA, scr);        /* 得到SCR寄存器数据 */

    if (errorstatus != SD_OK)return errorstatus;

    if ((scr[1]&SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) /* 支持宽总线 */
    {
        sdmmc_send_cmd(SD_CMD_APP_CMD, 1, (uint32_t)RCA << 16); /* 发送CMD55+RCA,短响应 */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_CMD);

        if (errorstatus != SD_OK)return errorstatus;

        sdmmc_send_cmd(SD_CMD_APP_SD_SET_BUSWIDTH, 1, arg);     /* 发送ACMD6,短响应,参数:10,4位;00,1位. */
        errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_SD_SET_BUSWIDTH);
        return errorstatus;
    }
    else
    {
        return SD_REQUEST_NOT_APPLICABLE;   /* 不支持宽总线设置 */
    }
}

/**
 * @brief       SDMMC 检查卡是否正在执行写操作
 * @param       pstatus : 当前状态.
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_is_card_programming(uint8_t *pstatus)
{
    volatile uint32_t respR1 = 0, status = 0;
    sdmmc_send_cmd(SD_CMD_SEND_STATUS, 1, (uint32_t)RCA << 16); /* 发送CMD13 */
    status = SDIO->STA;

    while (!(status & ((1 << 0) | (1 << 6) | (1 << 2))))status = SDIO->STA; /* 等待操作完成 */

    if (status & (1 << 0))      /* CRC检测失败 */
    {
        SDIO->ICR |= 1 << 0;    /* 清除错误标记 */
        return SD_CMD_CRC_FAIL;
    }

    if (status & (1 << 2))      /* 命令超时 */
    {
        SDIO->ICR |= 1 << 2;    /* 清除错误标记 */
        return SD_CMD_RSP_TIMEOUT;
    }

    if (SDIO->RESPCMD != SD_CMD_SEND_STATUS)return SD_ILLEGAL_CMD;

    SDIO->ICR = 0X1FE00FFF;     /* 清除所有标记 */
    respR1 = SDIO->RESP1;
    *pstatus = (uint8_t)((respR1 >> 9) & 0x0000000F);
    return SD_OK;
}

/**
 * @brief       SDMMC 读取当前卡状态
 * @param       pstatus : 当前状态.
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_send_status(uint32_t *pstatus)
{
    SD_Error errorstatus = SD_OK;

    if (pstatus == NULL)
    {
        errorstatus = SD_INVALID_PARAMETER;
        return errorstatus;
    }

    sdmmc_send_cmd(SD_CMD_SEND_STATUS, 1, RCA << 16);	/* 发送CMD13,短响应 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SEND_STATUS);	/* 查询响应状态 */

    if (errorstatus != SD_OK)return errorstatus;

    *pstatus = SDIO->RESP1;     /* 读取响应值 */
    return errorstatus;
}

/**
 * @brief       返回SD卡的状态
 * @param       pstatus : 当前状态.
 * @retval      SD卡状态(详见SDCardState定义)
 */
SDCardState sdmmc_get_status(void)
{
    uint32_t resp1 = 0;

    if (sdmmc_send_status(&resp1) != SD_OK)
    {
        return SD_CARD_ERROR;
    }
    else
    {
        return (SDCardState)((resp1 >> 9) & 0x0F);
    }
}

/**
 * @brief       SDMMC 查找SD卡的SCR寄存器值
 * @param       rca  : 卡相对地址
 * @param       pscr : 数据缓存区(存储SCR内容)
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
static SD_Error sdmmc_find_scr(uint16_t rca, uint32_t *pscr)
{
    SD_Error errorstatus = SD_OK;
    uint32_t tempscr[2] = {0, 0};
    sdmmc_send_cmd(SD_CMD_SET_BLOCKLEN, 1, 8);      /* 发送CMD16,短响应,设置Block Size为8字节 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SET_BLOCKLEN);

    if (errorstatus != SD_OK)return errorstatus;

    sdmmc_send_cmd(SD_CMD_APP_CMD, 1, (uint32_t)rca << 16); /* 发送CMD55,短响应 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_APP_CMD);

    if (errorstatus != SD_OK)return errorstatus;

    sdmmc_send_data_cfg(SD_DATATIMEOUT, 8, 3, 1);   /* 8个字节长度,block为8字节,SD卡到SDMMC. */
    sdmmc_send_cmd(SD_CMD_SD_APP_SEND_SCR, 1, 0);   /* 发送ACMD51,短响应,参数为0 */
    errorstatus = sdmmc_cmd_resp1_error(SD_CMD_SD_APP_SEND_SCR);

    if (errorstatus != SD_OK)return errorstatus;

    while (!(SDIO->STA & (SDIO_STA_RXOVERR | SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_DBCKEND | SDIO_STA_DATAEND)))
    {
        if (!(SDIO->STA & (1 << 19))) /* 接收FIFO数据可用 */
        {
            tempscr[0] = SDIO->FIFO;  /* 读取FIFO内容 */
            tempscr[1] = SDIO->FIFO;  /* 读取FIFO内容 */
            break;
        }
    }

    if (SDIO->STA & (1 << 3))         /* 接收数据超时 */
    {
        SDIO->ICR |= 1 << 3;          /* 清除标记 */
        return SD_DATA_TIMEOUT;
    }
    else if (SDIO->STA & (1 << 1))    /* 已发送/接收的数据块CRC校验错误 */
    {
        SDIO->ICR |= 1 << 1;          /* 清除标记 */
        return SD_DATA_CRC_FAIL;
    }
    else if (SDIO->STA & (1 << 5))    /* 接收FIFO溢出 */
    {
        SDIO->ICR |= 1 << 5;          /* 清除标记 */
        return SD_RX_OVERRUN;
    }

    SDIO->ICR = 0X1FE00FFF;           /* 清除标记 */
    /* 把数据顺序按8位为单位倒过来. */
    *(pscr + 1) = ((tempscr[0] & SD_0TO7BITS) << 24) | ((tempscr[0] & SD_8TO15BITS) << 8) | ((tempscr[0] & SD_16TO23BITS) >> 8) | ((tempscr[0] & SD_24TO31BITS) >> 24);
    *(pscr) = ((tempscr[1] & SD_0TO7BITS) << 24) | ((tempscr[1] & SD_8TO15BITS) << 8) | ((tempscr[1] & SD_16TO23BITS) >> 8) | ((tempscr[1] & SD_24TO31BITS) >> 24);
    return errorstatus;
}

/**
 * @brief       读SD卡(fatfs/usb调用)
 * @param       pbuf  : 数据缓存区
 * @param       saddr : 扇区地址
 * @param       cnt   : 扇区个数
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
uint8_t sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = SD_OK;
    long long lsaddr = saddr;

    if (CardType != STD_CAPACITY_SD_CARD_V1_1)lsaddr <<= 9;

    sta = sdmmc_read_blocks(pbuf, lsaddr, 512, cnt);    /* 读取单个/多个sector */

    return sta;
}

/**
 * @brief       写SD卡(fatfs/usb调用)
 * @param       pbuf  : 数据缓存区
 * @param       saddr : 扇区地址
 * @param       cnt   : 扇区个数
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
uint8_t sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = SD_OK;
    long long lsaddr = saddr;

    if (CardType != STD_CAPACITY_SD_CARD_V1_1)lsaddr <<= 9;


    sta = sdmmc_write_blocks(pbuf, lsaddr, 512, cnt);   /* 写单个/多个sector */

    return sta;
}

2.3 主函数

主函数中主要是根据标志位来判断是否接收完成一次数据(以 0xaa66 结尾为一次完成接收),当接收到完整数据的时候,就写入 SD 卡中,并且通过串口发送相关信息

int main(void)
{
    uint8_t key;
    uint16_t t = 0;
    sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
    usart_init(84, 115200);                     /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */

    while (sd_init())    /* 检测不到SD卡 */
    {

    }
    /* 打印SD卡相关信息 */
    show_sdcard_info(); 
    
    uint8_t k=0;
    uint8_t i=0;
    state[i] = sd_write_disk(data,0,10);
    uint16_t len;
    len = 0;

    while (1)
    {
        key = key_scan(0);
        if (key == KEY0_PRES)       /* KEY0按下了 */
        {
            sd_test_read(0,1);  /* 从0扇区读取1*512字节的内容 */
        }
        
        if (g_usart_rx_sta & 0x8000)        /* 接收到了数据? */
        {
            len = g_usart_rx_sta & 0x3fff;  /* 得到此次接收到的数据长度 */
            for (t = 0; t < len; t++)
            {
                USART_UX->DR = g_usart_rx_buf[t];
                while ((USART_UX->SR & 0X40) == 0); /* 等待发送结束 */
            }
            state[0] = sd_write_disk(g_usart_rx_buf,0,1);
            if (state[0] == 0)
            {
                printf("\r\n%d\r\n",len);
                printf("Write over!\r\n");
            }
            printf("\r\n\r\n"); /* 插入换行 */
            g_usart_rx_sta = 0;
        }
    }
}

3. Python读取SD卡代码

使用读卡器将 SD 卡连接到电脑上,
如果弹出磁盘已损坏之类的千万不要管!!!
如果弹出磁盘已损坏之类的千万不要管!!!
如果弹出磁盘已损坏之类的千万不要管!!!
继续往下看!

import struct
disk = open(r"\\.\PhysicalDrive1","rb") # 打开磁盘0,PhysicalDrive不区分大小写
# 读取第一个扇区, 也就是磁盘主引导记录, 1扇区为512字节
data = disk.read(512)
data = struct.unpack(len(data)*'B',data)
print(data)

然后注意上方代码中的PhysicalDrive1这里的1对应电脑的硬盘序号,可以此电脑(右键)->管理->磁盘管理中看到,这里的序号就是 PhysicalDrive 后面要跟的数字,我的电脑显示是磁盘 1,所以写的是 1

STM32 接收串口数据并且存储 SD,Python 读取 SD 验证_第2张图片

STM32 接收串口数据并且存储 SD,Python 读取 SD 验证_第3张图片

4. 验证结果

运行上面的程序即可得到结果,下图是没有解包的结果

在这里插入图片描述

下面的代码是解包的过程,详细的可以查看这一篇博客:Python Struct 库之 pack 和 unpack 详解
取消注释下列代码后的结果,可以看到原本的字节流被解包为了一个个的数字,并且和我们用 Python 生成的数字是一样的,说明我们往 SD 卡写入数据成功

data = struct.unpack(len(data)*'B',data)

在这里插入图片描述

你可能感兴趣的:(stm32,python,单片机,stm32,python)