在我们使用 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
的二进制文件,我们可以使用十六进制的文本阅读器打开查看里面的内容
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
4. 验证结果
运行上面的程序即可得到结果,下图是没有解包的结果
下面的代码是解包的过程,详细的可以查看这一篇博客:Python Struct 库之 pack 和 unpack 详解
取消注释下列代码后的结果,可以看到原本的字节流被解包为了一个个的数字,并且和我们用 Python 生成的数字是一样的,说明我们往 SD 卡写入数据成功文章来源:https://www.toymoban.com/news/detail-468629.html
data = struct.unpack(len(data)*'B',data)
文章来源地址https://www.toymoban.com/news/detail-468629.html
到了这里,关于Python读取SD卡二进制数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!