From b8c3a3aeeee51a736b941a2683f26294db85daf2 Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Thu, 15 Jun 2023 09:22:07 +0200 Subject: [PATCH] Added support for write protection polarity for SDCard Closes https://github.com/espressif/esp-idf/issues/11208 --- .../driver/sdmmc/include/driver/sdmmc_host.h | 5 +++++ components/driver/sdmmc/sdmmc_host.c | 8 ++++--- .../driver/spi/include/driver/sdspi_host.h | 21 ++++++++++++------- components/driver/spi/sdspi/sdspi_host.c | 19 ++++++++++++----- components/sdmmc/test/test_sd.c | 19 ++++++++++++----- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/components/driver/sdmmc/include/driver/sdmmc_host.h b/components/driver/sdmmc/include/driver/sdmmc_host.h index 9005d4eaf4..38375f9f7d 100644 --- a/components/driver/sdmmc/include/driver/sdmmc_host.h +++ b/components/driver/sdmmc/include/driver/sdmmc_host.h @@ -82,6 +82,11 @@ typedef struct { are insufficient however, please make sure external pullups are connected on the bus. This is for debug / example purpose only. */ +#define SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH BIT(1) + /**< GPIO write protect polarity. + * 0 means "active low", i.e. card is protected when the GPIO is low; + * 1 means "active high", i.e. card is protected when GPIO is high. + */ } sdmmc_slot_config_t; #define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used diff --git a/components/driver/sdmmc/sdmmc_host.c b/components/driver/sdmmc/sdmmc_host.c index 7a1a0a5db6..a7602932b0 100644 --- a/components/driver/sdmmc/sdmmc_host.c +++ b/components/driver/sdmmc/sdmmc_host.c @@ -558,6 +558,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) } int gpio_cd = slot_config->cd; int gpio_wp = slot_config->wp; + bool gpio_wp_polarity = slot_config->flags & SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH; uint8_t slot_width = slot_config->width; // Configure pins @@ -649,9 +650,10 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) // if not set, default to WP high (not write protected) matrix_in_wp = GPIO_MATRIX_CONST_ONE_INPUT; } - // WP signal is normally active low, but hardware expects - // an active-high signal, so invert it in GPIO matrix - esp_rom_gpio_connect_in_signal(matrix_in_wp, slot_info->write_protect, true); + // As hardware expects an active-high signal, + // if WP signal is active low, then invert it in GPIO matrix, + // else keep it in its default state + esp_rom_gpio_connect_in_signal(matrix_in_wp, slot_info->write_protect, (gpio_wp_polarity? false : true)); // By default, set probing frequency (400kHz) and 1-bit bus esp_err_t ret = sdmmc_host_set_card_clk(slot, 400); diff --git a/components/driver/spi/include/driver/sdspi_host.h b/components/driver/spi/include/driver/sdspi_host.h index 5f8189fa6b..04c0258e0d 100644 --- a/components/driver/spi/include/driver/sdspi_host.h +++ b/components/driver/spi/include/driver/sdspi_host.h @@ -61,16 +61,20 @@ typedef int sdspi_dev_handle_t; */ typedef struct { spi_host_device_t host_id; ///< SPI host to use, SPIx_HOST (see spi_types.h). - gpio_num_t gpio_cs; ///< GPIO number of CS signal - gpio_num_t gpio_cd; ///< GPIO number of card detect signal - gpio_num_t gpio_wp; ///< GPIO number of write protect signal - gpio_num_t gpio_int; ///< GPIO number of interrupt line (input) for SDIO card. + gpio_num_t gpio_cs; ///< GPIO number of CS signal + gpio_num_t gpio_cd; ///< GPIO number of card detect signal + gpio_num_t gpio_wp; ///< GPIO number of write protect signal + gpio_num_t gpio_int; ///< GPIO number of interrupt line (input) for SDIO card. + bool gpio_wp_polarity; ///< GPIO write protect polarity + /// 0 means "active low", i.e. card is protected when the GPIO is low; + /// 1 means "active high", i.e. card is protected when GPIO is high. } sdspi_device_config_t; -#define SDSPI_SLOT_NO_CS GPIO_NUM_NC ///< indicates that card select line is not used -#define SDSPI_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used -#define SDSPI_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used -#define SDSPI_SLOT_NO_INT GPIO_NUM_NC ///< indicates that interrupt line is not used +#define SDSPI_SLOT_NO_CS GPIO_NUM_NC ///< indicates that card select line is not used +#define SDSPI_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used +#define SDSPI_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used +#define SDSPI_SLOT_NO_INT GPIO_NUM_NC ///< indicates that interrupt line is not used +#define SDSPI_IO_ACTIVE_LOW 0 /** * Macro defining default configuration of SD SPI device. @@ -81,6 +85,7 @@ typedef struct { .gpio_cd = SDSPI_SLOT_NO_CD, \ .gpio_wp = SDSPI_SLOT_NO_WP, \ .gpio_int = GPIO_NUM_NC, \ + .gpio_wp_polarity = SDSPI_IO_ACTIVE_LOW, \ } /** diff --git a/components/driver/spi/sdspi/sdspi_host.c b/components/driver/spi/sdspi/sdspi_host.c index b94f13869d..9fb87753a2 100644 --- a/components/driver/spi/sdspi/sdspi_host.c +++ b/components/driver/spi/sdspi/sdspi_host.c @@ -46,7 +46,11 @@ typedef struct { uint8_t gpio_cs; //!< CS GPIO, or GPIO_UNUSED uint8_t gpio_cd; //!< Card detect GPIO, or GPIO_UNUSED uint8_t gpio_wp; //!< Write protect GPIO, or GPIO_UNUSED - uint8_t gpio_int; //!< Write protect GPIO, or GPIO_UNUSED + uint8_t gpio_int; //!< Write protect GPIO, or GPIO_UNUSED + /// GPIO write protect polarity. + /// 0 means "active low", i.e. card is protected when the GPIO is low; + /// 1 means "active high", i.e. card is protected when GPIO is high. + uint8_t gpio_wp_polarity : 1; /// Set to 1 if the higher layer has asked the card to enable CRC checks uint8_t data_crc_enabled : 1; /// Intermediate buffer used when application buffer is not in DMA memory; @@ -133,13 +137,13 @@ static void cs_low(slot_info_t *slot) } } -/// Return true if WP pin is configured and is low +/// Return true if WP pin is configured and is set as per its polarity static bool card_write_protected(slot_info_t *slot) { if (slot->gpio_wp == GPIO_UNUSED) { return false; } - return gpio_get_level(slot->gpio_wp) == 0; + return gpio_get_level(slot->gpio_wp) == (slot->gpio_wp_polarity ? 1 : 0); } /// Return true if CD pin is configured and is high @@ -322,9 +326,9 @@ static void gpio_intr(void* arg) esp_err_t sdspi_host_init_device(const sdspi_device_config_t* slot_config, sdspi_dev_handle_t* out_handle) { - ESP_LOGD(TAG, "%s: SPI%d cs=%d cd=%d wp=%d", + ESP_LOGD(TAG, "%s: SPI%d cs=%d cd=%d wp=%d wp_polarity:%d", __func__, slot_config->host_id + 1, slot_config->gpio_cs, - slot_config->gpio_cd, slot_config->gpio_wp); + slot_config->gpio_cd, slot_config->gpio_wp, slot_config->gpio_wp_polarity); slot_info_t* slot = (slot_info_t*)malloc(sizeof(slot_info_t)); if (slot == NULL) { @@ -380,6 +384,11 @@ esp_err_t sdspi_host_init_device(const sdspi_device_config_t* slot_config, sdspi if (slot_config->gpio_wp != SDSPI_SLOT_NO_WP) { io_conf.pin_bit_mask |= (1ULL << slot_config->gpio_wp); slot->gpio_wp = slot_config->gpio_wp; + slot->gpio_wp_polarity = slot_config->gpio_wp_polarity; + if (slot->gpio_wp_polarity) { + io_conf.pull_down_en = true; + io_conf.pull_up_en = false; + } } else { slot->gpio_wp = GPIO_UNUSED; } diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c index 1aefc1f928..775777d7aa 100644 --- a/components/sdmmc/test/test_sd.c +++ b/components/sdmmc/test/test_sd.c @@ -69,6 +69,8 @@ #define SDSPI_TEST_CS_PIN GPIO_NUM_13 #endif +#define GPIO_ACTIVE_LOW 0 +#define GPIO_ACTIVE_HIGH 1 TEST_CASE("MMC_RSP_BITS", "[sd]") { @@ -595,7 +597,7 @@ static void test_cd_input(int gpio_cd_num, const sdmmc_host_t* config) free(card); } -static void test_wp_input(int gpio_wp_num, const sdmmc_host_t* config) +static void test_wp_input(int gpio_wp_num, bool gpio_wp_polarity, const sdmmc_host_t* config) { sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); TEST_ASSERT_NOT_NULL(card); @@ -613,12 +615,12 @@ static void test_wp_input(int gpio_wp_num, const sdmmc_host_t* config) uint32_t* data = heap_caps_calloc(1, 512, MALLOC_CAP_DMA); // Check that card write succeeds if WP is high - REG_WRITE(GPIO_OUT_W1TS_REG, BIT(gpio_wp_num)); + REG_WRITE((gpio_wp_polarity? GPIO_OUT_W1TC_REG : GPIO_OUT_W1TS_REG), BIT(gpio_wp_num)); usleep(1000); TEST_ESP_OK(sdmmc_write_sectors(card, &data, 0, 1)); // Check that write fails if WP is low - REG_WRITE(GPIO_OUT_W1TC_REG, BIT(gpio_wp_num)); + REG_WRITE((gpio_wp_polarity? GPIO_OUT_W1TS_REG : GPIO_OUT_W1TC_REG), BIT(gpio_wp_num)); usleep(1000); TEST_ESP_ERR(ESP_ERR_INVALID_STATE, sdmmc_write_sectors(card, &data, 0, 1)); // ...but reads still work @@ -652,11 +654,17 @@ TEST_CASE("WP input works in SD mode", "[sd][test_env=UT_T1_SDMODE]") sdmmc_host_t config = SDMMC_HOST_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); slot_config.gpio_wp = CD_WP_TEST_GPIO; + bool gpio_wp_polarity = GPIO_ACTIVE_LOW; + if (gpio_wp_polarity) { + slot_config.flags |= SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH; + } else { + slot_config.flags &= ~(SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH); + } TEST_ESP_OK(sdmmc_host_init()); usleep(10000); TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); - test_wp_input(CD_WP_TEST_GPIO, &config); + test_wp_input(slot_config.gpio_wp, gpio_wp_polarity, &config); TEST_ESP_OK(sdmmc_host_deinit()); sd_test_board_power_off(); @@ -697,6 +705,7 @@ TEST_CASE("WP input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") dev_config.host_id = config.slot; dev_config.gpio_cs = SDSPI_TEST_CS_PIN; dev_config.gpio_wp = CD_WP_TEST_GPIO; + dev_config.gpio_wp_polarity = GPIO_ACTIVE_LOW; test_sdspi_init_bus(dev_config.host_id, SDSPI_TEST_MOSI_PIN, SDSPI_TEST_MISO_PIN, SDSPI_TEST_SCLK_PIN, SPI_DMA_CH_AUTO); TEST_ESP_OK(sdspi_host_init()); @@ -704,7 +713,7 @@ TEST_CASE("WP input works in SPI mode", "[sd][test_env=UT_T1_SPIMODE]") config.slot = handle; - test_wp_input(CD_WP_TEST_GPIO, &config); + test_wp_input(dev_config.gpio_wp, dev_config.gpio_wp_polarity, &config); TEST_ESP_OK(sdspi_host_deinit()); test_sdspi_deinit_bus(dev_config.host_id);