wch-code/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.c

565 lines
19 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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));
}