| |
| |
| |
| |
| #include "stdio.h" |
| #include "stdlib.h" |
| #include "pico/stdlib.h" |
| #include "spi_sdmmc.h" |
| #include "msc_storage_driver.h" |
| |
| |
| #define SDMMC_CD 0 |
| #define SDMMC_WP 0 |
| |
| static uint8_t dummy_block[SDMMC_SECT_SIZE]; |
| |
| void sdmmc_spi_cs_high(sdmmc_data_t *sdmmc); |
| void sdmmc_spi_cs_low(sdmmc_data_t *sdmmc); |
| static int sdmmc_wait_ready(uint timeout, sdmmc_data_t *sdmmc); |
| static void sdmmc_init_spi(sdmmc_data_t *sdmmc); |
| |
| static void sdmmc_deselect(sdmmc_data_t *sdmmc) |
| { |
| uint8_t src = 0xFF; |
| sdmmc_spi_cs_high(sdmmc); |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| } |
| |
| |
| |
| |
| static int sdmmc_select(sdmmc_data_t *sdmmc) |
| { |
| uint8_t src = 0xFF; |
| sdmmc_spi_cs_low(sdmmc); |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| if (sdmmc_wait_ready(500, sdmmc)) |
| return 1; |
| sdmmc_deselect(sdmmc); |
| return 0; |
| } |
| |
| uint64_t sdmmc_get_sector_count(sdmmc_data_t *sdmmc) { |
| uint8_t n, csd[16]; |
| uint32_t st, ed, csize; |
| |
| uint64_t sectorCounter; |
| |
| uint8_t src = 0xFF; |
| uint8_t sc = sdmmc_send_cmd(CMD9, 0, sdmmc); |
| int rd = sdmmc_read_datablock(csd, 16, sdmmc); |
| |
| if ((sc == 0) && rd) |
| { |
| if ((csd[0] >> 6) == 1) |
| { |
| csize = csd[9] + ((uint16_t)csd[8] << 8) + ((uint32_t)(csd[7] & 63) << 16) + 1; |
| sectorCounter = csize << 10; |
| } |
| else |
| { |
| n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; |
| csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1; |
| sectorCounter = csize << (n - 9); |
| } |
| |
| } else { |
| sectorCounter=0; |
| } |
| sdmmc_deselect(sdmmc); |
| return sectorCounter; |
| } |
| |
| uint32_t sdmmc_get_block_count(sdmmc_data_t *sdmmc) { |
| uint8_t n, csd[16]; |
| uint32_t st, ed, csize; |
| |
| uint32_t sectorCounter=0; |
| |
| uint8_t src = 0xFF; |
| |
| if (sdmmc->cardType & CT_SDC2) |
| { |
| if (sdmmc_send_cmd(ACMD13, 0, sdmmc) == 0) |
| { |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| if (sdmmc_read_datablock(csd, 16, sdmmc)) |
| { |
| for (n = 64 - 16; n; n--) |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| sectorCounter = 16UL << (csd[10] >> 4); |
| } |
| } |
| } |
| else |
| { |
| if ((sdmmc_send_cmd(CMD9, 0, sdmmc) == 0) && sdmmc_read_datablock(csd, 16, sdmmc)) |
| { |
| if (sdmmc->cardType & CT_SDC1) |
| { |
| sectorCounter = (((csd[10] & 63) << 1) + ((uint16_t)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); |
| } |
| else |
| { |
| sectorCounter = ((uint16_t)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); |
| } |
| |
| } |
| } |
| sdmmc_deselect(sdmmc); |
| return sectorCounter; |
| } |
| |
| uint8_t msc_sdmmc_read_sector(uint32_t sector, uint8_t* buff, uint32_t len, sdmmc_data_t *sdmmc) { |
| uint8_t ret=0; |
| uint count; |
| count = (len % sdmmc->sectSize) ? ((len / sdmmc->sectSize) + 1) : (len / sdmmc->sectSize); |
| |
| if (!count) |
| return ret; |
| |
| if (!(sdmmc->cardType & CT_BLOCK)) |
| sector *= sdmmc->sectSize; |
| if (count == 1) |
| { |
| if ((sdmmc_send_cmd(CMD17, sector, sdmmc) == 0) |
| && sdmmc_read_datablock(buff, sdmmc->sectSize, sdmmc)) |
| { |
| ret = 1; |
| } |
| led_blinking_task(); |
| } |
| else |
| { |
| if (sdmmc_send_cmd(CMD18, sector, sdmmc) == 0) |
| { |
| do |
| { |
| if (!sdmmc_read_datablock(buff, sdmmc->sectSize, sdmmc)) |
| break; |
| buff += sdmmc->sectSize; |
| led_blinking_task(); |
| } while (--count); |
| |
| sdmmc_send_cmd(CMD12, 0, sdmmc); |
| ret = 1; |
| } |
| } |
| led_blinking_task_off(); |
| sdmmc_deselect(sdmmc); |
| |
| return ret; |
| } |
| |
| uint8_t msc_sdmmc_write_sector(uint32_t sector, uint8_t *buff, uint32_t len, sdmmc_data_t *sdmmc) { |
| |
| uint8_t ret=0; |
| uint count; |
| count = (len % sdmmc->sectSize) ? ((len / sdmmc->sectSize)+1) : (len / sdmmc->sectSize); |
| |
| if (!count) |
| return ret; |
| |
| |
| |
| |
| |
| if (!(sdmmc->cardType & CT_BLOCK)) |
| sector *= sdmmc->sectSize; |
| |
| if (count == 1) |
| { |
| if ((sdmmc_send_cmd(CMD24, sector, sdmmc) == 0) |
| && sdmmc_write_datablock(buff, 0xFE, sdmmc)) |
| { |
| ret = 1; |
| } |
| led_blinking_task(); |
| } |
| else |
| { |
| if (sdmmc->cardType & CT_SDC) |
| sdmmc_send_cmd(ACMD23, count, sdmmc); |
| if (sdmmc_send_cmd(CMD25, sector, sdmmc) == 0) |
| { |
| do |
| { |
| if (!sdmmc_write_datablock(buff, 0xFC, sdmmc)) |
| break; |
| buff += sdmmc->sectSize; |
| |
| led_blinking_task(); |
| } while (--count); |
| |
| if (!sdmmc_write_datablock(0, 0xFD, sdmmc)) |
| count = 1; |
| ret =1; |
| } |
| } |
| led_blinking_task_off(); |
| sdmmc_deselect(sdmmc); |
| |
| } |
| |
| |
| void sdmmc_spi_port_init(sdmmc_data_t *sdmmc) |
| { |
| sdmmc->spiPort = SDMMC_SPI_PORT; |
| sdmmc->csPin = SDMMC_PIN_CS; |
| spi_init(sdmmc->spiPort, SPI_BAUDRATE_LOW); |
| gpio_set_function(SDMMC_PIN_MISO, GPIO_FUNC_SPI); |
| gpio_set_function(sdmmc->csPin, GPIO_FUNC_SIO); |
| gpio_set_function(SDMMC_PIN_SCK, GPIO_FUNC_SPI); |
| gpio_set_function(SDMMC_PIN_MOSI, GPIO_FUNC_SPI); |
| gpio_set_dir(sdmmc->csPin, GPIO_OUT); |
| gpio_put(sdmmc->csPin, 1); |
| |
| sdmmc->spiInit = true; |
| } |
| |
| |
| #ifdef __SPI_SDMMC_DMA |
| void config_spi_dma(sdmmc_data_t *sdmmc) |
| { |
| sdmmc->read_dma_ch = dma_claim_unused_channel(true); |
| sdmmc->write_dma_ch = dma_claim_unused_channel(true); |
| sdmmc->dma_rc = dma_channel_get_default_config(sdmmc->read_dma_ch); |
| sdmmc->dma_wc = dma_channel_get_default_config(sdmmc->write_dma_ch); |
| channel_config_set_transfer_data_size(&(sdmmc->dma_rc), DMA_SIZE_8); |
| channel_config_set_transfer_data_size(&(sdmmc->dma_wc), DMA_SIZE_8); |
| channel_config_set_read_increment(&(sdmmc->dma_rc), false); |
| channel_config_set_write_increment(&(sdmmc->dma_rc), true); |
| channel_config_set_read_increment(&(sdmmc->dma_wc), true); |
| channel_config_set_write_increment(&(sdmmc->dma_wc), false); |
| channel_config_set_dreq(&(sdmmc->dma_rc), spi_get_dreq(sdmmc->spiPort, false)); |
| channel_config_set_dreq(&(sdmmc->dma_wc), spi_get_dreq(sdmmc->spiPort, true)); |
| |
| for (int i = 0; i < SDMMC_SECT_SIZE; i++) |
| dummy_block[i] = 0xFF; |
| |
| dma_channel_configure(sdmmc->read_dma_ch, |
| &(sdmmc->dma_rc), |
| NULL, |
| &spi_get_hw(sdmmc->spiPort)->dr, |
| sdmmc->sectSize, false); |
| dma_channel_configure(sdmmc->write_dma_ch, |
| &(sdmmc->dma_wc), |
| &spi_get_hw(sdmmc->spiPort)->dr, |
| NULL, |
| sdmmc->sectSize, false); |
| sdmmc->dmaInit = true; |
| } |
| #endif |
| |
| |
| void sdmmc_spi_cs_low(sdmmc_data_t *sdmmc) |
| { |
| gpio_put(sdmmc->csPin, 0); |
| } |
| |
| void sdmmc_spi_cs_high(sdmmc_data_t *sdmmc) |
| { |
| gpio_put(sdmmc->csPin, 1); |
| } |
| |
| static void sdmmc_init_spi(sdmmc_data_t *sdmmc) |
| { |
| sdmmc_spi_port_init(sdmmc); |
| #ifdef __SPI_SDMMC_DMA |
| if (!sdmmc->dmaInit) |
| config_spi_dma(sdmmc); |
| #endif |
| |
| sleep_ms(10); |
| } |
| |
| |
| static void sdmmc_read_spi_dma( |
| uint8_t *buff, |
| uint btr, |
| sdmmc_data_t *sdmmc) |
| { |
| #ifdef __SPI_SDMMC_DMA |
| dma_channel_set_read_addr(sdmmc->write_dma_ch, dummy_block, false); |
| dma_channel_set_trans_count(sdmmc->write_dma_ch, btr, false); |
| |
| dma_channel_set_write_addr(sdmmc->read_dma_ch, buff, false); |
| dma_channel_set_trans_count(sdmmc->read_dma_ch, btr, false); |
| |
| dma_start_channel_mask((1u << (sdmmc->read_dma_ch)) | (1u << (sdmmc->write_dma_ch))); |
| dma_channel_wait_for_finish_blocking(sdmmc->read_dma_ch); |
| #else |
| spi_read_blocking(sdmmc->spiPort, 0xFF, buff, btr); |
| #endif |
| } |
| |
| |
| |
| static void sdmmc_write_spi_dma( |
| const uint8_t *buff, |
| uint btx, |
| sdmmc_data_t *sdmmc) |
| { |
| #ifdef __SPI_SDMMC_DMA |
| dma_channel_set_read_addr(sdmmc->write_dma_ch, buff, false); |
| dma_channel_set_trans_count(sdmmc->write_dma_ch, btx, false); |
| dma_channel_start(sdmmc->write_dma_ch); |
| dma_channel_wait_for_finish_blocking(sdmmc->write_dma_ch); |
| #else |
| spi_write_blocking(sdmmc->spiPort, buff, btx); |
| #endif |
| } |
| |
| |
| |
| |
| |
| static int sdmmc_wait_ready(uint timeout, sdmmc_data_t *sdmmc) |
| { |
| uint8_t dst; |
| absolute_time_t timeout_time = make_timeout_time_ms(timeout); |
| do |
| { |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &dst, 1); |
| } while (dst != 0xFF && 0 < absolute_time_diff_us(get_absolute_time(), timeout_time)); |
| |
| return (dst == 0xFF) ? 1 : 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int sdmmc_read_datablock( |
| uint8_t *buff, |
| uint btr, |
| sdmmc_data_t *sdmmc) |
| { |
| uint8_t token; |
| absolute_time_t timeout_time = make_timeout_time_ms(200); |
| do |
| { |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &token, 1); |
| |
| } while ((token == 0xFF) && 0 < absolute_time_diff_us(get_absolute_time(), timeout_time)); |
| if (token != 0xFE) |
| return 0; |
| |
| sdmmc_read_spi_dma(buff, btr, sdmmc); |
| |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &token, 1); |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &token, 1); |
| return 1; |
| } |
| |
| |
| |
| |
| |
| |
| int sdmmc_write_datablock( |
| const uint8_t *buff, |
| uint8_t token, |
| sdmmc_data_t *sdmmc) |
| { |
| uint8_t resp; |
| if (!sdmmc_wait_ready(500, sdmmc)) |
| return 0; |
| |
| spi_write_blocking(sdmmc->spiPort, &token, 1); |
| if (token != 0xFD) |
| { |
| sdmmc_write_spi_dma(buff, sdmmc->sectSize, sdmmc); |
| |
| token = 0xFF; |
| spi_write_blocking(sdmmc->spiPort, &token, 1); |
| spi_write_blocking(sdmmc->spiPort, &token, 1); |
| |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &resp, 1); |
| |
| if ((resp & 0x1F) != 0x05) |
| return 0; |
| } |
| return 1; |
| } |
| |
| |
| |
| |
| |
| |
| uint8_t sdmmc_send_cmd( |
| uint8_t cmd, |
| uint32_t arg, |
| sdmmc_data_t *sdmmc) |
| { |
| uint8_t n, res; |
| uint8_t tcmd[5]; |
| |
| if (cmd & 0x80) |
| { |
| cmd &= 0x7F; |
| res = sdmmc_send_cmd(CMD55, 0, sdmmc); |
| if (res > 1) |
| return res; |
| } |
| |
| |
| if (cmd != CMD12) |
| { |
| sdmmc_deselect(sdmmc); |
| if (!sdmmc_select(sdmmc)) |
| return 0xFF; |
| } |
| |
| |
| tcmd[0] = 0x40 | cmd; |
| tcmd[1] = (uint8_t)(arg >> 24); |
| tcmd[2] = (uint8_t)(arg >> 16); |
| tcmd[3] = (uint8_t)(arg >> 8); |
| tcmd[4] = (uint8_t)arg; |
| spi_write_blocking(sdmmc->spiPort, tcmd, 5); |
| n = 0x01; |
| if (cmd == CMD0) |
| n = 0x95; |
| if (cmd == CMD8) |
| n = 0x87; |
| |
| spi_write_blocking(sdmmc->spiPort, &n, 1); |
| |
| |
| if (cmd == CMD12) |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &res, 1); |
| n = 10; |
| do |
| { |
| spi_read_blocking(sdmmc->spiPort, 0xFF, &res, 1); |
| } while ((res & 0x80) && --n); |
| |
| return res; |
| } |
| |
| |
| |
| |
| uint8_t sdmmc_init(sdmmc_data_t *sdmmc) |
| { |
| uint8_t n, cmd, ty, src, ocr[4]; |
| |
| sdmmc->Stat = RES_OK; |
| |
| spi_set_baudrate(sdmmc->spiPort, SPI_BAUDRATE_LOW); |
| src = 0xFF; |
| sdmmc_spi_cs_low(sdmmc); |
| for (n = 10; n; n--) |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| sdmmc_spi_cs_high(sdmmc); |
| |
| ty = 0; |
| if (sdmmc_send_cmd(CMD0, 0, sdmmc) == 1) |
| { |
| absolute_time_t timeout_time = make_timeout_time_ms(1000); |
| if (sdmmc_send_cmd(CMD8, 0x1AA, sdmmc) == 1) |
| { |
| spi_read_blocking(sdmmc->spiPort, 0xFF, ocr, 4); |
| if (ocr[2] == 0x01 && ocr[3] == 0xAA) |
| { |
| while ((0 < absolute_time_diff_us(get_absolute_time(), timeout_time)) && sdmmc_send_cmd(ACMD41, 1UL << 30, sdmmc)) |
| ; |
| if ((0 < absolute_time_diff_us(get_absolute_time(), timeout_time)) && sdmmc_send_cmd(CMD58, 0, sdmmc) == 0) |
| { |
| spi_read_blocking(sdmmc->spiPort, 0xFF, ocr, 4); |
| ty = (ocr[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; |
| } |
| } |
| } |
| else |
| { |
| if (sdmmc_send_cmd(ACMD41, 0, sdmmc) <= 1) |
| { |
| ty = CT_SDC1; |
| cmd = ACMD41; |
| } |
| else |
| { |
| ty = CT_MMC3; |
| cmd = CMD1; |
| } |
| while ((0 < absolute_time_diff_us(get_absolute_time(), timeout_time)) && sdmmc_send_cmd(cmd, 0, sdmmc)) |
| ; |
| if (!(0 < absolute_time_diff_us(get_absolute_time(), timeout_time)) || sdmmc_send_cmd(CMD16, SDMMC_SECT_SIZE, sdmmc) != 0) |
| ty = 0; |
| } |
| } |
| sdmmc->cardType = ty; |
| sdmmc_deselect(sdmmc); |
| if (ty) |
| { |
| |
| printf("\nThe actual baudrate(SD/MMC):%d\n",spi_set_baudrate(sdmmc->spiPort, SPI_BAUDRATE_HIGH)); |
| sdmmc->sectSize = SDMMC_SECT_SIZE; |
| sdmmc->Stat = RES_OK; |
| } |
| else |
| { |
| sdmmc->Stat = STA_NOINIT; |
| } |
| sdmmc->sectCount = sdmmc_get_sector_count(sdmmc); |
| return sdmmc->Stat; |
| } |
| |
| |
| DSTATUS sdmmc_disk_initialize(sdmmc_data_t *sdmmc) |
| { |
| if (!sdmmc->spiInit) |
| sdmmc_init_spi(sdmmc); |
| DSTATUS stat = sdmmc_init(sdmmc); |
| |
| return stat; |
| } |
| |
| DSTATUS sdmmc_disk_status(sdmmc_data_t *sdmmc) |
| { |
| return sdmmc->Stat; |
| } |
| |
| |
| DSTATUS sdmmc_disk_read( |
| BYTE *buff, |
| LBA_t sector, |
| UINT count, |
| sdmmc_data_t *sdmmc) |
| { |
| DWORD sect = (DWORD)(sector); |
| |
| if (!count) |
| return RES_PARERR; |
| if (sdmmc->Stat & STA_NOINIT) |
| return RES_NOTRDY; |
| |
| if (!(sdmmc->cardType & CT_BLOCK)) |
| sect *= 512; |
| if (count == 1) |
| { |
| if ((sdmmc_send_cmd(CMD17, sect, sdmmc) == 0) |
| && sdmmc_read_datablock(buff, 512, sdmmc)) |
| { |
| count = 0; |
| } |
| |
| } |
| else |
| { |
| if (sdmmc_send_cmd(CMD18, sect, sdmmc) == 0) |
| { |
| do |
| { |
| if (!sdmmc_read_datablock(buff, 512, sdmmc)) |
| break; |
| buff += 512; |
| |
| } while (--count); |
| |
| sdmmc_send_cmd(CMD12, 0, sdmmc); |
| } |
| } |
| |
| sdmmc_deselect(sdmmc); |
| |
| return count ? RES_ERROR : RES_OK; |
| } |
| |
| DSTATUS sdmmc_disk_write( |
| const BYTE *buff, |
| LBA_t sector, |
| UINT count, |
| sdmmc_data_t *sdmmc) |
| { |
| DWORD sect = (DWORD)sector; |
| if (!count) |
| return RES_PARERR; |
| if (sdmmc->Stat & STA_NOINIT) |
| return RES_NOTRDY; |
| if (sdmmc->Stat & STA_PROTECT) |
| return RES_WRPRT; |
| |
| if (!(sdmmc->cardType & CT_BLOCK)) |
| sect *= 512; |
| |
| if (count == 1) |
| { |
| if ((sdmmc_send_cmd(CMD24, sect, sdmmc) == 0) |
| && sdmmc_write_datablock(buff, 0xFE, sdmmc)) |
| { |
| count = 0; |
| } |
| |
| } |
| else |
| { |
| if (sdmmc->cardType & CT_SDC) |
| sdmmc_send_cmd(ACMD23, count, sdmmc); |
| if (sdmmc_send_cmd(CMD25, sect, sdmmc) == 0) |
| { |
| do |
| { |
| if (!sdmmc_write_datablock(buff, 0xFC, sdmmc)) |
| break; |
| buff += 512; |
| |
| |
| } while (--count); |
| |
| if (!sdmmc_write_datablock(0, 0xFD, sdmmc)) |
| count = 1; |
| } |
| } |
| |
| sdmmc_deselect(sdmmc); |
| |
| return count ? RES_ERROR : RES_OK; |
| } |
| |
| |
| DSTATUS sdmmc_disk_ioctl( |
| BYTE cmd, |
| void *buff, |
| sdmmc_data_t *sdmmc) |
| { |
| DRESULT res; |
| BYTE n, csd[16]; |
| DWORD st, ed, csize; |
| LBA_t *dp; |
| |
| BYTE src = 0xFF; |
| |
| if (sdmmc->Stat & STA_NOINIT) |
| return RES_NOTRDY; |
| |
| res = RES_ERROR; |
| switch (cmd) |
| { |
| case CTRL_SYNC: |
| if (sdmmc_select(sdmmc)) |
| res = RES_OK; |
| break; |
| case GET_SECTOR_COUNT: |
| if ((sdmmc_send_cmd(CMD9, 0, sdmmc) == 0) && sdmmc_read_datablock(csd, 16, sdmmc)) |
| { |
| if ((csd[0] >> 6) == 1) |
| { |
| csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; |
| *(LBA_t *)buff = csize << 10; |
| } |
| else |
| { |
| n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; |
| csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; |
| *(LBA_t *)buff = csize << (n - 9); |
| } |
| res = RES_OK; |
| } |
| break; |
| case GET_SECTOR_SIZE: |
| |
| *(WORD *)buff = sdmmc->sectSize; |
| |
| res = RES_OK; |
| break; |
| case GET_BLOCK_SIZE: |
| if (sdmmc->cardType & CT_SDC2) |
| { |
| if (sdmmc_send_cmd(ACMD13, 0, sdmmc) == 0) |
| { |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| if (sdmmc_read_datablock(csd, 16, sdmmc)) |
| { |
| for (n = 64 - 16; n; n--) |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| *(DWORD *)buff = 16UL << (csd[10] >> 4); |
| res = RES_OK; |
| } |
| } |
| } |
| else |
| { |
| if ((sdmmc_send_cmd(CMD9, 0, sdmmc) == 0) && sdmmc_read_datablock(csd, 16, sdmmc)) |
| { |
| if (sdmmc->cardType & CT_SDC1) |
| { |
| *(DWORD *)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); |
| } |
| else |
| { |
| *(DWORD *)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); |
| } |
| res = RES_OK; |
| } |
| } |
| break; |
| |
| case CTRL_TRIM: |
| if (!(sdmmc->cardType & CT_SDC)) |
| break; |
| if (sdmmc_disk_ioctl(MMC_GET_CSD, csd, sdmmc)) |
| break; |
| if (!(csd[10] & 0x40)) |
| break; |
| dp = buff; |
| st = (DWORD)dp[0]; |
| ed = (DWORD)dp[1]; |
| if (!(sdmmc->cardType & CT_BLOCK)) |
| { |
| st *= 512; |
| ed *= 512; |
| } |
| if (sdmmc_send_cmd(CMD32, st, sdmmc) == 0 && sdmmc_send_cmd(CMD33, ed, sdmmc) == 0 && sdmmc_send_cmd(CMD38, 0, sdmmc) == 0 && sdmmc_wait_ready(30000, sdmmc)) |
| { |
| res = RES_OK; |
| } |
| break; |
| |
| |
| |
| case MMC_GET_TYPE: |
| *(BYTE *)buff = sdmmc->cardType; |
| res = RES_OK; |
| break; |
| |
| case MMC_GET_CSD: |
| if (sdmmc_send_cmd(CMD9, 0, sdmmc) == 0 && sdmmc_read_datablock((BYTE *)buff, 16, sdmmc)) |
| { |
| res = RES_OK; |
| } |
| break; |
| |
| case MMC_GET_CID: |
| if (sdmmc_send_cmd(CMD10, 0, sdmmc) == 0 && sdmmc_read_datablock((BYTE *)buff, 16, sdmmc)) |
| { |
| res = RES_OK; |
| } |
| break; |
| |
| case MMC_GET_OCR: |
| if (sdmmc_send_cmd(CMD58, 0, sdmmc) == 0) |
| { |
| for (n = 0; n < 4; n++) |
| *(((BYTE *)buff) + n) = spi_write_blocking(sdmmc->spiPort, &src, 1); |
| res = RES_OK; |
| } |
| break; |
| |
| case MMC_GET_SDSTAT: |
| if (sdmmc_send_cmd(ACMD13, 0, sdmmc) == 0) |
| { |
| spi_write_blocking(sdmmc->spiPort, &src, 1); |
| if (sdmmc_read_datablock((BYTE *)buff, 64, sdmmc)) |
| res = RES_OK; |
| } |
| break; |
| |
| default: |
| res = RES_PARERR; |
| } |
| |
| sdmmc_deselect(sdmmc); |
| |
| return res; |
| } |
| |
| |