mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feat/sdmmc_support_concurrent_use' into 'master'
feat(sdmmc): Concurrent use of SDMMC peripheral Closes IDF-9152 See merge request espressif/esp-idf!31150
This commit is contained in:
commit
d1571c144b
@ -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
|
||||
*/
|
||||
@ -26,7 +26,8 @@ extern "C" {
|
||||
.flags = SDMMC_HOST_FLAG_8BIT | \
|
||||
SDMMC_HOST_FLAG_4BIT | \
|
||||
SDMMC_HOST_FLAG_1BIT | \
|
||||
SDMMC_HOST_FLAG_DDR, \
|
||||
SDMMC_HOST_FLAG_DDR | \
|
||||
SDMMC_HOST_FLAG_DEINIT_ARG, \
|
||||
.slot = SDMMC_HOST_SLOT_1, \
|
||||
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
|
||||
.io_voltage = 3.3f, \
|
||||
@ -37,7 +38,7 @@ extern "C" {
|
||||
.set_card_clk = &sdmmc_host_set_card_clk, \
|
||||
.set_cclk_always_on = &sdmmc_host_set_cclk_always_on, \
|
||||
.do_transaction = &sdmmc_host_do_transaction, \
|
||||
.deinit = &sdmmc_host_deinit, \
|
||||
.deinit_p = &sdmmc_host_deinit_slot, \
|
||||
.io_int_enable = sdmmc_host_io_int_enable, \
|
||||
.io_int_wait = sdmmc_host_io_int_wait, \
|
||||
.command_timeout_ms = 0, \
|
||||
|
@ -58,14 +58,21 @@ typedef struct {
|
||||
*/
|
||||
} sdmmc_slot_config_t;
|
||||
|
||||
/**
|
||||
* SD/MMC host state structure
|
||||
*/
|
||||
typedef struct {
|
||||
bool host_initialized; ///< Whether the host is initialized
|
||||
int num_of_init_slots; ///< Number of initialized slots
|
||||
} sdmmc_host_state_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize SDMMC host peripheral
|
||||
*
|
||||
* @note This function is not thread safe
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called
|
||||
* - ESP_OK on success or if sdmmc_host_init was already initialized with this function
|
||||
* - ESP_ERR_NO_MEM if memory can not be allocated
|
||||
*/
|
||||
esp_err_t sdmmc_host_init(void);
|
||||
@ -201,13 +208,31 @@ esp_err_t sdmmc_host_io_int_enable(int slot);
|
||||
esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks);
|
||||
|
||||
/**
|
||||
* @brief Disable SDMMC host and release allocated resources
|
||||
* @brief Disable SDMMC host and release allocated resources gracefully
|
||||
*
|
||||
* @note If there are more than 1 active slots, this function will just decrease the reference count
|
||||
* and won't actually disable the host until the last slot is disabled
|
||||
*
|
||||
* @note This function is not thread safe
|
||||
*
|
||||
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if SDMMC host has not been initialized
|
||||
* - ESP_ERR_INVALID_ARG if invalid slot number is used
|
||||
*/
|
||||
esp_err_t sdmmc_host_deinit_slot(int slot);
|
||||
|
||||
/**
|
||||
* @brief Disable SDMMC host and release allocated resources forcefully
|
||||
*
|
||||
* @note This function will deinitialize the host immediately, regardless of the number of active slots
|
||||
*
|
||||
* @note This function is not thread safe
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called
|
||||
* - ESP_ERR_INVALID_STATE if SDMMC host has not been initialized
|
||||
*/
|
||||
esp_err_t sdmmc_host_deinit(void);
|
||||
|
||||
@ -258,6 +283,17 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase);
|
||||
*/
|
||||
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
|
||||
|
||||
/**
|
||||
* @brief Get the state of SDMMC host
|
||||
*
|
||||
* @param[out] state output parameter for SDMMC host state structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG on invalid argument
|
||||
*/
|
||||
esp_err_t sdmmc_host_get_state(sdmmc_host_state_t* state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
@ -45,6 +46,11 @@
|
||||
#define SDMMC_CLK_SRC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#define SLOT_CHECK(slot_num) \
|
||||
if (slot_num < 0 || slot_num >= SOC_SDMMC_NUM_SLOTS) { \
|
||||
return ESP_ERR_INVALID_ARG; \
|
||||
}
|
||||
|
||||
static const char *TAG = "sdmmc_periph";
|
||||
|
||||
/**
|
||||
@ -54,6 +60,11 @@ typedef struct slot_ctx_t {
|
||||
size_t slot_width;
|
||||
sdmmc_slot_io_info_t slot_gpio_num;
|
||||
bool use_gpio_matrix;
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
int slot_host_div;
|
||||
uint32_t slot_freq_khz;
|
||||
sdmmc_ll_delay_phase_t slot_ll_delay_phase;
|
||||
#endif
|
||||
} slot_ctx_t;
|
||||
|
||||
/**
|
||||
@ -65,13 +76,24 @@ typedef struct host_ctx_t {
|
||||
SemaphoreHandle_t io_intr_event;
|
||||
sdmmc_hal_context_t hal;
|
||||
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS];
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
uint8_t num_of_init_slots;
|
||||
int8_t active_slot_num;
|
||||
#endif
|
||||
} host_ctx_t;
|
||||
|
||||
static host_ctx_t s_host_ctx;
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
static host_ctx_t s_host_ctx = {.active_slot_num = -1};
|
||||
#else
|
||||
static host_ctx_t s_host_ctx = {0};
|
||||
#endif
|
||||
|
||||
static void sdmmc_isr(void *arg);
|
||||
static void sdmmc_host_dma_init(void);
|
||||
static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width);
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
static void sdmmc_host_change_to_slot(int slot);
|
||||
#endif
|
||||
|
||||
esp_err_t sdmmc_host_reset(void)
|
||||
{
|
||||
@ -227,11 +249,16 @@ static int sdmmc_host_calc_freq(const int host_div, const int card_div)
|
||||
return clk_src_freq_hz / host_div / ((card_div == 0) ? 1 : card_div * 2) / 1000;
|
||||
}
|
||||
|
||||
static void sdmmc_host_set_data_timeout(uint32_t freq_khz)
|
||||
{
|
||||
const uint32_t data_timeout_ms = 100;
|
||||
uint32_t data_timeout_cycles = data_timeout_ms * freq_khz;
|
||||
sdmmc_ll_set_data_timeout(s_host_ctx.hal.dev, data_timeout_cycles);
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
// Disable clock first
|
||||
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, false);
|
||||
@ -269,24 +296,25 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
||||
return err;
|
||||
}
|
||||
|
||||
// set data timeout
|
||||
const uint32_t data_timeout_ms = 100;
|
||||
uint32_t data_timeout_cycles = data_timeout_ms * freq_khz;
|
||||
sdmmc_ll_set_data_timeout(s_host_ctx.hal.dev, data_timeout_cycles);
|
||||
sdmmc_host_set_data_timeout(freq_khz);
|
||||
// always set response timeout to highest value, it's small enough anyway
|
||||
sdmmc_ll_set_response_timeout(s_host_ctx.hal.dev, 255);
|
||||
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
// save the current frequency
|
||||
s_host_ctx.slot_ctx[slot].slot_freq_khz = freq_khz;
|
||||
// save host_div value
|
||||
s_host_ctx.slot_ctx[slot].slot_host_div = host_div;
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_get_real_freq(int slot, int *real_freq_khz)
|
||||
{
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
if (real_freq_khz == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int host_div = sdmmc_ll_get_clock_div(s_host_ctx.hal.dev);
|
||||
int card_div = sdmmc_ll_get_card_clock_div(s_host_ctx.hal.dev, slot);
|
||||
@ -338,6 +366,10 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase)
|
||||
int phase_diff_ps = src_clk_period_ps * sdmmc_ll_get_clock_div(s_host_ctx.hal.dev) / SOC_SDMMC_DELAY_PHASE_NUM;
|
||||
ESP_LOGD(TAG, "difference between input delay phases is %d ps", phase_diff_ps);
|
||||
ESP_LOGI(TAG, "host sampling edge is delayed by %d ps", phase_diff_ps * delay_phase_num);
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
// save the current phase delay setting
|
||||
s_host_ctx.slot_ctx[slot].slot_ll_delay_phase = phase;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
@ -345,9 +377,13 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase)
|
||||
|
||||
esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
// change the host settings to the appropriate slot before starting the transaction
|
||||
sdmmc_host_change_to_slot(slot);
|
||||
#endif
|
||||
|
||||
// if this isn't a clock update command, check the card detect status
|
||||
if (!sdmmc_ll_is_card_detected(s_host_ctx.hal.dev, slot) && !cmd.update_clk_reg) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
@ -378,10 +414,25 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void sdmmc_host_intmask_clear_disable(void)
|
||||
{
|
||||
sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, 0xffffffff);
|
||||
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, 0xffffffff, false);
|
||||
sdmmc_ll_enable_global_interrupt(s_host_ctx.hal.dev, false);
|
||||
}
|
||||
|
||||
static void sdmmc_host_intmask_set_enable(void)
|
||||
{
|
||||
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, 0xffffffff, false);
|
||||
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_LL_INTMASK_DEFAULT, true);
|
||||
sdmmc_ll_enable_global_interrupt(s_host_ctx.hal.dev, true);
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_init(void)
|
||||
{
|
||||
if (s_host_ctx.intr_handle) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
ESP_LOGI(TAG, "%s: SDMMC host already initialized, skipping init flow", __func__);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//enable bus clock for registers
|
||||
@ -406,9 +457,7 @@ esp_err_t sdmmc_host_init(void)
|
||||
ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, SDMMC.verid, SDMMC.hcon.val);
|
||||
|
||||
// Clear interrupt status and set interrupt mask to known state
|
||||
SDMMC.rintsts.val = 0xffffffff;
|
||||
SDMMC.intmask.val = 0;
|
||||
SDMMC.ctrl.int_enable = 0;
|
||||
sdmmc_host_intmask_clear_disable();
|
||||
|
||||
// Allocate event queue
|
||||
s_host_ctx.event_queue = xQueueCreate(SDMMC_EVENT_QUEUE_LENGTH, sizeof(sdmmc_event_t));
|
||||
@ -431,15 +480,7 @@ esp_err_t sdmmc_host_init(void)
|
||||
return ret;
|
||||
}
|
||||
// Enable interrupts
|
||||
SDMMC.intmask.val =
|
||||
SDMMC_INTMASK_CD |
|
||||
SDMMC_INTMASK_CMD_DONE |
|
||||
SDMMC_INTMASK_DATA_OVER |
|
||||
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC |
|
||||
SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO |
|
||||
SDMMC_INTMASK_SBE | SDMMC_INTMASK_EBE |
|
||||
SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_HLE; //sdio is enabled only when use.
|
||||
SDMMC.ctrl.int_enable = 1;
|
||||
sdmmc_host_intmask_set_enable();
|
||||
|
||||
// Disable generation of Busy Clear Interrupt
|
||||
SDMMC.cardthrctl.busy_clr_int_en = 0;
|
||||
@ -517,9 +558,9 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||
if (!s_host_ctx.intr_handle) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
if (slot_config == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -537,6 +578,8 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
s_host_ctx.slot_ctx[slot].slot_width = slot_width;
|
||||
s_host_ctx.slot_ctx[slot].slot_gpio_num.cd = gpio_cd;
|
||||
s_host_ctx.slot_ctx[slot].slot_gpio_num.wp = gpio_wp;
|
||||
|
||||
bool pin_not_set = s_check_pin_not_set(slot_config);
|
||||
//SD driver behaviour is: all pins not defined == using iomux
|
||||
@ -590,7 +633,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||
|
||||
bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||
if (pullup) {
|
||||
sdmmc_host_pullup_en_internal(slot, slot_config->width);
|
||||
sdmmc_host_pullup_en_internal(slot, s_host_ctx.slot_ctx[slot].slot_width);
|
||||
}
|
||||
|
||||
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.clk, sdmmc_slot_gpio_sig[slot].clk, GPIO_MODE_OUTPUT, "clk", use_gpio_matrix);
|
||||
@ -664,14 +707,17 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
if (s_host_ctx.num_of_init_slots < SOC_SDMMC_NUM_SLOTS && s_host_ctx.active_slot_num != slot) {
|
||||
s_host_ctx.num_of_init_slots += 1;
|
||||
}
|
||||
s_host_ctx.active_slot_num = slot;
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_deinit(void)
|
||||
static void sdmmc_host_deinit_internal(void)
|
||||
{
|
||||
if (!s_host_ctx.intr_handle) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_intr_free(s_host_ctx.intr_handle);
|
||||
s_host_ctx.intr_handle = NULL;
|
||||
vQueueDelete(s_host_ctx.event_queue);
|
||||
@ -684,10 +730,110 @@ esp_err_t sdmmc_host_deinit(void)
|
||||
SDMMC_RCC_ATOMIC() {
|
||||
sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false);
|
||||
}
|
||||
ESP_LOGD(TAG, "SDMMC host deinitialized");
|
||||
}
|
||||
|
||||
static int sdmmc_host_decrease_init_slot_num(void)
|
||||
{
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
s_host_ctx.active_slot_num = -1; // Reset the active slot number, will be set again before the next transaction
|
||||
if (s_host_ctx.num_of_init_slots > 0) {
|
||||
s_host_ctx.num_of_init_slots -= 1;
|
||||
}
|
||||
return s_host_ctx.num_of_init_slots;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sdmmc_host_deinit_slot_internal(int slot)
|
||||
{
|
||||
int8_t gpio_pin_num;
|
||||
sdmmc_slot_io_info_t* gpio = &s_host_ctx.slot_ctx[slot].slot_gpio_num;
|
||||
// Disconnect signals and reset used GPIO pins
|
||||
for (size_t i = 0; i < (sizeof(gpio->val) / (sizeof(gpio->val[0]))); i++) {
|
||||
gpio_pin_num = gpio->val[i];
|
||||
if (gpio_pin_num != GPIO_NUM_NC && GPIO_IS_VALID_GPIO(gpio_pin_num)) {
|
||||
gpio_reset_pin(gpio_pin_num);
|
||||
}
|
||||
}
|
||||
// Reset the slot context
|
||||
memset(&(s_host_ctx.slot_ctx[slot]), 0, sizeof(slot_ctx_t));
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_deinit_slot(int slot)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!s_host_ctx.intr_handle) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
sdmmc_host_deinit_slot_internal(slot);
|
||||
int num_of_init_slots = sdmmc_host_decrease_init_slot_num();
|
||||
if (num_of_init_slots != 0) {
|
||||
ESP_LOGD(TAG, "SDMMC host not deinitialized yet, number of initialized slots: %d",
|
||||
num_of_init_slots);
|
||||
return ESP_OK;
|
||||
}
|
||||
sdmmc_host_deinit_internal();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_deinit(void)
|
||||
{
|
||||
if (!s_host_ctx.intr_handle) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
for (int slot = 0; slot < SOC_SDMMC_NUM_SLOTS; slot++) {
|
||||
sdmmc_host_deinit_slot_internal(slot);
|
||||
}
|
||||
sdmmc_host_deinit_internal();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool sdmmc_host_slot_initialized(int slot)
|
||||
{
|
||||
// slot_host_div is initialized to 0 and is set in sdmmc_host_set_card_clk during card initialization
|
||||
// during card deinitialization it is set back to 0
|
||||
// should not be 0 if the slot is initialized
|
||||
if (s_host_ctx.slot_ctx[slot].slot_host_div == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
static void sdmmc_host_change_to_slot(int slot)
|
||||
{
|
||||
// If the slot is not initialized (slot_host_div not set) or already active, do nothing
|
||||
if (s_host_ctx.active_slot_num == slot || sdmmc_host_slot_initialized(slot) == false) {
|
||||
return;
|
||||
}
|
||||
s_host_ctx.active_slot_num = slot;
|
||||
|
||||
// Clear interrupt status and set interrupt mask to known state
|
||||
sdmmc_host_intmask_clear_disable();
|
||||
|
||||
// Apply the appropriate saved host settings for the new slot before starting the transaction
|
||||
SDMMC_CLK_SRC_ATOMIC() {
|
||||
sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, s_host_ctx.slot_ctx[slot].slot_host_div);
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
sdmmc_ll_set_din_delay(s_host_ctx.hal.dev, s_host_ctx.slot_ctx[slot].slot_ll_delay_phase);
|
||||
#endif
|
||||
}
|
||||
sdmmc_host_set_data_timeout(s_host_ctx.slot_ctx[slot].slot_freq_khz);
|
||||
|
||||
// Wait for the clock to propagate
|
||||
esp_rom_delay_us(10);
|
||||
|
||||
// Enable interrupts again
|
||||
sdmmc_host_intmask_set_enable();
|
||||
}
|
||||
#endif // SOC_SDMMC_NUM_SLOTS >= 2
|
||||
|
||||
esp_err_t sdmmc_host_wait_for_event(int tick_count, sdmmc_event_t *out_event)
|
||||
{
|
||||
if (!out_event) {
|
||||
@ -705,9 +851,8 @@ esp_err_t sdmmc_host_wait_for_event(int tick_count, sdmmc_event_t *out_event)
|
||||
|
||||
esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
if (sdmmc_slot_info[slot].width < width) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@ -739,9 +884,8 @@ size_t sdmmc_host_get_slot_width(int slot)
|
||||
|
||||
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
if (s_host_ctx.slot_ctx[slot].slot_width == 8 && ddr_enabled) {
|
||||
ESP_LOGW(TAG, "DDR mode with 8-bit bus width is not supported yet");
|
||||
// requires reconfiguring controller clock for 2x card frequency
|
||||
@ -755,9 +899,9 @@ esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
||||
|
||||
esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
// During initialization this is not protected by a mutex
|
||||
if (cclk_always_on) {
|
||||
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, false);
|
||||
} else {
|
||||
@ -925,10 +1069,31 @@ static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width)
|
||||
|
||||
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info)
|
||||
{
|
||||
if (!(slot == 0 || slot == 1)) {
|
||||
SLOT_CHECK(slot);
|
||||
|
||||
if (dma_mem_info == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
|
||||
dma_mem_info->dma_alignment_bytes = 4;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_host_get_state(sdmmc_host_state_t* state)
|
||||
{
|
||||
if (state == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (s_host_ctx.intr_handle) {
|
||||
state->host_initialized = true;
|
||||
state->num_of_init_slots = 1;
|
||||
} else {
|
||||
state->host_initialized = false;
|
||||
state->num_of_init_slots = 0;
|
||||
}
|
||||
#if SOC_SDMMC_NUM_SLOTS >= 2
|
||||
state->num_of_init_slots = s_host_ctx.num_of_init_slots;
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "hal/assert.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/sdmmc_struct.h"
|
||||
#include "soc/sdmmc_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -26,6 +27,22 @@ extern "C" {
|
||||
|
||||
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||
|
||||
/* Default disabled interrupts (on init):
|
||||
* SDMMC_INTMASK_RXDR,
|
||||
* SDMMC_INTMASK_TXDR,
|
||||
* SDMMC_INTMASK_BCI,
|
||||
* SDMMC_INTMASK_ACD,
|
||||
* SDMMC_INTMASK_IO_SLOT1,
|
||||
* SDMMC_INTMASK_IO_SLOT0
|
||||
*/
|
||||
// Default enabled interrupts (sdio is enabled only when use):
|
||||
#define SDMMC_LL_INTMASK_DEFAULT \
|
||||
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \
|
||||
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \
|
||||
SDMMC_INTMASK_HLE | \
|
||||
SDMMC_INTMASK_SBE | \
|
||||
SDMMC_INTMASK_EBE)
|
||||
|
||||
/**
|
||||
* SDMMC capabilities
|
||||
*/
|
||||
@ -391,6 +408,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||
hw->rintsts.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable / disable interrupts globally
|
||||
*
|
||||
* @param hw hardware instance address
|
||||
* @param en enable / disable
|
||||
*/
|
||||
static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
|
||||
{
|
||||
hw->ctrl.int_enable = (uint32_t)en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "hal/assert.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/sdmmc_struct.h"
|
||||
#include "soc/sdmmc_reg.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
#include "soc/lp_clkrst_struct.h"
|
||||
|
||||
@ -28,6 +29,22 @@ extern "C" {
|
||||
|
||||
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||
|
||||
/* Default disabled interrupts (on init):
|
||||
* SDMMC_INTMASK_RXDR,
|
||||
* SDMMC_INTMASK_TXDR,
|
||||
* SDMMC_INTMASK_BCI,
|
||||
* SDMMC_INTMASK_ACD,
|
||||
* SDMMC_INTMASK_IO_SLOT1,
|
||||
* SDMMC_INTMASK_IO_SLOT0
|
||||
*/
|
||||
// Default enabled interrupts (sdio is enabled only when use):
|
||||
#define SDMMC_LL_INTMASK_DEFAULT \
|
||||
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \
|
||||
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \
|
||||
SDMMC_INTMASK_HLE | \
|
||||
SDMMC_INTMASK_SBE | \
|
||||
SDMMC_INTMASK_EBE)
|
||||
|
||||
/**
|
||||
* SDMMC capabilities
|
||||
*/
|
||||
@ -438,6 +455,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||
hw->rintsts.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable / disable interrupts globally
|
||||
*
|
||||
* @param hw hardware instance address
|
||||
* @param en enable / disable
|
||||
*/
|
||||
static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
|
||||
{
|
||||
hw->ctrl.int_enable = (uint32_t)en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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
|
||||
*/
|
||||
@ -18,6 +18,7 @@
|
||||
#include "hal/assert.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/sdmmc_struct.h"
|
||||
#include "soc/sdmmc_reg.h"
|
||||
#include "soc/system_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -26,6 +27,22 @@ extern "C" {
|
||||
|
||||
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||
|
||||
/* Default disabled interrupts (on init):
|
||||
* SDMMC_INTMASK_RXDR,
|
||||
* SDMMC_INTMASK_TXDR,
|
||||
* SDMMC_INTMASK_BCI,
|
||||
* SDMMC_INTMASK_ACD,
|
||||
* SDMMC_INTMASK_IO_SLOT1,
|
||||
* SDMMC_INTMASK_IO_SLOT0
|
||||
*/
|
||||
// Default enabled interrupts (sdio is enabled only when use):
|
||||
#define SDMMC_LL_INTMASK_DEFAULT \
|
||||
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \
|
||||
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \
|
||||
SDMMC_INTMASK_HLE | \
|
||||
SDMMC_INTMASK_SBE | \
|
||||
SDMMC_INTMASK_EBE)
|
||||
|
||||
/**
|
||||
* SDMMC capabilities
|
||||
*/
|
||||
@ -427,6 +444,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||
hw->rintsts.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable / disable interrupts globally
|
||||
*
|
||||
* @param hw hardware instance address
|
||||
* @param en enable / disable
|
||||
*/
|
||||
static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
|
||||
{
|
||||
hw->ctrl.int_enable = (uint32_t)en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -9,6 +9,7 @@
|
||||
//include soc related (generated) definitions
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_pins.h"
|
||||
#include "soc/gpio_num.h"
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
#include "soc/sdmmc_reg.h"
|
||||
#include "soc/sdmmc_struct.h"
|
||||
@ -31,7 +32,7 @@ typedef struct {
|
||||
uint8_t card_int; /*!< Card interrupt signal in GPIO Matrix */
|
||||
} sdmmc_slot_info_t;
|
||||
|
||||
/** Width and GPIO matrix signal numbers for auxillary SD host signals, one structure per slot */
|
||||
/** Width and GPIO matrix signal numbers for auxiliary SD host signals, one structure per slot */
|
||||
extern const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS];
|
||||
|
||||
/**
|
||||
@ -39,17 +40,22 @@ extern const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS];
|
||||
* or GPIO Matrix signal numbers (if SOC_SDMMC_USE_GPIO_MATRIX is set)
|
||||
* for the SD bus signals. Field names match SD bus signal names.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t clk;
|
||||
uint8_t cmd;
|
||||
uint8_t d0;
|
||||
uint8_t d1;
|
||||
uint8_t d2;
|
||||
uint8_t d3;
|
||||
uint8_t d4;
|
||||
uint8_t d5;
|
||||
uint8_t d6;
|
||||
uint8_t d7;
|
||||
typedef union {
|
||||
struct {
|
||||
gpio_num_t cd;
|
||||
gpio_num_t wp;
|
||||
gpio_num_t clk;
|
||||
gpio_num_t cmd;
|
||||
gpio_num_t d0;
|
||||
gpio_num_t d1;
|
||||
gpio_num_t d2;
|
||||
gpio_num_t d3;
|
||||
gpio_num_t d4;
|
||||
gpio_num_t d5;
|
||||
gpio_num_t d6;
|
||||
gpio_num_t d7;
|
||||
};
|
||||
gpio_num_t val[12]; // for iteration, num of entries in struct
|
||||
} sdmmc_slot_io_info_t;
|
||||
|
||||
/** GPIO pin numbers of SD bus signals, one structure per slot */
|
||||
|
Loading…
Reference in New Issue
Block a user