New kernel drivers, filesystem API, and more (#513)
* **New Features** * BMI270 6-axis IMU driver added; new unified filesystem abstraction for mounted filesystems. * Public Wi‑Fi API surface (no implementation yet) * SDMMC driver added (kernel drive$) * expanded GPIO interrupt/callback support * **Improvements** * M5Stack Tab5: revamped GPIO/power initialization and IMU integration. * LVGL updates including device fontSize configuration. * Updated all code related to SD card device/fs handling * Rename LilyGO T-HMI S3 to LilyGO T-HMI * **Bug Fixes** * Simplified and consolidated SD card handling and mount discovery.
This commit is contained in:
committed by
GitHub
parent
2de35b2d2d
commit
aa7530e515
@@ -6,5 +6,5 @@ idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "include/"
|
||||
PRIV_INCLUDE_DIRS "private/"
|
||||
REQUIRES TactilityKernel driver
|
||||
REQUIRES TactilityKernel driver vfs fatfs
|
||||
)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
description: ESP32 SDMMC
|
||||
|
||||
compatible: "espressif,esp32-sdmmc"
|
||||
|
||||
properties:
|
||||
pin-clk:
|
||||
type: phandle-array
|
||||
required: true
|
||||
pin-cmd:
|
||||
type: phandle-array
|
||||
required: true
|
||||
pin-d0:
|
||||
type: phandle-array
|
||||
required: true
|
||||
pin-d1:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d2:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d3:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d4:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d5:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d6:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d7:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-cd:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-wp:
|
||||
type: phandle-array
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
bus-width:
|
||||
type: int
|
||||
required: true
|
||||
description: Bus width in bits
|
||||
wp-active-high:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Whether the WP pin is active high
|
||||
enable-uhs:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Enable UHS mode
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(esp32_sdmmc, struct Esp32SdmmcConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
#include <soc/soc_caps.h>
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
|
||||
#include <sd_protocol_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <tactility/drivers/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32SdmmcConfig {
|
||||
struct GpioPinSpec pin_clk;
|
||||
struct GpioPinSpec pin_cmd;
|
||||
struct GpioPinSpec pin_d0;
|
||||
struct GpioPinSpec pin_d1;
|
||||
struct GpioPinSpec pin_d2;
|
||||
struct GpioPinSpec pin_d3;
|
||||
struct GpioPinSpec pin_d4;
|
||||
struct GpioPinSpec pin_d5;
|
||||
struct GpioPinSpec pin_d6;
|
||||
struct GpioPinSpec pin_d7;
|
||||
struct GpioPinSpec pin_cd;
|
||||
struct GpioPinSpec pin_wp;
|
||||
uint8_t bus_width;
|
||||
bool wp_active_high;
|
||||
bool enable_uhs;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the SD card handle for the given device.
|
||||
* @param[in] device the device to get the card handle for
|
||||
* @return the SD card handle, or NULL if the device is not mounted
|
||||
*/
|
||||
sdmmc_card_t* esp32_sdmmc_get_card(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
#include <soc/soc_caps.h>
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32SdmmcConfig;
|
||||
typedef void* Esp32SdmmcHandle;
|
||||
|
||||
extern Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const struct Esp32SdmmcConfig* config, const char* mount_path);
|
||||
|
||||
extern void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle);
|
||||
|
||||
extern sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle);
|
||||
|
||||
extern const FileSystemApi esp32_sdmmc_fs_api;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,12 @@
|
||||
|
||||
#define TAG "esp32_gpio"
|
||||
|
||||
struct Esp32GpioInternal {
|
||||
uint8_t isr_service_ref_count = 0;
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config)
|
||||
#define GET_INTERNAL_FROM_DESCRIPTOR(gpio_descriptor) ((struct Esp32GpioInternal*)gpio_descriptor->controller_context)
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -97,15 +102,76 @@ static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_numbe
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
|
||||
auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor);
|
||||
if (internal->isr_service_ref_count == 0) {
|
||||
auto esp_error = gpio_install_isr_service(0);
|
||||
if (esp_error != ESP_OK && esp_error != ESP_ERR_INVALID_STATE) {
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
}
|
||||
|
||||
auto esp_error = gpio_isr_handler_add(static_cast<gpio_num_t>(descriptor->pin), callback, arg);
|
||||
|
||||
if (esp_error == ESP_OK) {
|
||||
internal->isr_service_ref_count++;
|
||||
} else if (internal->isr_service_ref_count == 0) {
|
||||
gpio_uninstall_isr_service();
|
||||
}
|
||||
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t remove_callback(GpioDescriptor* descriptor) {
|
||||
auto esp_error = gpio_isr_handler_remove(static_cast<gpio_num_t>(descriptor->pin));
|
||||
if (esp_error == ESP_OK) {
|
||||
auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor);
|
||||
check(internal->isr_service_ref_count > 0);
|
||||
internal->isr_service_ref_count--;
|
||||
if (internal->isr_service_ref_count == 0) {
|
||||
gpio_uninstall_isr_service();
|
||||
}
|
||||
}
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t enable_interrupt(GpioDescriptor* descriptor) {
|
||||
auto esp_error = gpio_intr_enable(static_cast<gpio_num_t>(descriptor->pin));
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t disable_interrupt(GpioDescriptor* descriptor) {
|
||||
auto esp_error = gpio_intr_disable(static_cast<gpio_num_t>(descriptor->pin));
|
||||
return esp_err_to_error(esp_error);
|
||||
}
|
||||
|
||||
static error_t start(Device* device) {
|
||||
ESP_LOGI(TAG, "start %s", device->name);
|
||||
auto pin_count = GET_CONFIG(device)->gpioCount;
|
||||
return gpio_controller_init_descriptors(device, pin_count, nullptr);
|
||||
LOG_I(TAG, "start %s", device->name);
|
||||
const Esp32GpioConfig* config = GET_CONFIG(device);
|
||||
auto* internal = new Esp32GpioInternal();
|
||||
return gpio_controller_init_descriptors(device, config->gpioCount, internal);
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
ESP_LOGI(TAG, "stop %s", device->name);
|
||||
return gpio_controller_deinit_descriptors(device);
|
||||
LOG_I(TAG, "stop %s", device->name);
|
||||
const Esp32GpioConfig* config = GET_CONFIG(device);
|
||||
auto* internal = static_cast<Esp32GpioInternal*>(gpio_controller_get_controller_context(device));
|
||||
|
||||
// First, remove all ISR handlers to prevent callbacks during cleanup
|
||||
for (uint8_t i = 0; i < config->gpioCount; ++i) {
|
||||
gpio_isr_handler_remove(static_cast<gpio_num_t>(i));
|
||||
}
|
||||
|
||||
// Then uninstall ISR service
|
||||
if (internal->isr_service_ref_count > 0) {
|
||||
gpio_uninstall_isr_service();
|
||||
}
|
||||
|
||||
// Now safe to deinit descriptors and delete internal
|
||||
check(gpio_controller_deinit_descriptors(device) == ERROR_NONE);
|
||||
delete internal;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
const static GpioControllerApi esp32_gpio_api = {
|
||||
@@ -113,17 +179,21 @@ const static GpioControllerApi esp32_gpio_api = {
|
||||
.get_level = get_level,
|
||||
.set_flags = set_flags,
|
||||
.get_flags = get_flags,
|
||||
.get_native_pin_number = get_native_pin_number
|
||||
.get_native_pin_number = get_native_pin_number,
|
||||
.add_callback = add_callback,
|
||||
.remove_callback = remove_callback,
|
||||
.enable_interrupt = enable_interrupt,
|
||||
.disable_interrupt = disable_interrupt
|
||||
};
|
||||
|
||||
extern struct Module platform_esp32_module;
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_gpio_driver = {
|
||||
.name = "esp32_gpio",
|
||||
.compatible = (const char*[]) { "espressif,esp32-gpio", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = (void*)&esp32_gpio_api,
|
||||
.api = static_cast<const void*>(&esp32_gpio_api),
|
||||
.device_type = &GPIO_CONTROLLER_TYPE,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <soc/soc_caps.h>
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <tactility/concurrent/recursive_mutex.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||
#include <tactility/drivers/gpio_descriptor.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#define TAG "esp32_sdmmc"
|
||||
|
||||
#define GET_CONFIG(device) ((const struct Esp32SdmmcConfig*)device->config)
|
||||
#define GET_DATA(device) ((struct Esp32SdmmcInternal*)device_get_driver_data(device))
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct Esp32SdmmcInternal {
|
||||
RecursiveMutex mutex = {};
|
||||
bool initialized = false;
|
||||
Esp32SdmmcHandle esp32_sdmmc_fs_handle = nullptr;
|
||||
FileSystem* file_system = nullptr;
|
||||
|
||||
// Pin descriptors
|
||||
GpioDescriptor* pin_clk_descriptor = nullptr;
|
||||
GpioDescriptor* pin_cmd_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d0_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d1_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d2_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d3_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d4_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d5_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d6_descriptor = nullptr;
|
||||
GpioDescriptor* pin_d7_descriptor = nullptr;
|
||||
GpioDescriptor* pin_cd_descriptor = nullptr;
|
||||
GpioDescriptor* pin_wp_descriptor = nullptr;
|
||||
|
||||
explicit Esp32SdmmcInternal() {
|
||||
recursive_mutex_construct(&mutex);
|
||||
}
|
||||
|
||||
~Esp32SdmmcInternal() {
|
||||
cleanup_pins();
|
||||
recursive_mutex_destruct(&mutex);
|
||||
if (esp32_sdmmc_fs_handle) esp32_sdmmc_fs_free(esp32_sdmmc_fs_handle);
|
||||
}
|
||||
|
||||
void cleanup_pins() {
|
||||
release_pin(&pin_clk_descriptor);
|
||||
release_pin(&pin_cmd_descriptor);
|
||||
release_pin(&pin_d0_descriptor);
|
||||
release_pin(&pin_d1_descriptor);
|
||||
release_pin(&pin_d2_descriptor);
|
||||
release_pin(&pin_d3_descriptor);
|
||||
release_pin(&pin_d4_descriptor);
|
||||
release_pin(&pin_d5_descriptor);
|
||||
release_pin(&pin_d6_descriptor);
|
||||
release_pin(&pin_d7_descriptor);
|
||||
release_pin(&pin_cd_descriptor);
|
||||
release_pin(&pin_wp_descriptor);
|
||||
}
|
||||
|
||||
void lock() { recursive_mutex_lock(&mutex); }
|
||||
|
||||
void unlock() { recursive_mutex_unlock(&mutex); }
|
||||
};
|
||||
|
||||
|
||||
static error_t start(Device* device) {
|
||||
LOG_I(TAG, "start %s", device->name);
|
||||
auto* data = new (std::nothrow) Esp32SdmmcInternal();
|
||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||
|
||||
data->lock();
|
||||
device_set_driver_data(device, data);
|
||||
|
||||
auto* sdmmc_config = GET_CONFIG(device);
|
||||
|
||||
// Acquire pins from the specified GPIO pin specs. Optional pins are allowed.
|
||||
bool pins_ok =
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_clk, &data->pin_clk_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_cmd, &data->pin_cmd_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d0, &data->pin_d0_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d1, &data->pin_d1_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d2, &data->pin_d2_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d3, &data->pin_d3_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d4, &data->pin_d4_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d5, &data->pin_d5_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d6, &data->pin_d6_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_d7, &data->pin_d7_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_cd, &data->pin_cd_descriptor) &&
|
||||
acquire_pin_or_set_null(sdmmc_config->pin_wp, &data->pin_wp_descriptor);
|
||||
|
||||
if (!pins_ok) {
|
||||
LOG_E(TAG, "Failed to acquire required one or more pins");
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
data->esp32_sdmmc_fs_handle = esp32_sdmmc_fs_alloc(sdmmc_config, "/sdcard");
|
||||
if (!data->esp32_sdmmc_fs_handle) {
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
data->file_system = file_system_add(&esp32_sdmmc_fs_api, data->esp32_sdmmc_fs_handle);
|
||||
if (file_system_mount(data->file_system) != ERROR_NONE) {
|
||||
// Error is not recoverable at the time, but it might be recoverable later,
|
||||
// so we don't return start() failure.
|
||||
LOG_E(TAG, "Failed to mount SD card filesystem");
|
||||
}
|
||||
|
||||
data->initialized = true;
|
||||
data->unlock();
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
LOG_I(TAG, "stop %s", device->name);
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return ERROR_NONE;
|
||||
|
||||
data->lock();
|
||||
|
||||
if (file_system_is_mounted(data->file_system)) {
|
||||
if (file_system_unmount(data->file_system) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to unmount SD card filesystem");
|
||||
data->unlock();
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
// Free file system
|
||||
file_system_remove(data->file_system);
|
||||
data->file_system = nullptr;
|
||||
// Free file system data
|
||||
esp32_sdmmc_fs_free(data->esp32_sdmmc_fs_handle);
|
||||
data->esp32_sdmmc_fs_handle = nullptr;
|
||||
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
sdmmc_card_t* esp32_sdmmc_get_card(Device* device) {
|
||||
if (!device_is_ready(device)) return nullptr;
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return nullptr;
|
||||
|
||||
data->lock();
|
||||
auto* card = esp32_sdmmc_fs_get_card(data->esp32_sdmmc_fs_handle);
|
||||
data->unlock();
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_sdmmc_driver = {
|
||||
.name = "esp32_sdmmc",
|
||||
.compatible = (const char*[]) { "espressif,esp32-sdmmc", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <soc/soc_caps.h>
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <tactility/drivers/gpio_descriptor.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <driver/sdmmc_host.h>
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <sdmmc_cmd.h>
|
||||
#include <string>
|
||||
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
#include <sd_pwr_ctrl_by_on_chip_ldo.h>
|
||||
#endif
|
||||
|
||||
#define TAG "esp32_sdmmc_fs"
|
||||
|
||||
#define GET_DATA(data) static_cast<Esp32SdmmcFsData*>(data)
|
||||
|
||||
struct Esp32SdmmcFsData {
|
||||
const std::string mount_path;
|
||||
const Esp32SdmmcConfig* config;
|
||||
sdmmc_card_t* card;
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
sd_pwr_ctrl_handle_t pwr_ctrl_handle;
|
||||
#endif
|
||||
|
||||
Esp32SdmmcFsData(const Esp32SdmmcConfig* config, const std::string& mount_path) :
|
||||
mount_path(mount_path),
|
||||
config(config),
|
||||
card(nullptr)
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
,pwr_ctrl_handle(nullptr)
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
static gpio_num_t to_native_pin(GpioPinSpec pin_spec) {
|
||||
if (pin_spec.gpio_controller == nullptr) { return GPIO_NUM_NC; }
|
||||
return static_cast<gpio_num_t>(pin_spec.pin);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static error_t get_path(void* data, char* out_path, size_t out_path_size);
|
||||
|
||||
Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const Esp32SdmmcConfig* config, const char* mount_path) {
|
||||
return new(std::nothrow) Esp32SdmmcFsData(config, mount_path);
|
||||
}
|
||||
|
||||
sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle) {
|
||||
return GET_DATA(handle)->card;
|
||||
}
|
||||
|
||||
void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle) {
|
||||
auto* fs_data = GET_DATA(handle);
|
||||
delete fs_data;
|
||||
}
|
||||
|
||||
static error_t mount(void* data) {
|
||||
auto* fs_data = GET_DATA(data);
|
||||
auto* config = fs_data->config;
|
||||
|
||||
LOG_I(TAG, "Mounting %s", fs_data->mount_path.c_str());
|
||||
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = false,
|
||||
.max_files = 4,
|
||||
.allocation_unit_size = 0, // Default is sector size
|
||||
.disk_status_check_enable = false,
|
||||
.use_one_fat = false
|
||||
};
|
||||
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
sd_pwr_ctrl_ldo_config_t ldo_config = {
|
||||
.ldo_chan_id = 4, // LDO4 is typically used for SDMMC on ESP32-S3
|
||||
};
|
||||
esp_err_t pwr_err = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &fs_data->pwr_ctrl_handle);
|
||||
if (pwr_err != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to create SD power control driver, err=0x%x", pwr_err);
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
host.pwr_ctrl_handle = fs_data->pwr_ctrl_handle;
|
||||
#endif
|
||||
|
||||
uint32_t slot_config_flags = 0;
|
||||
if (config->enable_uhs) slot_config_flags |= SDMMC_SLOT_FLAG_UHS1;
|
||||
if (config->wp_active_high) slot_config_flags |= SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH;
|
||||
|
||||
sdmmc_slot_config_t slot_config = {
|
||||
.clk = to_native_pin(config->pin_clk),
|
||||
.cmd = to_native_pin(config->pin_cmd),
|
||||
.d0 = to_native_pin(config->pin_d0),
|
||||
.d1 = to_native_pin(config->pin_d1),
|
||||
.d2 = to_native_pin(config->pin_d2),
|
||||
.d3 = to_native_pin(config->pin_d3),
|
||||
.d4 = to_native_pin(config->pin_d4),
|
||||
.d5 = to_native_pin(config->pin_d5),
|
||||
.d6 = to_native_pin(config->pin_d6),
|
||||
.d7 = to_native_pin(config->pin_d7),
|
||||
.cd = to_native_pin(config->pin_cd),
|
||||
.wp = to_native_pin(config->pin_wp),
|
||||
.width = config->bus_width,
|
||||
.flags = slot_config_flags
|
||||
};
|
||||
|
||||
esp_err_t result = esp_vfs_fat_sdmmc_mount(fs_data->mount_path.c_str(), &host, &slot_config, &mount_config, &fs_data->card);
|
||||
|
||||
if (result != ESP_OK || fs_data->card == nullptr) {
|
||||
if (result == ESP_FAIL) {
|
||||
LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT.");
|
||||
} else {
|
||||
LOG_E(TAG, "Mounting failed: %s", esp_err_to_name(result));
|
||||
}
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
if (fs_data->pwr_ctrl_handle) {
|
||||
sd_pwr_ctrl_del_on_chip_ldo(fs_data->pwr_ctrl_handle);
|
||||
fs_data->pwr_ctrl_handle = nullptr;
|
||||
}
|
||||
#endif
|
||||
return ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
LOG_I(TAG, "Mounted %s", fs_data->mount_path.c_str());
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t unmount(void* data) {
|
||||
auto* fs_data = GET_DATA(data);
|
||||
LOG_I(TAG, "Unmounting %s", fs_data->mount_path.c_str());
|
||||
|
||||
if (esp_vfs_fat_sdcard_unmount(fs_data->mount_path.c_str(), fs_data->card) != ESP_OK) {
|
||||
LOG_E(TAG, "Unmount failed for %s", fs_data->mount_path.c_str());
|
||||
return ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
fs_data->card = nullptr;
|
||||
|
||||
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||
if (fs_data->pwr_ctrl_handle) {
|
||||
sd_pwr_ctrl_del_on_chip_ldo(fs_data->pwr_ctrl_handle);
|
||||
fs_data->pwr_ctrl_handle = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_I(TAG, "Unmounted %s", fs_data->mount_path.c_str());
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static bool is_mounted(void* data) {
|
||||
const auto* fs_data = GET_DATA(data);
|
||||
if (fs_data->card == nullptr) return false;
|
||||
return sdmmc_get_status(fs_data->card) == ESP_OK;
|
||||
}
|
||||
|
||||
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||
const auto* fs_data = GET_DATA(data);
|
||||
if (fs_data->mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||
strncpy(out_path, fs_data->mount_path.c_str(), out_path_size);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
const FileSystemApi esp32_sdmmc_fs_api = {
|
||||
.mount = mount,
|
||||
.unmount = unmount,
|
||||
.is_mounted = is_mounted,
|
||||
.get_path = get_path
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -2,11 +2,11 @@
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/esp32_spi.h>
|
||||
#include <tactility/concurrent/recursive_mutex.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include "tactility/drivers/gpio_descriptor.h"
|
||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||
#include <cstring>
|
||||
#include <esp_log.h>
|
||||
#include <new>
|
||||
#include <soc/gpio_num.h>
|
||||
|
||||
@@ -84,7 +84,7 @@ static error_t start(Device* device) {
|
||||
acquire_pin_or_set_null(dts_config->pin_hd, &data->hd_descriptor);
|
||||
|
||||
if (!pins_ok) {
|
||||
ESP_LOGE(TAG, "Failed to acquire required SPI pins");
|
||||
LOG_E(TAG, "Failed to acquire required SPI pins");
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete data;
|
||||
@@ -113,7 +113,7 @@ static error_t start(Device* device) {
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete data;
|
||||
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
|
||||
LOG_E(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ static error_t start(Device* device) {
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
ESP_LOGI(TAG, "stop %s", device->name);
|
||||
LOG_I(TAG, "stop %s", device->name);
|
||||
auto* driver_data = GET_DATA(device);
|
||||
auto* dts_config = GET_CONFIG(device);
|
||||
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
#include <soc/soc_caps.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver esp32_gpio_driver;
|
||||
extern Driver esp32_i2c_driver;
|
||||
extern Driver esp32_i2s_driver;
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
extern Driver esp32_sdmmc_driver;
|
||||
#endif
|
||||
extern Driver esp32_spi_driver;
|
||||
extern Driver esp32_uart_driver;
|
||||
|
||||
@@ -16,6 +21,9 @@ static error_t start() {
|
||||
check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||
return ERROR_NONE;
|
||||
@@ -27,12 +35,15 @@ static error_t stop() {
|
||||
check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
struct Module platform_esp32_module = {
|
||||
Module platform_esp32_module = {
|
||||
.name = "platform-esp32",
|
||||
.start = start,
|
||||
.stop = stop,
|
||||
|
||||
Reference in New Issue
Block a user