565 lines
19 KiB
C
565 lines
19 KiB
C
#include "bsp_sd_spi.h"
|
||
#include <string.h>
|
||
|
||
#define SD_DUMMY_BYTE 0xFF
|
||
|
||
#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40 */
|
||
#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41 */
|
||
#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48 */
|
||
#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49 */
|
||
#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */
|
||
#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */
|
||
#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */
|
||
#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */
|
||
#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */
|
||
#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */
|
||
#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */
|
||
#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */
|
||
#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */
|
||
#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */
|
||
#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */
|
||
#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */
|
||
#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */
|
||
#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */
|
||
#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */
|
||
#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */
|
||
#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */
|
||
#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */
|
||
#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */
|
||
#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */
|
||
#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */
|
||
#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */
|
||
#define SD_CMD_READ_OCR 58 /* CMD55 = 0x7A */
|
||
|
||
#define SD_R1_NO_ERROR 0x00
|
||
#define SD_R1_RESP_IDLE_BIT 0x01
|
||
#define SD_R1_ILLEGAL_COMMAND 0x04
|
||
#define SD_DATA_RESP_OK 0x05
|
||
|
||
#define SD_SPI_PRESCALER_LOW SPI_BaudRatePrescaler_256
|
||
#define SD_SPI_PRESCALER_HIGH SPI_BaudRatePrescaler_4
|
||
|
||
#define SD_WAIT_CMD_RESP_TIMEOUT 10000U //等待指令响应的超时
|
||
#define SD_WAIT_READ_WRITE_TIMEOUT 100000U //等待读写操作的超时
|
||
|
||
static bsp_card_info_t card_info = { 0 };
|
||
|
||
static void sd_spi_init(void)
|
||
{
|
||
RCC_APB2PeriphClockCmd(BSP_SD_CS_GPIO_CLK | BSP_SD_SPI_MOSI_GPIO_CLK |
|
||
BSP_SD_SPI_MISO_GPIO_CLK | BSP_SD_SPI_SCK_GPIO_CLK, ENABLE);
|
||
BSP_SD_SPI_CLK_ENABLE();
|
||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||
|
||
GPIO_InitTypeDef GPIO_InitStructure;
|
||
GPIO_InitStructure.GPIO_Pin = BSP_SD_SPI_SCK_PIN;
|
||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||
GPIO_Init(BSP_SD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
|
||
|
||
GPIO_InitStructure.GPIO_Pin = BSP_SD_SPI_MOSI_PIN;
|
||
GPIO_Init(BSP_SD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
|
||
|
||
GPIO_InitStructure.GPIO_Pin = BSP_SD_SPI_MISO_PIN;
|
||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||
GPIO_Init(BSP_SD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
|
||
|
||
GPIO_InitStructure.GPIO_Pin = BSP_SD_CS_PIN;
|
||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||
GPIO_Init(BSP_SD_CS_GPIO_PORT, &GPIO_InitStructure);
|
||
|
||
SPI_InitTypeDef SPI_InitStructure;
|
||
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
||
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
|
||
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
|
||
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
|
||
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
|
||
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
|
||
SPI_InitStructure.SPI_BaudRatePrescaler = SD_SPI_PRESCALER_LOW;
|
||
|
||
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
|
||
SPI_InitStructure.SPI_CRCPolynomial = 7;
|
||
SPI_Init(BSP_SD_SPI, &SPI_InitStructure);
|
||
|
||
SPI_Cmd(BSP_SD_SPI, ENABLE);
|
||
}
|
||
|
||
static void sd_set_spi_prescaler(uint32_t prescaler)
|
||
{
|
||
BSP_SD_SPI->CTLR1 &= 0xFFC7;
|
||
BSP_SD_SPI->CTLR1 |= prescaler;
|
||
}
|
||
|
||
static void sd_select(void)
|
||
{
|
||
GPIO_ResetBits(BSP_SD_CS_GPIO_PORT, BSP_SD_CS_PIN);
|
||
}
|
||
|
||
static void sd_deselect(void)
|
||
{
|
||
GPIO_SetBits(BSP_SD_CS_GPIO_PORT, BSP_SD_CS_PIN);
|
||
}
|
||
|
||
static __always_inline uint8_t sd_write_read_byte(uint8_t tx_byte)
|
||
{
|
||
while((BSP_SD_SPI->STATR & SPI_I2S_FLAG_TXE) == RESET);
|
||
BSP_SD_SPI->DATAR = tx_byte;
|
||
while((BSP_SD_SPI->STATR & SPI_I2S_FLAG_RXNE) == RESET);
|
||
return BSP_SD_SPI->DATAR;
|
||
}
|
||
|
||
static void sd_write_bytes(const uint8_t *buffer, uint16_t length)
|
||
{
|
||
if (length < BSP_SD_BLOCK_SIZE) { //数据量较小时使用查询方式
|
||
for (uint32_t i = 0; i < length; i ++) {
|
||
sd_write_read_byte(buffer[i]);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
uint8_t spi_rx_dummy_byte;
|
||
|
||
/* 等待上次传输完成 */
|
||
while((BSP_SD_SPI->STATR & SPI_I2S_FLAG_TXE) == 0);
|
||
|
||
/* 首先配置DMA接收通道 */
|
||
DMA_InitTypeDef DMA_InitStructure;
|
||
DMA_InitStructure.DMA_BufferSize = length;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&BSP_SD_SPI->DATAR;
|
||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&spi_rx_dummy_byte;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
|
||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //SPI处于全双工模式时,需要DMA RX通道从而复位SPI_I2S_FLAG_RXNE标志位
|
||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
|
||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||
DMA_Init(BSP_SD_RX_DMA_CHANNEL, &DMA_InitStructure);
|
||
|
||
/* 然后配置DMA发送通道 */
|
||
DMA_InitStructure.DMA_BufferSize = length;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(BSP_SD_SPI->DATAR);
|
||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_Low; //发送DMA优先级应低于接收,防止FIFO溢出
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||
DMA_Init(BSP_SD_TX_DMA_CHANNEL, &DMA_InitStructure);
|
||
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Rx, ENABLE);
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Tx, ENABLE);
|
||
DMA_Cmd(BSP_SD_RX_DMA_CHANNEL, ENABLE);
|
||
DMA_Cmd(BSP_SD_TX_DMA_CHANNEL, ENABLE);
|
||
|
||
while (DMA_GetITStatus(BSP_SD_TX_DMA_IT_TC_FLAG) != SET); //使用RTOS时改为中断模式
|
||
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Rx, DISABLE);
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Tx, DISABLE);
|
||
DMA_DeInit(BSP_SD_RX_DMA_CHANNEL);
|
||
DMA_DeInit(BSP_SD_TX_DMA_CHANNEL);
|
||
}
|
||
|
||
static void sd_read_bytes(uint8_t *buffer, uint16_t length)
|
||
{
|
||
if (length < BSP_SD_BLOCK_SIZE) { //数据量较小时使用查询方式
|
||
for (uint32_t i = 0; i < length; i ++) {
|
||
buffer[i] = sd_write_read_byte(SD_DUMMY_BYTE);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
uint8_t spi_tx_dummy_byte = SD_DUMMY_BYTE;
|
||
|
||
/* 等待上次传输完成 */
|
||
while((BSP_SD_SPI->STATR & SPI_I2S_FLAG_TXE) == 0);
|
||
|
||
/* 配置DMA接收通道 */
|
||
DMA_InitTypeDef DMA_InitStructure;
|
||
DMA_InitStructure.DMA_BufferSize = length;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&BSP_SD_SPI->DATAR;
|
||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
|
||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
|
||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||
DMA_Init(BSP_SD_RX_DMA_CHANNEL, &DMA_InitStructure);
|
||
|
||
/* 配置DMA发送通道产生SPI时钟 */
|
||
DMA_InitStructure.DMA_BufferSize = length;
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(BSP_SD_SPI->DATAR);
|
||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&spi_tx_dummy_byte;
|
||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||
DMA_InitStructure.DMA_Priority = DMA_Priority_Low; //发送DMA优先级应低于接收,防止FIFO溢出
|
||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //重复发送dummy字节从而产生时钟
|
||
DMA_Init(BSP_SD_TX_DMA_CHANNEL, &DMA_InitStructure);
|
||
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Rx, ENABLE);
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Tx, ENABLE);
|
||
DMA_Cmd(BSP_SD_RX_DMA_CHANNEL, ENABLE);
|
||
DMA_Cmd(BSP_SD_TX_DMA_CHANNEL, ENABLE);
|
||
|
||
while (DMA_GetITStatus(BSP_SD_TX_DMA_IT_TC_FLAG) != SET); //使用RTOS时改为中断模式
|
||
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Rx, DISABLE);
|
||
SPI_I2S_DMACmd(BSP_SD_SPI, SPI_I2S_DMAReq_Tx, DISABLE);
|
||
DMA_DeInit(BSP_SD_RX_DMA_CHANNEL);
|
||
DMA_DeInit(BSP_SD_TX_DMA_CHANNEL);
|
||
}
|
||
|
||
static void sd_enable(void)
|
||
{
|
||
sd_write_read_byte(SD_DUMMY_BYTE); //发送额外的8个时钟
|
||
sd_select();
|
||
}
|
||
|
||
static void sd_disable(void)
|
||
{
|
||
sd_deselect();
|
||
sd_write_read_byte(SD_DUMMY_BYTE); //发送额外的8个时钟
|
||
}
|
||
|
||
static bsp_sd_error_t sd_wait_response(uint8_t response)
|
||
{
|
||
uint32_t timeout = SD_WAIT_READ_WRITE_TIMEOUT;
|
||
|
||
do {
|
||
if (sd_write_read_byte(SD_DUMMY_BYTE) == response) {
|
||
return bsp_sd_error_none;
|
||
}
|
||
} while (timeout --);
|
||
|
||
return bsp_sd_error_timeout;
|
||
}
|
||
|
||
static uint8_t sd_send_command(uint8_t command, uint32_t argument, uint8_t crc)
|
||
{
|
||
sd_enable(); //拉低片选
|
||
|
||
sd_write_bytes((uint8_t[]){ command | 0x40, argument >> 24, argument >> 16, argument >> 8, argument, crc }, 6); //发送指令+数据+CRC校验值
|
||
|
||
uint8_t r1_response = 0xFF;
|
||
uint32_t timeout = SD_WAIT_CMD_RESP_TIMEOUT;
|
||
do {
|
||
r1_response = sd_write_read_byte(SD_DUMMY_BYTE); //等待卡响应或超时
|
||
} while ((r1_response == 0xFF || r1_response == 0x7F) && timeout --); //一些较旧的卡的CMD12回应首字节为0x7F,此后才为0xFF
|
||
|
||
return r1_response;
|
||
}
|
||
|
||
static bsp_sd_error_t sd_wait_ready(void)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_timeout;
|
||
|
||
uint32_t timeout = SD_WAIT_READ_WRITE_TIMEOUT;
|
||
do {
|
||
uint8_t r1_response = sd_send_command(SD_CMD_SEND_STATUS, 0x00, 0x00); //发送CMD13请求卡片状态
|
||
if (r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
uint8_t status_register[4];
|
||
for (uint8_t i = 0; i < 4; i ++) { //继续读取R7格式回应的剩余4字节
|
||
status_register[i] = sd_write_read_byte(SD_DUMMY_BYTE);
|
||
}
|
||
|
||
if (status_register[2] & 0x01) { //READY_FOR_DATA=1
|
||
error = bsp_sd_error_none;
|
||
goto error;
|
||
}
|
||
} while (timeout --);
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
bsp_sd_error_t bsp_sd_init(void)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_none;
|
||
|
||
sd_spi_init();
|
||
|
||
for (uint8_t i = 0; i < 10; i ++) {
|
||
sd_write_read_byte(0xFF); //在MOSI上发送不少于74个脉冲
|
||
}
|
||
|
||
memset(&card_info, 0, sizeof(card_info)); //复位卡信息结构体
|
||
|
||
uint8_t r1_response;
|
||
uint32_t timeout = SD_WAIT_CMD_RESP_TIMEOUT;
|
||
do {
|
||
r1_response = sd_send_command(SD_CMD_GO_IDLE_STATE, 0, 0x95); //等待卡进入IDLE状态
|
||
} while ((r1_response != SD_R1_RESP_IDLE_BIT) && timeout --);
|
||
|
||
if (timeout == 0) {
|
||
error = bsp_sd_error_timeout;
|
||
goto error;
|
||
}
|
||
|
||
r1_response = sd_send_command(SD_CMD_SEND_IF_COND, 0x1AA, 0x87); //发送CMD8判断卡是否为SD V2.0
|
||
if (r1_response & SD_R1_ILLEGAL_COMMAND) { //CMD8无响应则卡为SD V1.0或MMC卡
|
||
sd_disable(); //结束CMD8
|
||
/* ACMD41有响应为SD V1.0否则为MMC卡 */
|
||
timeout = SD_WAIT_CMD_RESP_TIMEOUT;
|
||
do {
|
||
sd_send_command(SD_CMD_APP_CMD, 0x00, 0x00); //在发送ACMD之前都需要发送CMD55
|
||
r1_response = sd_send_command(SD_CMD_SD_APP_OP_COND, 0x00, 0x00); //发送ACMD41尝试初始化卡
|
||
} while (r1_response != SD_R1_NO_ERROR && timeout --); //等待R1就绪直到超时
|
||
|
||
if (timeout == 0) { //ACMD41无响应超时
|
||
timeout = SD_WAIT_CMD_RESP_TIMEOUT;
|
||
do {
|
||
r1_response = sd_send_command(SD_CMD_SEND_OP_COND, 0x00, 0x00); //发送CMD1判断是否为MMC卡
|
||
} while (r1_response != SD_R1_NO_ERROR && timeout --);
|
||
|
||
if (timeout == 0) { //CMD1无响应超时
|
||
error = bsp_sd_error_unknown_card_type; //卡类型未知
|
||
goto error;
|
||
}
|
||
|
||
card_info.card_type = bsp_sd_type_mmc; //CMD1有响应为MMC卡
|
||
} else {
|
||
card_info.card_type = bsp_sd_type_sdv1;
|
||
}
|
||
} else if (r1_response == SD_R1_RESP_IDLE_BIT) { //CMD8有响应则卡为SD V2.0
|
||
uint8_t r7_response[4];
|
||
for (uint8_t i = 0; i < 4; i ++) { //继续读取R7格式回应的剩余4字节
|
||
r7_response[i] = sd_write_read_byte(SD_DUMMY_BYTE);
|
||
}
|
||
|
||
if (r7_response[2] == 0x01 && r7_response[3] == 0xAA) { //判断工作电压范围是否为2.7-3.6V
|
||
timeout = SD_WAIT_CMD_RESP_TIMEOUT;
|
||
do {
|
||
sd_send_command(SD_CMD_APP_CMD, 0x00, 0x00); //在发送ACMD之前都需要发送CMD55
|
||
r1_response = sd_send_command(SD_CMD_SD_APP_OP_COND,0x40000000,0x01); //发送ACMD41尝试初始化卡
|
||
} while(r1_response != SD_R1_NO_ERROR && timeout --);
|
||
|
||
if(timeout == 0) {
|
||
error = bsp_sd_error_timeout;
|
||
goto error;
|
||
}
|
||
|
||
r1_response = sd_send_command(SD_CMD_READ_OCR, 0x00, 0x00); //发送CMD58判断卡是否为HC
|
||
if(r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_timeout;
|
||
goto error;
|
||
}
|
||
for (uint8_t i = 0; i < 4; i ++) { //继续读取R7格式回应的剩余4字节
|
||
r7_response[i] = sd_write_read_byte(SD_DUMMY_BYTE);
|
||
}
|
||
|
||
card_info.card_type = (r7_response[0] & 0x40) ? bsp_sd_type_sdv2hc : bsp_sd_type_sdv2;
|
||
} else {
|
||
error = bsp_sd_error_unknown_card_type;
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
sd_disable(); //开始获取SD卡Block数量
|
||
|
||
r1_response = sd_send_command(SD_CMD_SEND_CSD, 0x00, 0x00); //发送读取CSD命令
|
||
if (r1_response != 0) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
error = sd_wait_response(0xFE); //等待读数据就绪的Token
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
uint8_t csd[16];
|
||
sd_read_bytes(csd, sizeof(csd)); //读取16字节CSD寄存器数据
|
||
|
||
if ((csd[0] & 0xC0) == 0x40) { //SD V2.0
|
||
uint32_t csize = csd[9] + ((uint32_t)csd[8] << 8) + ((uint32_t)(csd[7] & 0x3F) << 16) + 1;
|
||
card_info.sector_count = csize << 10;
|
||
} else { // SD V1.0或MMC卡
|
||
uint32_t n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||
uint32_t csize = (csd[8] >> 6) + ((uint32_t)csd[7] << 2) + ((uint32_t)(csd[6] & 3) << 10) + 1;
|
||
card_info.sector_count = csize << (n - 9);
|
||
}
|
||
|
||
sd_set_spi_prescaler(SD_SPI_PRESCALER_HIGH);
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
bsp_sd_error_t bsp_sd_read_block(uint8_t* buffer, uint32_t sector_address)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_none;
|
||
|
||
if (card_info.card_type != bsp_sd_type_sdv2hc) {
|
||
sector_address <<= 9;
|
||
}
|
||
|
||
uint8_t r1_response = sd_send_command(SD_CMD_READ_SINGLE_BLOCK, sector_address, 0x00); //发送单Block读取命令
|
||
if (r1_response != 0) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
error = sd_wait_response(0xFE); //等待读数据就绪的Token
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
sd_read_bytes(buffer, BSP_SD_BLOCK_SIZE); //读取单个Block的数据
|
||
sd_write_bytes((uint8_t[]){ 0xFF, 0xFF }, 2); //跳过2字节CRC
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
bsp_sd_error_t bsp_sd_read_multi_blocks(uint8_t* buffer, uint32_t sector_address, uint16_t sector_count)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_none;
|
||
|
||
if (card_info.card_type != bsp_sd_type_sdv2hc) {
|
||
sector_address <<= 9;
|
||
}
|
||
|
||
if (sector_count <= 1) {
|
||
return bsp_sd_error_invalid_parameter;
|
||
} else {
|
||
uint8_t r1_response = sd_send_command(SD_CMD_READ_MULT_BLOCK, sector_address, 0x00);
|
||
if (r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
for (uint16_t i = 0; i < sector_count; i ++) { //循环读取多个Block
|
||
error = sd_wait_response(0xFE); //等待读数据就绪的Token
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
sd_read_bytes(buffer, BSP_SD_BLOCK_SIZE); //读取单个Block的数据
|
||
sd_write_bytes((uint8_t[]){ 0xFF, 0xFF }, 2); //跳过2字节CRC
|
||
|
||
buffer += BSP_SD_BLOCK_SIZE; //准备读取下一个Block
|
||
}
|
||
|
||
r1_response = sd_send_command(SD_CMD_STOP_TRANSMISSION, 0, 0x00); //结束单个Block的读取
|
||
if (r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
bsp_sd_error_t bsp_sd_write_block(const uint8_t *buffer, uint32_t sector_address)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_none;
|
||
|
||
if (card_info.card_type != bsp_sd_type_sdv2hc) {
|
||
sector_address <<= 9;
|
||
}
|
||
|
||
sd_wait_ready(); //一些较慢的卡在连续写操作前需要检查卡是否忙
|
||
|
||
uint8_t r1_response = sd_send_command(SD_CMD_WRITE_SINGLE_BLOCK, sector_address, 0x00);
|
||
if (r1_response != 0) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
sd_write_read_byte(0xFE); //发送单Block写的Token
|
||
|
||
sd_write_bytes(buffer, BSP_SD_BLOCK_SIZE); //写入单个Block的数据
|
||
sd_write_bytes((uint8_t[]){ 0xFF, 0xFF }, 2); //跳过2字节CRC
|
||
|
||
uint8_t data_response = sd_write_read_byte(0xFF) & 0x1F;
|
||
if (data_response != SD_DATA_RESP_OK) { //判断卡是否成功接收数据
|
||
error = bsp_sd_error_not_ready;
|
||
goto error;
|
||
}
|
||
|
||
error = sd_wait_response(0xFF); //等待写入操作完成
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
bsp_sd_error_t bsp_sd_write_multi_blocks(const uint8_t *buffer, uint32_t sector_address, uint16_t sector_count)
|
||
{
|
||
bsp_sd_error_t error = bsp_sd_error_none;
|
||
|
||
if (card_info.card_type != bsp_sd_type_sdv2hc) {
|
||
sector_address <<= 9;
|
||
}
|
||
|
||
sd_wait_ready(); //一些较慢的卡在连续写操作前需要检查卡是否忙
|
||
|
||
uint8_t r1_response;
|
||
if (card_info.card_type != bsp_sd_type_mmc) { //非MMC卡必须要发送CMD55与ACMD23
|
||
sd_send_command(SD_CMD_APP_CMD, 0x00, 0x00);
|
||
|
||
r1_response = sd_send_command(SD_CMD_SET_BLOCK_COUNT, sector_count, 0x00);
|
||
if (r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
r1_response = sd_send_command(SD_CMD_WRITE_MULT_BLOCK, sector_address, 0x00);
|
||
if (r1_response != SD_R1_NO_ERROR) {
|
||
error = bsp_sd_error_invalid_response;
|
||
goto error;
|
||
}
|
||
|
||
for (uint16_t i = 0; i < sector_count; i ++) { //循环写入多个Block
|
||
sd_write_read_byte(0xFC); //发送多Block写开始的Token
|
||
|
||
sd_write_bytes(buffer, BSP_SD_BLOCK_SIZE);
|
||
sd_write_bytes((uint8_t[]){ 0xFF, 0xFF }, 2); //跳过2字节CRC
|
||
|
||
uint8_t data_response = sd_write_read_byte(0xFF) & 0x1F;
|
||
if (data_response != SD_DATA_RESP_OK) { //判断卡是否成功接收数据
|
||
error = bsp_sd_error_not_ready;
|
||
goto error;
|
||
}
|
||
|
||
error = sd_wait_response(0xFF); //等待写入操作完成
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
buffer += BSP_SD_BLOCK_SIZE;
|
||
}
|
||
|
||
sd_write_read_byte(0xFD); //发送多Block写结束的Token
|
||
|
||
error = sd_wait_response(0xFF); //等待写入操作完成
|
||
if (error != bsp_sd_error_none) {
|
||
goto error;
|
||
}
|
||
|
||
error:
|
||
sd_disable();
|
||
return error;
|
||
}
|
||
|
||
void bsp_sd_spi_get_card_info(bsp_card_info_t *card_info_out)
|
||
{
|
||
memcpy(card_info_out, &card_info, sizeof(bsp_card_info_t));
|
||
}
|