#include "SdCard.hpp" #include "esp_log.h" #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" #include "driver/sdmmc_host.h" #include "sd_pwr_ctrl_by_on_chip_ldo.h" #include "tinyusb_default_config.h" #include "tinyusb_msc.h" #include static const char* TAG = "SdCard"; // ESP32-P4 Waveshare Board SDMMC Pins (from official docs) #define SDMMC_CLK_GPIO 43 #define SDMMC_CMD_GPIO 44 #define SDMMC_D0_GPIO 39 #define SDMMC_D1_GPIO 40 #define SDMMC_D2_GPIO 41 #define SDMMC_D3_GPIO 42 // SD card power control LDO channel (from Waveshare example) #define SD_PWR_CTRL_LDO_CHANNEL 4 static sdmmc_card_t* s_card = nullptr; static sd_pwr_ctrl_handle_t s_pwr_ctrl_handle = nullptr; SdCard& SdCard::instance() { static SdCard inst; return inst; } bool SdCard::init() { if (mounted_) { ESP_LOGW(TAG, "SD card already mounted"); return true; } ESP_LOGI(TAG, "Initializing SD card (SDMMC 4-wire mode)"); // Configure SDMMC host sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = SDMMC_FREQ_DEFAULT; // 20 MHz // Initialize SD card power control via internal LDO sd_pwr_ctrl_ldo_config_t ldo_config = { .ldo_chan_id = SD_PWR_CTRL_LDO_CHANNEL, }; esp_err_t ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &s_pwr_ctrl_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to create SD power control driver: %s", esp_err_to_name(ret)); return false; } host.pwr_ctrl_handle = s_pwr_ctrl_handle; ESP_LOGI(TAG, "SD power control LDO initialized (channel %d)", SD_PWR_CTRL_LDO_CHANNEL); // Configure SDMMC slot with official Waveshare pinout sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); slot_config.width = 4; slot_config.clk = static_cast(SDMMC_CLK_GPIO); slot_config.cmd = static_cast(SDMMC_CMD_GPIO); slot_config.d0 = static_cast(SDMMC_D0_GPIO); slot_config.d1 = static_cast(SDMMC_D1_GPIO); slot_config.d2 = static_cast(SDMMC_D2_GPIO); slot_config.d3 = static_cast(SDMMC_D3_GPIO); slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; // Mount FAT filesystem esp_vfs_fat_sdmmc_mount_config_t mount_config = VFS_FAT_MOUNT_DEFAULT_CONFIG(); mount_config.max_files = 5; mount_config.allocation_unit_size = 16 * 1024; ESP_LOGI(TAG, "Mounting SD card..."); ret = esp_vfs_fat_sdmmc_mount(MOUNT_POINT, &host, &slot_config, &mount_config, &s_card); if (ret != ESP_OK) { if (ret == ESP_FAIL) { ESP_LOGE(TAG, "Failed to mount filesystem."); } else { ESP_LOGE(TAG, "Failed to initialize SD card (%s).", esp_err_to_name(ret)); } // Clean up power control on failure sd_pwr_ctrl_del_on_chip_ldo(s_pwr_ctrl_handle); s_pwr_ctrl_handle = nullptr; return false; } mounted_ = true; // Print card info sdmmc_card_print_info(stdout, s_card); ESP_LOGI(TAG, "SD card mounted at %s", MOUNT_POINT); // Create directories if they don't exist struct stat st; const char* dirs[] = { "/sdcard/webseite", "/sdcard/images", "/sdcard/fonts" }; for (const char* dir : dirs) { if (stat(dir, &st) != 0) { if (mkdir(dir, 0755) == 0) { ESP_LOGI(TAG, "Created directory: %s", dir); } else { ESP_LOGW(TAG, "Failed to create directory: %s", dir); } } } return true; } bool SdCard::enableUsbMsc() { if (usbMscActive_) { ESP_LOGW(TAG, "USB MSC already active"); return true; } if (!s_card) { ESP_LOGE(TAG, "SD card not initialized"); return false; } ESP_LOGI(TAG, "Enabling USB Mass Storage mode..."); // Unmount filesystem first (so PC has exclusive access) if (mounted_) { ESP_LOGI(TAG, "Unmounting SD card from filesystem..."); esp_err_t ret = esp_vfs_fat_sdcard_unmount(MOUNT_POINT, s_card); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to unmount SD card: %s", esp_err_to_name(ret)); return false; } mounted_ = false; } // Initialize TinyUSB ESP_LOGI(TAG, "Initializing TinyUSB..."); const tinyusb_config_t cfg = TINYUSB_DEFAULT_CONFIG(); esp_err_t ret = tinyusb_driver_install(&cfg); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to install TinyUSB driver: %s", esp_err_to_name(ret)); return false; } // Initialize MSC storage with SD card ESP_LOGI(TAG, "Initializing USB MSC with SD card..."); tinyusb_msc_storage_config_t storage_cfg = {}; storage_cfg.medium.card = s_card; storage_cfg.mount_point = TINYUSB_MSC_STORAGE_MOUNT_USB; storage_cfg.fat_fs.base_path = nullptr; storage_cfg.fat_fs.config = VFS_FAT_MOUNT_DEFAULT_CONFIG(); storage_cfg.fat_fs.config.max_files = 5; storage_cfg.fat_fs.config.allocation_unit_size = 16 * 1024; storage_cfg.fat_fs.do_not_format = true; storage_cfg.fat_fs.format_flags = 0; tinyusb_msc_storage_handle_t storage_hdl = nullptr; ret = tinyusb_msc_new_storage_sdmmc(&storage_cfg, &storage_hdl); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize MSC storage: %s", esp_err_to_name(ret)); return false; } if (storage_hdl == nullptr) { ESP_LOGE(TAG, "MSC storage handle not initialized"); return false; } usbMscActive_ = true; ESP_LOGI(TAG, "USB Mass Storage mode enabled!"); ESP_LOGI(TAG, "Connect USB cable to access SD card from PC."); ESP_LOGI(TAG, "Reboot device to return to normal mode."); return true; }