From 92657f5fd26025b6fa7b3d08c614cfd1778d5b1f Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 28 Jun 2023 17:31:54 +0200 Subject: [PATCH 1/8] cpu/esp32: add SDMMC support --- cpu/esp32/Kconfig.esp32 | 3 + cpu/esp32/Kconfig.esp32s3 | 4 + cpu/esp32/Kconfig.esp32x | 1 + cpu/esp32/Makefile.dep | 5 + cpu/esp32/Makefile.features | 9 + cpu/esp32/doc.txt | 129 +++-- cpu/esp32/doc_esp32.txt | 46 ++ cpu/esp32/doc_esp32s3.txt | 48 ++ cpu/esp32/esp-idf/Kconfig | 1 + cpu/esp32/esp-idf/Makefile | 4 + cpu/esp32/esp-idf/sdmmc/Kconfig | 17 + cpu/esp32/esp-idf/sdmmc/Makefile | 18 + cpu/esp32/include/irq_arch.h | 1 + cpu/esp32/include/periph_cpu.h | 79 ++- cpu/esp32/include/periph_cpu_esp32.h | 7 +- cpu/esp32/irq_arch.c | 3 + cpu/esp32/periph/sdmmc.c | 481 ++++++++++++++++++ ...dmmc-avoid-type-definition-conflicts.patch | 48 ++ 18 files changed, 866 insertions(+), 38 deletions(-) create mode 100644 cpu/esp32/esp-idf/sdmmc/Kconfig create mode 100644 cpu/esp32/esp-idf/sdmmc/Makefile create mode 100644 cpu/esp32/periph/sdmmc.c create mode 100644 pkg/esp32_sdk/patches/0031-driver-sdmmc-avoid-type-definition-conflicts.patch diff --git a/cpu/esp32/Kconfig.esp32 b/cpu/esp32/Kconfig.esp32 index cd2ef71806c7..c5da0ee870e6 100644 --- a/cpu/esp32/Kconfig.esp32 +++ b/cpu/esp32/Kconfig.esp32 @@ -14,6 +14,9 @@ config CPU_FAM_ESP32 select HAS_ESP_BLE select HAS_ESP_BLE_ESP32 select HAS_PUF_SRAM + select HAS_PERIPH_SDMMC_AUTO_CLK + select HAS_PERIPH_SDMMC_AUTO_CMD12 + select HAS_PERIPH_SDMMC_MMC config CPU_FAM default "esp32" if CPU_FAM_ESP32 diff --git a/cpu/esp32/Kconfig.esp32s3 b/cpu/esp32/Kconfig.esp32s3 index a0787460b907..0af20b4e9616 100644 --- a/cpu/esp32/Kconfig.esp32s3 +++ b/cpu/esp32/Kconfig.esp32s3 @@ -15,6 +15,10 @@ config CPU_FAM_ESP32S3 select HAS_BLE_PHY_2MBIT select HAS_ESP_BLE select HAS_ESP_BLE_ESP32C3 + select HAS_PERIPH_SDMMC_AUTO_CLK + select HAS_PERIPH_SDMMC_AUTO_CMD12 + select HAS_PERIPH_SDMMC_HS + select HAS_PERIPH_SDMMC_MMC select MODULE_USBDEV_SYNOPSYS_DWC2 if MODULE_PERIPH_USBDEV select MODULE_USB_BOARD_RESET if MODULE_USBUS_CDC_ACM || MODULE_TINYUSB_CLASS_CDC diff --git a/cpu/esp32/Kconfig.esp32x b/cpu/esp32/Kconfig.esp32x index 60f735cf6ecd..bbee9fd493e1 100644 --- a/cpu/esp32/Kconfig.esp32x +++ b/cpu/esp32/Kconfig.esp32x @@ -26,6 +26,7 @@ config CPU_COMMON_ESP32X select PACKAGE_ESP32_SDK if TEST_KCONFIG + select MODULE_PERIPH_GPIO_IRQ if MODULE_PERIPH_SDMMC select MODULE_PERIPH_RTT if HAS_PERIPH_RTT && MODULE_PM_LAYERED select MODULE_PS if MODULE_SHELL select MODULE_PTHREAD if MODULE_CPP diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep index ca2556901e5e..9d4b62ab470a 100644 --- a/cpu/esp32/Makefile.dep +++ b/cpu/esp32/Makefile.dep @@ -105,6 +105,11 @@ ifneq (,$(filter periph_i2c,$(USEMODULE))) endif endif +ifneq (,$(filter periph_sdmmc,$(USEMODULE))) + USEMODULE += esp_idf_sdmmc + USEMODULE += periph_gpio_irq +endif + ifneq (,$(filter esp_spi_ram,$(USEMODULE))) FEATURES_REQUIRED += esp_spi_ram FEATURES_OPTIONAL += esp_spi_oct diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index 1e87ecbcc817..dcc8dba6be9b 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -46,6 +46,15 @@ else ifneq (,$(filter esp32c3 esp32s3,$(CPU_FAM))) FEATURES_PROVIDED += esp_ble_esp32c3 endif +ifneq (,$(filter esp32 esp32s3,$(CPU_FAM))) + FEATURES_PROVIDED += periph_sdmmc_auto_clk + FEATURES_PROVIDED += periph_sdmmc_auto_cmd12 + FEATURES_PROVIDED += periph_sdmmc_mmc + ifeq (esp32s3,$(CPU_FAM)) + FEATURES_PROVIDED += periph_sdmmc_hs + endif +endif + ifneq (,$(filter esp32-wrover% esp32s2%r2 esp32s3%r2 esp32s3%r8 esp32s3%r8v,$(CPU_MODEL))) FEATURES_PROVIDED += esp_spi_ram ifneq (,$(filter esp32s3%r8 esp32s3%r8v,$(CPU_MODEL))) diff --git a/cpu/esp32/doc.txt b/cpu/esp32/doc.txt index c1225a13521e..66c5439586f1 100644 --- a/cpu/esp32/doc.txt +++ b/cpu/esp32/doc.txt @@ -55,13 +55,14 @@ This document describes the RIOT implementation for supported variants 3. [DAC Channels](#esp32_dac_channels) 4. [I2C Interfaces](#esp32_i2c_interfaces) 5. [PWM Channels](#esp32_pwm_channels) - 6. [SPI Interfaces](#esp32_spi_interfaces) - 7. [Timers](#esp32_timers) - 8. [RTT Implementation](#esp32_rtt_counter) - 9. [UART Interfaces](#esp32_uart_interfaces) - 10. [CAN Interfaces](#esp32_can_interfaces) - 11. [Power Management](#esp32_power_management) - 12. [Other Peripherals](#esp32_other_peripherals) + 6. [SDMMC Interfaces](#esp32_sdmmc_interfaces) + 8. [SPI Interfaces](#esp32_spi_interfaces) + 9. [Timers](#esp32_timers) + 10. [RTT Implementation](#esp32_rtt_counter) + 12. [UART Interfaces](#esp32_uart_interfaces) + 13. [CAN Interfaces](#esp32_can_interfaces) + 14. [Power Management](#esp32_power_management) + 15. [Other Peripherals](#esp32_other_peripherals) 7. [Special On-board Peripherals](#esp32_special_on_board_peripherals) 1. [SPI RAM Modules](#esp32_spi_ram) 2. [SPIFFS Device](#esp32_spiffs_device) @@ -212,13 +213,14 @@ The key features of ESP32 are: | Flash | 512 KiB ... 16 MiB | yes | | Frequency | 240 MHz, 160 MHz, 80 MHz | yes | | Power Consumption | 68 mA @ 240 MHz
44 mA @ 160 MHz (34 mA @ 160 MHz single core)
31 mA @ 80 MHz (25 mA @ 80 MHz single core)
800 uA in light sleep mode
10 uA in deep sleep mode | yes
yes
yes
yes
yes | -| Timers | 4 x 64 bit | yes | -| ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes | -| DACs | 2 x DAC with 8 bit | yes | -| GPIOs | 34 (6 are only inputs, 18 are RTC GPIOs) | yes | -| I2Cs | 2 | yes | -| SPIs | 4 | yes (2) | -| UARTs | 3 | yes | +| Timer | 4 x 64 bit | yes | +| ADC | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes | +| DAC | 2 x DAC with 8 bit | yes | +| GPIO | 34 (6 are only inputs, 18 are RTC GPIOs) | yes | +| I2C | 2 | yes | +| SDMMC | 2 | yes | +| SPI | 4 | yes (2) | +| UART | 3 | yes | | WiFi | IEEE 802.11 b/g/n built in | yes | | Bluetooth | v4.2 BR/EDR and BLE | yes | | Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes | @@ -248,13 +250,13 @@ The key features of ESP32-C3 are: | Flash | 8 MiB | yes | | Frequency | 160 MHz, 80 MHz | yes | | Power Consumption | 20 mA @ 240 MHz
15 mA @ 80 MHz
130 uA in light sleep mode
5 uA in deep sleep mode | yes
yes
yes
yes | -| Timers | 2 x 54 bit | yes | -| ADCs | 2 x SAR-ADC with up to 6 x 12 bit channels total | yes | -| DACs | - | - | -| GPIOs | 22 | yes | -| I2Cs | 1 | yes | -| SPIs | 3 | yes (1) | -| UARTs | 2 | yes | +| Timer | 2 x 54 bit | yes | +| ADC | 2 x SAR-ADC with up to 6 x 12 bit channels total | yes | +| DAC | - | - | +| GPIO | 22 | yes | +| I2C | 1 | yes | +| SPI | 3 | yes (1) | +| UART | 2 | yes | | WiFi | IEEE 802.11 b/g/n built in | yes | | Bluetooth | Bluetooth 5 (LE) | yes | | Ethernet | - | - | @@ -284,13 +286,13 @@ The key features of ESP32-S2 are: | Flash | 512 KiB ... 32 MiB Dual/Quad/Octal SPI (external or internal) | yes | | Frequency | 240 MHz, 160 MHz, 80 MHz | yes | | Power Consumption | 66 mA @ 240 MHz
50 mA @ 160 MHz (40 mA @ 160 MHz single core)
33 mA @ 80 MHz (28 mA @ 80 MHz single core)
19 mA @ 40 MHz (16 mA @ 40 MHz single core)
240 uA in light sleep mode
8 uA in deep sleep mode | yes
yes
yes
yes
yes
yes | -| Timers | 4 x 54 bit | yes | -| ADCs | 2 x SAR-ADC with up to 20 x 13 bit channels total | yes | -| DACs | 2 x DAC with 8 bit | - | -| GPIOs | 43 (22 are RTC GPIOs) | yes | -| I2Cs | 2 | yes | -| SPIs | 4 | yes (2) | -| UARTs | 2 | yes | +| Timer | 4 x 54 bit | yes | +| ADC | 2 x SAR-ADC with up to 20 x 13 bit channels total | yes | +| DAC | 2 x DAC with 8 bit | - | +| GPIO | 43 (22 are RTC GPIOs) | yes | +| I2C | 2 | yes | +| SPI | 4 | yes (2) | +| UART | 2 | yes | | WiFi | IEEE 802.11 b/g/n built in | yes | | Bluetooth | - | - | | Ethernet | - | - | @@ -320,13 +322,14 @@ The key features of ESP32-S3 are: | Flash | 512 KiB ... 32 MiB Dual/Quad/Octal SPI (external or internal) | yes | | Frequency | 240 MHz, 160 MHz, 80 MHz | yes | | Power Consumption | 66 mA @ 240 MHz
50 mA @ 160 MHz (40 mA @ 160 MHz single core)
33 mA @ 80 MHz (28 mA @ 80 MHz single core)
19 mA @ 40 MHz (16 mA @ 40 MHz single core)
240 uA in light sleep mode
8 uA in deep sleep mode | yes
yes
yes
yes
yes
yes | -| Timers | 4 x 54 bit | yes | -| ADCs | 2 x SAR-ADC with up to 20 x 12 bit channels total | yes | -| DACs | - | - | -| GPIOs | 45 (22 are RTC GPIOs) | yes | -| I2Cs | 2 | yes | -| SPIs | 4 | yes (2) | -| UARTs | 3 | yes | +| Timer | 4 x 54 bit | yes | +| ADC | 2 x SAR-ADC with up to 20 x 12 bit channels total | yes | +| DAC | - | - | +| GPIO | 45 (22 are RTC GPIOs) | yes | +| I2C | 2 | yes | +| SDMMC | 2 | yes | +| SPI | 4 | yes (2) | +| UART | 3 | yes | | WiFi | IEEE 802.11 b/g/n built in | yes | | Bluetooth | Bluetooth 5 (LE) | yes | | Ethernet | - | - | @@ -1012,6 +1015,62 @@ definition of `PWM0_GPIOS`, `PWM1_GPIOS`, `PWM2_GPIOS` and `PWM3_GPIOS`. [Back to table of contents](#esp32_toc) +## SDMMC Interfaces {#esp32_sdmmc_interfaces} + +ESP32 and ESP32-S3 variants integrate a SD/MMC host controller which supports +two slots for + +- SD Memory Cards, +- SDIO Cards and +- MMC/eMMCs. + +The SD/MMC host controller on the ESP32 variant + +- supports 1-bit, 4-bit and 8-bit data bus width for slot 0 (@ref SDMMC_SLOT_0), +- supports 1-bit and 4-bit data bus width for slot 1 (@ref SDMMC_SLOT_1), +- uses direct I/O for SD/MMC signals so that the GPIOs used for the slots are + therefore fixed. + +The SD/MMC host controller on the ESP32-S3 variant +- supports 1-, 4- and 8-bit data bus width for both slots +- uses the GPIO matrix to connect the SD/MMC signals to the GPIOs so that + all pins are configurable. + +@note Since the GPIOs are fixed on the ESP32 variant and the same GPIOs are +used for slot 0 and the flash, slot 0 cannot be used on ESP32 variant. + +The board-specific configuration is realized by defining the array +@ref sdmmc_config +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +static const sdmmc_conf_t sdmmc_config[] = { + { + .slot = SDMMC_SLOT_1, + .cd = GPIO_UNDEF, + .wp = GPIO_UNDEF, + ... + }, +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and the macro `SDMMC_NUMOF` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +#define SDMMC_NUMOF 1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +where the value of @ref SDMMC_NUMOF must correspond to the number of elements +in @ref sdmmc_config. + +While for the ESP32 variant it is sufficient to define the data bus width, used +GPIOs have to be defined in the configuration for the ESP32-S3 variant instead. +For details of ESP32x variant specific configuration, see: + +- \ref esp32_sdmmc_interfaces_esp32 "ESP32" +- \ref esp32_sdmmc_interfaces_esp32s3 "ESP32-S3" + +If the board supports a Card Detect pin or a Write Protect pin, the +corresponding GPIOs have to be defined in @ref sdmmc_conf_t::cd and +@ref sdmmc_conf_t::wp. Otherwise they have to be set to undefined +(@ref GPIO_UNDEF). + ## SPI Interfaces {#esp32_spi_interfaces} ESP32x SoCs have up to four SPI controllers dependent on the specific ESP32x diff --git a/cpu/esp32/doc_esp32.txt b/cpu/esp32/doc_esp32.txt index d533594e044a..3cb89d508d6b 100644 --- a/cpu/esp32/doc_esp32.txt +++ b/cpu/esp32/doc_esp32.txt @@ -139,6 +139,52 @@ I2C_DEV(0) | SDA | GPIO21 | `#I2C0_SDA` | - The ESP32 LEDC module has 2 channel groups with 8 channels each. Each of these channels can be clocked by one of the 4 timers. +## SDMMC Interfaces {#esp32_sdmmc_interfaces_esp32} + +The ESP32 variant uses the direct I/O (i.e. `SOC_SDMMC_USE_IOMUX` is defined in +the SoC capabilities file). The GPIOs used for SDMMC signals are therefore fixed +for each slot. Since the GPIOs used for slot 0 are the same as those used +for the Flash, slot 0 cannot be used. Therefore, only slot 1 can be used. + +The GPIOs used by ESP32 for slot 1 are: + +
+| Signal | GPIO Slot 1 | +|:------ |:------------| +| CLK | GPIO14 | +| CMD | GPIO15 | +| DAT0 | GPIO2 | +| DAT1 | GPIO4 | +| DAT2 | GPIO12 | +| DAT3 | GPIO13 | +
+ +The board-specific configuration is realized by defining the @ref sdmmc_config +array, for example: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +static const sdmmc_conf_t sdmmc_config[] = { + { + .slot = SDMMC_SLOT_1, + .cd = GPIO21, + .wp = GPIO_UNDEF, + .bus_width = 1, + }, +}; + +#define SDMMC_NUMOF 1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Used data bus width has to be defined in sdmmc_conf_t::bus_width in addition +to the slot, where 1 and 4 are valid values. + +@note The slot must be @ref SDMMC_SLOT_1 for ESP32. + +If the board supports a Card Detect pin or a Write Protect +pin, the corresponding GPIOs have to be defined in @ref sdmmc_conf_t::cd and +@ref sdmmc_conf_t::wp. Otherwise they have to be set to undefined +(@ref GPIO_UNDEF). + ## SPI Interfaces {#esp32_spi_interfaces_esp32} ESP32 has four SPI controllers where SPI0 and SPI1 share the same bus and diff --git a/cpu/esp32/doc_esp32s3.txt b/cpu/esp32/doc_esp32s3.txt index d44ee143b030..9661713cdc81 100644 --- a/cpu/esp32/doc_esp32s3.txt +++ b/cpu/esp32/doc_esp32s3.txt @@ -209,6 +209,54 @@ I2C_DEV(0) | SDA | GPIO8 | `#I2C0_SDA` | - The ESP32-S3 LEDC module has 1 channel group with 8 channels. Each of these channels can be clocked by one of the 4 timers. +## SDMMC Interfaces {#esp32_sdmmc_interfaces_esp32s3} + +The ESP32-S3 variant uses the GPIO matrix (i.e. `SOC_SDMMC_USE_GPIO_MATRIX` +is defined in the SoC Capabilities file) to route the SDMMC signals to +arbitrary pins. The GPIOs used for the SDMMC signals are therefore +configurable and have to be defined in the board-specific configuration in +array @ref sdmmc_config in addition to the used slot. + +The width of the data bus used is determined by the GPIOs defined for the +DAT lines. To use a 1-bit data bus, only DAT0 (@ref sdmmc_conf_t::dat0) +must be defined. All other GPIOs for the DAT lines must be set undefined +(@ref GPIO_UNDEF). For a 4-bit data bus, the GPIOs for pins DAT1 to DAT3 +(@ref sdmmc_conf_t::dat1 ... @ref sdmmc_conf_t::dat3) must also be defined. +An 8-bit data bus width requires the definition of DAT4 to DAT7 +(@ref sdmmc_conf_t::dat4 ... @ref sdmmc_conf_t::dat7) and the enabling +of the `periph_sdmmc_8bit` module. + +The following example shows a configuration with 4-bit or 8-bit data +bus width dependent on whether the `periph_sdmmc_8bit` module is enabled. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c} +static const sdmmc_conf_t sdmmc_config[] = { + { + .slot = SDMMC_SLOT_0, + .cd = GPIO16, + .wp = GPIO_UNDEF, + .clk = GPIO14, + .cmd = GPIO15, + .dat0 = GPIO2, + .dat1 = GPIO4, + .dat2 = GPIO12, + .dat3 = GPIO13, +#if IS_USED(MODULE_PERIPH_SMMC_8BIT) + .dat4 = GPIO33, + .dat5 = GPIO33, + .dat6 = GPIO33, + .dat7 = GPIO33, +#endif + }, +}; + +#define SDMMC_NUMOF 1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the board supports a Card Detect pin or a Write Protect pin, the +corresponding GPIOs have to be defined in @ref sdmmc_conf_t::cd and +@ref sdmmc_conf_t::wp. Otherwise they have to be set to undefined +(@ref GPIO_UNDEF). + ## SPI Interfaces {#esp32_spi_interfaces_esp32s3} ESP32-S3 has four SPI controllers where SPI0 and SPI1 share the same bus diff --git a/cpu/esp32/esp-idf/Kconfig b/cpu/esp32/esp-idf/Kconfig index 1967cb12dc37..d76951ae574f 100644 --- a/cpu/esp32/esp-idf/Kconfig +++ b/cpu/esp32/esp-idf/Kconfig @@ -29,6 +29,7 @@ rsource "heap/Kconfig" rsource "lcd/Kconfig" rsource "nvs_flash/Kconfig" rsource "rmt/Kconfig" +rsource "sdmmc/Kconfig" rsource "spi_flash/Kconfig" rsource "spi_ram/Kconfig" rsource "usb/Kconfig" diff --git a/cpu/esp32/esp-idf/Makefile b/cpu/esp32/esp-idf/Makefile index 47090883ead9..7f5fe8c47c55 100644 --- a/cpu/esp32/esp-idf/Makefile +++ b/cpu/esp32/esp-idf/Makefile @@ -48,6 +48,10 @@ ifneq (,$(filter esp_idf_rmt,$(USEMODULE))) DIRS += rmt endif +ifneq (,$(filter esp_idf_sdmmc,$(USEMODULE))) + DIRS += sdmmc +endif + ifneq (,$(filter esp_idf_spi_flash,$(USEMODULE))) DIRS += spi_flash endif diff --git a/cpu/esp32/esp-idf/sdmmc/Kconfig b/cpu/esp32/esp-idf/sdmmc/Kconfig new file mode 100644 index 000000000000..d3bbea952bf8 --- /dev/null +++ b/cpu/esp32/esp-idf/sdmmc/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2021 HAW Hamburg +# 2022 Gunar Schorcht +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +config MODULE_ESP_IDF_SDMMC + bool + depends on TEST_KCONFIG + depends on MODULE_ESP_IDF + default y if MODULE_PERIPH_SDMMC + select PACKAGE_TLSF + help + ESP-IDF heap library. This library is required if external SPI RAM + or the WiFi interface is used. diff --git a/cpu/esp32/esp-idf/sdmmc/Makefile b/cpu/esp32/esp-idf/sdmmc/Makefile new file mode 100644 index 000000000000..6ff7663f0fbf --- /dev/null +++ b/cpu/esp32/esp-idf/sdmmc/Makefile @@ -0,0 +1,18 @@ +MODULE = esp_idf_sdmmc + +# source files to be compiled for this module +ESP32_SDK_SRC = \ + components/driver/sdmmc_host.c \ + components/driver/sdmmc_transaction.c \ + components/soc/$(CPU_FAM)/sdmmc_periph.c \ + # + +# additional include pathes required by this module +# INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include + +include $(RIOTBASE)/Makefile.base + +ESP32_SDK_BIN = $(BINDIR)/$(MODULE) + +include ../esp_idf.mk +include ../esp_idf_cflags.mk diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index da7c759a7b5a..8d54971a8ccf 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -52,6 +52,7 @@ extern "C" { #define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */ #define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */ #define CPU_INUM_BLE 21 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_SDMMC 23 /**< Level interrupt with medium priority 2 */ #define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */ /** @} */ diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index fe2aaeea3139..6e0623533fe5 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -604,6 +604,82 @@ typedef struct { /** @} */ +/** + * @name SDMMC configuration + * + * ESP32x SoC with SDMMC peripheral provide two SDMMC interfaces called slots. + * How many slots can be used depends on the ESP32x SoC, see @ref sdmmc_slot_t. + * + * @{ + */ +/** + * @brief SDIO/SDMMC slots + * + * ESP32x SoCs that have a SDMMC peripheral provide two SDMMC interfaces called + * slots. + * + * @note If the ESP32x variant uses direct I/O functions for the SDMMC signals + * (i.e. `SOC_SDMMC_USE_IOMUX` is defined in SoC capabilities), the + * GPIOs used for the SDMMC slots are fixed. In this case, slot 0 + * can't be used because the GPIOs are defined for Slot 0 are the + * same as those used for the Flash. If the ESP32x variant uses + * the GPIO matrix to route the SDMMC signals to arbitrary pins + * (i.e. `SOC_SDMMC_USE_GPIO_MATRIX` is defined in SoC capabilities), + * slot 0 can be used but the GPIOs used for the slot have to be + * different from those used for the Flash. + */ +typedef enum { +#if IS_USED(SOC_SDMMC_USE_GPIO_MATRIX) || DOXYGEN + SDMMC_SLOT_0 = 0, /**< SD/MMC host controller slot 0 (not usable on ESP32 variant) */ +#endif + SDMMC_SLOT_1 = 1, /**< SD/MMC host controller slot 1 */ +} sdmmc_slot_t; + +/** + * @brief SDMMC slot configuration + * + * If the ESP32x variant uses the GPIO matrix to route the SDMMC signals + * to arbitrary pins (i.e. `SOC_SDMMC_USE_GPIO_MATRIX` is defined in SoC + * capabilities file), the pins must be configured. The bus width is then + * determined from the defined pins. Define the pins for the DAT lines + * as `GPIO_UNDEF` to use a smaller data bus width. + * If the ESP32x variant uses direct I/O (i.e. `SOC_SDMMC_USE_IOMUX` is + * defined in SoC capabilities file), the bus width has to be specified instead. + */ +typedef struct { + sdmmc_slot_t slot; /**< SDMMC slot used [ SDMMC_SLOT_0 | SDMMC_SLOT_1] */ + gpio_t cd; /**< Card Detect pin (must be GPIO_UNDEF if not connected) */ + gpio_t wp; /**< Write Protect pin (must be GPIO_UNDEF if not connected) */ +#if IS_USED(SOC_SDMMC_USE_GPIO_MATRIX) || DOXYGEN + gpio_t clk; /**< CLK pin (must be defined) */ + gpio_t cmd; /**< CMD pin (must be defined) */ + gpio_t dat0; /**< DAT[0] pin (must be defined) */ + gpio_t dat1; /**< DAT[1] pin (GPIO_UNDEF if not connected) */ + gpio_t dat2; /**< DAT[2] pin (GPIO_UNDEF if not connected) */ + gpio_t dat3; /**< DAT[3] pin (GPIO_UNDEF if not connected) */ +#if IS_USED(MODULE_PERIPH_SMMC_8BIT) || DOXYGEN + gpio_t dat4; /**< DAT[4] pin (GPIO_UNDEF if not connected) */ + gpio_t dat5; /**< DAT[5] pin (GPIO_UNDEF if not connected) */ + gpio_t dat6; /**< DAT[6] pin (GPIO_UNDEF if not connected) */ + gpio_t dat7; /**< DAT[7] pin (GPIO_UNDEF if not connected) */ +#endif /* IS_USED(MODULE_PERIPH_SMMC_8BIT) */ +#else /* IS_USED(SOC_SDMMC_USE_IOMUX) */ + uint8_t bus_width; /**< Bus width */ +#endif +} sdmmc_conf_t; + +/** + * @brief SDIO/SDMMC buffer instantiation requirement for SDHC + */ +#define SDMMC_CPU_DMA_REQUIREMENTS __attribute__((aligned(SDMMC_CPU_DMA_ALIGNMENT))) + +/** + * @brief SDIO/SDMMC buffer alignment for SDHC because of DMA/FIFO buffer restrictions + */ +#define SDMMC_CPU_DMA_ALIGNMENT 4 + +/** @} */ + /** * @name SPI configuration * @@ -857,7 +933,8 @@ typedef struct { * @name USB device configuration * @{ * - * ESP32x SoCs integrate depending on the specific ESP32x SoC variant (family) an USB OTG FS controller based on the Synopsys DWC2 IP core. + * ESP32x SoCs integrate depending on the specific ESP32x SoC variant (family) + * an USB OTG FS controller based on the Synopsys DWC2 IP core. */ #include "usbdev_synopsys_dwc2.h" diff --git a/cpu/esp32/include/periph_cpu_esp32.h b/cpu/esp32/include/periph_cpu_esp32.h index 98fe0a3a9197..b7fd02ce747d 100644 --- a/cpu/esp32/include/periph_cpu_esp32.h +++ b/cpu/esp32/include/periph_cpu_esp32.h @@ -95,8 +95,6 @@ extern "C" { * - Vref can be read with function #adc_line_vref_to_gpio at GPIO25. */ -/** @} */ - /** * @name DAC configuration * @@ -130,6 +128,10 @@ extern "C" { * these channels can be clocked by one of the 4 timers. */ +/** + * @name SDMMC configuration + */ + /** * @name SPI configuration * @@ -213,6 +215,7 @@ extern "C" { #define TIMER_NUMOF (2) #define TIMER_CHANNEL_NUMOF (1) #endif +/** @} */ /** * @name UART configuration diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index 7510df505206..f84b92410fc2 100644 --- a/cpu/esp32/irq_arch.c +++ b/cpu/esp32/irq_arch.c @@ -92,6 +92,9 @@ static const struct intr_handle_data_t _irq_data_table[] = { #elif defined(CPU_FAM_ESP32S3) { ETS_LCD_CAM_INTR_SOURCE, CPU_INUM_LCD, 1 }, #endif +#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) + { ETS_SDIO_HOST_INTR_SOURCE, CPU_INUM_SDMMC, 2 }, +#endif }; #define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table) diff --git a/cpu/esp32/periph/sdmmc.c b/cpu/esp32/periph/sdmmc.c new file mode 100644 index 000000000000..06ffce79ac3e --- /dev/null +++ b/cpu/esp32/periph/sdmmc.c @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2023 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp32 + * @{ + * + * @file + * @brief Low-level SDIO/SD/MMC peripheral driver interface for ESP32 + * + * @author Gunar Schorcht + * + * @} + */ + +#include +#include +#include +#include + +#include "assert.h" +#include "bitarithm.h" +#include "container.h" +#include "log.h" +#include "periph/gpio.h" +#include "syscalls.h" +#include "ztimer.h" + +#include "sdmmc/sdmmc.h" + +#include "driver/sdmmc_types.h" +#include "driver/sdmmc_host.h" +#include "soc/sdmmc_reg.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/* CLK_EDGE_SEL - clock phase selection register */ +#define SDMMC_CLOCK_REG_CCLKIN_EDGE_SAM_SEL_S (3) +#define SDMMC_CLOCK_REG_CCLKIN_EDGE_SAM_SEL_M (0x7 << SDMMC_CLOCK_REG_CCLKIN_EDGE_SAM_SEL_S) + +/* we have to redefine it here since we can't include "gpio_types.h" due to + * naming conflicts */ +#define GPIO_NUM_NC (GPIO_UNDEF) + +/* debounce time for CD pin */ +#define CONFIG_CD_PIN_DEBOUNCE_US 25000 + +/* limit the Default and High Speed clock rates for debugging */ +#if CONFIG_SDMMC_CLK_MAX_400KHZ +#define CONFIG_SDMMC_CLK_MAX KHZ(400) +#elif CONFIG_SDMMC_CLK_MAX_1MHZ +#define CONFIG_SDMMC_CLK_MAX MHZ(1) +#elif CONFIG_SDMMC_CLK_MAX_4MHZ +#define CONFIG_SDMMC_CLK_MAX MHZ(4) +#elif CONFIG_SDMMC_CLK_MAX_10MHZ +#define CONFIG_SDMMC_CLK_MAX MHZ(10) +#elif CONFIG_SDMMC_CLK_MAX_20MHZ || !IS_USED(MODULE_PERIPH_SDMMC_HS) +#define CONFIG_SDMMC_CLK_MAX MHZ(20) +#else +#define CONFIG_SDMMC_CLK_MAX MHZ(40) +#endif + +/* millisecond timer definitions dependent on active ztimer backend */ +#if IS_USED(MODULE_ZTIMER_MSEC) +#define _ZTIMER_SLEEP_MS(n) ztimer_sleep(ZTIMER_MSEC, n) +#elif IS_USED(MODULE_ZTIMER_USEC) +#define _ZTIMER_SLEEP_MS(n) ztimer_sleep(ZTIMER_USEC, n * US_PER_MS) +#else +#error "Either ztimer_msec or ztimer_usec is needed" +#endif + +/* forward declaration of _driver */ +static const sdmmc_driver_t _driver; + +/* driver related */ +typedef struct { + sdmmc_dev_t sdmmc_dev; /**< Inherited sdmmc_dev_t struct */ + const sdmmc_conf_t *config; /**< SDIO/SD/MMC peripheral config */ + uint32_t last_cd_pin_irq; /**< Last CD Pin IRQ time for debouncing */ + bool data_transfer; /**< Transfer active */ +} esp32_sdmmc_dev_t; + +static esp32_sdmmc_dev_t _sdmmc_devs[] = { + { + .sdmmc_dev = { + .driver = &_driver, + }, + .config = &sdmmc_config[0], + }, +#if SDMMC_CONFIG_NUMOF == 2 + { + .sdmmc_dev = { + .driver = &_driver, + }, + .config = &sdmmc_config[1], + } +#endif +}; + +/* sanity check of configuration */ +static_assert(SDMMC_CONFIG_NUMOF == ARRAY_SIZE(sdmmc_config), + "SDMMC_CONFIG_NUMOF and the number of elements in sdmmc_config differ"); +static_assert(SDMMC_CONFIG_NUMOF == ARRAY_SIZE(_sdmmc_devs), + "SDMMC_CONFIG_NUMOF and the number of elements in sdmmc_devs differ"); +static_assert(SDMMC_CONFIG_NUMOF <= SOC_SDMMC_NUM_SLOTS, + "SDMMC_CONFIG_NUMOF is greater than the supported number of slots"); + +XFA_CONST(sdmmc_devs, 0) sdmmc_dev_t * const _sdmmc_0 = (sdmmc_dev_t * const)&_sdmmc_devs[0]; +#if SDMMC_CONFIG_NUMOF > 1 +XFA_CONST(sdmmc_devs, 0) sdmmc_dev_t * const _sdmmc_1 = (sdmmc_dev_t * const)&_sdmmc_devs[1]; +#endif + +/* forward declaration of internal functions */ +static int _esp_err_to_sdmmc_err_code(esp_err_t code); +static void _isr_cd_pin(void *arg); + +static void _init(sdmmc_dev_t *sdmmc_dev) +{ + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + assert(dev); + + const sdmmc_conf_t *conf = dev->config; + assert(conf); + + /* additional sanity checks */ + assert(conf->slot < SOC_SDMMC_NUM_SLOTS); + + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + +#if IS_USED(CPU_FAM_ESP32) + + /* On ESP32 only Slot 1 can be used */ + assert(conf->slot == SDMMC_SLOT_1); + /* Slot 1 has only 4 data lines */ + assert((conf->bus_width == 1) || (conf->bus_width == 4)); + + sdmmc_dev->bus_width = conf->bus_width; + +#elif IS_USED(CPU_FAM_ESP32S3) + + assert(gpio_is_valid(conf->clk) && !gpio_is_equal(conf->clk, GPIO0)); + assert(gpio_is_valid(conf->cmd) && !gpio_is_equal(conf->cmd, GPIO0)); + assert(gpio_is_valid(conf->dat0) && !gpio_is_equal(conf->dat0, GPIO0)); + + /* TODO Check for collision with Flash GPIOs */ + slot_config.clk = conf->clk; + slot_config.cmd = conf->cmd; + slot_config.d0 = conf->dat0; + + sdmmc_dev->bus_width = SDMMC_BUS_WIDTH_1BIT; + + slot_config.d1 = GPIO_UNDEF; + slot_config.d2 = GPIO_UNDEF; + slot_config.d3 = GPIO_UNDEF; + slot_config.d4 = GPIO_UNDEF; + slot_config.d5 = GPIO_UNDEF; + slot_config.d6 = GPIO_UNDEF; + slot_config.d7 = GPIO_UNDEF; + + if (gpio_is_valid(conf->dat1) && !gpio_is_equal(conf->dat1, GPIO0) && + gpio_is_valid(conf->dat2) && !gpio_is_equal(conf->dat2, GPIO0) && + gpio_is_valid(conf->dat3) && !gpio_is_equal(conf->dat3, GPIO0)) { + slot_config.d1 = conf->dat1; + slot_config.d2 = conf->dat2; + slot_config.d3 = conf->dat3; + sdmmc_dev->bus_width = SDMMC_BUS_WIDTH_4BIT; + +#if IS_USED(MODULE_PERIPH_SDMMC_8BIT) + if (gpio_is_valid(conf->dat4) && !gpio_is_equal(conf->dat4, GPIO0) && + gpio_is_valid(conf->dat5) && !gpio_is_equal(conf->dat5, GPIO0) && + gpio_is_valid(conf->dat6) && !gpio_is_equal(conf->dat6, GPIO0) && + gpio_is_valid(conf->dat7) && !gpio_is_equal(conf->dat7, GPIO0)) { + slot_config.d4 = conf->dat4; + slot_config.d5 = conf->dat5; + slot_config.d6 = conf->dat6; + slot_config.d7 = conf->dat7; + sdmmc_dev->bus_width = SDMMC_BUS_WIDTH_8BIT; + } +#endif + } + +#else +#error "ESP32x variant not supported" +#endif + +#if IS_USED(CONFIG_SDMMC_INTERNAL_PULLUP) + slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; +#endif + + slot_config.width = sdmmc_dev->bus_width; + + dev->data_transfer = false; + + esp_err_t res; + + if ((res = sdmmc_host_init())) { + LOG_ERROR("[sdmmc] Could not initialize SDMMC host controller\n"); + assert(false); + } + if ((res = sdmmc_host_init_slot(dev->config->slot, &slot_config))) { + LOG_ERROR("[sdmmc] Could not initialize SDMMC slot\n"); + assert(false); + } + + if (gpio_is_valid(conf->cd)) { + dev->last_cd_pin_irq = system_get_time(); + + gpio_init_int(conf->cd, GPIO_IN, GPIO_BOTH, _isr_cd_pin, sdmmc_dev); + sdmmc_dev->present = gpio_read(conf->cd) == 0; + } + else { + sdmmc_dev->present = true; + } + + sdmmc_dev->bus_width = SDMMC_BUS_WIDTH_1BIT; // SDMMC_BUS_WIDTH_4BIT; +} + +static int _send_cmd(sdmmc_dev_t *sdmmc_dev, sdmmc_cmd_t cmd_idx, uint32_t arg, + sdmmc_resp_t resp_type, uint32_t *resp) +{ + /* to ensure that `sdmmc_send_acmd` is used for application specific commands */ + assert((cmd_idx & SDMMC_ACMD_PREFIX) == 0); + + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + + assert(dev); + assert(dev->config); + + if (dev->data_transfer) { + /* data transfer command is issued in _xfer_execute as one transaction + * together with data phase */ + return 0; + } + + sdmmc_command_t cmd = { + .opcode =cmd_idx, + .flags = 0, + .arg = arg, + .data = 0, + .datalen = 0, + .blklen = 0, + .timeout_ms = 100, + }; + + switch (resp_type) { + case SDMMC_R1: + cmd.flags |= SCF_RSP_R1; + break; + case SDMMC_R1B: + cmd.flags |= SCF_RSP_R1B; + break; + case SDMMC_R2: + cmd.flags |= SCF_RSP_R2; + break; + case SDMMC_R3: + cmd.flags |= SCF_RSP_R3; + break; + case SDMMC_R4: + cmd.flags |= SCF_RSP_R4; + break; + case SDMMC_R5: + cmd.flags |= SCF_RSP_R5; + break; + case SDMMC_R6: + cmd.flags |= SCF_RSP_R7; + break; + case SDMMC_R7: + cmd.flags |= SCF_RSP_R7; + break; + default: + break; + } + + esp_err_t res = sdmmc_host_do_transaction(dev->config->slot, &cmd); + if (res) { + return _esp_err_to_sdmmc_err_code(res); + } + else if (cmd.error) { + return _esp_err_to_sdmmc_err_code(cmd.error); + } + + if ((resp_type == SDMMC_R1) || (resp_type == SDMMC_R1B)) { + sdmmc_dev->status = cmd.response[0]; + } + + if (resp) { + if (resp_type == SDMMC_R2) { + resp[0] = cmd.response[3]; + resp[1] = cmd.response[2]; + resp[2] = cmd.response[1]; + resp[3] = cmd.response[0]; + } + else if (resp_type != SDMMC_NO_R) { + resp[0] = cmd.response[0]; + } + } + + return 0; +} + +static int _set_bus_width(sdmmc_dev_t *sdmmc_dev, sdmmc_bus_width_t width) +{ + DEBUG("[sdmmc] %s width=%d\n", __func__, width); + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + assert(dev); + + esp_err_t res = sdmmc_host_set_bus_width(dev->config->slot, width); + if (res) { + return _esp_err_to_sdmmc_err_code(res); + } + + return 0; +} + +static int _set_clock_rate(sdmmc_dev_t *sdmmc_dev, sdmmc_clock_rate_t rate) +{ + DEBUG("[sdmmc] %s rate=%"PRIu32" ", __func__, (uint32_t)rate); + + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + assert(dev); + + if (rate > CONFIG_SDMMC_CLK_MAX) { + rate = CONFIG_SDMMC_CLK_MAX; + } + + DEBUG("actual_rate=%"PRIu32"\n", (uint32_t)rate); + + esp_err_t res = sdmmc_host_set_card_clk(dev->config->slot, rate / KHZ(1)); + if (res) { + return _esp_err_to_sdmmc_err_code(res); + } + +#if SOC_SDMMC_USE_GPIO_MATRIX + /* phase has to be modified to get it working for MMCs if + * SOC_SDMMC_USE_GPIO_MATRIX is used */ + uint32_t reg = *((uint32_t *)SDMMC_CLOCK_REG); + reg &= ~SDMMC_CLOCK_REG_CCLKIN_EDGE_SAM_SEL_M; + reg |= (6 << SDMMC_CLOCK_REG_CCLKIN_EDGE_SAM_SEL_S); + *((uint32_t *)SDMMC_CLOCK_REG) = reg; +#endif + + return 0; +} + +static int _xfer_prepare(sdmmc_dev_t *sdmmc_dev, sdmmc_xfer_desc_t *xfer) +{ + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + + assert(dev); + assert(dev->config); + + /* SDIO/SD/MMC uses 32-bit words */ + /* TODO: at the moment only 32-bit words supported */ + assert((xfer->block_size % sizeof(uint32_t)) == 0); + + dev->data_transfer = true; + + return 0; +} + +static int _xfer_execute(sdmmc_dev_t *sdmmc_dev, sdmmc_xfer_desc_t *xfer, + const void *data_wr, void *data_rd, + uint16_t *done) +{ + assert(xfer); + assert((xfer->write && data_wr) || (!xfer->write && data_rd)); + + /* check the alignment required for the buffers */ + assert(HAS_ALIGNMENT_OF(data_wr, SDMMC_CPU_DMA_ALIGNMENT)); + assert(HAS_ALIGNMENT_OF(data_rd, SDMMC_CPU_DMA_ALIGNMENT)); + + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + + assert(dev); + assert(dev->config); + + sdmmc_command_t cmd = { + .opcode = xfer->cmd_idx & ~SDMMC_ACMD_PREFIX, + .flags = SCF_RSP_R1 | (xfer->write ? 0 : SCF_CMD_READ), + .arg = xfer->arg, + .data = xfer->write ? (void *)data_wr : data_rd, + .datalen = xfer->block_num * xfer->block_size, + .blklen = xfer->block_size, + .timeout_ms = xfer->write ? 2500 : 1000, // TODO + }; + + if (done) { + *done = 0; + } + + esp_err_t res = sdmmc_host_do_transaction(dev->config->slot, &cmd); + if (res) { + return _esp_err_to_sdmmc_err_code(res); + } + else if (cmd.error) { + return _esp_err_to_sdmmc_err_code(cmd.error); + } + + if (done) { + *done = xfer->block_num; + } + + return 0; +} + +static int _xfer_finish(sdmmc_dev_t *sdmmc_dev, sdmmc_xfer_desc_t *xfer) +{ + (void)xfer; + + esp32_sdmmc_dev_t *dev = container_of(sdmmc_dev, esp32_sdmmc_dev_t, sdmmc_dev); + dev->data_transfer = false; + + return 0; +} + +static int _esp_err_to_sdmmc_err_code(esp_err_t error) +{ + switch (error) { + case ESP_ERR_TIMEOUT: + DEBUG("[sdmmc] Timeout error\n"); + return -ETIMEDOUT; + case ESP_ERR_INVALID_CRC: + DEBUG("[sdmmc] CRC error\n"); + return -EBADMSG; + case ESP_ERR_INVALID_RESPONSE: + DEBUG("[sdmmc] Invalid response\n"); + return -EIO; + case ESP_ERR_INVALID_SIZE: + DEBUG("[sdmmc] Invalid size\n"); + return -EIO; + case ESP_ERR_INVALID_ARG: + DEBUG("[sdmmc] Invalid argument\n"); + return -EIO; + default: + DEBUG("[sdmmc] Other error\n"); + return -EIO; + } +} + +static void _isr_cd_pin(void *arg) +{ + uint32_t state = irq_disable(); + + esp32_sdmmc_dev_t *dev = arg; + assert(dev); + + /* for debouncing handle only the first CD Pin interrupts and ignore further + * interrupts that happen within the debouncing time interval */ + if ((system_get_time() - dev->last_cd_pin_irq) > CONFIG_CD_PIN_DEBOUNCE_US) { + dev->last_cd_pin_irq = system_get_time(); + + sdmmc_dev_t *sdmmc_dev = &dev->sdmmc_dev; + + sdmmc_dev->present = !sdmmc_dev->present; + sdmmc_dev->init_done = false; + + if (sdmmc_dev->event_cb) { + sdmmc_dev->event_cb(sdmmc_dev, + sdmmc_dev->present ? SDMMC_EVENT_CARD_INSERTED + : SDMMC_EVENT_CARD_REMOVED); + } + } + irq_restore(state); +} + +static const sdmmc_driver_t _driver = { + .init = _init, + .card_init = NULL, /* no own card init function */ + .send_cmd = _send_cmd, + .set_bus_width = _set_bus_width, + .set_clock_rate = _set_clock_rate, + .xfer_prepare = _xfer_prepare, + .xfer_execute = _xfer_execute, + .xfer_finish = _xfer_finish, +}; diff --git a/pkg/esp32_sdk/patches/0031-driver-sdmmc-avoid-type-definition-conflicts.patch b/pkg/esp32_sdk/patches/0031-driver-sdmmc-avoid-type-definition-conflicts.patch new file mode 100644 index 000000000000..cfe293be65bd --- /dev/null +++ b/pkg/esp32_sdk/patches/0031-driver-sdmmc-avoid-type-definition-conflicts.patch @@ -0,0 +1,48 @@ +From b00693f50e7f4b8239384c7b06ef1dd5a85f2ca9 Mon Sep 17 00:00:00 2001 +From: Gunar Schorcht +Date: Tue, 27 Jun 2023 16:24:27 +0200 +Subject: [PATCH 31/31] driver/sdmmc: avoid type definition conflicts + +--- + components/driver/include/driver/sdmmc_types.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/components/driver/include/driver/sdmmc_types.h b/components/driver/include/driver/sdmmc_types.h +index cbb796fdbb3..c3d27bec18d 100644 +--- a/components/driver/include/driver/sdmmc_types.h ++++ b/components/driver/include/driver/sdmmc_types.h +@@ -29,6 +29,7 @@ + #include "esp_err.h" + #include "freertos/FreeRTOS.h" + ++#if !defined(RIOT_VERSION) + /** + * Decoded values from SD card Card Specific Data register + */ +@@ -69,6 +70,8 @@ typedef struct { + uint8_t power_class; /*!< Power class used by the card */ + } sdmmc_ext_csd_t; + ++#endif /* !defined(RIOT_VERSION) */ ++ + /** + * SD/MMC command response buffer + */ +@@ -160,6 +163,7 @@ typedef struct { + int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */ + } sdmmc_host_t; + ++#if !defined(RIOT_VERSION) + /** + * SD/MMC card information structure + */ +@@ -185,5 +189,6 @@ typedef struct { + uint32_t reserved : 23; /*!< Reserved for future expansion */ + } sdmmc_card_t; + ++#endif /* !defined(RIOT_VERSION) */ + + #endif // _SDMMC_TYPES_H_ +-- +2.34.1 + From 5646cc02e400f8049fa721cef3179c0073de18e1 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 13 Sep 2023 06:53:39 +0200 Subject: [PATCH 2/8] boards/common/esp32x: add SDMMC support --- boards/common/esp32x/include/board_common.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/boards/common/esp32x/include/board_common.h b/boards/common/esp32x/include/board_common.h index 30b98def2c70..b39c1d03b95d 100644 --- a/boards/common/esp32x/include/board_common.h +++ b/boards/common/esp32x/include/board_common.h @@ -7,7 +7,7 @@ */ /** - * @ingroup boards_common + * @ingroup boards_common_esp32x * @brief Board definitions that are common for all ESP32x boards. * * This file contains board configurations that are valid for all ESP32. @@ -103,17 +103,30 @@ extern "C" { #if MODULE_MTD_SDCARD_DEFAULT || DOXYGEN #define MTD_1 mtd_dev_get(1) /**< MTD device for the SD Card */ +#elif MODULE_MTD_SDMMC_DEFAULT +#define MTD_1 mtd_dev_get(1) /**< MTD device for the SD/MMC Card */ #endif /* MODULE_MTD_SDCARD_DEFAULT || DOXYGEN */ /** - * @brief MTD offset for SD Card interfaces + * @brief Default MTD offset for SPI SD Card interfaces * - * MTD_1 is used for SD Card. + * mtd1 is used for SPI SD Cards by default if module `mtd_sdcard_default` + * is used. */ #ifndef CONFIG_SDCARD_GENERIC_MTD_OFFSET #define CONFIG_SDCARD_GENERIC_MTD_OFFSET 1 #endif +/** + * @brief Default MTD offset for SD/MMC interfaces + * + * mtd1 is used for SD/MMCs by default if module `mtd_sdmmc_default` + * is used. + */ +#ifndef CONFIG_SDMMC_GENERIC_MTD_OFFSET +#define CONFIG_SDMMC_GENERIC_MTD_OFFSET 1 +#endif + /** @} */ #endif /* MODULE_MTD || DOXYGEN */ From c4de3435773a1c8ca5e55e93eab8a97c2cfee9f9 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 29 Jun 2023 12:50:39 +0200 Subject: [PATCH 3/8] board/esp32-mh-et-live-minikit: improve the use of SPI SD Card module --- boards/esp32-mh-et-live-minikit/Makefile.dep | 12 ++++++++++++ boards/esp32-mh-et-live-minikit/doc.txt | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/boards/esp32-mh-et-live-minikit/Makefile.dep b/boards/esp32-mh-et-live-minikit/Makefile.dep index 29d6c99ba8ee..9b22e1fdcbfd 100644 --- a/boards/esp32-mh-et-live-minikit/Makefile.dep +++ b/boards/esp32-mh-et-live-minikit/Makefile.dep @@ -1 +1,13 @@ +# if the sdcard_spi module is enabled, the SD Card Shield is used +ifneq (,$(filter sdcard_spi,$(USEMODULE))) + # default to using fatfs on SD card + ifneq (,$(filter vfs_default,$(USEMODULE))) + USEMODULE += fatfs_vfs + USEMODULE += mtd + endif + ifneq (,$(filter mtd,$(USEMODULE))) + USEMODULE += mtd_sdcard_default + endif +endif + include $(RIOTBOARD)/common/esp32/Makefile.dep diff --git a/boards/esp32-mh-et-live-minikit/doc.txt b/boards/esp32-mh-et-live-minikit/doc.txt index 8deca0fc66f5..7a9deb65f851 100644 --- a/boards/esp32-mh-et-live-minikit/doc.txt +++ b/boards/esp32-mh-et-live-minikit/doc.txt @@ -31,7 +31,7 @@ interesting development kit as it uses in the stackable Wemos D1 Mini format. Thus, all [shields for Wemos D1 mini](https://docs.wemos.cc/en/latest/d1_mini_shield/index.html) for ESP8266 can also be used with ESP32. Examples for such shields are: -- Micro SD-Card Shield +- Micro SD-Card Shield (enable module `sdcard_spi` to use it) - MRF24J40 IEEE 802.15.4 radio Shield - Button Shield - RGB LED Shield From a376b3c91587a3538a58acfb8242e6970eb5bec0 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 2 Jul 2023 15:18:20 +0200 Subject: [PATCH 4/8] boards/common/esp32x: add sanity check for SPI in case SDMMC is used --- boards/common/esp32x/include/periph_conf_common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/common/esp32x/include/periph_conf_common.h b/boards/common/esp32x/include/periph_conf_common.h index 2f7bfe6bfab5..0d56301e4885 100644 --- a/boards/common/esp32x/include/periph_conf_common.h +++ b/boards/common/esp32x/include/periph_conf_common.h @@ -338,6 +338,10 @@ static const spi_conf_t spi_config[] = { * @note SPI_NUMOF definition must not be changed. */ #define SPI_NUMOF ARRAY_SIZE(spi_config) + +#if IS_USED(MODULE_PERIPH_SPI) +static_assert(SPI_NUMOF != 0, "No SPI devices defined"); +#endif /** @} */ /** From 7ba9cbe736f051c870e5ab0945ad3f0239e62afb Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 2 Jul 2023 15:33:08 +0200 Subject: [PATCH 5/8] boards/esp32-olimex-evb: add SDMMC support --- boards/esp32-olimex-evb/Kconfig | 3 ++ boards/esp32-olimex-evb/Makefile.dep | 10 ++++ boards/esp32-olimex-evb/Makefile.features | 11 ++++- boards/esp32-olimex-evb/doc.txt | 12 ++--- boards/esp32-olimex-evb/include/periph_conf.h | 47 ++++++++++++++----- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/boards/esp32-olimex-evb/Kconfig b/boards/esp32-olimex-evb/Kconfig index 7b52efabd3f7..e3758545c4bd 100644 --- a/boards/esp32-olimex-evb/Kconfig +++ b/boards/esp32-olimex-evb/Kconfig @@ -17,8 +17,11 @@ config BOARD_ESP32_OLIMEX_EVB select HAS_PERIPH_ADC if USEMODULE_OLIMEX_ESP32_GATEWAY select HAS_PERIPH_I2C select HAS_PERIPH_PWM + select HAS_PERIPH_SDMMC select HAS_PERIPH_SPI select HAS_PERIPH_CAN select HAS_PERIPH_IR + select HAVE_MTD_SDMMC_DEFAULT + source "$(RIOTBOARD)/common/esp32/Kconfig" diff --git a/boards/esp32-olimex-evb/Makefile.dep b/boards/esp32-olimex-evb/Makefile.dep index 1b7c4590a759..bd77f00ea246 100644 --- a/boards/esp32-olimex-evb/Makefile.dep +++ b/boards/esp32-olimex-evb/Makefile.dep @@ -4,3 +4,13 @@ include $(RIOTBOARD)/common/esp32/Makefile.dep ifneq (,$(filter netdev_default,$(USEMODULE))) USEMODULE += esp_eth endif + +# default to using fatfs on SD card +ifneq (,$(filter vfs_default,$(USEMODULE))) + USEMODULE += fatfs_vfs + USEMODULE += mtd +endif + +ifneq (,$(filter mtd,$(USEMODULE))) + USEMODULE += mtd_sdmmc_default +endif diff --git a/boards/esp32-olimex-evb/Makefile.features b/boards/esp32-olimex-evb/Makefile.features index 7db04be96b69..29a36ef6fa0a 100644 --- a/boards/esp32-olimex-evb/Makefile.features +++ b/boards/esp32-olimex-evb/Makefile.features @@ -3,13 +3,20 @@ CPU_MODEL = esp32-wroom_32 # common board and CPU features include $(RIOTBOARD)/common/esp32/Makefile.features -# additional features provided by the board (no ADC and no DAC) ifneq (,$(filter olimex_esp32_gateway,$(USEMODULE))) + # additional features provided by Olimex ESP32 Gateway FEATURES_PROVIDED += periph_adc +else + # SPI interface is not available on Olimex ESP32 Gateway + FEATURES_PROVIDED += periph_spi endif + FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm -FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_sdmmc + +FEATURES_CONFLICT += periph_sdmmc:periph_spi +FEATURES_CONFLICT_MSG += "SD/MMC and SPI cannot be used at the same time on this board." # unique features of the board FEATURES_PROVIDED += esp_eth # Ethernet MAC (EMAC) diff --git a/boards/esp32-olimex-evb/doc.txt b/boards/esp32-olimex-evb/doc.txt index 4456a24aa230..c2d01521b159 100644 --- a/boards/esp32-olimex-evb/doc.txt +++ b/boards/esp32-olimex-evb/doc.txt @@ -92,15 +92,15 @@ overridden by \ref esp32_application_specific_configurations
Pin | Configuration\n ESP32-EVB | Configuration\n ESP32-GATEWAY | Remarks / Prerequisites | Configuration :------|:------------------|:-----------------|-|-| -GPIO13 | I2C_DEV(0):SDA | SDCARD_CS | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_i2c_interfaces "I2C Interfaces" +GPIO13 | I2C_DEV(0):SDA | SDMMC_DEV(0):DAT3 | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_i2c_interfaces "I2C Interfaces", \ref esp32_sdmmc_interfaces "SDMMC Interfaces" GPIO16 | I2C_DEV(0):SCL | I2C_DEV(0):SCL | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_i2c_interfaces "I2C Interfaces" -GPIO14 | SPI_DEV(0):CLK | SDCARD_CLK | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces" -GPIO2 | SPI_DEV(0):MISO | SDCARD_MISO | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces" -GPIO15 | SPI_DEV(0):MOSI | SDCARD_MOSI | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces" +GPIO14 | SPI_DEV(0):CLK, SDMMC_DEV(0):CLK | SDMMC_DEV(0):CLK | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces", \ref esp32_sdmmc_interfaces "SDMMC Interfaces" +GPIO2 | SPI_DEV(0):MISO, SDMMC_DEV(0):DAT0 | SDMMC_DEV(0):DAT0 | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces", \ref esp32_sdmmc_interfaces "SDMMC Interfaces" +GPIO15 | SPI_DEV(0):MOSI, SDMMC_DEV(0):CMD | SDMMC_DEV(0):CMD | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces", \ref esp32_sdmmc_interfaces "SDMMC Interfaces" GPIO17 | SPI_DEV(0):CS0 | I2C_DEV(0):SDA | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_spi_interfaces "SPI Interfaces" GPIO1 | UART_DEV(0):TxD | UART_DEV(0):TxD | Console (cannot be changed) | \ref esp32_uart_interfaces "UART interfaces" GPIO3 | UART_DEV(0):RxD | UART_DEV(0):RxD | Console (cannot be changed) | \ref esp32_uart_interfaces "UART interfaces" -GPIO4 | UART_DEV(1):TxD | N/A | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_uart_interfaces "UART interfaces" +GPIO4 | UART_DEV(1):TxD | SDMMC_DEV(0):DAT1 | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_uart_interfaces "UART interfaces", \ref esp32_sdmmc_interfaces "SDMMC Interfaces" GPIO36 | UART_DEV(1):RxD | ADC_LINE(2) | on ESP32-EVB available at [UEXT1](https://www.olimex.com/Products/Modules/UEXT) | \ref esp32_uart_interfaces "UART interfaces" GPIO32 | Relais 1 | ADC_LINE(0) | | \ref esp32_adc_channels "ADC Channels" GPIO33 | Relais 2 | LED0 | | | @@ -109,7 +109,7 @@ GPIO9 | PWM_DEV(0):0 | PWM_DEV(0):0 | | \ref esp32_pwm_channels "PWM C GPIO10 | PWM_DEV(0):1 | PWM_DEV(0):1 | | \ref esp32_pwm_channels "PWM Channels" GPIO5 | CAN_DEV(0):TX | | | \ref esp32_can_interfaces "CAN Interfaces" GPIO35 | CAN_DEV(0):RX | ADC_LINE(1) | | \ref esp32_adc_channels "ADC Channels" -GPIO12 | IR_DEV(0):TX | N/A | IR is not yet supported | | +GPIO12 | IR_DEV(0):TX | SDMMC_DEV(0):DAT2 | IR is not yet supported | \ref esp32_sdmmc_interfaces "SDMMC Interfaces" | GPIO39 | IR_DEV(0):RX | ADC_LINE(3) | IR is not yet supported | \ref esp32_adc_channels "ADC Channels" GPIO18 | EMAC_SMI:MDIO | EMAC_SMI:MDIO | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC" GPIO23 | EMAC_SMI:MDC | EMAC_SMI:MDC | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC" diff --git a/boards/esp32-olimex-evb/include/periph_conf.h b/boards/esp32-olimex-evb/include/periph_conf.h index 6d921cf739ea..32e1a2b7c972 100644 --- a/boards/esp32-olimex-evb/include/periph_conf.h +++ b/boards/esp32-olimex-evb/include/periph_conf.h @@ -36,6 +36,8 @@ #include +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -139,6 +141,29 @@ extern "C" { /** @} */ +/** + * @name SD/MMC host controller configuration + * @{ + */ + +/** SDMMC devices */ +static const sdmmc_conf_t sdmmc_config[] = { + { + .slot = SDMMC_SLOT_1, + .cd = GPIO_UNDEF, + .wp = GPIO_UNDEF, +#if MODULE_OLIMEX_ESP32_GATEWAY + .bus_width = 4, +#else + .bus_width = 1, +#endif + }, +}; + +/** Number of configured SDMMC devices */ +#define SDMMC_CONFIG_NUMOF 1 +/** @} */ + /** * @name SPI configuration * @{ @@ -147,12 +172,7 @@ extern "C" { * @brief HSPI is used as SPI_DEV(0) * * It is available at the [UEXT] connector on Olimex ESP32-EVB. - * - * Although the SD card interface of the Olimex ESP32-EVB is also available at - * the `SPI_DEV(0)` interface, it does not have a CS signal. Therefore, - * it cannot be used in SPI mode with the `sdcard_spi` module. Olimex - * ESP32-GATEWAY uses the integrated SD card interface with another GPIO for - * the CS signal. + * If the SD Card/MMC interface is used, the SPI interface is not available. * * @note The GPIOs listed in the configuration are first initialized as SPI * signals when the corresponding SPI interface is used for the first time @@ -160,6 +180,8 @@ extern "C" { * function. That is, they are not allocated as SPI signals before and can * be used for other purposes as long as the SPI interface is not used. */ +#if !MODULE_PERIPH_SDMMC && !MODULE_OLIMEX_ESP32_GATEWAY + #ifndef SPI0_CTRL #define SPI0_CTRL HSPI #endif @@ -173,14 +195,11 @@ extern "C" { #ifndef SPI0_MOSI #define SPI0_MOSI GPIO15 /**< MOSI [UEXT] / SD Card interface] */ #endif - #ifndef SPI0_CS0 -#ifndef MODULE_OLIMEX_ESP32_GATEWAY #define SPI0_CS0 GPIO17 /**< CS0 [UEXT] */ -#else /* MODULE_OLIMEX_ESP32_GATEWAY */ -#define SPI0_CS0 GPIO13 /**< CS0 SD Card interface */ -#endif /* MODULE_OLIMEX_ESP32_GATEWAY */ -#endif /* SPI0_CS0 */ +#endif + +#endif /* !MODULE_PERIPH_SDMMC && !MODULE_OLIMEX_ESP32_GATEWAY */ /** @} */ @@ -201,12 +220,16 @@ extern "C" { #define UART0_TXD GPIO1 /**< direct I/O pin for UART_DEV(0), can't be changed */ #define UART0_RXD GPIO3 /**< direct I/O pin for UART_DEV(0), can't be changed */ +#if !MODULE_OLIMEX_ESP32_GATEWAY + #ifndef UART1_TXD #define UART1_TXD GPIO4 /**< UART_DEV(1) TxD */ #endif #ifndef UART1_RXD #define UART1_RXD GPIO36 /**< UART_DEV(1) RxD */ #endif + +#endif /* !MODULE_OLIMEX_ESP32_GATEWAY */ /** @} */ #ifdef __cplusplus From 517cbc59ffddca04835c87735665b954ae1bb3c8 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Mon, 3 Jul 2023 12:19:11 +0200 Subject: [PATCH 6/8] boards/esp32-wrover-kit: add SDMMC support --- boards/esp32-wrover-kit/Kconfig | 4 +- boards/esp32-wrover-kit/Makefile.dep | 11 +++-- boards/esp32-wrover-kit/Makefile.features | 1 + boards/esp32-wrover-kit/doc.txt | 29 ++++++++----- boards/esp32-wrover-kit/include/periph_conf.h | 42 ++++++++++++++++--- 5 files changed, 66 insertions(+), 21 deletions(-) diff --git a/boards/esp32-wrover-kit/Kconfig b/boards/esp32-wrover-kit/Kconfig index e19495d7efe0..c9e7748ae721 100644 --- a/boards/esp32-wrover-kit/Kconfig +++ b/boards/esp32-wrover-kit/Kconfig @@ -18,11 +18,13 @@ config BOARD_ESP32_WROVER_KIT select HAS_PERIPH_ADC select HAS_PERIPH_I2C select HAS_PERIPH_PWM + select HAS_PERIPH_SDMMC select HAS_PERIPH_SPI select HAS_SDCARD_SPI select HAVE_ILI9341 - select HAVE_MTD_SDCARD_DEFAULT + select HAVE_MTD_SDMMC_DEFAULT if !MODULE_SDCARD_SPI + select MODULE_FATFS_VFS if MODULE_VFS_DEFAULT source "$(RIOTBOARD)/common/esp32/Kconfig" diff --git a/boards/esp32-wrover-kit/Makefile.dep b/boards/esp32-wrover-kit/Makefile.dep index 11982c736c00..5c610ad04811 100644 --- a/boards/esp32-wrover-kit/Makefile.dep +++ b/boards/esp32-wrover-kit/Makefile.dep @@ -5,14 +5,17 @@ endif # Sets up configuration for openocd USEMODULE += esp_jtag -ifneq (,$(filter mtd,$(USEMODULE))) - USEMODULE += mtd_sdcard_default -endif - # default to using fatfs on SD card ifneq (,$(filter vfs_default,$(USEMODULE))) USEMODULE += fatfs_vfs USEMODULE += mtd endif +ifneq (,$(filter mtd,$(USEMODULE))) + ifeq (,$(filter sdcard_spi,$(USEMODULE))) + # use mtd_sdmmc_default if sdcard_spi isn't explicitly enabled + USEMODULE += mtd_sdmmc_default + endif +endif + include $(RIOTBOARD)/common/esp32/Makefile.dep diff --git a/boards/esp32-wrover-kit/Makefile.features b/boards/esp32-wrover-kit/Makefile.features index c93ac66276b4..2f8181395a28 100644 --- a/boards/esp32-wrover-kit/Makefile.features +++ b/boards/esp32-wrover-kit/Makefile.features @@ -7,6 +7,7 @@ include $(RIOTBOARD)/common/esp32/Makefile.features FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm +FEATURES_PROVIDED += periph_sdmmc FEATURES_PROVIDED += periph_spi # unique features provided by the board diff --git a/boards/esp32-wrover-kit/doc.txt b/boards/esp32-wrover-kit/doc.txt index b74766eb9b7a..22bb6593427c 100644 --- a/boards/esp32-wrover-kit/doc.txt +++ b/boards/esp32-wrover-kit/doc.txt @@ -83,7 +83,7 @@ configuration can be overridden by These abbreviations are used in subsequent tables: -*SDC* = SD-Card interface is used (module **sdcard_spi** is enabled)\n +*SDC* = SD-Card interface is used (module **periph_sdmmc** is enabled)\n *CAM* = Camera is plugged in/used
@@ -95,12 +95,18 @@ These abbreviations are used in subsequent tables: | `ADC_LINE(2)` | `GPIO36` | `GPIO36` | - | - | `CAMERA_D4` | \ref esp32_adc_channels | | `ADC_LINE(3)` | `GPIO39` | `GPIO39` | - | - | `CAMERA_D5` | \ref esp32_adc_channels | | `PWM_DEV(0):0 / LED0` | `GPIO0` | `GPIO0` | - | - | `LED_RED` / `CAMERA_RESET` | \ref esp32_pwm_channels | -| `PWM_DEV(0):2 / LED2` | `GPIO4` | `GPIO4` | - | - | `LED_BLUE` / `CAMERA_D0` | \ref esp32_pwm_channels | +| `PWM_DEV(0):1 / LED2` | `GPIO4` | `GPIO4` | - | - | `LED_BLUE` / `CAMERA_D0` | \ref esp32_pwm_channels | | `LED1` | `GPIO2` | `GPIO2` | `GPIO2` | `GPIO2` | `LED_GREEN` | | | `I2C_DEV(0):SCL` | `GPIO27` | `GPIO27` | `GPIO27` | `GPIO27` | `CAMERA_SIO_C` | \ref esp32_i2c_interfaces | -| `I2C_DEV(0):SDA` | `GPIO26` | `GPIO26` | `GPIO26` | `GPIO27` | `CAMERA_SIO_D` | \ref esp32_i2c_interfaces | +| `I2C_DEV(0):SDA` | `GPIO26` | `GPIO26` | `GPIO26` | `GPIO26` | `CAMERA_SIO_D` | \ref esp32_i2c_interfaces | | `UART_DEV(0):TX` | `GPIO1` | `GPIO1` | `GPIO1` | `GPIO1` | | \ref esp32_uart_interfaces | | `UART_DEV(0):RX` | `GPIO3` | `GPIO3` | `GPIO3` | `GPIO3` | | \ref esp32_uart_interfaces | +| `SDMMC_DEV(0):CLK` | `GPIO14` | `GPIO14` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | +| `SDMMC_DEV(0):CMD` | `GPIO15` | `GPIO` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | +| `SDMMC_DEV(0):DAT0` | `GPIO2` | `GPIO2` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | +| `SDMMC_DEV(0):DAT1` | `GPIO4` | `GPIO4` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | +| `SDMMC_DEV(0):DAT2` | `GPIO12` | `GPIO` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | +| `SDMMC_DEV(0):DAT3` | `GPIO13` | `GPIO` | - | - | SD-Card | \ref esp32_sdmmc_interfaces | | `SPI_DEV(0):SCK` | `GPIO14` | `GPIO14` | `GPIO14` | `GPIO14` | HSPI: SD-Card / Peripherals | \ref esp32_spi_interfaces | | `SPI_DEV(0):MOSI` | `GPIO15` | `GPIO15` | `GPIO15` | `GPIO15` | HSPI: SD-Card / Peripherals | \ref esp32_spi_interfaces | | `SPI_DEV(0):CS0` | `GPIO13` | `GPIO13` | `GPIO13` | `GPIO13` | HSPI: SD-Card CS | \ref esp32_spi_interfaces | @@ -133,17 +139,18 @@ These abbreviations are used in subsequent tables:
-Following table shows the default board configuration sorted by GPIOs. +Following table shows the default board configuration sorted by GPIOs depending +on used hardware.
-| Pin | None | SDC | CAM | SDC+CAM | Remarks | +| Pin | None | SDC 4-bit | CAM | SDC 1-bit + CAM | Remarks | |:-------|:-----------------------|:--------------------|:--------------------|:---------------------------|:-----| | GPIO0 | PWM_DEV(0):0 / LED0 | PWM_DEV(0):0 / LED0 | CAMERA_RESET | CAMERA_RESET | | | GPIO1 | UART_DEV(0):TX | UART_DEV(0):TX | UART_DEV(0):TX | UART_DEV(0):TX | | -| GPIO2 | SPI_DEV(0):MISO / LED1 | SPI_DEV(0):MISO | SPI_DEV(0):MISO | SPI_DEV(0):MISO | HSPI | +| GPIO2 | SPI_DEV(0):MISO / LED1 | SDMMC_DEV(0):DAT0 | SPI_DEV(0):MISO | SDMMC_DEV(0):DAT0 | HSPI | | GPIO3 | UART_DEV(0):RX | UART_DEV(0):RX | UART_DEV(0):RX | UART_DEV(0):RX | | -| GPIO4 | PWM_DEV(0):1 / LED2 | PWM_DEV(0):1 / LED2 | CAMERA_D0 | CAMERA_D0 | | +| GPIO4 | PWM_DEV(0):1 / LED2 | SDMMC_DEV(0):DAT1 | CAMERA_D0 | CAMERA_D0 | | | GPIO5 | LCD LED | LCD_LED | CAMERA_D1 | CAMERA_D1 | | | GPIO6 | Flash CLK | Flash CLK | Flash CLK | Flash CLK | | | GPIO7 | Flash SD0 | Flash SD0 | Flash SD0 | Flash SD0 | | @@ -151,10 +158,10 @@ Following table shows the default board configuration sorted by GPIOs. | GPIO9 | | | | | | | GPIO10 | | | | | | | GPIO11 | Flash CMD | Flash CMD | Flash CMD | Flash CMD | | -| GPIO12 | | | | | | -| GPIO13 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | HSPI / SD-Card CS | -| GPIO14 | SPI_DEV(0):SCK | SPI_DEV(0):SCK | SPI_DEV(0):SCK | SPI_DEV(0):SCK | HSPI | -| GPIO15 | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | HSPI | +| GPIO12 | | SDMMC_DEV(0):DAT2 | | | | +| GPIO13 | SPI_DEV(0):CS0 | SDMMC_DEV(0):DAT3 | SPI_DEV(0):CS0 | | HSPI / SPI SD-Card CS | +| GPIO14 | SPI_DEV(0):SCK | SDMMC_DEV(0):CLK | SPI_DEV(0):SCK | | HSPI | +| GPIO15 | SPI_DEV(0):MOSI | SDMMC_DEV(0):CMD | SPI_DEV(0):MOSI | | HSPI | | GPIO16 | N/A | N/A | N/A | N/A | see below | | GPIO17 | N/A | N/A | N/A | N/A | see below | | GPIO18 | LCD_RESET | LCD_RESET | LCD_RESET | CAMERA_D2 | | diff --git a/boards/esp32-wrover-kit/include/periph_conf.h b/boards/esp32-wrover-kit/include/periph_conf.h index 2899d47dfa80..9ba9cb2d608f 100644 --- a/boards/esp32-wrover-kit/include/periph_conf.h +++ b/boards/esp32-wrover-kit/include/periph_conf.h @@ -46,6 +46,7 @@ #define PERIPH_CONF_H #include +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { @@ -109,10 +110,6 @@ * * LEDs are used as PWM channels for device PWM_DEV(0). * - * @note As long as the according PWM device is not initialized with function - * pwm_init, the GPIOs declared for this device can be used for other - * purposes. - * * @note As long as the according PWM device is not initialized with * the `pwm_init`, the GPIOs declared for this device can be used * for other purposes. @@ -120,8 +117,10 @@ * @{ */ #ifndef PWM0_GPIOS -#if !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN +#if (!MODULE_ESP32_WROVER_KIT_CAMERA && !MODULE_PERIPH_SDMMC) || DOXYGEN #define PWM0_GPIOS { GPIO0, GPIO4 } /**< only available when camera is not connected */ +#elif !MODULE_ESP32_WROVER_KIT_CAMERA +#define PWM0_GPIOS { GPIO0 } #else #define PWM0_GPIOS { } #endif @@ -129,6 +128,33 @@ /** @} */ +/** + * @name SD/MMC host controller configuration + * + * @warning If the camera is plugged in, the SD Card has to be used in + * 1-bit mode. + * @{ + */ + +/** SDMMC devices */ +static const sdmmc_conf_t sdmmc_config[] = { + { + .slot = SDMMC_SLOT_1, + .cd = GPIO21, + .wp = GPIO_UNDEF, +#if MODULE_ESP32_WROVER_KIT_CAMERA + /* if camera used, only DAT0 is available */ + .bus_width = 1, +#else + .bus_width = 4, +#endif + }, +}; + +/** Number of configured SDMMC devices */ +#define SDMMC_CONFIG_NUMOF 1 +/** @} */ + /** * @name SPI configuration * @@ -137,6 +163,12 @@ * HSPI is always available and therefore used as SPI_DEV(0) * VSPI is only available when the camera is not plugged. * + * @warning In order not to change the index of the SPI devices depending on + * the different hardware configuration options including the camera, + * SPI_DEV(0) is also defined in case of using the SD/MMC host + * controller, by default but cannot be used once an SD card is + * inserted. Use SPI_DEV(1) instead in this case. + * * @{ */ From 00c9bb73d8e361e29a0de23924ac3747c236d27a Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 9 Dec 2023 18:58:21 +0100 Subject: [PATCH 7/8] tests/pkg/fatfs: add SDMMC support --- tests/pkg/fatfs/main.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/pkg/fatfs/main.c b/tests/pkg/fatfs/main.c index 1ea15caaa566..5ab8eb474411 100644 --- a/tests/pkg/fatfs/main.c +++ b/tests/pkg/fatfs/main.c @@ -51,16 +51,28 @@ FATFS fat_fs; /* FatFs work area needed for each volume */ #ifdef MODULE_MTD_NATIVE + /* mtd device for native is provided in boards/native/board_init.c */ mtd_dev_t *fatfs_mtd_devs[1]; + +#elif MODULE_MTD_SDMMC + +#include "mtd_sdmmc.h" + +mtd_dev_t *fatfs_mtd_devs[1]; + #elif MODULE_MTD_SDCARD + #include "mtd_sdcard.h" #include "sdcard_spi_params.h" + #define SDCARD_SPI_NUM ARRAY_SIZE(sdcard_spi_params) + /* sdcard devs are provided by drivers/sdcard_spi/sdcard_spi.c */ extern sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM]; mtd_sdcard_t mtd_sdcard_devs[SDCARD_SPI_NUM]; mtd_dev_t *fatfs_mtd_devs[SDCARD_SPI_NUM]; + #endif #define MTD_NUM ARRAY_SIZE(fatfs_mtd_devs) @@ -105,11 +117,11 @@ static int _mount(int argc, char **argv) } else { - #if FF_MAX_SS == FF_MIN_SS +#if FF_MAX_SS == FF_MIN_SS uint16_t sector_size = TEST_FATFS_FIXED_SECTOR_SIZE; - #else +#else uint16_t sector_size = fs->ssize; - #endif +#endif uint64_t total_bytes = (fs->n_fatent - TEST_FATFS_FATENT_OFFSET) * fs->csize; total_bytes *= sector_size; @@ -375,7 +387,7 @@ static const shell_command_t shell_commands[] = { int main(void) { - #if FATFS_FFCONF_OPT_FS_NORTC == 0 +#if FATFS_FFCONF_OPT_FS_NORTC == 0 /* the rtc is used in diskio.c for timestamps of files */ puts("Initializing the RTC driver"); rtc_poweron(); @@ -396,11 +408,14 @@ int main(void) time.tm_min, time.tm_sec); rtc_set_time(&time); - #endif +#endif - #if MODULE_MTD_NATIVE +#if MODULE_MTD_NATIVE fatfs_mtd_devs[0] = mtd_dev_get(0); - #elif MODULE_MTD_SDCARD +#elif MODULE_MTD_SDMMC + extern mtd_sdmmc_t mtd_sdmmc_dev0; + fatfs_mtd_devs[0] = &mtd_sdmmc_dev0.base; +#elif MODULE_MTD_SDCARD for (unsigned int i = 0; i < SDCARD_SPI_NUM; i++){ mtd_sdcard_devs[i].base.driver = &mtd_sdcard_driver; mtd_sdcard_devs[i].sd_card = &sdcard_spi_devs[i]; @@ -413,7 +428,7 @@ int main(void) printf("init sdcard_mtd %u [FAILED]\n", i); } } - #endif +#endif char line_buf[SHELL_DEFAULT_BUFSIZE]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); From 60ab86b2732486deb5ac33792cea00625e7536ec Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 9 Dec 2023 18:58:53 +0100 Subject: [PATCH 8/8] tests/pkg/fatfs_vfs: add SDMMC support --- tests/pkg/fatfs_vfs/main.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/pkg/fatfs_vfs/main.c b/tests/pkg/fatfs_vfs/main.c index f7f4e4050d07..ce206bf7efff 100644 --- a/tests/pkg/fatfs_vfs/main.c +++ b/tests/pkg/fatfs_vfs/main.c @@ -29,7 +29,9 @@ #include "kernel_defines.h" -#ifdef MODULE_MTD_SDCARD +#if MODULE_MTD_SDMMC +#include "mtd_sdmmc.h" +#elif MODULE_MTD_SDCARD #include "mtd_sdcard.h" #include "sdcard_spi.h" #include "sdcard_spi_params.h" @@ -64,9 +66,9 @@ static vfs_mount_t _test_vfs_mount = { #if defined(MODULE_MTD_NATIVE) || defined(MODULE_MTD_MCI) /* mtd devices are provided in the board's board_init.c*/ -#endif - -#if defined(MODULE_MTD_SDCARD) +#elif defined(MODULE_MTD_SDMMC) +extern mtd_sdmmc_t mtd_sdmmc_dev0; +#elif defined(MODULE_MTD_SDCARD) #define SDCARD_SPI_NUM ARRAY_SIZE(sdcard_spi_params) extern sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM]; mtd_sdcard_t mtd_sdcard_devs[SDCARD_SPI_NUM]; @@ -398,20 +400,18 @@ static void test_libc(void) int main(void) { -#if MODULE_MTD_SDCARD +#if defined(MODULE_MTD_NATIVE) || defined(MODULE_MTD_MCI) + fatfs.dev = mtd_dev_get(0); +#elif defined(MODULE_MTD_SDMMC) + fatfs.dev = &mtd_sdmmc_dev0.base; +#elif defined(MODULE_MTD_SDCARD) for(unsigned int i = 0; i < SDCARD_SPI_NUM; i++){ mtd_sdcard_devs[i].base.driver = &mtd_sdcard_driver; mtd_sdcard_devs[i].sd_card = &sdcard_spi_devs[i]; mtd_sdcard_devs[i].params = &sdcard_spi_params[i]; mtd_init(&mtd_sdcard_devs[i].base); } -#endif - -#if defined(MODULE_MTD_NATIVE) || defined(MODULE_MTD_MCI) - fatfs.dev = mtd_dev_get(0); -#endif -#if defined(MODULE_MTD_SDCARD) fatfs.dev = mtd_sdcard; #endif