diff --git a/components/driver/include/driver/sdmmc_host.h b/components/driver/include/driver/sdmmc_host.h index 63023e9030..c298889ed3 100644 --- a/components/driver/include/driver/sdmmc_host.h +++ b/components/driver/include/driver/sdmmc_host.h @@ -39,6 +39,7 @@ extern "C" { .io_voltage = 3.3f, \ .init = &sdmmc_host_init, \ .set_bus_width = &sdmmc_host_set_bus_width, \ + .get_bus_width = &sdmmc_host_get_slot_width, \ .set_card_clk = &sdmmc_host_set_card_clk, \ .do_transaction = &sdmmc_host_do_transaction, \ .deinit = &sdmmc_host_deinit, \ @@ -115,6 +116,14 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) */ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width); +/** + * @brief Get bus width configured in ``sdmmc_host_init_slot`` to be used for data transfer + * + * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) + * @return configured bus width of the specified slot. + */ +size_t sdmmc_host_get_slot_width(int slot); + /** * @brief Set card clock frequency * diff --git a/components/driver/include/driver/sdmmc_types.h b/components/driver/include/driver/sdmmc_types.h index 835eaa3fb7..cece4174ef 100644 --- a/components/driver/include/driver/sdmmc_types.h +++ b/components/driver/include/driver/sdmmc_types.h @@ -125,6 +125,7 @@ typedef struct { float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */ esp_err_t (*init)(void); /*!< Host function to initialize the driver */ esp_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */ + size_t (*get_bus_width)(int slot); /*!< host function to get bus width */ esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */ esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */ esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */ diff --git a/components/driver/sdmmc_host.c b/components/driver/sdmmc_host.c index e233df0a5d..4c297a58f7 100644 --- a/components/driver/sdmmc_host.c +++ b/components/driver/sdmmc_host.c @@ -40,6 +40,7 @@ typedef struct { uint32_t d5; uint32_t d6; uint32_t d7; + uint8_t d3_gpio; uint8_t card_detect; uint8_t write_protect; uint8_t width; @@ -57,6 +58,7 @@ static const sdmmc_slot_info_t s_slot_info[2] = { .d1 = PERIPHS_IO_MUX_SD_DATA1_U, .d2 = PERIPHS_IO_MUX_SD_DATA2_U, .d3 = PERIPHS_IO_MUX_SD_DATA3_U, + .d3_gpio = 10, .d4 = PERIPHS_IO_MUX_GPIO16_U, .d5 = PERIPHS_IO_MUX_GPIO17_U, .d6 = PERIPHS_IO_MUX_GPIO5_U, @@ -72,6 +74,7 @@ static const sdmmc_slot_info_t s_slot_info[2] = { .d1 = PERIPHS_IO_MUX_GPIO4_U, .d2 = PERIPHS_IO_MUX_MTDI_U, .d3 = PERIPHS_IO_MUX_MTCK_U, + .d3_gpio = 13, .card_detect = HOST_CARD_DETECT_N_2_IDX, .write_protect = HOST_CARD_WRITE_PRT_2_IDX, .width = 4 @@ -82,6 +85,7 @@ static const char* TAG = "sdmmc_periph"; static intr_handle_t s_intr_handle; static QueueHandle_t s_event_queue; +size_t s_slot_width[2] = {1,1}; void sdmmc_host_reset() { @@ -324,14 +328,25 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) else if (slot_width > pslot->width) { return ESP_ERR_INVALID_ARG; } + s_slot_width[slot] = slot_width; configure_pin(pslot->clk); configure_pin(pslot->cmd); configure_pin(pslot->d0); + if (slot_width >= 4) { configure_pin(pslot->d1); configure_pin(pslot->d2); - configure_pin(pslot->d3); + //force pull-up D3 to make slave detect SD mode. connect to peripheral after width configuration. + gpio_config_t gpio_conf = { + .pin_bit_mask = BIT(pslot->d3_gpio), + .mode = GPIO_MODE_OUTPUT , + .pull_up_en = 0, + .pull_down_en = 0, + .intr_type = GPIO_INTR_DISABLE, + }; + gpio_config( &gpio_conf ); + gpio_set_level( pslot->d3_gpio, 1 ); if (slot_width == 8) { configure_pin(pslot->d4); configure_pin(pslot->d5); @@ -404,8 +419,10 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width) } else if (width == 4) { SDMMC.ctype.card_width_8 &= ~mask; SDMMC.ctype.card_width |= mask; + configure_pin(s_slot_info[slot].d3); // D3 was set to GPIO high to force slave into SD 1-bit mode, until 4-bit mode is set } else if (width == 8){ SDMMC.ctype.card_width_8 |= mask; + configure_pin(s_slot_info[slot].d3); // D3 was set to GPIO high to force slave into SD 1-bit mode, until 4-bit mode is set } else { return ESP_ERR_INVALID_ARG; } @@ -413,6 +430,12 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width) return ESP_OK; } +size_t sdmmc_host_get_slot_width(int slot) +{ + assert( slot == 0 || slot == 1 ); + return s_slot_width[slot]; +} + static void sdmmc_host_dma_init() { SDMMC.ctrl.dma_enable = 1; diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index a55440225e..594e469767 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -82,6 +82,17 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) memcpy(&card->host, config, sizeof(*config)); const bool is_spi = host_is_spi(card); + if ( !is_spi ) { + //check HOST flags compatible with slot configuration. + int slot_bit_width = config->get_bus_width(config->slot); + if ( slot_bit_width == 1 && (config->flags & (SDMMC_HOST_FLAG_4BIT|SDMMC_HOST_FLAG_8BIT))) { + ESP_LOGW(TAG, "HOST slot only enables 1-bit."); + card->host.flags = ((card->host.flags&(~(SDMMC_HOST_FLAG_4BIT|SDMMC_HOST_FLAG_8BIT)))|SDMMC_HOST_FLAG_1BIT); + } else if ( slot_bit_width == 4 && (config->flags & SDMMC_HOST_FLAG_8BIT)){ + ESP_LOGW(TAG, "HOST slot only enables 4-bit."); + card->host.flags = ((card->host.flags&(~(SDMMC_HOST_FLAG_1BIT|SDMMC_HOST_FLAG_8BIT)))|SDMMC_HOST_FLAG_4BIT); + } + } /* GO_IDLE_STATE (CMD0) command resets the card */ esp_err_t err = sdmmc_send_cmd_go_idle_state(card); if (err != ESP_OK) { @@ -218,7 +229,7 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) /* If the host has been initialized with 4-bit bus support, and the card * supports 4-bit bus, switch to 4-bit bus now. */ - if ((config->flags & SDMMC_HOST_FLAG_4BIT) && + if ((card->host.flags & SDMMC_HOST_FLAG_4BIT) && (card->scr.bus_width & SCR_SD_BUS_WIDTHS_4BIT)) { ESP_LOGD(TAG, "switching to 4-bit bus mode"); err = sdmmc_send_cmd_set_bus_width(card, 4); diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c index 3f2ce01344..0fbe6c5aee 100644 --- a/components/sdmmc/test/test_sd.c +++ b/components/sdmmc/test/test_sd.c @@ -36,7 +36,7 @@ TEST_CASE("MMC_RSP_BITS", "[sd]") TEST_ASSERT_EQUAL_HEX32(0x11, MMC_RSP_BITS(data, 59, 5)); } -TEST_CASE("can probe SD", "[sd][test_env=UT_T1_SDMODE][ignore]") +TEST_CASE("can probe SD (4-bit)", "[sd][test_env=UT_T1_SDMODE]") { sdmmc_host_t config = SDMMC_HOST_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); @@ -50,8 +50,37 @@ TEST_CASE("can probe SD", "[sd][test_env=UT_T1_SDMODE][ignore]") free(card); } +TEST_CASE("can probe SD (1-bit)", "[sd][test_env=UT_T1_SDMODE]") +{ + //the card DAT3 should be connected to high in SD 1-bit mode + //do it by our own GPIO. + gpio_config_t conf = { + .pin_bit_mask = GPIO_SEL_13, + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = 1, + .pull_down_en = 0, + .intr_type = GPIO_INTR_DISABLE, + }; + gpio_config(&conf); + gpio_set_level(GPIO_NUM_13, 1); -TEST_CASE("can probe SD(using SPI)", "[sdspi][test_env=UT_T1_SPIMODE][ignore]") + sdmmc_host_t config = SDMMC_HOST_DEFAULT(); + config.flags = SDMMC_HOST_FLAG_1BIT; + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.width=1; + TEST_ESP_OK(sdmmc_host_init()); + TEST_ESP_OK(sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config)); + sdmmc_card_t* card = malloc(sizeof(sdmmc_card_t)); + TEST_ASSERT_NOT_NULL(card); + TEST_ESP_OK(sdmmc_card_init(&config, card)); + sdmmc_card_print_info(stdout, card); + TEST_ESP_OK(sdmmc_host_deinit()); + free(card); +} + + + +TEST_CASE("can probe SD(using SPI)", "[sdspi][test_env=UT_T1_SPIMODE]") { sdmmc_host_t config = SDSPI_HOST_DEFAULT(); sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();