diff --git a/examples/sdio_raw/Makefile b/examples/sdio_raw/Makefile new file mode 100644 index 0000000..1629f05 --- /dev/null +++ b/examples/sdio_raw/Makefile @@ -0,0 +1,4 @@ +PROGRAM = sdio_raw +EXTRA_COMPONENTS = extras/sdio +#ESPBAUD = 460800 +include ../../common.mk diff --git a/examples/sdio_raw/main.c b/examples/sdio_raw/main.c new file mode 100644 index 0000000..0d620fc --- /dev/null +++ b/examples/sdio_raw/main.c @@ -0,0 +1,117 @@ +/* + * Example of using SDIO driver + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include +#include +#include + +// Blink while IO :) +#define CS_GPIO_PIN 2 +// Set SPI frequency to 20MHz +#define SDIO_SPI_FREQ_DIV SPI_FREQ_DIV_20M + +static const char *errors[] = { + [SDIO_ERR_NONE] = NULL, + [SDIO_ERR_TIMEOUT] = "Timeout", + [SDIO_ERR_UNSUPPORTED] = "Unsupported", + [SDIO_ERR_IO] = "General I/O error", + [SDIO_ERR_CRC] = "CRC check failed" +}; + +static const char *types[] = { + [SDIO_TYPE_UNKNOWN] = "Unknown", + [SDIO_TYPE_MMC] = "MMC", + [SDIO_TYPE_SD1] = "SD v1.x", + [SDIO_TYPE_SD2] = "SD v2.x", + [SDIO_TYPE_SDHC] = "SDHC", +}; + +static void dump_line(const uint8_t *data) +{ + for (uint8_t i = 0; i < 16; i ++) + printf(" %02x", data[i]); + printf("\n"); +} + +static uint8_t buffer[SDIO_BLOCK_SIZE]; + +#define TEST_COUNT 1000 + +inline static void test_read(sdio_card_t *card) +{ + printf("Simple random access test speed: "); + uint32_t start = sdk_system_get_time(); + //sdk_system_update_cpu_freq(160); + for (uint32_t i = 0; i < TEST_COUNT; i ++) + { + printf("%08u / %08u\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08", i + 1, TEST_COUNT); + if (sdio_read_sectors(card, hwrand() % card->sectors, buffer, 1) != SDIO_ERR_NONE) + { + printf("Error: %d (%s)\n", card->error, errors[card->error]); + return; + } + } + uint32_t time = sdk_system_get_time() - start; + float speed = (float)TEST_COUNT / time * 1000000; + float stime = (time / 1000000.0) / TEST_COUNT; + uint32_t bs = (uint32_t)speed * 512; + printf("\nDone. Time: %u ms, speed: %.4f sectors/s, sector in %.4f s, %u bytes/s \n", time, speed, stime, bs); +} + +inline static void dump_card(sdio_card_t *card) +{ + char product_name[6]; + memcpy(product_name, card->cid.bits.product_name, 5); + product_name[5] = 0; + + printf("-------------------------------------------\n"); + printf(" SD/MMC card info\n"); + printf("-------------------------------------------\n"); + printf("%20s : %s\n", "Card type", types[card->type]); + printf("%20s : %s\n", "CRC enabled", card->crc_enabled ? "yes" : "no"); + printf("%20s : %d\n", "512 byte sectors", card->sectors); + printf("%20s : 0x%02x\n", "Manufacturer ID", card->cid.bits.manufacturer_id); + printf("%20s : %c%c\n", "OEM ID", card->cid.bits.oem_id[0], card->cid.bits.oem_id[1]); + printf("%20s : %s\n", "Product name", product_name); + printf("%20s : %d.%d\n", "Product revision", card->cid.bits.product_rev_major, card->cid.bits.product_rev_minor); + printf("%20s : 0x%08x\n", "Serial #", card->cid.bits.product_serial); + printf("%20s : %02d / %04d\n", "Manufacturing date", card->cid.bits.date_month, card->cid.bits.date_year_h * 10 + card->cid.bits.date_year_l + 2000); + printf("%20s : 0x%08x\n", "OCR", card->ocr.data); + printf("%20s :", "CID"); + dump_line(card->cid.data); + printf("%20s :", "CSD"); + dump_line(card->csd.data); + test_read(card); +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); + + while (true) + { + printf("\nInitializing card...\n"); + do + { + sdio_card_t card; + if (sdio_init(&card, CS_GPIO_PIN, SDIO_SPI_FREQ_DIV)) + { + printf("Error: %d (%s)\n", card.error, errors[card.error]); + break; + } + dump_card(&card); + } while (0); + + for (size_t i = 0; i < 1000; i ++) + sdk_os_delay_us(1000); + } +} diff --git a/examples/sdio_raw/schematics.png b/examples/sdio_raw/schematics.png new file mode 100644 index 0000000..93fb227 Binary files /dev/null and b/examples/sdio_raw/schematics.png differ diff --git a/extras/sdio/component.mk b/extras/sdio/component.mk new file mode 100644 index 0000000..5ed3ce0 --- /dev/null +++ b/extras/sdio/component.mk @@ -0,0 +1,7 @@ +# Component makefile for extras/sdio +INC_DIRS += $(sdio_ROOT).. + +# args for passing into compile rule generation +sdio_SRC_DIR = $(sdio_ROOT) + +$(eval $(call component_compile_rules,sdio)) \ No newline at end of file diff --git a/extras/sdio/sdio.c b/extras/sdio/sdio.c new file mode 100644 index 0000000..573d038 --- /dev/null +++ b/extras/sdio/sdio.c @@ -0,0 +1,449 @@ +/* + * Hardware SPI driver for MMC/SD/SDHC cards + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include "sdio.h" + +#define BUS 1 + +#define BV(x) (1 << (x)) + +#define MS 1000 + +#define INIT_TIMEOUT_US (2000 * MS) +#define IO_TIMEOUT_US (500 * MS) + +#define MAX_ERR_COUNT 0xff + +#define R1_IDLE_STATE 0 +#define R1_ERASE_RESET 1 +#define R1_ILLEGAL_CMD 2 +#define R1_CRC_ERR 3 +#define R1_ERASE_SEQ_ERR 4 +#define R1_ADDR_ERR 5 +#define R1_PARAM_ERR 6 +#define R1_BUSY 7 +#define R2_LOCKED 8 +#define R2_WPE_SKIP_LF 9 +#define R2_ERROR 10 +#define R2_CC_ERROR 11 +#define R2_ECC_FAILED 12 +#define R2_WP_VIOLATION 13 +#define R2_ERASE_PARAM 14 +#define R2_OUT_OF_RANGE 15 + +#define OCR_CCS 30 +#define OCR_BUSY 31 +#define OCR_SDHC (BV(OCR_CCS) | BV(OCR_BUSY)) + +#define TOKEN_SINGLE_TRAN 0xfe +#define TOKEN_MULTI_TRAN 0xfc +#define TOKEN_STOP_TRAN 0xfd +#define WRITE_RES_MASK 0x1f +#define WRITE_RES_OK 0x05 + + +#define CMD0 0x00 // GO_IDLE_STATE - Resets the SD Memory Card +#define CMD1 0x01 // SEND_OP_COND - Sends host capacity support information + // and activates the card's initialization process. +#define CMD6 0x06 // SWITCH_FUNC - Checks switchable function (mode 0) and + // switches card function (mode 1). +#define CMD8 0x08 // SEND_IF_COND - Sends SD Memory Card interface condition + // that includes host supply voltage information and asks + // the accessed card whether card can operate in supplied + // voltage range. +#define CMD9 0x09 // SEND_CSD - Asks the selected card to send its + // card-specific data (CSD register) +#define CMD10 0x0a // SEND_CID - Asks the selected card to send its card + // identification (CID register) +#define CMD12 0x0c // STOP_TRANSMISSION - Forces the card to stop transmission + // in Multiple Block Read Operation +#define CMD13 0x0d // SEND_STATUS - Asks the selected card to send its + // status register. +#define CMD16 0x10 // SET_BLOCKLEN - Sets a block length (in bytes) for all + // following block commands (read and write) of a Standard + // Capacity Card. Block length of the read and write + // commands are fixed to 512 bytes in a High Capacity Card. + // The length of LOCK_UNLOCK command is set by this command + // in both capacity cards. +#define CMD17 0x11 // READ_SINGLE_BLOCK - Reads a block of the size selected + // by the SET_BLOCKLEN command. +#define CMD18 0x12 // READ_MULTIPLE_BLOCK - Continuously transfers data blocks + // from card to host until interrupted by a + // STOP_TRANSMISSION command. +#define CMD24 0x18 // WRITE_BLOCK - Writes a block of the size selected by the + // SET_BLOCKLEN command. +#define CMD25 0x19 // WRITE_MULTIPLE_BLOCK - Continuously writes blocks of + // data until ’Stop Tran’ token is sent (instead ’Start + // Block’). +#define CMD27 0x1b // PROGRAM_CSD - Programming of the programmable bits of + // the CSD. +#define CMD28 0x1c // SET_WRITE_PROT +#define CMD29 0x1d // CLR_WRITE_PROT +#define CMD32 0x20 // ERASE_WR_BLK_START - Sets the address of the first block + // to be erased. +#define CMD33 0x21 // ERASE_WR_BLK_END - Sets the address of the last block of + // the continuous range to be erased. +#define CMD38 0x26 // ERASE - Erases all previously selected blocks. +#define CMD55 0x37 // APP_CMD - Defines to the card that the next command is + // an application specific command rather than a standard + // command. +#define CMD58 0x3a // READ_OCR - Reads the OCR register of a card. +#define CMD59 0x3b // CRC_ON_OFF - Turns the CRC option on or off. + +#define ACMD23 0x17 // SET_WR_BLK_ERASE_COUNT - Sets the number of write blocks + // to be pre-erased before writing +#define ACMD41 0x29 // SD_SEND_OP_COMD - Sends host capacity support information + // and activates the card's initialization process + +static uint8_t crc7(const uint8_t* data, uint8_t n) +{ + uint8_t crc = 0; + for (uint8_t i = 0; i < n; i++) + { + uint8_t d = data[i]; + for (uint8_t j = 0; j < 8; j++) + { + crc <<= 1; + if ((d & 0x80) ^ (crc & 0x80)) + crc ^= 0x09; + d <<= 1; + } + } + return (crc << 1) | 1; +} + +static uint16_t crc_ccitt(const uint8_t *data, size_t n) +{ + uint16_t crc = 0; + for (size_t i = 0; i < n; i++) + { + crc = (uint8_t)(crc >> 8) | (crc << 8); + crc ^= data[i]; + crc ^= (uint8_t)(crc & 0xff) >> 4; + crc ^= crc << 12; + crc ^= (crc & 0xff) << 5; + } + return crc; +} + +#define spi_cs_low(card) do { gpio_write(card->cs_pin, false); } while(0) +#define spi_cs_high(card) do { gpio_write(card->cs_pin, true); } while(0) +#define spi_read_byte() (spi_transfer_8(BUS, 0xff)) +#define spi_read_word() (((uint16_t)spi_read_byte() << 8) | spi_read_byte()) +#define spi_read_dword() (((uint32_t)spi_read_byte() << 24) | ((uint32_t)spi_read_byte() << 16) | ((uint32_t)spi_read_byte() << 8) | spi_read_byte()) +#define spi_skip_word() do { spi_read_byte(); spi_read_byte(); } while(0) +#define spi_skip_dword() do { spi_read_byte(); spi_read_byte(); spi_read_byte(); spi_read_byte(); } while(0) + +inline static uint16_t spi_write_word(uint16_t word) +{ + return (spi_transfer_8(BUS, word >> 8) << 8) | spi_transfer_8(BUS, word); +} + +inline static void spi_read_bytes(uint8_t *dst, size_t size) +{ + for (uint8_t *offs = dst; offs < dst + size; offs ++) + *offs = spi_read_byte(); +} + +static bool wait() +{ + uint32_t stop = sdk_system_get_time() + IO_TIMEOUT_US; + while (spi_read_byte() != 0xff) + if (sdk_system_get_time() >= stop) + return false; + return true; +} + +static uint8_t command(sdio_card_t *card, uint8_t cmd, uint32_t arg) +{ + uint8_t buf[6] = { + cmd | 0x40, + arg >> 24, + arg >> 16, + arg >> 8, + arg + }; + if (card->crc_enabled) + buf[5] = crc7(buf, 5); + else + buf[5] = cmd == CMD0 ? 0x95 : 0x87; + + spi_cs_low(card); + wait(); + spi_transfer(BUS, buf, NULL, 6, SPI_8BIT); + + // R1b response + if (cmd == CMD12 || cmd == CMD28 || cmd == CMD29) + spi_read_byte(); + + uint8_t res; + for (uint8_t i = 0; i < MAX_ERR_COUNT; i ++) + { + res = spi_read_byte(); + if (!(res & BV(R1_BUSY))) + break; + } + return res; +} + +inline static uint8_t app_command(sdio_card_t *card, uint8_t cmd, uint32_t arg) +{ + command(card, CMD55, 0); + return command(card, cmd, arg); +} + +inline static sdio_error_t set_error(sdio_card_t *card, sdio_error_t err) +{ + card->error = err; + spi_cs_high(card); + return err; +} + +static sdio_error_t read_data(sdio_card_t *card, uint8_t *dst, size_t size) +{ + uint32_t timeout = sdk_system_get_time() + IO_TIMEOUT_US; + + while (true) + { + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + + uint8_t b = spi_read_byte(); + if (b == TOKEN_SINGLE_TRAN) + break; + + if (b != 0xff) + return set_error(card, SDIO_ERR_IO); + } + + spi_read_bytes(dst, size); + + uint16_t crc = spi_read_word(); + if (card->crc_enabled && crc_ccitt(dst, size) != crc) + return set_error(card, SDIO_ERR_CRC); + + return SDIO_ERR_NONE; +} + +static sdio_error_t read_register(sdio_card_t *card, uint8_t cmd, void *dst) +{ + if (command(card, cmd, 0)) + return set_error(card, SDIO_ERR_IO); + return read_data(card, dst, 16); +} + +static sdio_error_t write_data_block(sdio_card_t *card, uint8_t token, uint8_t *src) +{ + if (!wait()) + return set_error(card, SDIO_ERR_TIMEOUT); + spi_transfer_8(BUS, token); + spi_transfer(BUS, src, NULL, SDIO_BLOCK_SIZE, SPI_8BIT); + spi_write_word(card->crc_enabled ? crc_ccitt(src, SDIO_BLOCK_SIZE) : 0xffff); + + if ((spi_read_byte() & WRITE_RES_MASK) != WRITE_RES_OK) + return set_error(card, SDIO_ERR_IO); + + return SDIO_ERR_NONE; +} + +sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_divider) +{ + card->cs_pin = cs_pin; + card->type = SDIO_TYPE_UNKNOWN; + + // setup SPI at 125kHz + spi_settings_t s = { + .mode = SPI_MODE0, + .freq_divider = SPI_FREQ_DIV_125K, + .msb = true, + .endianness = SPI_LITTLE_ENDIAN, + .minimal_pins = true + }; + spi_set_settings(BUS, &s); + gpio_enable(card->cs_pin, GPIO_OUTPUT); + + uint32_t timeout = sdk_system_get_time() + INIT_TIMEOUT_US; + + spi_cs_low(card); + spi_cs_high(card); + for (uint8_t i = 0; i < 10; i++) + spi_read_byte(); + + // Set card to the SPI idle mode + while (command(card, CMD0, 0) != BV(R1_IDLE_STATE)) + { + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + } + + // Enable CRC + card->crc_enabled = command(card, CMD59, 1) == BV(R1_IDLE_STATE); + + // Get card type + while (true) + { + if (command(card, CMD8, 0x1aa) & BV(R1_ILLEGAL_CMD)) + { + card->type = SDIO_TYPE_SD1; + break; + } + if ((spi_read_dword() & 0xff) == 0xaa) + { + card->type = SDIO_TYPE_SD2; + break; + } + + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + } + + if (card->type == SDIO_TYPE_SD1) + { + // SD1 or MMC3 + if (app_command(card, ACMD41, 0) > 1) + { + card->type = SDIO_TYPE_MMC; + while (command(card, CMD1, 0)) + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + } + else + { + while (app_command(card, ACMD41, 0)) + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + } + + if (command(card, CMD16, SDIO_BLOCK_SIZE)) + return set_error(card, SDIO_ERR_UNSUPPORTED); + } + else + { + // SD2 or SDHC + while (app_command(card, ACMD41, BV(30)) != 0) + if (sdk_system_get_time() >= timeout) + return set_error(card, SDIO_ERR_TIMEOUT); + } + // read OCR + if (command(card, CMD58, 0)) + return set_error(card, SDIO_ERR_IO); + card->ocr.data = spi_read_dword(); + + if (card->type == SDIO_TYPE_SD2 && (card->ocr.data & OCR_SDHC) == OCR_SDHC) + card->type = SDIO_TYPE_SDHC; + + spi_set_frequency_div(BUS, high_freq_divider); + + if (read_register(card, CMD10, &card->cid.data) != SDIO_ERR_NONE) + return card->error; + if (read_register(card, CMD9, &card->csd.data) != SDIO_ERR_NONE) + return card->error; + + // Card size + if (card->csd.v1.csd_ver == 0) + card->sectors = (uint32_t)(((card->csd.v1.c_size_high << 10) | (card->csd.v1.c_size_mid << 2) | card->csd.v1.c_size_low) + 1) + << (((card->csd.v1.c_size_mult_high << 1) | card->csd.v1.c_size_mult_low) + card->csd.v1.read_bl_len - 7); + else if (card->csd.v2.csd_ver == 1) + card->sectors = (((uint32_t)card->csd.v2.c_size_high << 16) + ((uint32_t)card->csd.v2.c_size_mid << 8) + card->csd.v2.c_size_low + 1) << 10; + else + return set_error(card, SDIO_ERR_UNSUPPORTED); + + return set_error(card, SDIO_ERR_NONE); +} + +sdio_error_t sdio_read_sectors(sdio_card_t *card, uint32_t sector, uint8_t *dst, uint32_t count) +{ + if (!count) + return set_error(card, SDIO_ERR_IO); + + if (card->type != SDIO_TYPE_SDHC) + sector <<= 9; + + bool multi = count > 1; + if (command(card, multi ? CMD18 : CMD17, sector)) + return set_error(card, SDIO_ERR_IO); + + while (count--) + { + if (read_data(card, dst, SDIO_BLOCK_SIZE) != SDIO_ERR_NONE) + return card->error; + dst += SDIO_BLOCK_SIZE; + } + + if (multi && command(card, CMD12, 0)) + return set_error(card, SDIO_ERR_IO); + + return set_error(card, SDIO_ERR_NONE); +} + +sdio_error_t sdio_write_sectors(sdio_card_t *card, uint32_t sector, uint8_t *src, uint32_t count) +{ + if (!count) + return set_error(card, SDIO_ERR_IO); + + if (card->type != SDIO_TYPE_SDHC) + sector <<= 9; + + if (count == 1) + { + // single block + if (command(card, CMD24, sector)) + return set_error(card, SDIO_ERR_IO); + return set_error(card, write_data_block(card, TOKEN_SINGLE_TRAN, src)); + } + + // send pre-erase count + if ((card->type == SDIO_TYPE_SD1 + || card->type == SDIO_TYPE_SD2 + || card->type == SDIO_TYPE_SDHC) + && app_command(card, ACMD23, count)) + { + return set_error(card, SDIO_ERR_IO); + } + + if (command(card, CMD25, sector)) + return set_error(card, SDIO_ERR_IO); + + while (count--) + { + if (write_data_block(card, TOKEN_MULTI_TRAN, src) != SDIO_ERR_NONE) + return card->error; + src += SDIO_BLOCK_SIZE; + } + spi_transfer_8(BUS, TOKEN_STOP_TRAN); + + return set_error(card, SDIO_ERR_NONE); +} + +sdio_error_t sdio_erase_sectors(sdio_card_t *card, uint32_t first, uint32_t last) +{ + if (!card->csd.v1.erase_blk_en) + { + uint8_t mask = (card->csd.v1.sector_size_high << 1) | card->csd.v1.sector_size_low; + if ((first & mask) || ((last + 1) & mask)) + return set_error(card, SDIO_ERR_UNSUPPORTED); + } + + if (card->type != SDIO_TYPE_SDHC) + { + first <<= 9; + last <<= 9; + } + + if (command(card, CMD32, first) + || command(card, CMD33, last) + || command(card, CMD38, 0)) + { + return set_error(card, SDIO_ERR_IO); + } + + return set_error(card, wait() ? SDIO_ERR_NONE : SDIO_ERR_TIMEOUT); +} + diff --git a/extras/sdio/sdio.h b/extras/sdio/sdio.h new file mode 100644 index 0000000..c51200d --- /dev/null +++ b/extras/sdio/sdio.h @@ -0,0 +1,98 @@ +/* + * Hardware SPI driver for MMC/SD/SDHC cards + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef _EXTRAS_SDIO_H_ +#define _EXTRAS_SDIO_H_ + +#include +#include +#include +#include "sdio_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SDIO_BLOCK_SIZE 512 + +typedef enum { + SDIO_ERR_NONE = 0, + SDIO_ERR_TIMEOUT, + SDIO_ERR_UNSUPPORTED, + SDIO_ERR_IO, + SDIO_ERR_CRC +} sdio_error_t; + +typedef enum { + SDIO_TYPE_UNKNOWN = 0, + SDIO_TYPE_MMC, + SDIO_TYPE_SD1, + SDIO_TYPE_SD2, + SDIO_TYPE_SDHC +} sdio_card_type_t; + +/** + * SD card descriptor + */ +typedef struct +{ + sdio_error_t error; //!< Last operation result + uint8_t cs_pin; //!< Chip Select GPIO pin + sdio_card_type_t type; //!< Card type + bool crc_enabled; //!< True if CRC enabled for IO + sdio_ocr_t ocr; //!< OCR register + sdio_csd_t csd; //!< CSD register + sdio_cid_t cid; //!< CID register + uint32_t sectors; //!< Card size in 512 byte sectors +} sdio_card_t; + +/** + * \brief Init SD card + * Device descriptor (registers, sectors count and so on) will be filled during initialization + * SPI_FREQ_DIV_40M is good for modern SD cards, older SD can use SPI_FREQ_DIV_20M and lower + * \param card Pointer to the device descriptor + * \param cs_pin GPIO pin used for CS + * \param high_freq_divider SPI bus frequency divider + * \return Operation result + */ +sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_divider); + +/** + * \brief Read 512 byte sectors from SD card + * \param card Pointer to the device descriptor + * \param sector Start sector + * \param dst Receive buffer + * \param count Number of sectors to read + * \return Operation result + */ +sdio_error_t sdio_read_sectors(sdio_card_t *card, uint32_t sector, uint8_t *dst, uint32_t count); + +/** + * \brief Write 512 byte sectors to SD card + * \param card Pointer to the device descriptor + * \param sector Start sector + * \param src Data to write + * \param count Number of sectors to read + * \return Operation result + */ +sdio_error_t sdio_write_sectors(sdio_card_t *card, uint32_t sector, uint8_t *src, uint32_t count); + +/** + * \brief Erase 512 byte sectors from SD card + * \param card Pointer to the device descriptor + * \param first First sector to erase + * \param last Last sector to erase + * \return Operation result + */ +sdio_error_t sdio_erase_sectors(sdio_card_t *card, uint32_t first, uint32_t last); + + +#ifdef __cplusplus +} +#endif + +#endif /* _EXTRAS_SDIO_H_ */ diff --git a/extras/sdio/sdio_impl.h b/extras/sdio/sdio_impl.h new file mode 100644 index 0000000..fc6a251 --- /dev/null +++ b/extras/sdio/sdio_impl.h @@ -0,0 +1,154 @@ +/* + * Hardware SPI driver for MMC/SD/SDHC cards + * + * Part of esp-open-rtos + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef _EXTRAS_SDIO_IMPL_H_ +#define _EXTRAS_SDIO_IMPL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union +{ + uint32_t data; + struct + { + uint16_t reserverd1 :15; + uint8_t vcc_2v7_2v8 :1; + uint8_t vcc_2v8_2v9 :1; + uint8_t vcc_2v9_3v0 :1; + uint8_t vcc_3v0_3v1 :1; + uint8_t vcc_3v1_3v2 :1; + uint8_t vcc_3v2_3v3 :1; + uint8_t vcc_3v3_3v4 :1; + uint8_t vcc_3v4_3v5 :1; + uint8_t vcc_3v5_3v6 :1; + uint8_t reserverd2 :6; + uint8_t ccs :1; + uint8_t busy :1; + } __attribute__((packed)) bits; +} sdio_ocr_t; + +typedef union +{ + uint8_t data[16]; + struct + { + uint8_t manufacturer_id; + char oem_id[2]; + char product_name[5]; + uint8_t product_rev_minor :4; + uint8_t product_rev_major :4; + uint32_t product_serial; + uint8_t reserved1 :4; + uint8_t date_year_h :4; + uint8_t date_year_l :4; + uint8_t date_month :4; + uint8_t always1 :1; + uint8_t crc :7; + } __attribute__((packed)) bits; +} sdio_cid_t; + +typedef union +{ + uint8_t data[16]; + struct + { + uint8_t reserved1 :6; + uint8_t csd_ver :2; + uint8_t taac; + uint8_t nsac; + uint8_t tran_speed; + uint8_t ccc_high; + uint8_t read_bl_len :4; + uint8_t ccc_low :4; + uint16_t c_size_high :2; + uint8_t reserved2 :2; + uint8_t dsr_imp :1; + uint8_t read_blk_misalign :1; + uint8_t write_blk_misalign :1; + uint8_t read_bl_partial :1; + uint8_t c_size_mid; + uint8_t vdd_r_curr_max :3; + uint8_t vdd_r_curr_min :3; + uint8_t c_size_low :2; + uint8_t c_size_mult_high :2; + uint8_t vdd_w_cur_max :3; + uint8_t vdd_w_curr_min :3; + uint8_t sector_size_high :6; + uint8_t erase_blk_en :1; + uint8_t c_size_mult_low :1; + uint8_t wp_grp_size :7; + uint8_t sector_size_low :1; + uint8_t write_bl_len_high :2; + uint8_t r2w_factor :3; + uint8_t reserved3 :2; + uint8_t wp_grp_enable :1; + uint8_t reserved4 :5; + uint8_t write_partial :1; + uint8_t write_bl_len_low :2; + uint8_t reserved5 :2; + uint8_t file_format :2; + uint8_t tmp_write_protect :1; + uint8_t perm_write_protect :1; + uint8_t copy :1; + uint8_t file_format_grp :1; + uint8_t always1 :1; + uint8_t crc :7; + } __attribute__((packed)) v1; + + struct + { + uint8_t reserved1 :6; + uint8_t csd_ver :2; + uint8_t taac; + uint8_t nsac; + uint8_t tran_speed; + uint8_t ccc_high; + uint8_t read_bl_len :4; + uint8_t ccc_low :4; + uint8_t reserved2 :4; + uint8_t dsr_imp :1; + uint8_t read_blk_misalign :1; + uint8_t write_blk_misalign :1; + uint8_t read_bl_partial :1; + uint16_t c_size_high :6; + uint8_t reserved3 :2; + uint8_t c_size_mid; + uint8_t c_size_low; + uint8_t sector_size_high :6; + uint8_t erase_blk_en :1; + uint8_t reserved4 :1; + uint8_t wp_grp_size :7; + uint8_t sector_size_low :1; + uint8_t write_bl_len_high :2; + uint8_t r2w_factor :3; + uint8_t reserved5 :2; + uint8_t wp_grp_enable :1; + uint8_t reserved6 :5; + uint8_t write_partial :1; + uint8_t write_bl_len_low :2; + uint8_t reserved7 :2; + uint8_t file_format :2; + uint8_t tmp_write_protect :1; + uint8_t perm_write_protect :1; + uint8_t copy :1; + uint8_t file_format_grp :1; + uint8_t always1 :1; + uint8_t crc :7; + } __attribute__((packed)) v2; +} sdio_csd_t; + + +#ifdef __cplusplus +} +#endif + + +#endif /* _EXTRAS_SDIO_IMPL_H_ */