summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2025-02-05 15:16:47 +1100
committerDamien George <damien@micropython.org>2025-03-13 12:27:01 +1100
commit79fb5aa8789e71c9bcd8430b58267d96552be94f (patch)
tree2a371b8a67d1ac81a67ced30702ef3d1a546c146
parent4d65b4e26119ab19de362174ec62cc3ea68a836a (diff)
esp32/machine_sdcard: Add SDCard pin assignments for ESP32-S3 support.
Previously ESP32-S3 SDMMC could only use fixed pin assignments, however the ESP-IDF defaults don't match common boards. The chip also supports using GPIO Matrix to assign any pin. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
-rw-r--r--docs/esp32/quickref.rst2
-rw-r--r--docs/library/machine.SDCard.rst161
-rw-r--r--ports/esp32/machine_sdcard.c47
3 files changed, 160 insertions, 50 deletions
diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst
index 0780e0130..d65782e50 100644
--- a/docs/esp32/quickref.rst
+++ b/docs/esp32/quickref.rst
@@ -747,7 +747,7 @@ See :ref:`machine.SDCard <machine.SDCard>`. ::
import machine, os, vfs
- # Slot 2 uses pins sck=18, cs=5, miso=19, mosi=23
+ # On original ESP32, slot 2 uses pins sck=18, cs=5, miso=19, mosi=23
sd = machine.SDCard(slot=2)
vfs.mount(sd, '/sd') # mount
diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst
index e4bb25dfc..62da8c3c2 100644
--- a/docs/library/machine.SDCard.rst
+++ b/docs/library/machine.SDCard.rst
@@ -23,7 +23,8 @@ arguments that might need to be set in order to use either a non-standard slot
or a non-standard pin assignment. The exact subset of arguments supported will
vary from platform to platform.
-.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None, freq=20000000)
+.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None,
+ cs=None, cmd=None, data=None, freq=20000000)
This class provides access to SD or MMC storage cards using either
a dedicated SD/MMC interface hardware or through an SPI channel.
@@ -37,7 +38,8 @@ vary from platform to platform.
- *slot* selects which of the available interfaces to use. Leaving this
unset will select the default interface.
- - *width* selects the bus width for the SD/MMC interface.
+ - *width* selects the bus width for the SD/MMC interface. This many data
+ pins must be connected to the SD card.
- *cd* can be used to specify a card-detect pin.
@@ -51,7 +53,14 @@ vary from platform to platform.
- *cs* can be used to specify an SPI chip select pin.
- - *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32).
+ The following additional parameters are only present on ESP32 port:
+
+ - *cmd* can be used to specify the SD CMD pin (ESP32-S3 only).
+
+ - *data* can be used to specify a list or tuple of SD data bus pins
+ (ESP32-S3 only).
+
+ - *freq* selects the SD/MMC interface frequency in Hz.
Implementation-specific details
-------------------------------
@@ -67,52 +76,106 @@ The standard PyBoard has just one slot. No arguments are necessary or supported.
ESP32
`````
-The ESP32 provides two channels of SD/MMC hardware and also supports
-access to SD Cards through either of the two SPI ports that are
-generally available to the user. As a result the *slot* argument can
-take a value between 0 and 3, inclusive. Slots 0 and 1 use the
-built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0
-supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit
-access; the SPI slots only support 1-bit access.
-
- .. note:: Slot 0 is used to communicate with on-board flash memory
- on most ESP32 modules and so will be unavailable to the
- user.
-
- .. note:: Most ESP32 modules that provide an SD card slot using the
- dedicated hardware only wire up 1 data pin, so the default
- value for *width* is 1.
-
-The pins used by the dedicated SD/MMC hardware are fixed. The pins
-used by the SPI hardware can be reassigned.
-
- .. note:: If any of the SPI signals are remapped then all of the SPI
- signals will pass through a GPIO multiplexer unit which
- can limit the performance of high frequency signals. Since
- the normal operating speed for SD cards is 40MHz this can
- cause problems on some cards.
-
-The default (and preferred) pin assignment are as follows:
-
- ====== ====== ====== ====== ======
- Slot 0 1 2 3
- ------ ------ ------ ------ ------
- Signal Pin Pin Pin Pin
- ====== ====== ====== ====== ======
- sck 6 14 18 14
- cmd 11 15
- cs 5 15
- miso 19 12
- mosi 23 13
- D0 7 2
- D1 8 4
- D2 9 12
- D3 10 13
- D4 16
- D5 17
- D6 5
- D7 18
- ====== ====== ====== ====== ======
+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.
+
+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.
+====== ================= ============ ========================
+
+.. note:: On the original ESP32, SDMMC slot 0 is unavailable as its pins are
+ used to communicate with on-board flash memory.
+
+.. note:: Most ESP32 modules that provide an SD card slot using the
+ dedicated hardware only wire up 1 data pin, so the default
+ value for ``width`` is 1.
+
+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.
+
+The default pin assignments are as follows:
+
+ ====== ====== ====== ====== ============
+ Slot 1 2 3 Can be set
+ ------ ------ ------ ------ ------------
+ Signal Pin Pin Pin
+ ====== ====== ====== ====== ============
+ CLK 14 No
+ CMD 15 No
+ D0 2 No
+ D1 4 No
+ D2 12 No
+ D3 13 No
+ sck 18 14 Yes
+ cs 5 15 Yes
+ miso 19 12 Yes
+ mosi 23 13 Yes
+ ====== ====== ====== ====== ============
+
+The ``cd`` and ``wp`` pins are not fixed in either mode and default to disabled, unless set.
+
+ESP32-S3
+~~~~~~~~
+
+The ESP32-S3 chip allows pins to be set to different values for both SD/MMC and
+SPI mode access.
+
+If not set, default pin assignments are as follows:
+
+ ======== ====== ====== ====== ======
+ Slot 0 1 2 3
+ -------- ------ ------ ------ ------
+ Signal Pin Pin Pin Pin
+ ======== ====== ====== ====== ======
+ CLK 14 14
+ CMD 15 15
+ D0 2 2
+ D1 4 4
+ D2 12 12
+ D3 13 13
+ D4 33*
+ D5 34*
+ D6 35*
+ D7 36*
+ sck 37* 14
+ cs 34* 13
+ miso 37* 2
+ mosi 35* 15
+ ======== ====== ====== ====== ======
+
+.. note:: Slots 0 and 1 cannot both be in use at the same time.
+
+.. note:: Pins marked with an asterisk * in the table must be changed from the
+ default if the ESP32-S3 board is configured for Octal SPI Flash or
+ PSRAM.
+
+To access a card in SD/MMC mode, set ``slot`` parameter value 0 or 1 and
+parameters ``sck`` (for CLK), ``cmd`` and ``data`` as needed to assign pins. If
+the ``data`` argument is passed then it should be a list or tuple of data pins
+or pin numbers with length equal to the ``width`` argument. For example::
+
+ sd = SDCard(slot=0, width=4, sck=8, cmd=9, data=(10, 11, 12, 13))
+
+To access a card in SPI mode, set ``slot`` parameter value 2 or 3 and pass
+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.
cc3200
``````
diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c
index da6b0df28..48fd96c6d 100644
--- a/ports/esp32/machine_sdcard.c
+++ b/ports/esp32/machine_sdcard.c
@@ -177,6 +177,10 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
ARG_mosi,
ARG_sck,
ARG_cs,
+ #if SOC_SDMMC_USE_GPIO_MATRIX
+ ARG_cmd,
+ ARG_data,
+ #endif
ARG_freq,
};
static const mp_arg_t allowed_args[] = {
@@ -189,6 +193,11 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
{ MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ // Optional assignment of SDMMC interface pins, if host supports this
+ #if SOC_SDMMC_USE_GPIO_MATRIX
+ { MP_QSTR_cmd, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ #endif
// freq is valid for both SPI and SDMMC interfaces
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 20000000} },
};
@@ -211,6 +220,11 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
arg_vals[ARG_miso].u_obj, arg_vals[ARG_mosi].u_obj,
arg_vals[ARG_sck].u_obj, arg_vals[ARG_cs].u_obj);
+ #if SOC_SDMMC_USE_GPIO_MATRIX
+ DEBUG_printf(" cmd=%p, data=%p",
+ arg_vals[ARG_cmd].u_obj, arg_vals[ARG_data].u_obj);
+ #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"));
@@ -221,6 +235,13 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
if (is_spi) {
slot_num -= 2;
}
+ // Verify valid argument combinations
+ #if SOC_SDMMC_USE_GPIO_MATRIX
+ if (is_spi && (arg_vals[ARG_cmd].u_obj != mp_const_none
+ || arg_vals[ARG_data].u_obj != mp_const_none)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid config: SPI slot with SDMMC pin arguments"));
+ }
+ #endif
DEBUG_printf(" Setting up host configuration");
@@ -307,6 +328,32 @@ static mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
mp_raise_ValueError(MP_ERROR_TEXT("width must be 1 or 4 (or 8 on slot 0)"));
}
+ #if SOC_SDMMC_USE_GPIO_MATRIX
+ // Optionally configure all the SDMMC pins, if chip supports this
+ SET_CONFIG_PIN(slot_config, clk, ARG_sck); // reuse SPI SCK for CLK
+ SET_CONFIG_PIN(slot_config, cmd, ARG_cmd);
+ if (arg_vals[ARG_data].u_obj != mp_const_none) {
+ mp_obj_t *data_vals;
+ size_t data_len;
+ mp_obj_get_array(arg_vals[ARG_data].u_obj, &data_len, &data_vals);
+ if (data_len != width) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("data argument length must match width %d"), width);
+ }
+ slot_config.d0 = machine_pin_get_id(data_vals[0]);
+ if (width > 1) {
+ slot_config.d1 = machine_pin_get_id(data_vals[1]);
+ slot_config.d2 = machine_pin_get_id(data_vals[2]);
+ slot_config.d3 = machine_pin_get_id(data_vals[3]);
+ }
+ if (width == 8) {
+ slot_config.d4 = machine_pin_get_id(data_vals[4]);
+ slot_config.d5 = machine_pin_get_id(data_vals[5]);
+ slot_config.d6 = machine_pin_get_id(data_vals[6]);
+ slot_config.d7 = machine_pin_get_id(data_vals[7]);
+ }
+ }
+ #endif
+
DEBUG_printf(" Calling init_slot()");
check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config));
}