Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ jobs:
target: esp32
- path: 'components/rx8130ce/example'
target: esp32s3
- path: 'components/sdcard/example'
target: esp32s3
- path: 'components/seeed-studio-round-display/example'
target: esp32s3
- path: 'components/serialization/example'
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/upload_components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jobs:
# ahead of its first-time dependents coredump / dispatcher / ota,
# so it is uploaded to the registry before they try to resolve it.
#
# Note: sdcard is intentionally listed (out of alphabetical order) ahead
# of the BSPs that depend on espp/sdcard (esp32-p4-*, lilygo-t5-47,
# m5stack-cardputer, m5stack-tab5, ...), so it is uploaded to the
# registry before they try to resolve it.
#
# Note: comments are not allowed in the "components" list, so please
# do not add any comments here.
components: |
Expand Down Expand Up @@ -89,6 +94,7 @@ jobs:
components/drv2605
components/encoder
components/esp-box
components/sdcard
components/ethernet
components/esp32-p4-eth
components/esp32-p4-function-ev-board
Expand Down
1 change: 1 addition & 0 deletions components/esp32-p4-eth/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ idf_component_register(
"esp_netif"
"fatfs"
"esp_driver_sdmmc"
"sdcard"
"sdmmc"
"codec"
"i2c"
Expand Down
1 change: 1 addition & 0 deletions components/esp32-p4-eth/example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(EXTRA_COMPONENT_DIRS
"../../../components/led"
"../../../components/logger"
"../../../components/lvgl"
"../../../components/sdcard"
"../../../components/spi"
"../../../components/task"
"../../../components/touch"
Expand Down
1 change: 1 addition & 0 deletions components/esp32-p4-eth/idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies:
espp/gt911: ">=1.0"
espp/input_drivers: ">=1.0"
espp/interrupt: ">=1.0"
espp/sdcard: ">=1.0"
# MIPI-CSI camera pipeline: esp_video provides the V4L2 capture framework
# (CSI + ISP) and esp_cam_sensor provides the OV5647 sensor driver.
espressif/esp_video: ">=2.0,<2.4" # 2.4.0 fails to compile against the CI IDF (ISP_LL_EVENT_ERROR_MASK undeclared)
Expand Down
21 changes: 15 additions & 6 deletions components/esp32-p4-eth/include/esp32-p4-eth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "ili9881.hpp"
#include "interrupt.hpp"
#include "jd9365.hpp"
#include "sdcard.hpp"
#include "task.hpp"
#include "touchpad_input.hpp"

Expand Down Expand Up @@ -456,11 +457,21 @@ class Esp32P4Eth : public BaseComponent {
/// \return True if the card was successfully mounted at \c mount_point.
bool initialize_sdcard(const SdCardConfig &config);

/// \return True if the SD card is present and mounted.
bool is_sd_card_available() const { return sd_card_initialized_; }
/// \return True if the SD card is initialized and its volume is currently
/// mounted (false after sdcard_component()->unmount()).
bool is_sd_card_available() const { return sdcard_ && sdcard_->is_mounted(); }

/// \return The SDMMC card handle, or nullptr if not initialized.
sdmmc_card_t *sdcard() const { return sdcard_; }
/// \note nullptr until initialize_sdcard() succeeded. The card stays valid while
/// its volume is unmounted (sdcard_component()->unmount()), e.g. to hand it
/// to a USB host through espp::UsbDevice's MSC function.
sdmmc_card_t *sdcard() const { return sdcard_ ? sdcard_->card() : nullptr; }

/// Get the SD card component: mount() / unmount() (e.g. to hand the card to a
/// USB host with the usb_device MSC function), format(), card_info(),
/// volume_info(), ...
/// \return The component, or nullptr until initialize_sdcard() succeeded
espp::SdCard *sdcard_component() const { return sdcard_.get(); }

/// Get total/free space of the mounted card.
/// \param size_mb Optional out: total size in MB.
Expand Down Expand Up @@ -630,9 +641,7 @@ class Esp32P4Eth : public BaseComponent {
static constexpr gpio_num_t sd_d2_io = GPIO_NUM_41;
static constexpr gpio_num_t sd_d3_io = GPIO_NUM_42;

std::atomic<bool> sd_card_initialized_{false};
sdmmc_card_t *sdcard_{nullptr};
void *sd_pwr_ctrl_handle_{nullptr};
std::unique_ptr<espp::SdCard> sdcard_;

/////////////////////////////////////////////////////////////////////////////
// Interrupts (used by the optional interrupt-driven touch path)
Expand Down
94 changes: 34 additions & 60 deletions components/esp32-p4-eth/src/sdcard.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#include "esp32-p4-eth.hpp"

#include <esp_vfs_fat.h>
#include <sd_pwr_ctrl_by_on_chip_ldo.h>
#include <sdmmc_cmd.h>

namespace espp {

bool Esp32P4Eth::initialize_sdcard(const SdCardConfig &config) {
Expand All @@ -13,75 +9,53 @@ bool Esp32P4Eth::initialize_sdcard(const SdCardConfig &config) {
}

logger_.info("Initializing SD card (4-bit SDMMC)");

esp_vfs_fat_sdmmc_mount_config_t mount_config{};
mount_config.format_if_mount_failed = config.format_if_mount_failed;
mount_config.max_files = config.max_files;
mount_config.allocation_unit_size = config.allocation_unit_size;

sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
host.slot = SDMMC_HOST_SLOT_0;

// The ESP32-P4 powers the SD card via an internal LDO (LDO_VO4). Configure the
// power control handle so the host can enable that rail.
sd_pwr_ctrl_ldo_config_t ldo_config{};
ldo_config.ldo_chan_id = sd_ldo_channel;
sd_pwr_ctrl_handle_t pwr_ctrl_handle = nullptr;
esp_err_t ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
if (ret != ESP_OK) {
logger_.error("Failed to create SD power control driver: {}", esp_err_to_name(ret));
return false;
}
host.pwr_ctrl_handle = pwr_ctrl_handle;
sd_pwr_ctrl_handle_ = pwr_ctrl_handle;

sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
slot_config.width = 4;
slot_config.clk = sd_clk_io;
slot_config.cmd = sd_cmd_io;
slot_config.d0 = sd_d0_io;
slot_config.d1 = sd_d1_io;
slot_config.d2 = sd_d2_io;
slot_config.d3 = sd_d3_io;

logger_.debug("Mounting filesystem");
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &sdcard_);

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
logger_.error("Failed to mount filesystem.");
} else {
logger_.warn("Failed to initialize the card ({}). "
"Make sure an SD card is inserted.",
esp_err_to_name(ret));
}
sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle);
sd_pwr_ctrl_handle_ = nullptr;
espp::SdCard::SdmmcConfig sdmmc;
sdmmc.slot = SDMMC_HOST_SLOT_0;
sdmmc.bus_width = 4;
sdmmc.clk = sd_clk_io;
sdmmc.cmd = sd_cmd_io;
sdmmc.d0 = sd_d0_io;
sdmmc.d1 = sd_d1_io;
sdmmc.d2 = sd_d2_io;
sdmmc.d3 = sd_d3_io;
sdmmc.frequency_khz = SDMMC_FREQ_HIGHSPEED; // 40 MHz
// The ESP32-P4 powers the SD card via an internal LDO (LDO_VO4): without it
// the bus floats and card init fails.
sdmmc.ldo_channel = sd_ldo_channel;
sdcard_ = std::make_unique<espp::SdCard>(espp::SdCard::Config{
.interface = sdmmc,
.mount_point = mount_point,
.format_if_mount_failed = config.format_if_mount_failed,
.max_files = config.max_files,
.allocation_unit_size = config.allocation_unit_size,
.log_level = get_log_level(),
});
std::error_code ec;
if (!sdcard_->initialize(ec)) {
logger_.error("Failed to initialize the SD card: {}. Make sure an SD card is inserted.",
ec.message());
sdcard_.reset();
return false;
}

logger_.info("Filesystem mounted");
sdmmc_card_print_info(stdout, sdcard_);
sd_card_initialized_ = true;
logger_.info("Filesystem mounted at {}", mount_point);
sdcard_->print_info(stdout);
return true;
}

bool Esp32P4Eth::get_sd_card_info(uint32_t *size_mb, uint32_t *free_mb) const {
if (!sd_card_initialized_) {
if (!sdcard_) {
return false;
}
uint64_t total_bytes = 0, free_bytes = 0;
esp_err_t ret = esp_vfs_fat_info(mount_point, &total_bytes, &free_bytes);
if (ret != ESP_OK) {
logger_.error("Failed to get SD card information ({})", esp_err_to_name(ret));
const auto volume = sdcard_->volume_info();
if (!volume) {
logger_.error("Failed to get SD card information (volume not mounted)");
return false;
}
if (size_mb) {
*size_mb = total_bytes / (1024 * 1024);
*size_mb = volume->total_bytes / (1024 * 1024);
}
if (free_mb) {
*free_mb = free_bytes / (1024 * 1024);
*free_mb = volume->free_bytes / (1024 * 1024);
}
return true;
}
Expand Down
1 change: 1 addition & 0 deletions components/esp32-p4-function-ev-board/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ idf_component_register(
"esp_netif"
"fatfs"
"esp_driver_sdmmc"
"sdcard"
"sdmmc"
)
1 change: 1 addition & 0 deletions components/esp32-p4-function-ev-board/idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies:
espp/i2c: ">=1.0"
espp/input_drivers: ">=1.0"
espp/interrupt: ">=1.0"
espp/sdcard: ">=1.0"
espp/led: ">=1.0"
espp/task: ">=1.0"
targets:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "ili9881.hpp"
#include "interrupt.hpp"
#include "led.hpp"
#include "sdcard.hpp"
#include "task.hpp"
#include "touchpad_input.hpp"

Expand Down Expand Up @@ -343,13 +344,23 @@ class Esp32P4FunctionEvBoard : public BaseComponent {
/// \return True if uSD card was successfully initialized
bool initialize_sdcard(const SdCardConfig &config);

/// Check if SD card is present and mounted
/// \return True if SD card is available
bool is_sd_card_available() const { return sd_card_initialized_; }
/// Check if the SD card is initialized and its volume is currently mounted
/// \return True if the SD card is available (false after
/// sdcard_component()->unmount())
bool is_sd_card_available() const { return sdcard_ && sdcard_->is_mounted(); }

/// Get the uSD card handle
/// \return A pointer to the uSD card, or nullptr if not initialized
sdmmc_card_t *sdcard() const { return sdcard_; }
/// \note nullptr until initialize_sdcard() succeeded. The card stays valid while
/// its volume is unmounted (sdcard_component()->unmount()), e.g. to hand it
/// to a USB host through espp::UsbDevice's MSC function.
sdmmc_card_t *sdcard() const { return sdcard_ ? sdcard_->card() : nullptr; }

/// Get the SD card component: mount() / unmount() (e.g. to hand the card to a
/// USB host with the usb_device MSC function), format(), card_info(),
/// volume_info(), ...
/// \return The component, or nullptr until initialize_sdcard() succeeded
espp::SdCard *sdcard_component() const { return sdcard_.get(); }
Comment thread
finger563 marked this conversation as resolved.

/// Get SD card info
/// \param size_mb Pointer to store size in MB
Expand Down Expand Up @@ -599,9 +610,7 @@ class Esp32P4FunctionEvBoard : public BaseComponent {
std::atomic<float> mic_volume_{70.0f};

// uSD card
std::atomic<bool> sd_card_initialized_{false};
sdmmc_card_t *sdcard_{nullptr};
void *sd_pwr_ctrl_handle_{nullptr};
std::unique_ptr<espp::SdCard> sdcard_;

#if CONFIG_ESP_P4_EV_BOARD_ETHERNET
// The board's RMII Ethernet is driven by the reusable espp::Ethernet component
Expand Down
94 changes: 34 additions & 60 deletions components/esp32-p4-function-ev-board/src/sdcard.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#include "esp32-p4-function-ev-board.hpp"

#include <esp_vfs_fat.h>
#include <sd_pwr_ctrl_by_on_chip_ldo.h>
#include <sdmmc_cmd.h>

namespace espp {

bool Esp32P4FunctionEvBoard::initialize_sdcard(const SdCardConfig &config) {
Expand All @@ -13,75 +9,53 @@ bool Esp32P4FunctionEvBoard::initialize_sdcard(const SdCardConfig &config) {
}

logger_.info("Initializing SD card (4-bit SDMMC)");

esp_vfs_fat_sdmmc_mount_config_t mount_config{};
mount_config.format_if_mount_failed = config.format_if_mount_failed;
mount_config.max_files = config.max_files;
mount_config.allocation_unit_size = config.allocation_unit_size;

sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
host.slot = SDMMC_HOST_SLOT_0;

// The ESP32-P4 powers the SD card via an internal LDO (LDO_VO4). Configure the
// power control handle so the host can enable that rail.
sd_pwr_ctrl_ldo_config_t ldo_config{};
ldo_config.ldo_chan_id = sd_ldo_channel;
sd_pwr_ctrl_handle_t pwr_ctrl_handle = nullptr;
esp_err_t ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
if (ret != ESP_OK) {
logger_.error("Failed to create SD power control driver: {}", esp_err_to_name(ret));
return false;
}
host.pwr_ctrl_handle = pwr_ctrl_handle;
sd_pwr_ctrl_handle_ = pwr_ctrl_handle;

sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
slot_config.width = 4;
slot_config.clk = sd_clk_io;
slot_config.cmd = sd_cmd_io;
slot_config.d0 = sd_d0_io;
slot_config.d1 = sd_d1_io;
slot_config.d2 = sd_d2_io;
slot_config.d3 = sd_d3_io;

logger_.debug("Mounting filesystem");
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &sdcard_);

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
logger_.error("Failed to mount filesystem.");
} else {
logger_.warn("Failed to initialize the card ({}). "
"Make sure an SD card is inserted.",
esp_err_to_name(ret));
}
sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle);
sd_pwr_ctrl_handle_ = nullptr;
espp::SdCard::SdmmcConfig sdmmc;
sdmmc.slot = SDMMC_HOST_SLOT_0;
sdmmc.bus_width = 4;
sdmmc.clk = sd_clk_io;
sdmmc.cmd = sd_cmd_io;
sdmmc.d0 = sd_d0_io;
sdmmc.d1 = sd_d1_io;
sdmmc.d2 = sd_d2_io;
sdmmc.d3 = sd_d3_io;
sdmmc.frequency_khz = SDMMC_FREQ_HIGHSPEED; // 40 MHz
// The ESP32-P4 powers the SD card via an internal LDO (LDO_VO4): without it
// the bus floats and card init fails.
sdmmc.ldo_channel = sd_ldo_channel;
sdcard_ = std::make_unique<espp::SdCard>(espp::SdCard::Config{
.interface = sdmmc,
.mount_point = mount_point,
.format_if_mount_failed = config.format_if_mount_failed,
.max_files = config.max_files,
.allocation_unit_size = config.allocation_unit_size,
.log_level = get_log_level(),
});
std::error_code ec;
if (!sdcard_->initialize(ec)) {
logger_.error("Failed to initialize the SD card: {}. Make sure an SD card is inserted.",
ec.message());
sdcard_.reset();
return false;
}

logger_.info("Filesystem mounted");
sdmmc_card_print_info(stdout, sdcard_);
sd_card_initialized_ = true;
logger_.info("Filesystem mounted at {}", mount_point);
sdcard_->print_info(stdout);
return true;
}

bool Esp32P4FunctionEvBoard::get_sd_card_info(uint32_t *size_mb, uint32_t *free_mb) const {
if (!sd_card_initialized_) {
if (!sdcard_) {
return false;
}
uint64_t total_bytes = 0, free_bytes = 0;
esp_err_t ret = esp_vfs_fat_info(mount_point, &total_bytes, &free_bytes);
if (ret != ESP_OK) {
logger_.error("Failed to get SD card information ({})", esp_err_to_name(ret));
const auto volume = sdcard_->volume_info();
if (!volume) {
logger_.error("Failed to get SD card information (volume not mounted)");
return false;
}
if (size_mb) {
*size_mb = total_bytes / (1024 * 1024);
*size_mb = volume->total_bytes / (1024 * 1024);
}
if (free_mb) {
*free_mb = free_bytes / (1024 * 1024);
*free_mb = volume->free_bytes / (1024 * 1024);
}
return true;
}
Expand Down
Loading
Loading