diff options
-rw-r--r-- | docs/library/machine.SDCard.rst | 60 | ||||
-rw-r--r-- | ports/esp32/machine_sdcard.c | 104 |
2 files changed, 121 insertions, 43 deletions
diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index 62da8c3c2..c4a0d5d17 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -77,24 +77,34 @@ ESP32 ````` SD cards support access in both SD/MMC mode and the simpler (but slower) SPI -mode. ESP32 and ESP32-S3 chips can access SD cards using either mode. SPI mode -makes use of a `SPI` host peripheral, which cannot concurrently be used for -something else. +mode. -The ``slot`` argument determines which mode is used. Different values are -available on different chips: - -====== ================= ============ ======================== -Slot Supported chips Mode Supported data width -====== ================= ============ ======================== -0 ESP32-S3 SD/MMC 1, 4, or 8 bits. -1 ESP32, ESP32-S3 SD/MMC 1 or 4 bits. -2 ESP32, ESP32-S3 `SPI` (id=1) 1 bit. -3 ESP32, ESP32-S3 `SPI` (id=0) 1 bit. -====== ================= ============ ======================== +SPI mode makes use of a `SPI` host peripheral, which cannot concurrently be used +for other SPI interactions. -.. note:: On the original ESP32, SDMMC slot 0 is unavailable as its pins are - used to communicate with on-board flash memory. +The ``slot`` argument determines which mode is used. Different values are +supported on different chips: + +========== ======== ======== ============ ============ +Chip Slot 0 Slot 1 Slot 2 Slot 3 +========== ======== ======== ============ ============ +ESP32 SD/MMC SPI (id=1) SPI (id=0) +ESP32-C3 SPI (id=0) +ESP32-C6 SPI (id=0) +ESP32-S2 SPI (id=1) SPI (id=0) +ESP32-S3 SD/MMC SD/MMC SPI (id=1) SPI (id=0) +========== ======== ======== ============ ============ + +Different slots support different data bus widths (number of data pins): + +========== ========== ===================== +Slot Type Supported data widths +========== ========== ===================== +0 SD/MMC 1, 4, 8 +1 SD/MMC 1, 4 +2 SPI 1 +3 SPI 1 +========== ========== ===================== .. note:: Most ESP32 modules that provide an SD card slot using the dedicated hardware only wire up 1 data pin, so the default @@ -105,8 +115,9 @@ Additional details depend on which ESP32 family chip is in use: Original ESP32 ~~~~~~~~~~~~~~ -Pin assignments in SD/MMC mode are fixed on the original ESP32. When accessing a -card in SPI mode, pins can be set to different values in the constructor. +In SD/MMC mode (slot 1), pin assignments in SD/MMC mode are fixed on the +original ESP32. The SPI mode slots (2 & 3) allow pins to be set to different +values in the constructor. The default pin assignments are as follows: @@ -177,6 +188,19 @@ parameters ``sck``, ``cs``, ``miso``, ``mosi`` as needed to assign pins. In either mode the ``cd`` and ``wp`` pins default to disabled, unless set in the constructor. +Other ESP32 chips +~~~~~~~~~~~~~~~~~ + +Other ESP32 family chips do not have hardware SD/MMC host controllers and can +only access SD cards in SPI mode. + +To access a card in SPI mode, set ``slot`` parameter value 2 or 3 and pass +parameters ``sck``, ``cs``, ``miso``, ``mosi`` to assign pins. + +.. note:: ESP32-C3 and ESP32-C6 only have one available `SPI` bus, so the only + valid ``slot`` parameter value is 2. Using this bus for the SD card + will prevent also using it for :class:`machine.SPI`. + cc3200 `````` diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 48fd96c6d..0f8bd8446 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -33,7 +33,9 @@ #if MICROPY_HW_ENABLE_SDCARD +#if SOC_SDMMC_HOST_SUPPORTED #include "driver/sdmmc_host.h" +#endif #include "driver/sdspi_host.h" #include "sdmmc_cmd.h" #include "esp_log.h" @@ -69,18 +71,34 @@ typedef struct _sdcard_obj_t { #define _SECTOR_SIZE(self) (self->card.csd.sector_size) +// Number SPI buses available for firmware app (including for SD) +#define NUM_SD_SPI_BUS (SOC_SPI_PERIPH_NUM - 1) + +#if CONFIG_IDF_TARGET_ESP32 +#define SD_SLOT_MIN 1 +#elif SOC_SDMMC_HOST_SUPPORTED +#define SD_SLOT_MIN 0 +#else +#define SD_SLOT_MIN 2 +#endif +#define SD_SLOT_MAX (NUM_SD_SPI_BUS + 1) // Inclusive + // SPI bus default bus and device configuration. -static const spi_bus_config_t spi_bus_defaults[2] = { +static const spi_bus_config_t spi_bus_defaults[NUM_SD_SPI_BUS] = { { #if CONFIG_IDF_TARGET_ESP32 .miso_io_num = GPIO_NUM_19, .mosi_io_num = GPIO_NUM_23, .sclk_io_num = GPIO_NUM_18, - #else + #elif CONFIG_IDF_TARGET_ESP32S3 .miso_io_num = GPIO_NUM_36, .mosi_io_num = GPIO_NUM_35, .sclk_io_num = GPIO_NUM_37, + #else + .miso_io_num = GPIO_NUM_NC, + .mosi_io_num = GPIO_NUM_NC, + .sclk_io_num = GPIO_NUM_NC, #endif .data2_io_num = GPIO_NUM_NC, .data3_io_num = GPIO_NUM_NC, @@ -92,6 +110,7 @@ static const spi_bus_config_t spi_bus_defaults[2] = { .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_MOSI, .intr_flags = 0, }, + #if NUM_SD_SPI_BUS > 1 { .miso_io_num = GPIO_NUM_2, .mosi_io_num = GPIO_NUM_15, @@ -106,28 +125,34 @@ static const spi_bus_config_t spi_bus_defaults[2] = { .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_MOSI, .intr_flags = 0, }, + #endif }; #if CONFIG_IDF_TARGET_ESP32 -static const uint8_t spi_dma_channel_defaults[2] = { +static const uint8_t spi_dma_channel_defaults[NUM_SD_SPI_BUS] = { 2, 1, }; #endif -static const sdspi_device_config_t spi_dev_defaults[2] = { +static const sdspi_device_config_t spi_dev_defaults[NUM_SD_SPI_BUS] = { + #if NUM_SD_SPI_BUS > 1 { #if CONFIG_IDF_TARGET_ESP32 .host_id = VSPI_HOST, .gpio_cs = GPIO_NUM_5, - #else + #elif CONFIG_IDF_TARGET_ESP32S3 .host_id = SPI3_HOST, .gpio_cs = GPIO_NUM_34, + #else + .host_id = SPI3_HOST, + .gpio_cs = GPIO_NUM_NC, #endif .gpio_cd = SDSPI_SLOT_NO_CD, .gpio_wp = SDSPI_SLOT_NO_WP, .gpio_int = SDSPI_SLOT_NO_INT, }, + #endif SDSPI_DEVICE_CONFIG_DEFAULT(), // HSPI (ESP32) / SPI2 (ESP32S3) }; @@ -159,12 +184,15 @@ static esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { // Expose the SD card or MMC as an object with the block protocol. // Create a new SDCard object -// The driver supports either the host SD/MMC controller (default) or SPI mode -// In both cases there are two "slots". Slot 0 on the SD/MMC controller is -// typically tied up with the flash interface in most ESP32 modules but in -// theory supports 1, 4 or 8-bit transfers. Slot 1 supports only 1 and 4-bit -// transfers. Only 1-bit is supported on the SPI interfaces. -// card = SDCard(slot=1, width=None, present_pin=None, wp_pin=None) +// +// SD/MMC or SPI mode is determined by the slot argument +// 0,1 is SD/MMC mode where supported. +// 2,3 is SPI mode where supported (1-bit only) +// +// Original ESP32 can't use 0 +// ESP32-C3/C6/etc can only use 2 (only one SPI bus, no SD/MMC controller) +// +// Consult machine.SDCard docs for more details. static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments @@ -183,8 +211,13 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args #endif ARG_freq, }; + #if SOC_SDMMC_HOST_SUPPORTED + static const int DEFAULT_SLOT = 1; + #else + static const int DEFAULT_SLOT = SD_SLOT_MAX; + #endif static const mp_arg_t allowed_args[] = { - { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SLOT} }, { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_cd, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_wp, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -226,15 +259,21 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args #endif int slot_num = arg_vals[ARG_slot].u_int; - if (slot_num < 0 || slot_num > 3) { - mp_raise_ValueError(MP_ERROR_TEXT("slot number must be between 0 and 3 inclusive")); + if (slot_num < SD_SLOT_MIN || slot_num > SD_SLOT_MAX) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid slot number")); } + #if SOC_SDMMC_HOST_SUPPORTED // Slots 0 and 1 are native SD/MMC, slots 2 and 3 are SPI bool is_spi = (slot_num >= 2); + #else + bool is_spi = true; + #endif if (is_spi) { slot_num -= 2; + assert(slot_num < NUM_SD_SPI_BUS); } + // Verify valid argument combinations #if SOC_SDMMC_USE_GPIO_MATRIX if (is_spi && (arg_vals[ARG_cmd].u_obj != mp_const_none @@ -242,6 +281,13 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args mp_raise_ValueError(MP_ERROR_TEXT("invalid config: SPI slot with SDMMC pin arguments")); } #endif + #if SOC_SDMMC_HOST_SUPPORTED + if (!is_spi && (arg_vals[ARG_miso].u_obj != mp_const_none + || arg_vals[ARG_mosi].u_obj != mp_const_none + || arg_vals[ARG_cs].u_obj != mp_const_none)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid config: SDMMC slot with SPI pin arguments")); + } + #endif DEBUG_printf(" Setting up host configuration"); @@ -253,21 +299,17 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args if (is_spi) { sdmmc_host_t _temp_host = SDSPI_HOST_DEFAULT(); _temp_host.max_freq_khz = freq / 1000; + // SPI SDMMC sets the slot to the SPI host ID + _temp_host.slot = spi_dev_defaults[slot_num].host_id; self->host = _temp_host; - } else { + } + #if SOC_SDMMC_HOST_SUPPORTED + else { sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); _temp_host.max_freq_khz = freq / 1000; self->host = _temp_host; } - - if (is_spi) { - // Needs to match spi_dev_defaults above. - #if CONFIG_IDF_TARGET_ESP32 - self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; - #else - self->host.slot = slot_num ? SPI2_HOST : SPI3_HOST; - #endif - } + #endif DEBUG_printf(" Calling host.init()"); @@ -294,6 +336,15 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args SET_CONFIG_PIN(dev_config, gpio_cd, ARG_cd); SET_CONFIG_PIN(dev_config, gpio_wp, ARG_wp); + // On chips other than original ESP32 and S3, there are not + // always default SPI pins assigned + if (dev_config.gpio_cs == GPIO_NUM_NC + || bus_config.miso_io_num == GPIO_NUM_NC + || bus_config.mosi_io_num == GPIO_NUM_NC + || bus_config.sclk_io_num == GPIO_NUM_NC) { + mp_raise_ValueError(MP_ERROR_TEXT("SPI pin values required")); + } + DEBUG_printf(" Calling spi_bus_initialize()"); check_esp_err(spi_bus_initialize(spi_host_id, &bus_config, dma_channel)); @@ -309,7 +360,9 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args spi_bus_free(spi_host_id); mp_raise_ValueError(MP_ERROR_TEXT("SPI bus already in use")); } - } else { + } + #if SOC_SDMMC_HOST_SUPPORTED + else { // SD/MMC interface DEBUG_printf(" Setting up SDMMC slot configuration"); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); @@ -357,6 +410,7 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args DEBUG_printf(" Calling init_slot()"); check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); } + #endif // SOC_SDMMC_HOST_SUPPORTED DEBUG_printf(" Returning new card object: %p", self); return MP_OBJ_FROM_PTR(self); |