mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(sd_card): add built-in checks for connections to the card and correct pullups
This commit is contained in:
parent
7be04869d2
commit
54647dbbd3
@ -3,4 +3,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
set(COMPONENTS main)
|
||||
|
||||
project(sd_card)
|
||||
|
@ -182,3 +182,72 @@ Connections between the card and the ESP32 are too long for the frequency used.
|
||||
example: Failed to mount filesystem. If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.
|
||||
```
|
||||
The example will be able to mount only cards formatted using FAT32 filesystem. If the card is formatted as exFAT or some other filesystem, you have an option to format it in the example code. Enable the `EXAMPLE_FORMAT_IF_MOUNT_FAILED` menuconfig option, then build and flash the example.
|
||||
|
||||
### Debug SD connections and pullup strength
|
||||
|
||||
> If the initialization of the SD card fails, initially follow the above options. If the issue persists, confirm the connection of pullups to the SD pins. To do this, enable the` Debug sd pin connections and pullup strength` option from menuconfig and rerun the code. This will provide the following result:
|
||||
|
||||
```
|
||||
**** PIN recovery time ****
|
||||
|
||||
PIN 14 CLK 10044 cycles
|
||||
PIN 15 CMD 10034 cycles
|
||||
PIN 2 D0 10034 cycles
|
||||
PIN 4 D1 10034 cycles
|
||||
PIN 12 D2 10034 cycles
|
||||
PIN 13 D3 10034 cycles
|
||||
|
||||
**** PIN recovery time with weak pullup ****
|
||||
|
||||
PIN 14 CLK 100 cycles
|
||||
PIN 15 CMD 100 cycles
|
||||
PIN 2 D0 100 cycles
|
||||
PIN 4 D1 100 cycles
|
||||
PIN 12 D2 100 cycles
|
||||
PIN 13 D3 100 cycles
|
||||
|
||||
**** PIN voltage levels ****
|
||||
|
||||
PIN 14 CLK 0.6V
|
||||
PIN 15 CMD 0.3V
|
||||
PIN 2 D0 0.8V
|
||||
PIN 4 D1 0.6V
|
||||
PIN 12 D2 0.4V
|
||||
PIN 13 D3 0.8V
|
||||
|
||||
**** PIN voltage levels with weak pullup ****
|
||||
|
||||
PIN 14 CLK 1.0V
|
||||
PIN 15 CMD 1.1V
|
||||
PIN 2 D0 1.0V
|
||||
PIN 4 D1 1.0V
|
||||
PIN 12 D2 1.0V
|
||||
PIN 13 D3 1.2V
|
||||
|
||||
**** PIN cross-talk ****
|
||||
|
||||
CLK CMD D0 D1 D2 D3
|
||||
PIN 14 CLK -- 0.2V 0.1V 0.1V 0.1V 0.2V
|
||||
PIN 15 CMD 0.1V -- 0.1V 0.1V 0.1V 0.1V
|
||||
PIN 2 D0 0.1V 0.1V -- 0.2V 0.1V 0.1V
|
||||
PIN 4 D1 0.1V 0.1V 0.3V -- 0.1V 0.1V
|
||||
PIN 12 D2 0.1V 0.2V 0.2V 0.1V -- 0.1V
|
||||
PIN 13 D3 0.1V 0.2V 0.1V 0.1V 0.1V --
|
||||
|
||||
**** PIN cross-talk with weak pullup ****
|
||||
|
||||
CLK CMD D0 D1 D2 D3
|
||||
PIN 14 CLK -- 1.0V 1.0V 1.0V 1.0V 1.2V
|
||||
PIN 15 CMD 0.9V -- 1.0V 1.0V 1.0V 1.2V
|
||||
PIN 2 D0 0.9V 1.0V -- 1.0V 1.0V 1.2V
|
||||
PIN 4 D1 0.9V 1.0V 1.2V -- 1.0V 1.2V
|
||||
PIN 12 D2 0.9V 1.1V 1.2V 0.9V -- 1.2V
|
||||
PIN 13 D3 0.9V 1.2V 1.1V 0.9V 0.9V --
|
||||
I (845) main_task: Returned from app_main()
|
||||
```
|
||||
|
||||
In the absence of connected pullups and having the weak pullups enabled, you can assess the pullup connections by comparing PIN recovery time measured in CPU cycles. To check pullup connections, configure the pin as open drain, set it to low state, and count the cpu cycles consumed before returning to high state. If a pullup is connected, the pin will get back to high state after reasonably small cycle count, typically around 50-300 cycles, depending on pullup strength. If no pullup is connected, the PIN stays low and the measurement times out after 10000 cycles.
|
||||
|
||||
It will also provide the voltage levels at the corresponding SD pins. By default, this information is provided for ESP32 chip only, and for other chipsets, verify the availability of ADC pins for the respective GPIO using [this](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html#gpio-summary) and configure ADC mapped pins using menuconfig. Then test the voltage levels accordingly.
|
||||
|
||||
You can monitor the voltage levels of individual pins using `PIN voltage levels` and `PIN voltage levels with weak pullup`. However, if one pin being pulled low and experiencing interference with another pin, you can detect it through `PIN cross-talk` and `PIN cross-talk with weak pullup`. In the absence of pullups, voltage levels at each pin should range from 0 to 0.3V. With 10k pullups connected, the voltage will be between 3.1V to 3.3V, contingent on the connection between ADC pins and SD pins, and with weak pullups connected, it can fluctuate between 0.8V to 1.2V, depending on pullup strength.
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "sd_test_io.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES fatfs esp_adc
|
||||
WHOLE_ARCHIVE)
|
231
examples/storage/sd_card/sdmmc/components/sd_card/sd_test_io.c
Normal file
231
examples/storage/sd_card/sdmmc/components/sd_card/sd_test_io.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_log.h"
|
||||
#include "sd_test_io.h"
|
||||
|
||||
const static char *TAG = "SD_TEST";
|
||||
|
||||
#define ADC_ATTEN_DB ADC_ATTEN_DB_12
|
||||
#define GPIO_INPUT_PIN_SEL(pin) (1ULL<<pin)
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
|
||||
{
|
||||
adc_cali_handle_t handle = NULL;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
bool calibrated = false;
|
||||
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
if (!calibrated) {
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.chan = channel,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK) {
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
#endif //ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
|
||||
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
if (!calibrated) {
|
||||
adc_cali_line_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
|
||||
if (ret == ESP_OK) {
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
#endif //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
|
||||
*out_handle = handle;
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
|
||||
ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid arg or no memory");
|
||||
}
|
||||
}
|
||||
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
static void example_adc_calibration_deinit(adc_cali_handle_t handle)
|
||||
{
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle));
|
||||
|
||||
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle));
|
||||
#endif
|
||||
}
|
||||
|
||||
static float get_pin_voltage(int i, adc_oneshot_unit_handle_t adc_handle, bool do_calibration, adc_cali_handle_t adc_cali_handle)
|
||||
{
|
||||
int voltage = 0;
|
||||
int val;
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, i, &config));
|
||||
|
||||
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle, i, &val));
|
||||
if (do_calibration) {
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle, val, &voltage));
|
||||
}
|
||||
|
||||
return (float)voltage/1000;
|
||||
}
|
||||
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
|
||||
static uint32_t get_cycles_until_pin_level(int i, int level, int timeout) {
|
||||
uint32_t start = esp_cpu_get_cycle_count();
|
||||
while(gpio_get_level(i) == !level && esp_cpu_get_cycle_count() - start < timeout) {
|
||||
;
|
||||
}
|
||||
uint32_t end = esp_cpu_get_cycle_count();
|
||||
return end - start;
|
||||
}
|
||||
|
||||
void check_sd_card_pins(pin_configuration_t *config, const int pin_count)
|
||||
{
|
||||
ESP_LOGI(TAG, "Testing SD pin connections and pullup strength");
|
||||
gpio_config_t io_conf = {};
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
|
||||
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL(config->pins[i]);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
printf("\n**** PIN recovery time ****\n\n");
|
||||
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_set_level(config->pins[i], 0);
|
||||
usleep(100);
|
||||
gpio_set_level(config->pins[i], 1);
|
||||
uint32_t cycles = get_cycles_until_pin_level(config->pins[i], 1, 10000);
|
||||
printf("PIN %2d %3s %"PRIu32" cycles\n", config->pins[i], config->names[i], cycles);
|
||||
}
|
||||
|
||||
printf("\n**** PIN recovery time with weak pullup ****\n\n");
|
||||
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_pullup_en(config->pins[i]);
|
||||
gpio_set_level(config->pins[i], 0);
|
||||
usleep(100);
|
||||
gpio_set_level(config->pins[i], 1);
|
||||
uint32_t cycles = get_cycles_until_pin_level(config->pins[i], 1, 10000);
|
||||
printf("PIN %2d %3s %"PRIu32" cycles\n", config->pins[i], config->names[i], cycles);
|
||||
gpio_pullup_dis(config->pins[i]);
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
|
||||
adc_oneshot_unit_handle_t adc_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config = {
|
||||
.unit_id = CONFIG_EXAMPLE_ADC_UNIT,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle));
|
||||
|
||||
adc_cali_handle_t *adc_cali_handle = (adc_cali_handle_t *)malloc(sizeof(adc_cali_handle_t)*pin_count);
|
||||
bool *do_calibration = (bool *)malloc(sizeof(bool)*pin_count);
|
||||
|
||||
for (int i = 0; i < pin_count; i++) {
|
||||
do_calibration[i] = adc_calibration_init(CONFIG_EXAMPLE_ADC_UNIT, i, ADC_ATTEN_DB, &adc_cali_handle[i]);
|
||||
}
|
||||
|
||||
printf("\n**** PIN voltage levels ****\n\n");
|
||||
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
float voltage = get_pin_voltage(config->adc_channels[i], adc_handle, do_calibration[i], adc_cali_handle[i]);
|
||||
printf("PIN %2d %3s %.1fV\n", config->pins[i], config->names[i], voltage);
|
||||
}
|
||||
|
||||
printf("\n**** PIN voltage levels with weak pullup ****\n\n");
|
||||
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
gpio_pullup_en(config->pins[i]);
|
||||
usleep(100);
|
||||
float voltage = get_pin_voltage(config->adc_channels[i], adc_handle, do_calibration[i], adc_cali_handle[i]);
|
||||
printf("PIN %2d %3s %.1fV\n", config->pins[i], config->names[i], voltage);
|
||||
gpio_pullup_dis(config->pins[i]);
|
||||
}
|
||||
|
||||
printf("\n**** PIN cross-talk ****\n\n");
|
||||
|
||||
printf(" ");
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
printf("%3s ", config->names[i]);
|
||||
}
|
||||
printf("\n");
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_set_level(config->pins[i], 0);
|
||||
printf("PIN %2d %3s ", config->pins[i], config->names[i]);
|
||||
for (int j = 0; j < pin_count; ++j) {
|
||||
if (j == i) {
|
||||
printf(" -- ");
|
||||
continue;
|
||||
}
|
||||
usleep(100);
|
||||
float voltage = get_pin_voltage(config->adc_channels[j], adc_handle, do_calibration[i], adc_cali_handle[i]);
|
||||
printf("%1.1fV ", voltage);
|
||||
}
|
||||
printf("\n");
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT);
|
||||
}
|
||||
|
||||
printf("\n**** PIN cross-talk with weak pullup ****\n\n");
|
||||
|
||||
printf(" ");
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
printf("%3s ", config->names[i]);
|
||||
}
|
||||
printf("\n");
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_set_level(config->pins[i], 0);
|
||||
printf("PIN %2d %3s ", config->pins[i], config->names[i]);
|
||||
for (int j = 0; j < pin_count; ++j) {
|
||||
if (j == i) {
|
||||
printf(" -- ");
|
||||
continue;
|
||||
}
|
||||
gpio_pullup_en(config->pins[j]);
|
||||
usleep(100);
|
||||
float voltage = get_pin_voltage(config->adc_channels[j], adc_handle, do_calibration[i], adc_cali_handle[i]);
|
||||
printf("%1.1fV ", voltage);
|
||||
gpio_pullup_dis(config->pins[j]);
|
||||
}
|
||||
printf("\n");
|
||||
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pin_count; ++i) {
|
||||
if (do_calibration[i]) {
|
||||
example_adc_calibration_deinit(adc_cali_handle[i]);
|
||||
}
|
||||
}
|
||||
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const char** names;
|
||||
const int* pins;
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
const int *adc_channels;
|
||||
#endif
|
||||
} pin_configuration_t;
|
||||
|
||||
|
||||
void check_sd_card_pins(pin_configuration_t *config, const int pin_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,6 +1,9 @@
|
||||
idf_component_register(SRCS "sd_card_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
set(srcs "sd_card_example_main.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES fatfs sd_card
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
if(NOT CONFIG_SOC_SDMMC_HOST_SUPPORTED)
|
||||
fail_at_build_time(sdmmc ""
|
||||
|
@ -60,4 +60,90 @@ menu "SD/MMC Example Configuration"
|
||||
|
||||
endif # SOC_SDMMC_USE_GPIO_MATRIX
|
||||
|
||||
config EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
bool "Debug sd pin connections and pullup strength"
|
||||
default n
|
||||
|
||||
if !SOC_SDMMC_USE_GPIO_MATRIX
|
||||
config EXAMPLE_PIN_CMD
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 15 if IDF_TARGET_ESP32
|
||||
|
||||
config EXAMPLE_PIN_CLK
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 14 if IDF_TARGET_ESP32
|
||||
|
||||
config EXAMPLE_PIN_D0
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 2 if IDF_TARGET_ESP32
|
||||
|
||||
if EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
|
||||
config EXAMPLE_PIN_D1
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 4 if IDF_TARGET_ESP32
|
||||
|
||||
config EXAMPLE_PIN_D2
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 12 if IDF_TARGET_ESP32
|
||||
|
||||
config EXAMPLE_PIN_D3
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 13 if IDF_TARGET_ESP32
|
||||
|
||||
endif # EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
endif
|
||||
|
||||
config EXAMPLE_ENABLE_ADC_FEATURE
|
||||
bool "Enable ADC feature"
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default y if IDF_TARGET_ESP32
|
||||
default n
|
||||
|
||||
config EXAMPLE_ADC_UNIT
|
||||
int "ADC Unit"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 1 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_CLK
|
||||
int "CLK mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 6 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_CMD
|
||||
int "CMD mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 3 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_D0
|
||||
int "D0 mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 2 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
if EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
|
||||
config EXAMPLE_ADC_PIN_D1
|
||||
int "D1 mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 0 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_D2
|
||||
int "D2 mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 5 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_D3
|
||||
int "D3 mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 4 if IDF_TARGET_ESP32
|
||||
default 1
|
||||
|
||||
endif # EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
|
||||
endmenu
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
#include "sd_test_io.h"
|
||||
|
||||
#define EXAMPLE_MAX_CHAR_SIZE 64
|
||||
|
||||
@ -21,6 +22,40 @@ static const char *TAG = "example";
|
||||
|
||||
#define MOUNT_POINT "/sdcard"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
const char* names[] = {"CLK", "CMD", "D0", "D1", "D2", "D3"};
|
||||
const int pins[] = {CONFIG_EXAMPLE_PIN_CLK,
|
||||
CONFIG_EXAMPLE_PIN_CMD,
|
||||
CONFIG_EXAMPLE_PIN_D0
|
||||
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
,CONFIG_EXAMPLE_PIN_D1,
|
||||
CONFIG_EXAMPLE_PIN_D2,
|
||||
CONFIG_EXAMPLE_PIN_D3
|
||||
#endif
|
||||
};
|
||||
|
||||
const int pin_count = sizeof(pins)/sizeof(pins[0]);
|
||||
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
const int adc_channels[] = {CONFIG_EXAMPLE_ADC_PIN_CLK,
|
||||
CONFIG_EXAMPLE_ADC_PIN_CMD,
|
||||
CONFIG_EXAMPLE_ADC_PIN_D0
|
||||
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||
,CONFIG_EXAMPLE_ADC_PIN_D1,
|
||||
CONFIG_EXAMPLE_ADC_PIN_D2,
|
||||
CONFIG_EXAMPLE_ADC_PIN_D3
|
||||
#endif
|
||||
};
|
||||
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
|
||||
pin_configuration_t config = {
|
||||
.names = names,
|
||||
.pins = pins,
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
.adc_channels = adc_channels,
|
||||
#endif
|
||||
};
|
||||
#endif //CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
|
||||
static esp_err_t s_example_write_file(const char *path, char *data)
|
||||
{
|
||||
@ -130,6 +165,9 @@ void app_main(void)
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
|
||||
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
|
||||
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
check_sd_card_pins(&config, pin_count);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2,5 +2,8 @@
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/storage/sd_card/sdmmc/components/sd_card")
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(sd_card)
|
||||
|
@ -155,3 +155,59 @@ Ensure that the board and SD card adapter you are using are powered using the ap
|
||||
Attempt to reboot the board. This error may occur if you reset the ESP board or host controller without power-cycling it. In such cases, the card may remain in its previous state, causing it to potentially not respond to commands sent by the host controller.
|
||||
|
||||
Additionally, if the example works with certain SD cards but encounters issues with others, please confirm the read/write speed of the SD card. If the card is not compatible with the host frequency, consider lowering the host frequency and then attempting the operation again.
|
||||
|
||||
### Debug SD connections and pullup strength
|
||||
|
||||
> If the initialization of the SD card fails, initially follow the above options. If the issue persists, confirm the connection of pullups to the SD pins. To do this, enable the` Debug sd pin connections and pullup strength` option from menuconfig and rerun the code. This will provide the following result:
|
||||
|
||||
```
|
||||
**** PIN recovery time ****
|
||||
|
||||
PIN 14 CLK 10049 cycles
|
||||
PIN 15 MOSI 10034 cycles
|
||||
PIN 2 MISO 10034 cycles
|
||||
PIN 13 CS 10034 cycles
|
||||
|
||||
**** PIN recovery time with weak pullup ****
|
||||
|
||||
PIN 14 CLK 100 cycles
|
||||
PIN 15 MOSI 100 cycles
|
||||
PIN 2 MISO 100 cycles
|
||||
PIN 13 CS 100 cycles
|
||||
|
||||
**** PIN voltage levels ****
|
||||
|
||||
PIN 14 CLK 0.6V
|
||||
PIN 15 MOSI 0.4V
|
||||
PIN 2 MISO 0.7V
|
||||
PIN 13 CS 0.9V
|
||||
|
||||
**** PIN voltage levels with weak pullup ****
|
||||
|
||||
PIN 14 CLK 0.9V
|
||||
PIN 15 MOSI 1.0V
|
||||
PIN 2 MISO 1.0V
|
||||
PIN 13 CS 1.2V
|
||||
|
||||
**** PIN cross-talk ****
|
||||
|
||||
CLK MOSI MISO CS
|
||||
PIN 14 CLK -- 0.2V 0.2V 0.2V
|
||||
PIN 15 MOSI 0.1V -- 0.1V 0.1V
|
||||
PIN 2 MISO 0.1V 0.1V -- 0.1V
|
||||
PIN 13 CS 0.1V 0.1V 0.1V --
|
||||
|
||||
**** PIN cross-talk with weak pullup ****
|
||||
|
||||
CLK MOSI MISO CS
|
||||
PIN 14 CLK -- 1.0V 1.1V 1.2V
|
||||
PIN 15 MOSI 0.9V -- 1.0V 1.2V
|
||||
PIN 2 MISO 0.9V 1.0V -- 1.2V
|
||||
PIN 13 CS 0.9V 1.1V 1.0V --
|
||||
|
||||
```
|
||||
In the absence of connected pullups and having the weak pullups enabled, you can assess the pullup connections by comparing PIN recovery time measured in CPU cycles. To check pullup connections, configure the pin as open drain, set it to low state, and count the cpu cycles consumed before returning to high state. If a pullup is connected, the pin will get back to high state after reasonably small cycle count, typically around 50-300 cycles, depending on pullup strength. If no pullup is connected, the PIN stays low and the measurement times out after 10000 cycles.
|
||||
|
||||
It will also provide the voltage levels at the corresponding SD pins. By default, this information is provided for ESP32 chip only, and for other chipsets, verify the availability of ADC pins for the respective GPIO using [this](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html#gpio-summary) and configure ADC mapped pins using menuconfig. Then test the voltage levels accordingly.
|
||||
|
||||
You can monitor the voltage levels of individual pins using `PIN voltage levels` and `PIN voltage levels with weak pullup`. However, if one pin being pulled low and experiencing interference with another pin, you can detect it through `PIN cross-talk` and `PIN cross-talk with weak pullup`. In the absence of pullups, voltage levels at each pin should range from 0 to 0.3V. With 10k pullups connected, the voltage will be between 3.1V to 3.3V, contingent on the connection between ADC pins and SD pins, and with weak pullups connected, it can fluctuate between 0.8V to 1.2V, depending on pullup strength.
|
||||
|
@ -1,2 +1,6 @@
|
||||
idf_component_register(SRCS "sd_card_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
set(srcs "sd_card_example_main.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES fatfs sd_card
|
||||
WHOLE_ARCHIVE)
|
||||
|
@ -42,4 +42,49 @@ menu "SD SPI Example Configuration"
|
||||
default 10 if IDF_TARGET_ESP32P4
|
||||
default 1 # C3 and others
|
||||
|
||||
config EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
bool "Debug sd pin connections and pullup strength"
|
||||
default n
|
||||
|
||||
config EXAMPLE_ENABLE_ADC_FEATURE
|
||||
bool "Enable ADC feature"
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default y if IDF_TARGET_ESP32
|
||||
default n
|
||||
|
||||
config EXAMPLE_ADC_UNIT
|
||||
int "ADC Unit"
|
||||
depends on EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
default 1 if IDF_TARGET_ESP32
|
||||
default 0 if IDF_TARGET_ESP32S3
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_MOSI
|
||||
int "MOSI mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 3 if IDF_TARGET_ESP32
|
||||
default 7 if IDF_TARGET_ESP32S3
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_MISO
|
||||
int "MISO mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 2 if IDF_TARGET_ESP32
|
||||
default 1 if IDF_TARGET_ESP32S3
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_CLK
|
||||
int "CLK mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 6 if IDF_TARGET_ESP32
|
||||
default 0 if IDF_TARGET_ESP32S3
|
||||
default 1
|
||||
|
||||
config EXAMPLE_ADC_PIN_CS
|
||||
int "CS mapped ADC pin"
|
||||
depends on EXAMPLE_ENABLE_ADC_FEATURE
|
||||
default 4 if IDF_TARGET_ESP32
|
||||
default 6 if IDF_TARGET_ESP32S3
|
||||
default 1
|
||||
|
||||
endmenu
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "sd_test_io.h"
|
||||
|
||||
#define EXAMPLE_MAX_CHAR_SIZE 64
|
||||
|
||||
@ -20,6 +21,30 @@ static const char *TAG = "example";
|
||||
|
||||
#define MOUNT_POINT "/sdcard"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
const char* names[] = {"CLK ", "MOSI", "MISO", "CS "};
|
||||
const int pins[] = {CONFIG_EXAMPLE_PIN_CLK,
|
||||
CONFIG_EXAMPLE_PIN_MOSI,
|
||||
CONFIG_EXAMPLE_PIN_MISO,
|
||||
CONFIG_EXAMPLE_PIN_CS};
|
||||
|
||||
const int pin_count = sizeof(pins)/sizeof(pins[0]);
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
const int adc_channels[] = {CONFIG_EXAMPLE_ADC_PIN_CLK,
|
||||
CONFIG_EXAMPLE_ADC_PIN_MOSI,
|
||||
CONFIG_EXAMPLE_ADC_PIN_MISO,
|
||||
CONFIG_EXAMPLE_ADC_PIN_CS};
|
||||
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
|
||||
pin_configuration_t config = {
|
||||
.names = names,
|
||||
.pins = pins,
|
||||
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
|
||||
.adc_channels = adc_channels,
|
||||
#endif
|
||||
};
|
||||
#endif //CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
|
||||
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
|
||||
// You can also change the pin assignments here by changing the following 4 lines.
|
||||
#define PIN_NUM_MISO CONFIG_EXAMPLE_PIN_MISO
|
||||
@ -125,6 +150,9 @@ void app_main(void)
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
|
||||
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
|
||||
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
|
||||
check_sd_card_pins(&config, pin_count);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user