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>
This commit is contained in:
Angus Gratton
2025-02-05 15:16:47 +11:00
committed by Damien George
parent 4d65b4e261
commit 79fb5aa878
3 changed files with 154 additions and 44 deletions

View File

@@ -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

View File

@@ -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.
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.
.. note:: Slot 0 is used to communicate with on-board flash memory
on most ESP32 modules and so will be unavailable to the
user.
The ``slot`` argument determines which mode is used. Different values are
available on different chips:
.. 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.
====== ================= ============ ========================
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.
====== ================= ============ ========================
The pins used by the dedicated SD/MMC hardware are fixed. The pins
used by the SPI hardware can be reassigned.
.. note:: On the original ESP32, SDMMC slot 0 is unavailable as its pins are
used to communicate with on-board flash memory.
.. 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.
.. 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 default (and preferred) pin assignment are as follows:
Additional details depend on which ESP32 family chip is in use:
====== ====== ====== ====== ======
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
====== ====== ====== ====== ======
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
``````

View File

@@ -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));
}