mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
Merge branch 'fix/sdmmc_send_acmd22_after_multiple_write_cmd_v5.4' into 'release/v5.4'
fix(sdmmc): Send ACMD22 if CMD25 fails (v5.4) See merge request espressif/esp-idf!34860
This commit is contained in:
commit
60c561792c
@ -9,7 +9,8 @@ if(CONFIG_SOC_SDMMC_HOST_SUPPORTED)
|
||||
"sdmmc_test_erase_sd.c"
|
||||
"sdmmc_test_trim_sd.c"
|
||||
"sdmmc_test_discard_sd.c"
|
||||
"sdmmc_test_sanitize_sd.c")
|
||||
"sdmmc_test_sanitize_sd.c"
|
||||
"sdmmc_test_various_cmds.c")
|
||||
endif()
|
||||
|
||||
set(priv_requires "sdmmc"
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/sdmmc_defs.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
#include "sdmmc_test_begin_end_sd.h"
|
||||
|
||||
#if !SOC_SDMMC_HOST_SUPPORTED
|
||||
#error "Targets with SDMMC host supported only"
|
||||
#endif // !SOC_SDMMC_HOST_SUPPORTED
|
||||
|
||||
static const char* TAG = "sdmmc_test_various_cmds";
|
||||
|
||||
static void sdmmc_write_sectors_cmd25_error_test_acmd22(sdmmc_card_t* card, uint32_t write_size)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
size_t block_size = (size_t)card->csd.sector_size;
|
||||
size_t block_count = write_size / block_size;
|
||||
void* buf = heap_caps_calloc(1, write_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||
TEST_ASSERT_NOT_NULL(buf);
|
||||
|
||||
if (!host_is_spi(card)) {
|
||||
err = sdmmc_wait_for_idle(card, 0); // wait for the card to be idle (in transfer state)
|
||||
if (err != ESP_OK) {
|
||||
free(buf);
|
||||
}
|
||||
TEST_ESP_OK(err);
|
||||
}
|
||||
|
||||
// Try to write to the card
|
||||
err = sdmmc_write_sectors(card, buf, 0, block_count);
|
||||
free(buf);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// Check if the number of written blocks is equal to the number ACMD22 returns
|
||||
// ACMD22 is usually only called if CMD25 fails but here we call it anyway to test it
|
||||
size_t sucessfully_written_blocks;
|
||||
err = sdmmc_send_cmd_num_of_written_blocks(card, &sucessfully_written_blocks);
|
||||
TEST_ESP_OK(err);
|
||||
TEST_ASSERT_EQUAL_size_t(sucessfully_written_blocks, block_count);
|
||||
ESP_LOGI(TAG, "%s: ACMD22 successfully written %zu blocks out of %zu", __func__, sucessfully_written_blocks, block_count);
|
||||
}
|
||||
|
||||
static void do_one_mmc_acmd22_test(int slot, int width, int freq_khz, int ddr)
|
||||
{
|
||||
sdmmc_card_t card;
|
||||
sdmmc_test_sd_skip_if_board_incompatible(slot, width, freq_khz, ddr);
|
||||
sdmmc_test_sd_begin(slot, width, freq_khz, ddr, &card);
|
||||
sdmmc_card_print_info(stdout, &card);
|
||||
sdmmc_write_sectors_cmd25_error_test_acmd22(&card, 4096 * 4);
|
||||
sdmmc_test_sd_end(&card);
|
||||
}
|
||||
|
||||
TEST_CASE("send ACMD22 after writing multiple blocks to check real number of successfully written blocks, slot 0, 1-bit", "[sdmmc]")
|
||||
{
|
||||
do_one_mmc_acmd22_test(SLOT_0, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR);
|
||||
}
|
||||
|
||||
TEST_CASE("send ACMD22 after writing multiple blocks to check real number of successfully written blocks, slot 1, 1-bit", "[sdmmc]")
|
||||
{
|
||||
do_one_mmc_acmd22_test(SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -30,6 +30,10 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_dma_utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SDMMC_GO_IDLE_DELAY_MS 20
|
||||
#define SDMMC_IO_SEND_OP_COND_DELAY_MS 10
|
||||
|
||||
@ -82,6 +86,7 @@ esp_err_t sdmmc_send_cmd_set_bus_width(sdmmc_card_t* card, int width);
|
||||
esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status);
|
||||
esp_err_t sdmmc_send_cmd_crc_on_off(sdmmc_card_t* card, bool crc_enable);
|
||||
esp_err_t sdmmc_send_cmd_voltage_switch(sdmmc_card_t* card);
|
||||
esp_err_t sdmmc_send_cmd_num_of_written_blocks(sdmmc_card_t* card, size_t* out_num_blocks);
|
||||
|
||||
/* Higher level functions */
|
||||
esp_err_t sdmmc_enter_higher_speed_mode(sdmmc_card_t* card);
|
||||
@ -166,10 +171,22 @@ static inline uint32_t get_host_ocr(float voltage)
|
||||
return SD_OCR_VOL_MASK;
|
||||
}
|
||||
|
||||
static inline bool sdmmc_ready_for_data(uint32_t status)
|
||||
{
|
||||
return (status & MMC_R1_READY_FOR_DATA) && (MMC_R1_CURRENT_STATE_STATUS(status) == MMC_R1_CURRENT_STATE_TRAN);
|
||||
}
|
||||
|
||||
void sdmmc_flip_byte_order(uint32_t* response, size_t size);
|
||||
|
||||
esp_err_t sdmmc_fix_host_flags(sdmmc_card_t* card);
|
||||
|
||||
// Use only with SDMMC mode (not SDSPI)
|
||||
esp_err_t sdmmc_wait_for_idle(sdmmc_card_t* card, uint32_t status);
|
||||
|
||||
//Currently only SDIO support using this buffer. And only 512 block size is supported.
|
||||
#define SDMMC_IO_BLOCK_SIZE 512
|
||||
esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -69,6 +69,7 @@ extern "C" {
|
||||
/* SD application commands */ /* response type */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
|
||||
#define SD_APP_SD_STATUS 13 /* R2 */
|
||||
#define SD_APP_SEND_NUM_WR_BLOCKS 22 /* R1 */
|
||||
#define SD_APP_OP_COND 41 /* R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* R1 */
|
||||
|
||||
@ -261,6 +262,7 @@ extern "C" {
|
||||
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
|
||||
(MMC_CSD_C_SIZE_MULT((resp))+2))
|
||||
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
|
||||
#define MMC_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
|
||||
|
||||
/* MMC v1 R2 response (CID) */
|
||||
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
|
||||
|
@ -5,8 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_timer.h"
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
|
||||
static const char* TAG = "sdmmc_cmd";
|
||||
|
||||
@ -409,6 +408,43 @@ esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_send_cmd_num_of_written_blocks(sdmmc_card_t* card, size_t* out_num_blocks)
|
||||
{
|
||||
size_t datalen = sizeof(uint32_t);
|
||||
esp_err_t err = ESP_OK;
|
||||
void* buf = NULL;
|
||||
esp_dma_mem_info_t dma_mem_info;
|
||||
card->host.get_dma_info(card->host.slot, &dma_mem_info);
|
||||
size_t actual_size = 0;
|
||||
err = esp_dma_capable_malloc(datalen, &dma_mem_info, &buf, &actual_size);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
sdmmc_command_t cmd = {
|
||||
.data = buf,
|
||||
.datalen = datalen,
|
||||
.buflen = actual_size,
|
||||
.blklen = datalen,
|
||||
.flags = SCF_CMD_ADTC | SCF_RSP_R1 | SCF_CMD_READ,
|
||||
.opcode = SD_APP_SEND_NUM_WR_BLOCKS
|
||||
};
|
||||
|
||||
err = sdmmc_send_app_cmd(card, &cmd);
|
||||
if (err != ESP_OK) {
|
||||
free(buf);
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_app_cmd returned 0x%x, failed to get number of written write blocks", __func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t result = __builtin_bswap32(*(uint32_t*)buf);
|
||||
if (out_num_blocks) {
|
||||
*out_num_blocks = result;
|
||||
}
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
||||
size_t start_block, size_t block_count)
|
||||
{
|
||||
@ -459,11 +495,6 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool sdmmc_ready_for_data(uint32_t status)
|
||||
{
|
||||
return (status & MMC_R1_READY_FOR_DATA) && (MMC_R1_CURRENT_STATE_STATUS(status) == MMC_R1_CURRENT_STATE_TRAN);
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||
size_t start_block, size_t block_count, size_t buffer_len)
|
||||
{
|
||||
@ -495,6 +526,19 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||
esp_err_t err_cmd13 = sdmmc_send_cmd_send_status(card, &status);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
if (cmd.opcode == MMC_WRITE_BLOCK_MULTIPLE) {
|
||||
if (!host_is_spi(card)) {
|
||||
sdmmc_wait_for_idle(card, status); // wait for the card to be idle (in transfer state)
|
||||
} else {
|
||||
vTaskDelay(1); // when the host is in spi mode
|
||||
}
|
||||
size_t successfully_written_blocks = 0;
|
||||
if (sdmmc_send_cmd_num_of_written_blocks(card, &successfully_written_blocks) == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: successfully wrote %zu blocks out of %zu", __func__, successfully_written_blocks, block_count);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_cmd_num_of_written_blocks returned 0x%x", __func__, err);
|
||||
}
|
||||
}
|
||||
if (err_cmd13 == ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x, status 0x%" PRIx32, __func__, err, status);
|
||||
} else {
|
||||
@ -503,30 +547,19 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
int64_t yield_delay_us = 100 * 1000; // initially 100ms
|
||||
int64_t t0 = esp_timer_get_time();
|
||||
int64_t t1 = 0;
|
||||
/* SD mode: wait for the card to become idle based on R1 status */
|
||||
while (!host_is_spi(card) && !sdmmc_ready_for_data(status)) {
|
||||
t1 = esp_timer_get_time();
|
||||
if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) {
|
||||
ESP_LOGE(TAG, "write sectors dma - timeout");
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
if (t1 - t0 > yield_delay_us) {
|
||||
yield_delay_us *= 2;
|
||||
vTaskDelay(1);
|
||||
}
|
||||
err = sdmmc_send_cmd_send_status(card, &status);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (++count % 16 == 0) {
|
||||
ESP_LOGV(TAG, "waiting for card to become ready (%" PRIu32 ")", (uint32_t) count);
|
||||
if (!host_is_spi(card)) {
|
||||
switch (sdmmc_wait_for_idle(card, status)) {
|
||||
case ESP_OK:
|
||||
break;
|
||||
case ESP_ERR_TIMEOUT:
|
||||
ESP_LOGE(TAG, "%s: sdmmc_wait_for_idle timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
default:
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* SPI mode: although card busy indication is based on the busy token,
|
||||
* SD spec recommends that the host checks the results of programming by sending
|
||||
* SEND_STATUS command. Some of the conditions reported in SEND_STATUS are not
|
||||
@ -633,28 +666,16 @@ esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
int64_t yield_delay_us = 100 * 1000; // initially 100ms
|
||||
int64_t t0 = esp_timer_get_time();
|
||||
int64_t t1 = 0;
|
||||
/* SD mode: wait for the card to become idle based on R1 status */
|
||||
while (!host_is_spi(card) && !sdmmc_ready_for_data(status)) {
|
||||
t1 = esp_timer_get_time();
|
||||
if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) {
|
||||
ESP_LOGE(TAG, "read sectors dma - timeout");
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
if (t1 - t0 > yield_delay_us) {
|
||||
yield_delay_us *= 2;
|
||||
vTaskDelay(1);
|
||||
}
|
||||
err = sdmmc_send_cmd_send_status(card, &status);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (++count % 16 == 0) {
|
||||
ESP_LOGV(TAG, "waiting for card to become ready (%d)", count);
|
||||
if (!host_is_spi(card)) {
|
||||
switch (sdmmc_wait_for_idle(card, status)) {
|
||||
case ESP_OK:
|
||||
break;
|
||||
case ESP_ERR_TIMEOUT:
|
||||
ESP_LOGE(TAG, "%s: sdmmc_wait_for_idle timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
default:
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -16,7 +16,9 @@
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
|
||||
static const char* TAG = "sdmmc_common";
|
||||
|
||||
@ -415,3 +417,33 @@ uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t er
|
||||
return sdmmc_sd_get_erase_timeout_ms(card, arg, erase_size_kb);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t sdmmc_wait_for_idle(sdmmc_card_t* card, uint32_t status)
|
||||
{
|
||||
assert(!host_is_spi(card));
|
||||
esp_err_t err = ESP_OK;
|
||||
size_t count = 0;
|
||||
int64_t yield_delay_us = 100 * 1000; // initially 100ms
|
||||
int64_t t0 = esp_timer_get_time();
|
||||
int64_t t1 = 0;
|
||||
/* SD mode: wait for the card to become idle based on R1 status */
|
||||
while (!sdmmc_ready_for_data(status)) {
|
||||
t1 = esp_timer_get_time();
|
||||
if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
if (t1 - t0 > yield_delay_us) {
|
||||
yield_delay_us *= 2;
|
||||
vTaskDelay(1);
|
||||
}
|
||||
err = sdmmc_send_cmd_send_status(card, &status);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (++count % 16 == 0) {
|
||||
ESP_LOGV(TAG, "waiting for card to become ready (%" PRIu32 ")", (uint32_t) count);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -15,7 +15,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
|
||||
#include "sd_pwr_ctrl.h"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_compiler.h"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
|
||||
static const char* TAG = "sdmmc_mmc";
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
* Adaptations to ESP-IDF Copyright (c) 2016-2024 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -19,7 +19,7 @@
|
||||
#include "esp_check.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_cache.h"
|
||||
#include "sdmmc_common.h"
|
||||
#include "esp_private/sdmmc_common.h"
|
||||
|
||||
static const char* TAG = "sdmmc_sd";
|
||||
|
||||
|
@ -503,8 +503,8 @@ components/protocomm/include/transports/protocomm_console.h
|
||||
components/protocomm/include/transports/protocomm_httpd.h
|
||||
components/riscv/include/riscv/csr.h
|
||||
components/riscv/include/riscv/encoding.h
|
||||
components/sdmmc/include/esp_private/sdmmc_common.h
|
||||
components/sdmmc/sdmmc_common.c
|
||||
components/sdmmc/sdmmc_common.h
|
||||
components/sdmmc/sdmmc_init.c
|
||||
components/sdmmc/sdmmc_io.c
|
||||
components/sdmmc/sdmmc_mmc.c
|
||||
|
Loading…
x
Reference in New Issue
Block a user