diff --git a/ch32v307_mp3_dac/User/3rdparty/fatfs/diskio.c b/ch32v307_mp3_dac/User/3rdparty/fatfs/diskio.c index 671c616..c68d0f3 100644 --- a/ch32v307_mp3_dac/User/3rdparty/fatfs/diskio.c +++ b/ch32v307_mp3_dac/User/3rdparty/fatfs/diskio.c @@ -10,7 +10,7 @@ #include "ff.h" /* Obtains integer types */ #include "diskio.h" /* Declarations of disk functions */ #include "debug.h" -#include "bsp_spi_sd.h" +#include "bsp_sd_spi.h" /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -33,11 +33,16 @@ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { - if(spisd_init() == SPISD_RESULT_OK) { - return 0; + if(bsp_sd_init() != bsp_sd_error_none) { + return STA_NOINIT; } - return STA_NOINIT; + bsp_card_info_t card_info; + bsp_sd_spi_get_card_info(&card_info); + + LOG_I("sd card successfully initialized, capacity: %dMB", (uint32_t)card_info.sector_count >> 11); + + return 0; } @@ -53,19 +58,19 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - spisd_result_t sd_result; + bsp_sd_error_t sd_error; if (count == 1) { - sd_result = spisd_read_block(sector, (uint8_t*)buff); + sd_error = bsp_sd_read_block(buff, sector); } else { - sd_result = spisd_read_multi_block(sector, (uint8_t*)buff, count); + sd_error = bsp_sd_read_multi_blocks(buff, sector, count); } - if(sd_result == SPISD_RESULT_OK) { + if(sd_error == bsp_sd_error_none) { return RES_OK; } - LOG_E("error while reading disk, error code=%d", sd_result); + LOG_E("error while reading disk, error code=%d", sd_error); return RES_PARERR; } @@ -78,50 +83,32 @@ DRESULT disk_read ( #if FF_FS_READONLY == 0 DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - LBA_t sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE *buff, /* Data to be written */ + LBA_t sector, /* Start sector in LBA */ + UINT count /* Number of sectors to write */ ) { - DRESULT res; - int result; + bsp_sd_error_t sd_result; - switch (pdrv) { - case DEV_RAM : - // translate the arguments here + if (count > 1) { + sd_result = bsp_sd_write_multi_blocks(buff, sector, count); + } else { + sd_result = bsp_sd_write_block(buff, sector); + } - result = RAM_disk_write(buff, sector, count); + if(sd_result == bsp_sd_error_none) { + return RES_OK; + } - // translate the reslut code here - - return res; - - case DEV_MMC : - // translate the arguments here - - result = MMC_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_USB : - // translate the arguments here - - result = USB_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - } - - return RES_PARERR; + LOG_E("error while writing disk, error code=%d", sd_error); + return RES_ERROR; } #endif + /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ @@ -135,8 +122,16 @@ DRESULT disk_ioctl ( switch(cmd) { case CTRL_SYNC: return RES_OK; + case GET_SECTOR_SIZE: + case GET_BLOCK_SIZE: + *(DWORD *)buff = BSP_SD_BLOCK_SIZE; + return RES_OK; + case GET_SECTOR_COUNT: + bsp_card_info_t card_info; + bsp_sd_spi_get_card_info(&card_info); + *(DWORD *)buff = card_info.sector_count; + return RES_OK; default: return RES_PARERR; } } - diff --git a/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.c b/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.c new file mode 100644 index 0000000..53e8153 --- /dev/null +++ b/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.c @@ -0,0 +1,564 @@ +#include "bsp_sd_spi.h" +#include + +#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)); +} diff --git a/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.h b/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.h new file mode 100644 index 0000000..61129ef --- /dev/null +++ b/ch32v307_mp3_dac/User/bsp/bsp_sd_spi.h @@ -0,0 +1,60 @@ +#ifndef __BSP_SD_SPI_H +#define __BSP_SD_SPI_H + +#include "ch32v30x.h" + +#define BSP_SD_BLOCK_SIZE 512 + +#define BSP_SD_SPI SPI2 +#define BSP_SD_SPI_CLK_ENABLE() RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE) + +#define BSP_SD_SPI_SCK_PIN GPIO_Pin_13 /* PB.13 */ +#define BSP_SD_SPI_SCK_GPIO_PORT GPIOB /* GPIOB */ +#define BSP_SD_SPI_SCK_GPIO_CLK RCC_APB2Periph_GPIOB +#define BSP_SD_SPI_MISO_PIN GPIO_Pin_14 /* PB.14 */ +#define BSP_SD_SPI_MISO_GPIO_PORT GPIOB /* GPIOB */ +#define BSP_SD_SPI_MISO_GPIO_CLK RCC_APB2Periph_GPIOB +#define BSP_SD_SPI_MOSI_PIN GPIO_Pin_15 /* PB.15 */ +#define BSP_SD_SPI_MOSI_GPIO_PORT GPIOB /* GPIOB */ +#define BSP_SD_SPI_MOSI_GPIO_CLK RCC_APB2Periph_GPIOB +#define BSP_SD_CS_PIN GPIO_Pin_12 /* PB.12 */ +#define BSP_SD_CS_GPIO_PORT GPIOB /* GPIOB */ +#define BSP_SD_CS_GPIO_CLK RCC_APB2Periph_GPIOB + +#define BSP_SD_TX_DMA_CHANNEL DMA1_Channel5 +#define BSP_SD_RX_DMA_CHANNEL DMA1_Channel4 +#define BSP_SD_TX_DMA_IT_TC_FLAG DMA1_IT_TC4 + +typedef enum { + bsp_sd_type_unknown = 0, + bsp_sd_type_mmc, + bsp_sd_type_sdv1, + bsp_sd_type_sdv2, + bsp_sd_type_sdv2hc, +} bsp_sd_type_t; + +typedef enum { + bsp_sd_error_none = 0, + bsp_sd_error_no_card, + bsp_sd_error_invalid_parameter, + bsp_sd_error_unknown_card_type, + bsp_sd_error_not_ready, + bsp_sd_error_invalid_response, + bsp_sd_error_timeout, +} bsp_sd_error_t; + +typedef struct { + bsp_sd_type_t card_type; + uint32_t sector_count; +} bsp_card_info_t; + +bsp_sd_error_t bsp_sd_init(void); + +bsp_sd_error_t bsp_sd_read_block(uint8_t* buffer, uint32_t sector_address); +bsp_sd_error_t bsp_sd_read_multi_blocks(uint8_t* buffer, uint32_t sector_address, uint16_t sector_count); +bsp_sd_error_t bsp_sd_write_block(const uint8_t *buffer, uint32_t sector_address); +bsp_sd_error_t bsp_sd_write_multi_blocks(const uint8_t *buffer, uint32_t sector_address, uint16_t sector_count); + +void bsp_sd_spi_get_card_info(bsp_card_info_t *card_info_out); + +#endif diff --git a/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.c b/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.c deleted file mode 100644 index fddc842..0000000 --- a/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.c +++ /dev/null @@ -1,809 +0,0 @@ -/* Includes ------------------------------------------------------------------*/ -#include "bsp_spi_sd.h" -#include "debug.h" - -/* Private types -------------------------------------------------------------*/ -typedef enum card_type_e { - CARD_TYPE_MMC = 0x00, - CARD_TYPE_SDV1 = 0x01, - CARD_TYPE_SDV2 = 0x02, - CARD_TYPE_SDV2HC = 0x04 -} card_type_t; - -/* Private define ------------------------------------------------------------*/ -#define DUMMY_BYTE 0xFF -#define BLOCK_SIZE 512 - -#define CMD0 0 /* Reset */ -#define CMD1 1 /* Send Operator Condition - SEND_OP_COND */ -#define CMD8 8 /* Send Interface Condition - SEND_IF_COND */ -#define CMD9 9 /* Read CSD */ -#define CMD10 10 /* Read CID */ -#define CMD12 12 /* Stop data transmit */ -#define CMD16 16 /* Set block size, should return 0x00 */ -#define CMD17 17 /* Read single block */ -#define CMD18 18 /* Read multi block */ -#define ACMD23 23 /* Prepare erase N-blocks before multi block write */ -#define CMD24 24 /* Write single block */ -#define CMD25 25 /* Write multi block */ -#define ACMD41 41 /* should return 0x00 */ -#define CMD55 55 /* should return 0x01 */ -#define CMD58 58 /* Read OCR */ -#define CMD59 59 /* CRC disable/enable, should return 0x00 */ - -#define CMD_WAIT_RESP_TIMEOUT (100000U) -#define WAIT_IDLE_TIMEOUT (20000U) - -#define SPI_PRESCALER_LOW (SPI_BaudRatePrescaler_256) -#define SPI_PRESCALER_HIGH (SPI_BaudRatePrescaler_4) - -/* Private variables ---------------------------------------------------------*/ -static card_type_t _card_type; - -/* Private functions ---------------------------------------------------------*/ -#define SPISD_LOG(...) LOG_E(__VA_ARGS__) - -static void _spi_init(void) -{ - GPIO_InitTypeDef GPIO_InitStructure; - SPI_InitTypeDef SPI_InitStructure; - - /*!< SD_SPI_CS_GPIO, SD_SPI_MOSI_GPIO, SD_SPI_MISO_GPIO, SD_SPI_DETECT_GPIO - and SD_SPI_SCK_GPIO Periph clock enable */ - RCC_APB2PeriphClockCmd(SD_CS_GPIO_CLK | SD_SPI_MOSI_GPIO_CLK | SD_SPI_MISO_GPIO_CLK | - SD_SPI_SCK_GPIO_CLK | SD_DETECT_GPIO_CLK, ENABLE); - - /*!< SD_SPI Periph clock enable */ - SD_SPI_CLK_ENABLE(); - - /*!< DMA1 Periph clock enable */ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); - - - /*!< Configure SD_SPI pins: SCK */ - GPIO_InitStructure.GPIO_Pin = SD_SPI_SCK_PIN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_Init(SD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure); - - /*!< Configure SD_SPI pins: MOSI */ - GPIO_InitStructure.GPIO_Pin = SD_SPI_MOSI_PIN; - GPIO_Init(SD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); - - /*!< Configure SD_SPI pins: MISO */ - GPIO_InitStructure.GPIO_Pin = SD_SPI_MISO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_Init(SD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure); - - /*!< Configure SD_SPI_CS_PIN pin: SD Card CS pin */ - GPIO_InitStructure.GPIO_Pin = SD_CS_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_Init(SD_CS_GPIO_PORT, &GPIO_InitStructure); - - /*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */ - GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure); - - /*!< SD_SPI Config */ - 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 = SPI_PRESCALER_LOW; - - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; - SPI_Init(SD_SPI, &SPI_InitStructure); - - SPI_Cmd(SD_SPI, ENABLE); /*!< SD_SPI enable */ -} - -static void _set_spi_prescaler(uint32_t prescaler) -{ - SD_SPI->CTLR1 &= 0xFFC7; - SD_SPI->CTLR1 |= prescaler; -} - -static void _select(void) -{ - GPIO_ResetBits(SD_CS_GPIO_PORT, SD_CS_PIN); -} - -static void _release(void) -{ - GPIO_SetBits(SD_CS_GPIO_PORT, SD_CS_PIN); -} - -static bool _is_present(void) -{ - return GPIO_ReadInputData(SD_DETECT_GPIO_PORT) & SD_DETECT_PIN ? false : true; -} - -static __always_inline uint8_t _wr_rd_byte(uint8_t byte) -{ - while((SD_SPI->STATR & SPI_I2S_FLAG_TXE) == RESET); - SD_SPI->DATAR = byte; - while((SD_SPI->STATR & SPI_I2S_FLAG_RXNE) == RESET); - return SD_SPI->DATAR; -} - -static void _write(uint8_t const *buffer, uint32_t size) -{ - if (size < BLOCK_SIZE) { //For small transactions, use polling - for (uint32_t i = 0; i < size; i ++) { - _wr_rd_byte(buffer[i]); - } - - return; - } - - uint8_t spi_rx_dummy_byte; - - /* Wait for last transaction to be done */ - while((SD_SPI->STATR & SPI_I2S_FLAG_TXE) == 0); - - /* Configure Rx channel first */ - DMA_InitTypeDef DMA_InitStructure; - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&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; //Repeatedly Rx dummy bytes to claer SPI_I2S_FLAG_RXNE flag - 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(DMA1_Channel4, &DMA_InitStructure); //SPI2_RX - - /* Tx dummy bytes to generate clock */ - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SD_SPI->DATAR); - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; - DMA_InitStructure.DMA_Priority = DMA_Priority_Low; //Tx priority should be lower than Rx to avoid FIFO overrun - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_Init(DMA1_Channel5, &DMA_InitStructure); //SPI2_TX - - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx, ENABLE); - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Tx, ENABLE); - DMA_Cmd(DMA1_Channel4, ENABLE); - DMA_Cmd(DMA1_Channel5, ENABLE); - - while (DMA_GetITStatus(DMA1_IT_TC4) != SET) { //Poll for Rx done, use interrupt instead when using RTOS -// __WFI(); - } - - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx, DISABLE); - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Tx, DISABLE); - DMA_DeInit(DMA1_Channel4); - DMA_DeInit(DMA1_Channel5); -} - -static void _read(uint8_t *buffer, uint32_t size) -{ - uint8_t spi_tx_dummy_byte = DUMMY_BYTE; - - /* Wait for last transaction to be done */ - while((SD_SPI->STATR & SPI_I2S_FLAG_TXE) == 0); - - /* Configure Rx channel first */ - DMA_InitTypeDef DMA_InitStructure; - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&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(DMA1_Channel4, &DMA_InitStructure); //SPI2_RX - - /* Tx dummy bytes to generate clock */ - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(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; //Tx priority should be lower than Rx to avoid FIFO overrun - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //Repeatedly Tx dummy byte for clock generation - DMA_Init(DMA1_Channel5, &DMA_InitStructure); //SPI2_TX - - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx, ENABLE); - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Tx, ENABLE); - DMA_Cmd(DMA1_Channel4, ENABLE); - DMA_Cmd(DMA1_Channel5, ENABLE); - - while (DMA_GetITStatus(DMA1_IT_TC4) != SET) { //Poll for Rx done, use interrupt instead when using RTOS -// __WFI(); - } - - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Rx, DISABLE); - SPI_I2S_DMACmd(SD_SPI, SPI_I2S_DMAReq_Tx, DISABLE); - DMA_DeInit(DMA1_Channel4); - DMA_DeInit(DMA1_Channel5); -} - -static uint8_t _send_command(uint8_t cmd, uint32_t arg, uint8_t crc) -{ - uint8_t response = 0xFF; - - /* Dummy byte and chip enable */ - _wr_rd_byte(DUMMY_BYTE); - _select(); - - uint8_t packet[] = {cmd | 0x40, arg >> 24, arg >> 16, arg >> 8, arg, crc}; - _write(packet, sizeof(packet)); - - /* Wait response, quit till timeout */ - for (uint32_t i = 0; i < CMD_WAIT_RESP_TIMEOUT; i++) { - response = _wr_rd_byte(DUMMY_BYTE); - - if (response != 0xFF) { - break; - } - } - - /* Chip disable and dummy byte */ - _release(); - _wr_rd_byte(DUMMY_BYTE); - - return response; -} - -static uint8_t _send_command_recv_response(uint8_t cmd, uint32_t arg, uint8_t crc, uint8_t* data, size_t size) -{ - /* Dummy byte and chip enable */ - _wr_rd_byte(DUMMY_BYTE); - _select(); - - uint8_t packet[] = {cmd | 0x40, arg >> 24, arg >> 16, arg >> 8, arg, crc}; - _write(packet, sizeof(packet)); - - uint8_t response = DUMMY_BYTE; - - /* Wait response, quit till timeout */ - for (uint32_t i = 0; i < CMD_WAIT_RESP_TIMEOUT; i++) { - - response = _wr_rd_byte(DUMMY_BYTE); - - if (response != DUMMY_BYTE) { - _read(data, size); - break; - } - } - - /* Chip disable and dummy byte */ - _release(); - _wr_rd_byte(DUMMY_BYTE); - - return response; -} - -static uint8_t _send_command_hold(uint8_t cmd, uint32_t arg, uint8_t crc) -{ - /* Dummy byte and chip enable */ - _wr_rd_byte(DUMMY_BYTE); - _select(); - - - uint8_t packet[] = {cmd | 0x40, arg >> 24, arg >> 16, arg >> 8, arg, crc}; - _write(packet, sizeof(packet)); - - - /* Wait response, quit till timeout */ - for (uint32_t i = 0; i < CMD_WAIT_RESP_TIMEOUT; i++) { - uint8_t response = _wr_rd_byte(DUMMY_BYTE); - - if (response != 0xFF) { - return response; - } - } - - return 0xFF; -} - -static spisd_result_t _read_buffer(uint8_t *buff, uint32_t len) -{ - uint8_t response = 0; - - /* Wait start-token 0xFE */ - for (uint32_t i = 0; i < CMD_WAIT_RESP_TIMEOUT; i++) { - response = _wr_rd_byte(DUMMY_BYTE); - - if (response == 0xFE) { - break; - } - } - - if (response != 0xFE) { - return SPISD_RESULT_ERROR; - } - - _read(buff, len); - - /* 2bytes dummy CRC */ - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - return SPISD_RESULT_OK; -} - -spisd_result_t spisd_init(void) -{ - _spi_init(); - - if ( !_is_present() ) { - SPISD_LOG("There is no card detected!"); - return SPISD_RESULT_NO_CARD; - } - - _release(); - _set_spi_prescaler(SPI_PRESCALER_LOW); - - /* Start send 74 clocks at least */ - for (uint32_t i = 0; i < 20; i++) { - _wr_rd_byte(DUMMY_BYTE); - } - - uint32_t timeout = WAIT_IDLE_TIMEOUT; - uint8_t response = 0; - - do { - response = _send_command(CMD0, 0, 0x95); - timeout--; - } while ((response != SPISD_R1_IDLE_FLAG) && timeout > 0 ); - - if (!timeout) { - SPISD_LOG("Reset card into IDLE state failed!"); - return SPISD_RESULT_TIMEOUT; - } - - uint8_t buff[4]; - response = _send_command_recv_response(CMD8, 0x1AA, 0x87, buff, sizeof(buff)); - - if (response == SPISD_R1_IDLE_FLAG) { - - /* Check voltage range be 2.7-3.6V */ - if (buff[2] == 0x01 && buff[3] == 0xAA) { - - for (uint32_t i = 0; i < 0xFFF; i++) { - response = _send_command(CMD55, 0, 0); /* should be return 0x01 */ - - if (response != 0x01) { - SPISD_LOG("Send CMD55 should return 0x01, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - response = _send_command(ACMD41, 0x40000000, 0); /* should be return 0x00 */ - - if (response == 0x00) { - break; - } - } - - if (response != 0x00) { - SPISD_LOG("Send ACMD41 should return 0x00, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - /* Read OCR by CMD58 */ - response = _send_command_recv_response(CMD58, 0, 0, buff, sizeof(buff)); - - if (response != 0x00) { - SPISD_LOG("Send CMD58 should return 0x00, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - /* OCR -> CCS(bit30) 1: SDV2HC 0: SDV2 */ - _card_type = (buff[0] & 0x40) ? CARD_TYPE_SDV2HC : CARD_TYPE_SDV2; - - _set_spi_prescaler(SPI_PRESCALER_HIGH); - } -#if USE_MMC_CARD == 1 - } else if (response & SPISD_R1_ILLEGAL_CMD_FLAG) { - - _card_type = CARD_TYPE_SDV1; - - /* End of CMD8, chip disable and dummy byte */ - _release(); - _wr_rd_byte(DUMMY_BYTE); - - /* SD1.0/MMC start initialize */ - /* Send CMD55+ACMD41, No-response is a MMC card, otherwise is a SD1.0 card */ - for (uint32_t i = 0; i < 0xFFF; i++) { - response = _send_command(CMD55, 0, 0); - - if (response != 0x01) { - SPISD_LOG("Send CMD55 should return 0x01, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - response = _send_command(ACMD41, 0, 0); - - if (response == 0x00) { - break; - } - } - - /* MMC card initialize start */ - if (response != 0x00) { - for (uint32_t i = 0; i < 0xFFF; i++) { - response = _send_command(CMD1, 0, 0); - - if (response == 0x00) { - break; - } - } - - /* Timeout return */ - if (response != 0x00) { - SPISD_LOG("Send CMD1 should return 0x00, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - _card_type = CARD_TYPE_MMC; - SPISD_LOG("Card Type : MMC"); - } else { - SPISD_LOG("Card Type : SD V1"); - } - - _set_spi_prescaler(true); - - /* CRC disable */ - response = _send_command(CMD59, 0, 0x01); - - if (response != 0x00) { - SPISD_LOG("Send CMD59 should return 0x00, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - - /* Set the block size */ - response = _send_command(CMD16, BLOCK_SIZE, 0xFF); - - if (response != 0x00) { - SPISD_LOG("Send CMD16 should return 0x00, response=0x%02x", response); - return SPISD_RESULT_TIMEOUT; - } - -#endif //USE_MMC_CARD - } else { - return SPISD_RESULT_ERROR; - } - - return SPISD_RESULT_OK; -} - -int spisd_get_card_info(spisd_info_t *cardinfo) -{ - _wr_rd_byte(DUMMY_BYTE); - - /* Send CMD9, Read CSD */ - uint8_t response = _send_command(CMD9, 0, 0xFF); - - if (response != 0x00) { - return response; - } - - uint8_t temp[16]; - - _select(); - - spisd_result_t ret = _read_buffer(temp, sizeof(temp)); - /* chip disable and dummy byte */ - _release(); - _wr_rd_byte(DUMMY_BYTE); - - if (ret != SPISD_RESULT_OK) { - return 1; - } - - /* Byte 0 */ - cardinfo->csd.CSDStruct = (temp[0] & 0xC0) >> 6; - cardinfo->csd.SysSpecVersion = (temp[0] & 0x3C) >> 2; - cardinfo->csd.Reserved1 = temp[0] & 0x03; - /* Byte 1 */ - cardinfo->csd.TAAC = temp[1] ; - /* Byte 2 */ - cardinfo->csd.NSAC = temp[2]; - /* Byte 3 */ - cardinfo->csd.MaxBusClkFrec = temp[3]; - /* Byte 4 */ - cardinfo->csd.CardComdClasses = temp[4] << 4; - /* Byte 5 */ - cardinfo->csd.CardComdClasses |= (temp[5] & 0xF0) >> 4; - cardinfo->csd.RdBlockLen = temp[5] & 0x0F; - /* Byte 6 */ - cardinfo->csd.PartBlockRead = (temp[6] & 0x80) >> 7; - cardinfo->csd.WrBlockMisalign = (temp[6] & 0x40) >> 6; - cardinfo->csd.RdBlockMisalign = (temp[6] & 0x20) >> 5; - cardinfo->csd.DSRImpl = (temp[6] & 0x10) >> 4; - cardinfo->csd.Reserved2 = 0; /* Reserved */ - cardinfo->csd.DeviceSize = (temp[6] & 0x03) << 10; - /* Byte 7 */ - cardinfo->csd.DeviceSize |= (temp[7]) << 2; - /* Byte 8 */ - cardinfo->csd.DeviceSize |= (temp[8] & 0xC0) >> 6; - cardinfo->csd.MaxRdCurrentVDDMin = (temp[8] & 0x38) >> 3; - cardinfo->csd.MaxRdCurrentVDDMax = (temp[8] & 0x07); - /* Byte 9 */ - cardinfo->csd.MaxWrCurrentVDDMin = (temp[9] & 0xE0) >> 5; - cardinfo->csd.MaxWrCurrentVDDMax = (temp[9] & 0x1C) >> 2; - cardinfo->csd.DeviceSizeMul = (temp[9] & 0x03) << 1; - /* Byte 10 */ - cardinfo->csd.DeviceSizeMul |= (temp[10] & 0x80) >> 7; - cardinfo->csd.EraseGrSize = (temp[10] & 0x7C) >> 2; - cardinfo->csd.EraseGrMul = (temp[10] & 0x03) << 3; - /* Byte 11 */ - cardinfo->csd.EraseGrMul |= (temp[11] & 0xE0) >> 5; - cardinfo->csd.WrProtectGrSize = (temp[11] & 0x1F); - /* Byte 12 */ - cardinfo->csd.WrProtectGrEnable = (temp[12] & 0x80) >> 7; - cardinfo->csd.ManDeflECC = (temp[12] & 0x60) >> 5; - cardinfo->csd.WrSpeedFact = (temp[12] & 0x1C) >> 2; - cardinfo->csd.MaxWrBlockLen = (temp[12] & 0x03) << 2; - /* Byte 13 */ - cardinfo->csd.MaxWrBlockLen |= (temp[13] & 0xc0) >> 6; - cardinfo->csd.WriteBlockPaPartial = (temp[13] & 0x20) >> 5; - cardinfo->csd.Reserved3 = 0; - cardinfo->csd.ContentProtectAppli = (temp[13] & 0x01); - /* Byte 14 */ - cardinfo->csd.FileFormatGrouop = (temp[14] & 0x80) >> 7; - cardinfo->csd.CopyFlag = (temp[14] & 0x40) >> 6; - cardinfo->csd.PermWrProtect = (temp[14] & 0x20) >> 5; - cardinfo->csd.TempWrProtect = (temp[14] & 0x10) >> 4; - cardinfo->csd.FileFormat = (temp[14] & 0x0C) >> 2; - cardinfo->csd.ECC = (temp[14] & 0x03); - /* Byte 15 */ - cardinfo->csd.CSD_CRC = (temp[15] & 0xFE) >> 1; - cardinfo->csd.Reserved4 = 1; - - if (cardinfo->card_type == CARD_TYPE_SDV2HC) { - /* Byte 7 */ - cardinfo->csd.DeviceSize = (uint16_t)(temp[8]) * 256; - /* Byte 8 */ - cardinfo->csd.DeviceSize += temp[9] ; - } - - cardinfo->capacity = cardinfo->csd.DeviceSize * BLOCK_SIZE * 1024; - cardinfo->block_size = BLOCK_SIZE; - - /* Send CMD10, Read CID */ - response = _send_command(CMD10, 0, 0xFF); - - if (response != 0x00) { - return response; - } - - - _select(); - ret = _read_buffer(temp, sizeof(temp)); - /* chip disable and dummy byte */ - _release(); - _wr_rd_byte(DUMMY_BYTE); - - if (ret != SPISD_RESULT_OK) { - return 2; - } - - - /* Byte 0 */ - cardinfo->cid.ManufacturerID = temp[0]; - /* Byte 1 */ - cardinfo->cid.OEM_AppliID = temp[1] << 8; - /* Byte 2 */ - cardinfo->cid.OEM_AppliID |= temp[2]; - /* Byte 3 */ - cardinfo->cid.ProdName1 = temp[3] << 24; - /* Byte 4 */ - cardinfo->cid.ProdName1 |= temp[4] << 16; - /* Byte 5 */ - cardinfo->cid.ProdName1 |= temp[5] << 8; - /* Byte 6 */ - cardinfo->cid.ProdName1 |= temp[6]; - /* Byte 7 */ - cardinfo->cid.ProdName2 = temp[7]; - /* Byte 8 */ - cardinfo->cid.ProdRev = temp[8]; - /* Byte 9 */ - cardinfo->cid.ProdSN = temp[9] << 24; - /* Byte 10 */ - cardinfo->cid.ProdSN |= temp[10] << 16; - /* Byte 11 */ - cardinfo->cid.ProdSN |= temp[11] << 8; - /* Byte 12 */ - cardinfo->cid.ProdSN |= temp[12]; - /* Byte 13 */ - cardinfo->cid.Reserved1 |= (temp[13] & 0xF0) >> 4; - /* Byte 14 */ - cardinfo->cid.ManufactDate = (temp[13] & 0x0F) << 8; - /* Byte 15 */ - cardinfo->cid.ManufactDate |= temp[14]; - /* Byte 16 */ - cardinfo->cid.CID_CRC = (temp[15] & 0xFE) >> 1; - cardinfo->cid.Reserved2 = 1; - - return 0; -} - -spisd_result_t spisd_read_block(uint32_t sector, uint8_t *buffer) -{ - if (_card_type != CARD_TYPE_SDV2HC) { - sector = sector << 9; - } - - spisd_result_t ret = SPISD_RESULT_ERROR; - - if (_send_command_hold(CMD17, sector, 0) == 0x00) { - ret = _read_buffer(buffer, BLOCK_SIZE); - } - - _release(); - _wr_rd_byte(DUMMY_BYTE); - - return ret; -} - -spisd_result_t spisd_write_block(uint32_t sector, const uint8_t *buffer) -{ - spisd_result_t ret = SPISD_RESULT_ERROR; - - if (_card_type != CARD_TYPE_SDV2HC) { - sector = sector << 9; - } - - if (_send_command(CMD24, sector, 0) != 0x00) { - return ret; - } - - _select(); - - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - /* Start data write token: 0xFE */ - _wr_rd_byte(0xFE); - - _write(buffer, BLOCK_SIZE); - - /* 2Bytes dummy CRC */ - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - /* MSD card accept the data */ - uint8_t response = _wr_rd_byte(DUMMY_BYTE); - - if ((response & 0x1F) == 0x05) { - /* Wait all the data program finished */ - for (uint32_t i = 0; i < 0x40000; i++) { - if ( _wr_rd_byte(DUMMY_BYTE) != 0x00) { - ret = SPISD_RESULT_OK; - break; - } - } - } - - _release(); - _wr_rd_byte(DUMMY_BYTE); - - return ret; -} - -spisd_result_t spisd_read_multi_block(uint32_t sector, uint8_t *buffer, uint32_t num_sectors) -{ - /* if ver = SD2.0 HC, sector need <<9 */ - if (_card_type != CARD_TYPE_SDV2HC) { - sector = sector << 9; - } - - if (_send_command(CMD18, sector, 0) != 0x00) { - return SPISD_RESULT_ERROR; - } - - _wr_rd_byte(DUMMY_BYTE); - _select(); - - for (uint32_t i = 0; i < num_sectors; i++) { - spisd_result_t ret = _read_buffer(&buffer[i * BLOCK_SIZE], BLOCK_SIZE); - - if (ret != SPISD_RESULT_OK) { - /* Send stop data transmit command - CMD12 */ - _send_command(CMD12, 0, 0); - return SPISD_RESULT_ERROR; - } - } - - _release(); - _wr_rd_byte(DUMMY_BYTE); - - /* Send stop data transmit command - CMD12 */ - _send_command(CMD12, 0, 0); - - return SPISD_RESULT_OK; -} - -spisd_result_t spisd_write_multi_block(uint32_t sector, uint8_t const *buffer, uint32_t num_sectors) -{ - /* if ver = SD2.0 HC, sector need <<9 */ - if (_card_type != CARD_TYPE_SDV2HC) { - sector = sector << 9; - } - - /* Send command ACMD23 before multi write if is not a MMC card */ - if (_card_type != CARD_TYPE_MMC) { - _send_command(CMD55, 0, 0x00); - _send_command(ACMD23, num_sectors, 0x00); - } - - if (_send_command(CMD25, sector, 0) != 0x00) { - return SPISD_RESULT_ERROR; - } - - _select(); - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - for (uint32_t i = 0; i < num_sectors; i++) { - /* Start multi block write token: 0xFC */ - _wr_rd_byte(0xFC); - - _write(&buffer[i * BLOCK_SIZE], BLOCK_SIZE); - - /* 2Bytes dummy CRC */ - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - /* MSD card accept the data */ - if ((_wr_rd_byte(DUMMY_BYTE) & 0x1F) != 0x05) { - _release(); - _wr_rd_byte(DUMMY_BYTE); - return SPISD_RESULT_ERROR; - } - - /* Wait all the data program finished */ - uint32_t timeout = 0; - - while (_wr_rd_byte(DUMMY_BYTE) != 0xFF) { - /* Timeout return */ - if (timeout++ == 0x40000) { - _release(); - _wr_rd_byte(DUMMY_BYTE); - return SPISD_RESULT_ERROR; - } - } - } - - /* Send end of transmit token: 0xFD */ - if (_wr_rd_byte(0xFD) != 0x00) { - - _wr_rd_byte(DUMMY_BYTE); - _wr_rd_byte(DUMMY_BYTE); - - /* Wait all the data program finished */ - for (uint32_t i = 0; i < 0x40000; i++) { - if (_wr_rd_byte(DUMMY_BYTE) == 0xFF) { - _release(); - _wr_rd_byte(DUMMY_BYTE); - - for (uint32_t i = 0; i < 0x40000; i++) { - if (_wr_rd_byte(DUMMY_BYTE) == 0xFF) { - return SPISD_RESULT_OK; - } - } - } - } - } - - _release(); - _wr_rd_byte(DUMMY_BYTE); - - return SPISD_RESULT_ERROR; -} diff --git a/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.h b/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.h deleted file mode 100644 index 360a0f5..0000000 --- a/ch32v307_mp3_dac/User/bsp/bsp_spi_sd.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef __BSP_SPI_SD_H -#define __BSP_SPI_SD_H - -/* Includes ------------------------------------------------------------------*/ -#include "ch32v30x.h" -#include - -#define SD_SPI SPI2 -#define SD_SPI_CLK_ENABLE() RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE) -#define SD_SPI_SCK_PIN GPIO_Pin_13 /* PB.13 */ -#define SD_SPI_SCK_GPIO_PORT GPIOB /* GPIOB */ -#define SD_SPI_SCK_GPIO_CLK RCC_APB2Periph_GPIOB -#define SD_SPI_MISO_PIN GPIO_Pin_14 /* PB.14 */ -#define SD_SPI_MISO_GPIO_PORT GPIOB /* GPIOB */ -#define SD_SPI_MISO_GPIO_CLK RCC_APB2Periph_GPIOB -#define SD_SPI_MOSI_PIN GPIO_Pin_15 /* PB.15 */ -#define SD_SPI_MOSI_GPIO_PORT GPIOB /* GPIOB */ -#define SD_SPI_MOSI_GPIO_CLK RCC_APB2Periph_GPIOB -#define SD_CS_PIN GPIO_Pin_12 /* PB.12 */ -#define SD_CS_GPIO_PORT GPIOB /* GPIOB */ -#define SD_CS_GPIO_CLK RCC_APB2Periph_GPIOB -#define SD_DETECT_PIN GPIO_Pin_0 /* PB.00 */ -#define SD_DETECT_GPIO_PORT GPIOB /* GPIOE */ -#define SD_DETECT_GPIO_CLK RCC_APB2Periph_GPIOB - -#define SPISD_R1_IDLE_FLAG (0x01) -#define SPISD_R1_ERASE_RESET_FLAG (0x02) -#define SPISD_R1_ILLEGAL_CMD_FLAG (0x04) -#define SPISD_R1_CMD_CRC_FLAG (0x08) -#define SPISD_R1_ERASE_SEQ_ERROR_FLAG (0x10) -#define SPISD_R1_ADDR_ERROR_FLAG (0x20) -#define SPISD_R1_PARAM_ERROR_FLAG (0x40) -#define SPISD_R1_ZERO_FLAG (0x80) - -typedef enum spisd_result_s { - SPISD_RESULT_OK = 0, - SPISD_RESULT_ERROR, - SPISD_RESULT_NO_CARD, - SPISD_RESULT_TIMEOUT, -} spisd_result_t; - -typedef union __attribute__((packed)) sppisd_r1_u { - uint8_t raw; - struct { - uint8_t idle: 1; /*