Driver improvements (#535)
- New drivers: - SD SPI - spi_peripheral - touch_placeholder - display_placeholder - Devicetree compiler: - Implement phandle-arrays - Implement device addresses - Add placeholder drivers to all devices with a SPI display - SPI driver: add `cs-pins` and set them to high on driver start - FileSystem: add `file_system_set_owner()` and `file_system_get_owner()` - File locking is now checking if the related `FileSystem` is part of a shared SPI bus - Add `device_get_child_count()` - SDMMC driver: Remove default of `slot` value - Fix for Crowpanel Basic 3.5" display (add delay to booting) - Fix for LilyGO T-HMI SD card mounting (delayed mounting by disabling it initially in the dts)
This commit is contained in:
committed by
GitHub
parent
e50659a3fb
commit
599fa46766
@@ -8,11 +8,11 @@ properties:
|
||||
required: true
|
||||
description: "One of enum Esp32GroveMode"
|
||||
pinSdaTx:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: SDA (I2C) or TX (UART) pin
|
||||
pinSclRx:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: SCL (I2C) or RX (UART) pin
|
||||
uartPort:
|
||||
|
||||
@@ -22,8 +22,8 @@ properties:
|
||||
Clock source for the I2C peripheral.
|
||||
If not specified, a default clock source will be used.
|
||||
pin-sda:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
pin-scl:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
|
||||
@@ -16,8 +16,8 @@ properties:
|
||||
required: true
|
||||
description: Initial clock frequency in Hz
|
||||
pin-sda:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
pin-scl:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
|
||||
@@ -12,22 +12,22 @@ properties:
|
||||
The port number, defined by i2s_port_t.
|
||||
Depending on the hardware, these values are available: I2S_NUM_0, I2S_NUM_1
|
||||
pin-bclk:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: Bit clock pin
|
||||
pin-ws:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: Word (slot) select pin
|
||||
pin-data-out:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Data output pin
|
||||
pin-data-in:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Data input pin
|
||||
pin-mclk:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Master clock pin
|
||||
|
||||
@@ -4,40 +4,40 @@ compatible: "espressif,esp32-sdmmc"
|
||||
|
||||
properties:
|
||||
pin-clk:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
pin-cmd:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
pin-d0:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
pin-d1:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d2:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d3:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d4:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d5:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d6:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-d7:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-cd:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-wp:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
bus-width:
|
||||
type: int
|
||||
@@ -45,7 +45,6 @@ properties:
|
||||
description: Bus width in bits
|
||||
slot:
|
||||
type: int
|
||||
default: 1
|
||||
enum: [0, 1]
|
||||
description: SDMMC host slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1). On ESP32-P4, slot 0 uses the dedicated (non-GPIO-matrix) pins.
|
||||
max-freq-khz:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
description: ESP32 SD card over SPI
|
||||
|
||||
compatible: "espressif,esp32-sdspi"
|
||||
|
||||
bus: spi
|
||||
|
||||
properties:
|
||||
pin-cd:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Card detect GPIO
|
||||
pin-wp:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Write protect GPIO
|
||||
pin-int:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Interrupt GPIO
|
||||
frequency-khz:
|
||||
type: int
|
||||
required: true
|
||||
description: SPI clock frequency in kHz
|
||||
@@ -12,27 +12,32 @@ properties:
|
||||
The SPI host (controller) to use.
|
||||
Defined by spi_host_device_t (e.g. SPI2_HOST, SPI3_HOST).
|
||||
pin-sclk:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-mosi:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: MOSI (Data 0) pin
|
||||
pin-miso:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: MISO (Data 1) pin
|
||||
pin-wp:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: WP (Data 2) pin
|
||||
pin-hd:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: HD (Data 3) pin
|
||||
max-transfer-size:
|
||||
type: int
|
||||
default: 0
|
||||
description: |
|
||||
Data transfer size limit in bytes.
|
||||
Data transfer size limit in bytes.
|
||||
0 means the platform decides the limit.
|
||||
cs-gpios:
|
||||
type: phandle-array
|
||||
element-type: "struct GpioPinSpec"
|
||||
default: "{ }"
|
||||
description: Null-terminated array of chip select GPIO pin specs for peripherals on this bus
|
||||
|
||||
@@ -12,18 +12,18 @@ properties:
|
||||
The port number, defined by uart_port_t.
|
||||
Depending on the hardware, these values are available: UART_NUM_0, UART_NUM_1, UART_NUM_2
|
||||
pin-tx:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: TX pin
|
||||
pin-rx:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
required: true
|
||||
description: RX pin
|
||||
pin-cts:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: CTS pin
|
||||
pin-rts:
|
||||
type: phandle-array
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: RTS pin
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <tactility/drivers/esp32_sdspi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(esp32_sdspi, struct Esp32SdspiConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <sd_protocol_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* Try to get the sdmmc_card_t* for the given device.
|
||||
* @param device any device.
|
||||
* @return the sdmmc_card_t* if it is available for this device, otherwise return null
|
||||
*/
|
||||
sdmmc_card_t* esp32_sdcard_get_card(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <sd_protocol_types.h>
|
||||
#include <tactility/drivers/gpio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32SdspiConfig {
|
||||
struct GpioPinSpec pin_cd;
|
||||
struct GpioPinSpec pin_wp;
|
||||
struct GpioPinSpec pin_int;
|
||||
uint32_t frequency_khz;
|
||||
};
|
||||
|
||||
sdmmc_card_t* esp32_sdspi_get_card(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -23,8 +23,29 @@ struct Esp32SpiConfig {
|
||||
struct GpioPinSpec pin_hd;
|
||||
/** Data transfer size limit in bytes. 0 means the platform decides the limit. */
|
||||
int max_transfer_size;
|
||||
/** Array of chip select GPIO pin specs */
|
||||
struct GpioPinSpec* cs_gpios;
|
||||
/** The item count of cs_gpios */
|
||||
uint8_t cs_gpios_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the CS pin spec for a child device on this SPI bus.
|
||||
* Uses the child device's address as index into the parent's cs_gpios array.
|
||||
* @param[in] child_device a child device of an SPI controller
|
||||
* @param[out] out_pin the GPIO pin spec for the CS pin
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval ERROR_INVALID_STATE if the parent is not an SPI controller
|
||||
* @retval ERROR_OUT_OF_RANGE if the device address exceeds the cs_gpios array
|
||||
*/
|
||||
error_t esp32_spi_get_cs_pin(struct Device* child_device, struct GpioPinSpec* out_pin);
|
||||
|
||||
/**
|
||||
* @brief Drive all CS pins on this SPI bus high (deselected).
|
||||
* @param[in] device the SPI controller device
|
||||
*/
|
||||
void esp32_spi_deselect_all_cs(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <sd_protocol_types.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32SdspiConfig;
|
||||
typedef void* Esp32SdspiHandle;
|
||||
|
||||
Esp32SdspiHandle esp32_sdspi_fs_alloc(const struct Esp32SdspiConfig* config, int spi_host, int cs_pin, const char* mount_path);
|
||||
void esp32_sdspi_fs_free(Esp32SdspiHandle handle);
|
||||
sdmmc_card_t* esp32_sdspi_fs_get_card(Esp32SdspiHandle handle);
|
||||
|
||||
extern const FileSystemApi esp32_sdspi_fs_api;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1000,7 +1000,7 @@ const BluetoothApi nimble_bluetooth_api = {
|
||||
|
||||
static void create_child_device(struct Device* parent, const char* name,
|
||||
Driver* drv, struct Device*& out) {
|
||||
out = new Device { .name = name, .config = nullptr, .parent = nullptr, .internal = nullptr };
|
||||
out = new Device { .address = 0, .name = name, .config = nullptr, .parent = nullptr, .internal = nullptr };
|
||||
device_construct(out);
|
||||
device_set_parent(out, parent);
|
||||
device_set_driver(out, drv);
|
||||
|
||||
@@ -238,7 +238,8 @@ static constexpr I2cControllerApi ESP32_I2C_API = {
|
||||
.write = write,
|
||||
.write_read = write_read,
|
||||
.read_register = read_register,
|
||||
.write_register = write_register
|
||||
.write_register = write_register,
|
||||
.probe = nullptr
|
||||
};
|
||||
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/esp32_sdcard.h>
|
||||
#include <tactility/drivers/esp32_sdspi.h>
|
||||
|
||||
#include <soc/soc_caps.h>
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
sdmmc_card_t* esp32_sdcard_get_card(Device* device) {
|
||||
auto* driver = device_get_driver(device);
|
||||
if (driver_is_compatible(driver, "espressif,esp32-sdspi")) {
|
||||
return esp32_sdspi_get_card(device);
|
||||
}
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
if (driver_is_compatible(driver, "espressif,esp32-sdmmc")) {
|
||||
return esp32_sdmmc_get_card(device);
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <tactility/drivers/esp32_sdmmc.h>
|
||||
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||
#include <tactility/drivers/gpio_descriptor.h>
|
||||
#include <tactility/drivers/sdcard.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
@@ -115,6 +116,7 @@ static error_t start(Device* device) {
|
||||
}
|
||||
|
||||
data->file_system = file_system_add(&esp32_sdmmc_fs_api, data->esp32_sdmmc_fs_handle);
|
||||
file_system_set_owner(data->file_system, device);
|
||||
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.
|
||||
@@ -176,7 +178,7 @@ Driver esp32_sdmmc_driver = {
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.device_type = &SDCARD_TYPE,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <new>
|
||||
|
||||
#include <tactility/concurrent/recursive_mutex.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||
#include <tactility/drivers/esp32_sdspi.h>
|
||||
#include <tactility/drivers/esp32_sdspi_fs.h>
|
||||
#include <tactility/drivers/esp32_spi.h>
|
||||
#include <tactility/drivers/gpio_descriptor.h>
|
||||
#include <tactility/drivers/spi_controller.h>
|
||||
#include <tactility/drivers/sdcard.h>
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#define TAG "esp32_sdspi"
|
||||
|
||||
#define GET_CONFIG(device) ((const struct Esp32SdspiConfig*)device->config)
|
||||
#define GET_DATA(device) ((struct Esp32SdspiInternal*)device_get_driver_data(device))
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct Esp32SdspiInternal {
|
||||
RecursiveMutex mutex = {};
|
||||
Esp32SdspiHandle fs_handle = nullptr;
|
||||
FileSystem* file_system = nullptr;
|
||||
GpioDescriptor* pin_cd_descriptor = nullptr;
|
||||
GpioDescriptor* pin_wp_descriptor = nullptr;
|
||||
GpioDescriptor* pin_int_descriptor = nullptr;
|
||||
|
||||
Esp32SdspiInternal() {
|
||||
recursive_mutex_construct(&mutex);
|
||||
}
|
||||
|
||||
~Esp32SdspiInternal() {
|
||||
cleanup_pins();
|
||||
recursive_mutex_destruct(&mutex);
|
||||
if (fs_handle) esp32_sdspi_fs_free(fs_handle);
|
||||
}
|
||||
|
||||
void cleanup_pins() {
|
||||
release_pin(&pin_cd_descriptor);
|
||||
release_pin(&pin_wp_descriptor);
|
||||
release_pin(&pin_int_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* parent = device_get_parent(device);
|
||||
if (device_get_type(parent) != &SPI_CONTROLLER_TYPE) {
|
||||
LOG_E(TAG, "Parent device is not an SPI controller");
|
||||
return ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
auto* data = new (std::nothrow) Esp32SdspiInternal();
|
||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||
|
||||
data->lock();
|
||||
device_set_driver_data(device, data);
|
||||
|
||||
auto* config = GET_CONFIG(device);
|
||||
|
||||
bool pins_ok =
|
||||
acquire_pin_or_set_null(config->pin_cd, &data->pin_cd_descriptor) &&
|
||||
acquire_pin_or_set_null(config->pin_wp, &data->pin_wp_descriptor) &&
|
||||
acquire_pin_or_set_null(config->pin_int, &data->pin_int_descriptor);
|
||||
|
||||
if (!pins_ok) {
|
||||
LOG_E(TAG, "Failed to acquire one or more pins");
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
GpioPinSpec cs_pin_spec;
|
||||
if (esp32_spi_get_cs_pin(device, &cs_pin_spec) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to get CS pin from parent SPI controller");
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
auto* spi_config = static_cast<const Esp32SpiConfig*>(parent->config);
|
||||
|
||||
// Lower all CS pins
|
||||
esp32_spi_deselect_all_cs(parent);
|
||||
// Manually set the CS pin fo
|
||||
gpio_set_direction(static_cast<gpio_num_t>(cs_pin_spec.pin), GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(static_cast<gpio_num_t>(cs_pin_spec.pin), 255);
|
||||
|
||||
data->fs_handle = esp32_sdspi_fs_alloc(config, spi_config->host, cs_pin_spec.pin, "/sdcard");
|
||||
if (!data->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_sdspi_fs_api, data->fs_handle);
|
||||
file_system_set_owner(data->file_system, device);
|
||||
if (file_system_mount(data->file_system) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to mount SD card filesystem");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
file_system_remove(data->file_system);
|
||||
data->file_system = nullptr;
|
||||
|
||||
esp32_sdspi_fs_free(data->fs_handle);
|
||||
data->fs_handle = nullptr;
|
||||
|
||||
data->cleanup_pins();
|
||||
device_set_driver_data(device, nullptr);
|
||||
|
||||
data->unlock();
|
||||
delete data;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
sdmmc_card_t* esp32_sdspi_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_sdspi_fs_get_card(data->fs_handle);
|
||||
data->unlock();
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_sdspi_driver = {
|
||||
.name = "esp32_sdspi",
|
||||
.compatible = (const char*[]) { "espressif,esp32-sdspi", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = &SDCARD_TYPE,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/drivers/esp32_sdspi.h>
|
||||
#include <tactility/drivers/esp32_sdspi_fs.h>
|
||||
#include <tactility/drivers/gpio_descriptor.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <driver/sdspi_host.h>
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <sdmmc_cmd.h>
|
||||
#include <string>
|
||||
|
||||
#define TAG "esp32_sdspi_fs"
|
||||
|
||||
#define GET_DATA(data) static_cast<Esp32SdspiFsData*>(data)
|
||||
|
||||
struct Esp32SdspiFsData {
|
||||
const std::string mount_path;
|
||||
const Esp32SdspiConfig* config;
|
||||
int spi_host;
|
||||
int cs_pin;
|
||||
sdmmc_card_t* card;
|
||||
|
||||
Esp32SdspiFsData(const Esp32SdspiConfig* config, int spi_host, int cs_pin, const std::string& mount_path) :
|
||||
mount_path(mount_path),
|
||||
config(config),
|
||||
spi_host(spi_host),
|
||||
cs_pin(cs_pin),
|
||||
card(nullptr)
|
||||
{}
|
||||
};
|
||||
|
||||
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" {
|
||||
|
||||
Esp32SdspiHandle esp32_sdspi_fs_alloc(const Esp32SdspiConfig* config, int spi_host, int cs_pin, const char* mount_path) {
|
||||
return new(std::nothrow) Esp32SdspiFsData(config, spi_host, cs_pin, mount_path);
|
||||
}
|
||||
|
||||
void esp32_sdspi_fs_free(Esp32SdspiHandle handle) {
|
||||
delete GET_DATA(handle);
|
||||
}
|
||||
|
||||
sdmmc_card_t* esp32_sdspi_fs_get_card(Esp32SdspiHandle handle) {
|
||||
return GET_DATA(handle)->card;
|
||||
}
|
||||
|
||||
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,
|
||||
.disk_status_check_enable = false,
|
||||
.use_one_fat = false
|
||||
};
|
||||
|
||||
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
|
||||
slot_config.host_id = static_cast<spi_host_device_t>(fs_data->spi_host);
|
||||
slot_config.gpio_cs = static_cast<gpio_num_t>(fs_data->cs_pin);
|
||||
slot_config.gpio_cd = to_native_pin(config->pin_cd);
|
||||
slot_config.gpio_wp = to_native_pin(config->pin_wp);
|
||||
slot_config.gpio_int = to_native_pin(config->pin_int);
|
||||
|
||||
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
|
||||
host.max_freq_khz = static_cast<int>(config->frequency_khz);
|
||||
host.slot = fs_data->spi_host;
|
||||
|
||||
esp_err_t result = esp_vfs_fat_sdspi_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));
|
||||
}
|
||||
return ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
sdmmc_card_print_info(stdout, fs_data->card);
|
||||
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;
|
||||
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_sdspi_fs_api = {
|
||||
.mount = mount,
|
||||
.unmount = unmount,
|
||||
.is_mounted = is_mounted,
|
||||
.get_path = get_path
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@@ -6,9 +6,11 @@
|
||||
|
||||
#include "tactility/drivers/gpio_descriptor.h"
|
||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <soc/gpio_num.h>
|
||||
#include <vector>
|
||||
|
||||
#define TAG "esp32_spi"
|
||||
|
||||
@@ -21,13 +23,16 @@ struct Esp32SpiInternal {
|
||||
RecursiveMutex mutex = {};
|
||||
bool initialized = false;
|
||||
|
||||
// Pin descriptors
|
||||
// Bus pin descriptors
|
||||
GpioDescriptor* sclk_descriptor = nullptr;
|
||||
GpioDescriptor* mosi_descriptor = nullptr;
|
||||
GpioDescriptor* miso_descriptor = nullptr;
|
||||
GpioDescriptor* wp_descriptor = nullptr;
|
||||
GpioDescriptor* hd_descriptor = nullptr;
|
||||
|
||||
// CS pin descriptors
|
||||
std::vector<GpioDescriptor*> cs_descriptors;
|
||||
|
||||
explicit Esp32SpiInternal() {
|
||||
recursive_mutex_construct(&mutex);
|
||||
}
|
||||
@@ -43,6 +48,10 @@ struct Esp32SpiInternal {
|
||||
release_pin(&miso_descriptor);
|
||||
release_pin(&wp_descriptor);
|
||||
release_pin(&hd_descriptor);
|
||||
for (auto*& desc : cs_descriptors) {
|
||||
release_pin(&desc);
|
||||
}
|
||||
cs_descriptors.clear();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -117,10 +126,30 @@ static error_t start(Device* device) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
// Acquire and deselect all CS pins (drive high)
|
||||
for (uint8_t i = 0; i < dts_config->cs_gpios_count; i++) {
|
||||
const GpioPinSpec* cs = &dts_config->cs_gpios[i];
|
||||
if (cs->gpio_controller == nullptr) continue;
|
||||
GpioDescriptor* desc = gpio_descriptor_acquire(cs->gpio_controller, cs->pin, GPIO_OWNER_SPI);
|
||||
if (desc != nullptr) {
|
||||
gpio_descriptor_set_flags(desc, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||
gpio_descriptor_set_level(desc, true);
|
||||
data->cs_descriptors.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
data->initialized = true;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
void esp32_spi_deselect_all_cs(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data == nullptr) return;
|
||||
for (auto* desc : data->cs_descriptors) {
|
||||
gpio_descriptor_set_level(desc, true);
|
||||
}
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
LOG_I(TAG, "stop %s", device->name);
|
||||
auto* driver_data = GET_DATA(device);
|
||||
@@ -136,6 +165,16 @@ static error_t stop(Device* device) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t esp32_spi_get_cs_pin(Device* child_device, GpioPinSpec* out_pin) {
|
||||
auto* parent = device_get_parent(child_device);
|
||||
if (parent == nullptr || device_get_type(parent) != &SPI_CONTROLLER_TYPE) return ERROR_INVALID_STATE;
|
||||
auto* config = GET_CONFIG(parent);
|
||||
int32_t index = child_device->address;
|
||||
if (index < 0 || index >= config->cs_gpios_count) return ERROR_OUT_OF_RANGE;
|
||||
*out_pin = config->cs_gpios[index];
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
const static struct SpiControllerApi esp32_spi_api = {
|
||||
.lock = lock,
|
||||
.try_lock = try_lock,
|
||||
|
||||
@@ -18,6 +18,7 @@ extern Driver esp32_i2s_driver;
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
extern Driver esp32_sdmmc_driver;
|
||||
#endif
|
||||
extern Driver esp32_sdspi_driver;
|
||||
extern Driver esp32_spi_driver;
|
||||
extern Driver esp32_uart_driver;
|
||||
extern Driver esp32_grove_driver;
|
||||
@@ -44,6 +45,7 @@ static error_t start() {
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
check(driver_construct_add(&esp32_sdspi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_grove_driver) == ERROR_NONE);
|
||||
@@ -84,6 +86,7 @@ static error_t stop() {
|
||||
#if SOC_SDMMC_HOST_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
check(driver_remove_destruct(&esp32_sdspi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_grove_driver) == ERROR_NONE);
|
||||
|
||||
Reference in New Issue
Block a user