feat(sd): added power control driver and implementation layer with ldo

pull/13550/head
Armando 2024-01-21 19:29:42 +08:00
rodzic 5154be52ac
commit ec44556a07
24 zmienionych plików z 414 dodań i 46 usunięć

Wyświetl plik

@ -43,7 +43,9 @@ extern "C" {
.command_timeout_ms = 0, \ .command_timeout_ms = 0, \
.get_real_freq = &sdmmc_host_get_real_freq, \ .get_real_freq = &sdmmc_host_get_real_freq, \
.input_delay_phase = SDMMC_DELAY_PHASE_0, \ .input_delay_phase = SDMMC_DELAY_PHASE_0, \
.set_input_delay = &sdmmc_host_set_input_delay \ .set_input_delay = &sdmmc_host_set_input_delay, \
.dma_aligned_buffer = NULL, \
.pwr_ctrl_handle = NULL, \
} }
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used #define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used

Wyświetl plik

@ -665,20 +665,6 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
return ret; return ret;
} }
#if SOC_MULTI_USAGE_LDO_SUPPORTED
esp_ldo_unit_init_cfg_t init_ldo_cfg = {
.unit_id = LDO_UNIT_4,
.cfg = {
.voltage_mv = 3300,
},
.flags.shared_ldo = true,
};
esp_ldo_unit_handle_t ldo_unit = NULL;
ESP_RETURN_ON_ERROR(esp_ldo_init_unit(&init_ldo_cfg, &ldo_unit), TAG, "LDO init failed");
ESP_RETURN_ON_ERROR(esp_ldo_enable_unit(ldo_unit), TAG, "LDO enable failed");
s_host_ctx.slot_ctx[slot].ldo_unit = ldo_unit;
#endif
return ESP_OK; return ESP_OK;
} }
@ -700,16 +686,6 @@ esp_err_t sdmmc_host_deinit(void)
sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false); sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false);
} }
#if SOC_MULTI_USAGE_LDO_SUPPORTED
for (int i = 0; i < SOC_SDMMC_NUM_SLOTS; i++) {
if (s_host_ctx.slot_ctx[i].ldo_unit) {
ESP_RETURN_ON_ERROR(esp_ldo_disable_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO disable failed");
ESP_RETURN_ON_ERROR(esp_ldo_deinit_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO deinit failed");
s_host_ctx.slot_ctx[i].ldo_unit = NULL;
}
}
#endif
return ESP_OK; return ESP_OK;
} }

Wyświetl plik

@ -1,3 +1,3 @@
idf_component_register(SRCS sdmmc_test_board.c sdmmc_test_board_defs.c idf_component_register(SRCS sdmmc_test_board.c sdmmc_test_board_defs.c
INCLUDE_DIRS include INCLUDE_DIRS include
REQUIRES esp_driver_sdmmc esp_driver_sdspi esp_driver_gpio) REQUIRES esp_driver_sdmmc esp_driver_sdspi esp_driver_gpio unity)

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */

Wyświetl plik

@ -1,12 +1,15 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include "sdmmc_test_board.h" #include "sdmmc_test_board.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "unity.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#include "sd_pwr_ctrl.h"
const sdmmc_test_board_slot_info_t* sdmmc_test_board_get_slot_info(int slot_index) const sdmmc_test_board_slot_info_t* sdmmc_test_board_get_slot_info(int slot_index)
{ {
@ -32,6 +35,18 @@ void sdmmc_test_board_get_config_sdmmc(int slot_index, sdmmc_host_t *out_host_co
out_host_config->max_freq_khz = slot->max_freq_khz; out_host_config->max_freq_khz = slot->max_freq_khz;
} }
#if SOC_SDMMC_IO_POWER_EXTERNAL
#define SDMMC_PWR_LDO_CHANNEL 4
sd_pwr_ctrl_ldo_config_t ldo_config = {
.ldo_unit_id = SDMMC_PWR_LDO_CHANNEL,
};
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
TEST_ESP_OK(sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle));
out_host_config->pwr_ctrl_handle = pwr_ctrl_handle;
#endif
#if SOC_SDMMC_USE_GPIO_MATRIX #if SOC_SDMMC_USE_GPIO_MATRIX
out_slot_config->clk = slot->clk; out_slot_config->clk = slot->clk;
out_slot_config->cmd = slot->cmd_mosi; out_slot_config->cmd = slot->cmd_mosi;

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -15,6 +15,8 @@
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
#include "sdmmc_test_begin_end_sd.h" #include "sdmmc_test_begin_end_sd.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "sd_pwr_ctrl.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
void sdmmc_test_sd_skip_if_board_incompatible(int slot, int width, int freq_khz, int ddr) void sdmmc_test_sd_skip_if_board_incompatible(int slot, int width, int freq_khz, int ddr)
{ {
@ -25,14 +27,22 @@ void sdmmc_test_sd_skip_if_board_incompatible(int slot, int width, int freq_khz,
TEST_IGNORE_MESSAGE("Board doesn't have the required slot"); TEST_IGNORE_MESSAGE("Board doesn't have the required slot");
} }
sdmmc_test_board_get_config_sdmmc(slot, &config, &slot_config); sdmmc_test_board_get_config_sdmmc(slot, &config, &slot_config);
int board_max_freq_khz = sdmmc_test_board_get_slot_info(slot)->max_freq_khz; int board_max_freq_khz = sdmmc_test_board_get_slot_info(slot)->max_freq_khz;
if (board_max_freq_khz > 0 && board_max_freq_khz < freq_khz) { if (board_max_freq_khz > 0 && board_max_freq_khz < freq_khz) {
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(config.pwr_ctrl_handle));
#endif
TEST_IGNORE_MESSAGE("Board doesn't support required max_freq_khz"); TEST_IGNORE_MESSAGE("Board doesn't support required max_freq_khz");
} }
if (slot_config.width < width) { if (slot_config.width < width) {
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(config.pwr_ctrl_handle));
#endif
TEST_IGNORE_MESSAGE("Board doesn't support required bus width"); TEST_IGNORE_MESSAGE("Board doesn't support required bus width");
} }
} }
void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_t *out_card) void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_t *out_card)
{ {
sdmmc_host_t config = SDMMC_HOST_DEFAULT(); sdmmc_host_t config = SDMMC_HOST_DEFAULT();
@ -115,4 +125,7 @@ void sdmmc_test_sd_end(sdmmc_card_t *card)
//Need to reset GPIO first, otherrwise cannot discharge VDD of card completely. //Need to reset GPIO first, otherrwise cannot discharge VDD of card completely.
sdmmc_test_board_card_power_set(false); sdmmc_test_board_card_power_set(false);
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(card->host.pwr_ctrl_handle));
#endif
} }

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -9,6 +9,8 @@
#include "driver/sdmmc_host.h" #include "driver/sdmmc_host.h"
#include "sdmmc_test_cd_wp_common.h" #include "sdmmc_test_cd_wp_common.h"
#include "sdmmc_test_board.h" #include "sdmmc_test_board.h"
#include "sd_pwr_ctrl.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
//TODO: IDF-8734 //TODO: IDF-8734
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3 #if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3
@ -27,6 +29,9 @@ TEST_CASE("CD input works in SD mode", "[sdmmc]")
TEST_ESP_OK(sdmmc_host_deinit()); TEST_ESP_OK(sdmmc_host_deinit());
sdmmc_test_board_card_power_set(false); sdmmc_test_board_card_power_set(false);
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(config.pwr_ctrl_handle));
#endif
} }
TEST_CASE("WP input works in SD mode", "[sdmmc]") TEST_CASE("WP input works in SD mode", "[sdmmc]")
@ -44,5 +49,8 @@ TEST_CASE("WP input works in SD mode", "[sdmmc]")
TEST_ESP_OK(sdmmc_host_deinit()); TEST_ESP_OK(sdmmc_host_deinit());
sdmmc_test_board_card_power_set(false); sdmmc_test_board_card_power_set(false);
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(config.pwr_ctrl_handle));
#endif
} }
#endif #endif

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -52,7 +52,7 @@ typedef struct {
esp_ldo_unit_handle_t esp_ldo_init_unit_early(const esp_ldo_unit_init_cfg_t *init_config); esp_ldo_unit_handle_t esp_ldo_init_unit_early(const esp_ldo_unit_init_cfg_t *init_config);
/** /**
* @Brief Init a LDO * @brief Init a LDO
* *
* @param[in] init_config LDO initial configurations * @param[in] init_config LDO initial configurations
* @param[out] ret_unit LDO unit handle * @param[out] ret_unit LDO unit handle
@ -65,7 +65,7 @@ esp_ldo_unit_handle_t esp_ldo_init_unit_early(const esp_ldo_unit_init_cfg_t *ini
esp_err_t esp_ldo_init_unit(const esp_ldo_unit_init_cfg_t *init_config, esp_ldo_unit_handle_t *ret_unit); esp_err_t esp_ldo_init_unit(const esp_ldo_unit_init_cfg_t *init_config, esp_ldo_unit_handle_t *ret_unit);
/** /**
* @Brief Enable a LDO * @brief Enable a LDO
* *
* @param[in] unit LDO unit handle * @param[in] unit LDO unit handle
* *
@ -76,6 +76,18 @@ esp_err_t esp_ldo_init_unit(const esp_ldo_unit_init_cfg_t *init_config, esp_ldo_
*/ */
esp_err_t esp_ldo_enable_unit(esp_ldo_unit_handle_t unit); esp_err_t esp_ldo_enable_unit(esp_ldo_unit_handle_t unit);
/**
* @brief Set LDO output voltage
*
* @param[in] unit LDO unit handle
* @param[in] voltage_mv Voltage in mV
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid arguments
*/
esp_err_t esp_ldo_set_voltage(esp_ldo_unit_handle_t unit, int voltage_mv);
/** /**
* @Brief Disable a LDO * @Brief Disable a LDO
* *
@ -89,7 +101,7 @@ esp_err_t esp_ldo_enable_unit(esp_ldo_unit_handle_t unit);
esp_err_t esp_ldo_disable_unit(esp_ldo_unit_handle_t unit); esp_err_t esp_ldo_disable_unit(esp_ldo_unit_handle_t unit);
/** /**
* @Brief Deinit a LDO * @brief Deinit a LDO
* *
* @param[in] unit LDO unit handle * @param[in] unit LDO unit handle
* *
@ -101,7 +113,7 @@ esp_err_t esp_ldo_disable_unit(esp_ldo_unit_handle_t unit);
esp_err_t esp_ldo_deinit_unit(esp_ldo_unit_handle_t unit); esp_err_t esp_ldo_deinit_unit(esp_ldo_unit_handle_t unit);
/** /**
* Dump LDO usages * @brief Dump LDO usages
* *
* @note This API shall not be called from an ISR. * @note This API shall not be called from an ISR.
* @note This API does not guarantee thread safety * @note This API does not guarantee thread safety

Wyświetl plik

@ -149,6 +149,15 @@ esp_err_t esp_ldo_enable_unit(esp_ldo_unit_handle_t unit)
return ESP_OK; return ESP_OK;
} }
esp_err_t esp_ldo_set_voltage(esp_ldo_unit_handle_t unit, int voltage_mv)
{
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ldo_ll_set_output_voltage_mv(unit->unit_id, voltage_mv);
return ESP_OK;
}
esp_err_t esp_ldo_disable_unit(esp_ldo_unit_handle_t unit) esp_err_t esp_ldo_disable_unit(esp_ldo_unit_handle_t unit)
{ {
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

Wyświetl plik

@ -4,11 +4,18 @@ if(${target} STREQUAL "linux")
return() # This component is not supported by the POSIX/Linux simulator return() # This component is not supported by the POSIX/Linux simulator
endif() endif()
idf_component_register(SRCS "sdmmc_cmd.c" set(srcs "sdmmc_cmd.c"
"sdmmc_common.c" "sdmmc_common.c"
"sdmmc_init.c" "sdmmc_init.c"
"sdmmc_io.c" "sdmmc_io.c"
"sdmmc_mmc.c" "sdmmc_mmc.c"
"sdmmc_sd.c" "sdmmc_sd.c"
INCLUDE_DIRS include "sd_pwr_ctrl/sd_pwr_ctrl.c")
PRIV_REQUIRES soc esp_timer esp_mm)
if(CONFIG_SOC_MULTI_USAGE_LDO_SUPPORTED)
list(APPEND srcs "sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c")
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include
PRIV_REQUIRES soc esp_timer esp_mm)

Wyświetl plik

@ -3,7 +3,7 @@
* *
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileContributor: 2016-2024 Espressif Systems (Shanghai) CO LTD
*/ */
/* /*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@ -27,6 +27,7 @@
#include <stddef.h> #include <stddef.h>
#include "esp_err.h" #include "esp_err.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "sd_pwr_ctrl.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -207,6 +208,7 @@ typedef struct {
sdmmc_delay_phase_t input_delay_phase; /*!< input delay phase, this will only take into effect when the host works in SDMMC_FREQ_HIGHSPEED or SDMMC_FREQ_52M. Driver will print out how long the delay is*/ sdmmc_delay_phase_t input_delay_phase; /*!< input delay phase, this will only take into effect when the host works in SDMMC_FREQ_HIGHSPEED or SDMMC_FREQ_52M. Driver will print out how long the delay is*/
esp_err_t (*set_input_delay)(int slot, sdmmc_delay_phase_t delay_phase); /*!< set input delay phase */ esp_err_t (*set_input_delay)(int slot, sdmmc_delay_phase_t delay_phase); /*!< set input delay phase */
void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */ void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */
sd_pwr_ctrl_handle_t pwr_ctrl_handle; /*!< Power control handle */
} sdmmc_host_t; } sdmmc_host_t;
/** /**

Wyświetl plik

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "esp_bit_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SD power control handle
*/
typedef struct sd_pwr_ctrl_drv_t *sd_pwr_ctrl_handle_t;
/**
* @brief Set SD IO voltage by a registered SD power control driver handle
*
* @param[in] handle SD power control driver handle
* @param[in] voltage_mv Voltage in mV
*/
esp_err_t sd_pwr_ctrl_set_io_voltage(sd_pwr_ctrl_handle_t handle, int voltage_mv);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#include "sd_pwr_ctrl.h"
#include "sd_protocol_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LDO configurations
*/
typedef struct {
int ldo_unit_id; ///< On-chip LDO ID
} sd_pwr_ctrl_ldo_config_t;
/**
* @brief New an SD power control driver via on-chip LDO
*
* @param[in] configs On-chip LDO power control driver configurations
* @param[out] ret_drv Created power control driver handle
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG Invalid arguments
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t sd_pwr_ctrl_new_on_chip_ldo(const sd_pwr_ctrl_ldo_config_t *configs, sd_pwr_ctrl_handle_t *ret_drv);
/**
* @brief Delete a previously created on-chip LDO power control driver
*
* @param[in] ctrl_handle Power control driver handle
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG Invalid arguments
*/
esp_err_t sd_pwr_ctrl_del_on_chip_ldo(sd_pwr_ctrl_handle_t ctrl_handle);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_types.h"
#include "esp_err.h"
#include "sd_pwr_ctrl.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sd_pwr_ctrl_drv_t sd_pwr_ctrl_drv_t;
struct sd_pwr_ctrl_drv_t {
/**
* @brief Set SD IO voltage
*
* @param[in] ctx SD power control specific driver context
* @param[in] voltage_mv Voltage in mV
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
*/
esp_err_t (*set_io_voltage)(void *ctx, int voltage_mv);
/**
* @brief SD power control driver context
* Can be customized to difference power control methods
*/
void *ctx;
};
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "soc/soc_caps.h"
#include "sd_pwr_ctrl_interface.h"
const static char *TAG = "sd_power";
esp_err_t sd_pwr_ctrl_set_io_voltage(sd_pwr_ctrl_handle_t handle, int voltage_mv)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
return handle->set_io_voltage(handle->ctx, voltage_mv);
}

Wyświetl plik

@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_private/esp_ldo.h"
#include "soc/soc_caps.h"
#include "sd_pwr_ctrl.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#include "sd_pwr_ctrl_interface.h"
typedef struct {
esp_ldo_unit_handle_t ldo_unit;
int voltage_mv;
} sd_pwr_ctrl_ldo_ctx_t;
const static char *TAG = "sd_ldo";
static esp_err_t s_ldo_set_voltage(void *arg, int voltage_mv);
esp_err_t sd_pwr_ctrl_new_on_chip_ldo(const sd_pwr_ctrl_ldo_config_t *configs, sd_pwr_ctrl_handle_t *ret_drv)
{
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE(configs && ret_drv, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
sd_pwr_ctrl_drv_t *driver = (sd_pwr_ctrl_drv_t *)heap_caps_calloc(1, sizeof(sd_pwr_ctrl_drv_t), MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(driver, ESP_ERR_NO_MEM, TAG, "no mem for on-chip ldo control driver");
sd_pwr_ctrl_ldo_ctx_t *ctx = (sd_pwr_ctrl_ldo_ctx_t *)heap_caps_calloc(1, sizeof(sd_pwr_ctrl_ldo_ctx_t), MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem for on-chip ldo control driver context");
esp_ldo_unit_init_cfg_t unit_cfg = {
.unit_id = configs->ldo_unit_id,
.cfg = {
.voltage_mv = 0, //will be adjusted dynamically by sdmmc driver later
},
};
esp_ldo_unit_handle_t ldo_unit = NULL;
ESP_GOTO_ON_ERROR(esp_ldo_init_unit(&unit_cfg, &ldo_unit), err, TAG, "failed to create an on-chip LDO unit handle");
ESP_GOTO_ON_ERROR(esp_ldo_enable_unit(ldo_unit), err, TAG, "failed to enable the on-chip LDO unit");
driver->set_io_voltage = s_ldo_set_voltage;
driver->ctx = ctx;
ctx->ldo_unit = ldo_unit;
ctx->voltage_mv = 0;
*ret_drv = driver;
return ESP_OK;
err:
free(ctx);
free(driver);
return ret;
}
esp_err_t sd_pwr_ctrl_del_on_chip_ldo(sd_pwr_ctrl_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
sd_pwr_ctrl_ldo_ctx_t *ctx = handle->ctx;
ESP_RETURN_ON_ERROR(esp_ldo_disable_unit(ctx->ldo_unit), TAG, "failed to disable the on-chip LDO unit");
ESP_RETURN_ON_ERROR(esp_ldo_deinit_unit(ctx->ldo_unit), TAG, "failed to deinit the LDO unit handle");
free(handle->ctx);
handle->ctx = NULL;
free(handle);
handle = NULL;
return ESP_OK;
}
static esp_err_t s_ldo_set_voltage(void *arg, int voltage_mv)
{
//API checks done by caller
sd_pwr_ctrl_ldo_ctx_t *ctx = arg;
ESP_RETURN_ON_ERROR(esp_ldo_set_voltage(ctx->ldo_unit, voltage_mv), TAG, "failed to set LDO unit output voltage");
ctx->voltage_mv = voltage_mv;
return ESP_OK;
}

Wyświetl plik

@ -16,6 +16,8 @@
*/ */
#include "sdmmc_common.h" #include "sdmmc_common.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#include "sd_pwr_ctrl.h"
static const char* TAG = "sdmmc_init"; static const char* TAG = "sdmmc_init";
@ -33,6 +35,7 @@ static const char* TAG = "sdmmc_init";
esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
{ {
esp_err_t ret = ESP_FAIL;
memset(card, 0, sizeof(*card)); memset(card, 0, sizeof(*card));
memcpy(&card->host, config, sizeof(*config)); memcpy(&card->host, config, sizeof(*config));
@ -40,6 +43,15 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
const bool always = true; const bool always = true;
const bool io_supported = true; const bool io_supported = true;
if (config->pwr_ctrl_handle) {
int voltage_mv = config->io_voltage * 1000;
ret = sd_pwr_ctrl_set_io_voltage(config->pwr_ctrl_handle, voltage_mv);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to set voltage (0x%x)", ret);
return ret;
}
}
/* Allocate cache-aligned buffer for SDIO over SDMMC.*/ /* Allocate cache-aligned buffer for SDIO over SDMMC.*/
SDMMC_INIT_STEP(!is_spi, sdmmc_allocate_aligned_buf); SDMMC_INIT_STEP(!is_spi, sdmmc_allocate_aligned_buf);

Wyświetl plik

@ -967,6 +967,10 @@ config SOC_SDMMC_DELAY_PHASE_NUM
int int
default 4 default 4
config SOC_SDMMC_IO_POWER_EXTERNAL
bool
default y
config SOC_SHA_DMA_MAX_BUFFER_SIZE config SOC_SHA_DMA_MAX_BUFFER_SIZE
int int
default 3968 default 3968

Wyświetl plik

@ -396,6 +396,7 @@
#define SOC_SDMMC_NUM_SLOTS 2 #define SOC_SDMMC_NUM_SLOTS 2
/* Supported host clock delay phase number */ /* Supported host clock delay phase number */
#define SOC_SDMMC_DELAY_PHASE_NUM 4 #define SOC_SDMMC_DELAY_PHASE_NUM 4
#define SOC_SDMMC_IO_POWER_EXTERNAL 1 ///< SDMMC IO power controlled by external power supply
// TODO: IDF-5353 (Copy from esp32c3, need check) // TODO: IDF-5353 (Copy from esp32c3, need check)
/*--------------------------- SHA CAPS ---------------------------------------*/ /*--------------------------- SHA CAPS ---------------------------------------*/

Wyświetl plik

@ -21,3 +21,5 @@ INPUT += \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/gpio_num.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/gpio_num.h \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/soc_caps.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/soc_caps.h \
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/uart_channel.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/uart_channel.h \
$(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl.h \
$(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h \

Wyświetl plik

@ -67,7 +67,7 @@ Overview
Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be concurrently shared between an SD card and an SPI flash. If you need to use Slot 0, establish an alternative connection for the SPI flash using different pins and configure the necessary eFuses accordingly. Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be concurrently shared between an SD card and an SPI flash. If you need to use Slot 0, establish an alternative connection for the SPI flash using different pins and configure the necessary eFuses accordingly.
.. only:: esp32s3 .. only:: SOC_SDMMC_USE_GPIO_MATRIX
Both slots :c:macro:`SDMMC_HOST_SLOT_0` and :c:macro:`SDMMC_HOST_SLOT_1` support 1-, 4- and 8-line SD interfaces. The slots are connected to {IDF_TARGET_NAME} GPIOs using the GPIO matrix. This means that any GPIO may be used for each of the SD card signals. Both slots :c:macro:`SDMMC_HOST_SLOT_0` and :c:macro:`SDMMC_HOST_SLOT_1` support 1-, 4- and 8-line SD interfaces. The slots are connected to {IDF_TARGET_NAME} GPIOs using the GPIO matrix. This means that any GPIO may be used for each of the SD card signals.
@ -76,7 +76,7 @@ Overview
- :c:macro:`SDMMC_HOST_SLOT_1` is routed via GPIO Matrix. This means that any GPIO may be used for each of the SD card signals. It is for non UHS-I usage. - :c:macro:`SDMMC_HOST_SLOT_1` is routed via GPIO Matrix. This means that any GPIO may be used for each of the SD card signals. It is for non UHS-I usage.
- :c:macro:`SDMMC_HOST_SLOT_0` is dedicated to UHS-I mode, which is not yet supported in the driver. - :c:macro:`SDMMC_HOST_SLOT_0` is dedicated to UHS-I mode, which is not yet supported in the driver.
Currently SDMMC host driver is using the on-chip LDO 4 as the default power supply. SDMMC power control driver is not supported yet. If you buy the ESP32P4 chip itself and plan to use SDMMC peripheral, make sure the VDDPST_5 pin is connected to the on-chip LDO 4 or correct external power supply. On {IDF_TARGET_NAME}, SDMMC host requires an external power supply for the IO voltage. Please refer to :ref:'pwr-ctrl' for details.
Supported Speed Modes Supported Speed Modes
--------------------- ---------------------
@ -162,6 +162,21 @@ To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_co
Once :cpp:class:`sdmmc_slot_config_t` structure is initialized this way, you can use it when calling :cpp:func:`sdmmc_host_init_slot` or one of the higher level functions (such as :cpp:func:`esp_vfs_fat_sdmmc_mount`). Once :cpp:class:`sdmmc_slot_config_t` structure is initialized this way, you can use it when calling :cpp:func:`sdmmc_host_init_slot` or one of the higher level functions (such as :cpp:func:`esp_vfs_fat_sdmmc_mount`).
.. only:: SOC_SDMMC_IO_POWER_EXTERNAL
.. _pwr-ctrl:
Configuring Voltage Level
-------------------------
{IDF_TARGET_NAME} SDMMC Host requires the IO voltage to be supplied externally via the VDDPST_5 (SD_VREF) pin. If the design doesn't require the higher speed SD modes, this pin can be simply connected to the 3.3V supply.
If the design does require higher speed SD modes (which only work at 1.8V IO levels), there are two options available:
- Use the on-chip programmable LDO. In this case, connect the desired LDO output channel to VDDPST_5 (SD_VREF) pin. Call :cpp:func:'sd_pwr_ctrl_new_on_chip_ldo' to initialize the SD power control driver, then set :cpp:class:'sdmmc_host_t::pwr_ctrl_handle' to the resulting handle.
- Use an external programmable LDO. Likewise, connect the LDO output to the VDDPST_5 (SD_VREF) pin. Then implement a custom `sd_pwr_ctrl` driver to control your LDO. Finally, assign :cpp:class:'sdmmc_host_t::pwr_ctrl_handle' to the handle of your driver instance.
DDR Mode for eMMC Chips DDR Mode for eMMC Chips
----------------------- -----------------------

Wyświetl plik

@ -71,6 +71,12 @@ SDMMC 主机驱动
卡槽 :c:macro:`SDMMC_HOST_SLOT_0`:c:macro:`SDMMC_HOST_SLOT_1` 都支持 1、4、8 线的 SD 接口,这些卡槽通过 GPIO 交换矩阵连接到 {IDF_TARGET_NAME} 的 GPIO即每个 SD 卡信号都可以使用任意 GPIO 连接。 卡槽 :c:macro:`SDMMC_HOST_SLOT_0`:c:macro:`SDMMC_HOST_SLOT_1` 都支持 1、4、8 线的 SD 接口,这些卡槽通过 GPIO 交换矩阵连接到 {IDF_TARGET_NAME} 的 GPIO即每个 SD 卡信号都可以使用任意 GPIO 连接。
.. only:: esp32p4
- 卡槽 :c:macro:`SDMMC_HOST_SLOT_1` 通过GPIO矩阵连接。这意味着任何GPIO都可以用于每个SD卡信号。它适用于非UHS-I用途。
- 卡槽 :c:macro:`SDMMC_HOST_SLOT_0` 专用于UHS-I模式驱动程序中尚不支持该模式。
目前SDMMC主机需要为IO电平提供外部电压参考。如果您自行购买ESP32P4芯片并计划使用SDMMC外设请参阅 :ref:'wr-ctrl' 。
支持的速率模式 支持的速率模式
--------------------- ---------------------
@ -156,6 +162,18 @@ SDMMC 主机驱动支持以下速率模式:
通过上述方式初始化 :cpp:class:`sdmmc_slot_config_t` 结构体后,即可在调用 :cpp:func:`sdmmc_host_init_slot` 或其他任意高层函数(如 :cpp:func:`esp_vfs_fat_sdmmc_mount`)时使用该结构体。 通过上述方式初始化 :cpp:class:`sdmmc_slot_config_t` 结构体后,即可在调用 :cpp:func:`sdmmc_host_init_slot` 或其他任意高层函数(如 :cpp:func:`esp_vfs_fat_sdmmc_mount`)时使用该结构体。
.. only:: SOC_SDMMC_IO_POWER_EXTERNAL
.. _pwr-ctrl:
配置供电和参考电压
------------------
{IDF_TARGET_NAME} SDMMC主机需要为IO电平提供外部电压参考 ,以支持高速设备, 驱动器将动态配置电压参考。您可以使用片上可编程LDO作为从机电源和电压参考 ,也可以提供正确的外部电源。
- 要使用片上LDO ,请确保 VDDPST_5(sd_vref) 引脚连接到所选的片上LD通道 ,并调用 :cpp:func:'sd_pwr_ctrl_new_on_chip_ldo' 分配所选的LDO通道 ,然后将 'pwr_ctr_handle' 传递给 :cpp:class:'sdmmc_host_t::pwr_ctl_handle' 。
- 要使用外部电源,请确保 VDDPST_5(sd_vref) 引脚已连接,然后按照 :cpp:class:'sd_pwr_ctrl_drv_t' 构造外部电源控制结构体,并将其传递给 :cpp:class:'sdmmc_host_t::pwr_ctr_handle'。
eMMC 芯片的 DDR 模式 eMMC 芯片的 DDR 模式
----------------------- -----------------------

Wyświetl plik

@ -152,4 +152,18 @@ menu "SD/MMC Example Configuration"
endif # EXAMPLE_SDMMC_BUS_WIDTH_4 endif # EXAMPLE_SDMMC_BUS_WIDTH_4
config EXAMPLE_SDMMC_IO_POWER_INTERNAL_LDO
depends on SOC_SDMMC_IO_POWER_EXTERNAL
bool "SDMMC IO power supply comes from internal LDO (READ HELP!)"
default y
help
Please read the schematic first and check if the SDMMC VDD is connected to any internal LDO output.
If the SDMMC is powered by an external supplier, unselect me
config EXAMPLE_SDMMC_IO_LDO_ID
depends on SOC_SDMMC_IO_POWER_EXTERNAL
int "LDO ID"
default 4
help
Please read the schematic first and input your LDO ID
endmenu endmenu

Wyświetl plik

@ -15,6 +15,7 @@
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h" #include "driver/sdmmc_host.h"
#include "sd_test_io.h" #include "sd_test_io.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#define EXAMPLE_MAX_CHAR_SIZE 64 #define EXAMPLE_MAX_CHAR_SIZE 64
@ -126,6 +127,23 @@ void app_main(void)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDMMC_HOST_DEFAULT(); sdmmc_host_t host = SDMMC_HOST_DEFAULT();
/**
* On these chips, the SDMMC IO power is supplied externally
*/
#if CONFIG_EXAMPLE_SDMMC_IO_POWER_INTERNAL_LDO
sd_pwr_ctrl_ldo_config_t ldo_config = {
.ldo_unit_id = 4,
};
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to new an on-chip ldo power control driver");
return;
}
host.pwr_ctrl_handle = pwr_ctrl_handle;
#endif
// This initializes the slot without card detect (CD) and write protect (WP) signals. // This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
@ -239,5 +257,14 @@ void app_main(void)
// All done, unmount partition and disable SDMMC peripheral // All done, unmount partition and disable SDMMC peripheral
esp_vfs_fat_sdcard_unmount(mount_point, card); esp_vfs_fat_sdcard_unmount(mount_point, card);
#if SOC_SDMMC_IO_POWER_EXTERNAL
ret = sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to delete on-chip ldo power control driver");
return;
}
#endif
ESP_LOGI(TAG, "Card unmounted"); ESP_LOGI(TAG, "Card unmounted");
} }