Selaa lähdekoodia

Merge branch 'bugfix/sdmmc_line_control' into 'master'

bugfix(sdmmc_host): fix some issue with bit width config .

See merge request idf/esp-idf!1900
Angus Gratton 8 vuotta sitten
vanhempi
sitoutus
7e870aefdb

+ 9 - 0
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
  *

+ 1 - 0
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 */

+ 24 - 1
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;

+ 12 - 1
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);

+ 31 - 2
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);
+
+    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][ignore]")
+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();