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:
Adam Múdry 2024-08-09 01:08:16 +08:00
commit d1571c144b
7 changed files with 361 additions and 69 deletions

View File

@ -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, \

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */