mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
refactor(sdmmc): Allow sdmmc_host_init to be called multiple times
Along with slight refactor for sdmmc_host.c
This commit is contained in:
parent
0f6004e06f
commit
caa4f7fd20
@ -64,8 +64,7 @@ typedef struct {
|
|||||||
* @note This function is not thread safe
|
* @note This function is not thread safe
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK on success
|
* - ESP_OK on success or if sdmmc_host_init was already initialized with this function
|
||||||
* - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called
|
|
||||||
* - ESP_ERR_NO_MEM if memory can not be allocated
|
* - ESP_ERR_NO_MEM if memory can not be allocated
|
||||||
*/
|
*/
|
||||||
esp_err_t sdmmc_host_init(void);
|
esp_err_t sdmmc_host_init(void);
|
||||||
|
@ -45,6 +45,27 @@
|
|||||||
#define SDMMC_CLK_SRC_ATOMIC()
|
#define SDMMC_CLK_SRC_ATOMIC()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 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_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)
|
||||||
|
|
||||||
|
#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";
|
static const char *TAG = "sdmmc_periph";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,7 +88,7 @@ typedef struct host_ctx_t {
|
|||||||
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS];
|
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS];
|
||||||
} host_ctx_t;
|
} host_ctx_t;
|
||||||
|
|
||||||
static host_ctx_t s_host_ctx;
|
static host_ctx_t s_host_ctx = {0};
|
||||||
|
|
||||||
static void sdmmc_isr(void *arg);
|
static void sdmmc_isr(void *arg);
|
||||||
static void sdmmc_host_dma_init(void);
|
static void sdmmc_host_dma_init(void);
|
||||||
@ -227,11 +248,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;
|
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)
|
esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
||||||
{
|
{
|
||||||
if (!(slot == 0 || slot == 1)) {
|
SLOT_CHECK(slot);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable clock first
|
// Disable clock first
|
||||||
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, false);
|
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, false);
|
||||||
@ -269,10 +295,7 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set data timeout
|
sdmmc_host_set_data_timeout(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);
|
|
||||||
// always set response timeout to highest value, it's small enough anyway
|
// always set response timeout to highest value, it's small enough anyway
|
||||||
sdmmc_ll_set_response_timeout(s_host_ctx.hal.dev, 255);
|
sdmmc_ll_set_response_timeout(s_host_ctx.hal.dev, 255);
|
||||||
|
|
||||||
@ -281,12 +304,11 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
|
|
||||||
esp_err_t sdmmc_host_get_real_freq(int slot, int *real_freq_khz)
|
esp_err_t sdmmc_host_get_real_freq(int slot, int *real_freq_khz)
|
||||||
{
|
{
|
||||||
|
SLOT_CHECK(slot);
|
||||||
|
|
||||||
if (real_freq_khz == NULL) {
|
if (real_freq_khz == NULL) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
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 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);
|
int card_div = sdmmc_ll_get_card_clock_div(s_host_ctx.hal.dev, slot);
|
||||||
@ -345,9 +367,8 @@ 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)
|
esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
||||||
{
|
{
|
||||||
if (!(slot == 0 || slot == 1)) {
|
SLOT_CHECK(slot);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
// if this isn't a clock update command, check the card detect status
|
// 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) {
|
if (!sdmmc_ll_is_card_detected(s_host_ctx.hal.dev, slot) && !cmd.update_clk_reg) {
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
@ -378,10 +399,24 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdmmc_host_intmask_clear_disable(void)
|
||||||
|
{
|
||||||
|
SDMMC.rintsts.val = 0xffffffff;
|
||||||
|
SDMMC.intmask.val = 0;
|
||||||
|
SDMMC.ctrl.int_enable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdmmc_host_intmask_set_enable(uint32_t mask)
|
||||||
|
{
|
||||||
|
SDMMC.intmask.val = mask;
|
||||||
|
SDMMC.ctrl.int_enable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_host_init(void)
|
esp_err_t sdmmc_host_init(void)
|
||||||
{
|
{
|
||||||
if (s_host_ctx.intr_handle) {
|
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
|
//enable bus clock for registers
|
||||||
@ -406,9 +441,7 @@ esp_err_t sdmmc_host_init(void)
|
|||||||
ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, SDMMC.verid, SDMMC.hcon.val);
|
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
|
// Clear interrupt status and set interrupt mask to known state
|
||||||
SDMMC.rintsts.val = 0xffffffff;
|
sdmmc_host_intmask_clear_disable();
|
||||||
SDMMC.intmask.val = 0;
|
|
||||||
SDMMC.ctrl.int_enable = 0;
|
|
||||||
|
|
||||||
// Allocate event queue
|
// Allocate event queue
|
||||||
s_host_ctx.event_queue = xQueueCreate(SDMMC_EVENT_QUEUE_LENGTH, sizeof(sdmmc_event_t));
|
s_host_ctx.event_queue = xQueueCreate(SDMMC_EVENT_QUEUE_LENGTH, sizeof(sdmmc_event_t));
|
||||||
@ -431,15 +464,7 @@ esp_err_t sdmmc_host_init(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
SDMMC.intmask.val =
|
sdmmc_host_intmask_set_enable(SDMMC_INTMASK_DEFAULT);
|
||||||
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;
|
|
||||||
|
|
||||||
// Disable generation of Busy Clear Interrupt
|
// Disable generation of Busy Clear Interrupt
|
||||||
SDMMC.cardthrctl.busy_clr_int_en = 0;
|
SDMMC.cardthrctl.busy_clr_int_en = 0;
|
||||||
@ -517,9 +542,9 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
|||||||
if (!s_host_ctx.intr_handle) {
|
if (!s_host_ctx.intr_handle) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
if (!(slot == 0 || slot == 1)) {
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
SLOT_CHECK(slot);
|
||||||
}
|
|
||||||
if (slot_config == NULL) {
|
if (slot_config == NULL) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -705,9 +730,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)
|
esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
|
||||||
{
|
{
|
||||||
if (!(slot == 0 || slot == 1)) {
|
SLOT_CHECK(slot);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if (sdmmc_slot_info[slot].width < width) {
|
if (sdmmc_slot_info[slot].width < width) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -739,9 +763,8 @@ size_t sdmmc_host_get_slot_width(int slot)
|
|||||||
|
|
||||||
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
||||||
{
|
{
|
||||||
if (!(slot == 0 || slot == 1)) {
|
SLOT_CHECK(slot);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
if (s_host_ctx.slot_ctx[slot].slot_width == 8 && ddr_enabled) {
|
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");
|
ESP_LOGW(TAG, "DDR mode with 8-bit bus width is not supported yet");
|
||||||
// requires reconfiguring controller clock for 2x card frequency
|
// requires reconfiguring controller clock for 2x card frequency
|
||||||
@ -755,9 +778,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)
|
esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on)
|
||||||
{
|
{
|
||||||
if (!(slot == 0 || slot == 1)) {
|
SLOT_CHECK(slot);
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
// During initialization this is not protected by a mutex
|
||||||
if (cclk_always_on) {
|
if (cclk_always_on) {
|
||||||
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, false);
|
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, false);
|
||||||
} else {
|
} else {
|
||||||
@ -925,7 +948,9 @@ 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)
|
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;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
|
dma_mem_info->extra_heap_caps = MALLOC_CAP_DMA;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user