Grove driver, I2C migrations, bugfixes and docs (#532)
This commit is contained in:
committed by
GitHub
parent
8dabda2b5b
commit
a35c88c8fd
@@ -0,0 +1,29 @@
|
||||
description: ESP32 Grove Port
|
||||
|
||||
compatible: "espressif,esp32-grove"
|
||||
|
||||
properties:
|
||||
defaultMode:
|
||||
type: int
|
||||
required: true
|
||||
description: "One of enum Esp32GroveMode"
|
||||
pinSdaRx:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: SDA (I2C) or RX (UART) pin
|
||||
pinSclTx:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: SCL (I2C) or TX (UART) pin
|
||||
uartPort:
|
||||
type: int
|
||||
required: true
|
||||
description: UART port number
|
||||
i2cPort:
|
||||
type: int
|
||||
required: true
|
||||
description: I2C port number
|
||||
i2cClockFrequency:
|
||||
type: int
|
||||
required: true
|
||||
description: I2C clock frequency
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <tactility/drivers/esp32_grove.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(esp32_grove, struct Esp32GroveConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <driver/uart.h>
|
||||
#include <hal/i2c_types.h>
|
||||
#include <tactility/drivers/gpio.h>
|
||||
#include <tactility/drivers/grove.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Esp32GroveConfig {
|
||||
enum GroveMode defaultMode;
|
||||
struct GpioPinSpec pinSdaRx;
|
||||
struct GpioPinSpec pinSclTx;
|
||||
uart_port_t uartPort;
|
||||
i2c_port_t i2cPort;
|
||||
uint32_t i2cClockFrequency;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -2,12 +2,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <tactility/drivers/gpio.h>
|
||||
#include <driver/i2c_types.h>
|
||||
#include <driver/i2c_master.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
|
||||
struct Esp32I2cMasterConfig {
|
||||
i2c_port_num_t port;
|
||||
uint32_t clockFrequency;
|
||||
@@ -16,6 +18,8 @@ struct Esp32I2cMasterConfig {
|
||||
struct GpioPinSpec pinScl;
|
||||
};
|
||||
|
||||
i2c_master_bus_handle_t esp32_i2c_master_get_bus_handle(struct Device* device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/esp32_grove.h>
|
||||
#include <tactility/drivers/esp32_i2c.h>
|
||||
#include <tactility/drivers/esp32_i2c_master.h>
|
||||
#include <tactility/drivers/esp32_uart.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
#define TAG "esp32_grove"
|
||||
|
||||
struct Esp32GroveInternal {
|
||||
Device* child_device = nullptr;
|
||||
void* child_config = nullptr;
|
||||
char* child_name = nullptr;
|
||||
GroveMode current_mode = GROVE_MODE_DISABLED;
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) ((const struct Esp32GroveConfig*)device->config)
|
||||
#define GET_DATA(device) ((struct Esp32GroveInternal*)device_get_driver_data(device))
|
||||
|
||||
extern "C" {
|
||||
|
||||
static error_t stop_child(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return ERROR_NONE;
|
||||
|
||||
if (data->child_device) {
|
||||
if (data->child_device->internal) {
|
||||
if (device_is_added(data->child_device)) {
|
||||
if (device_is_ready(data->child_device)) {
|
||||
if (device_stop(data->child_device) != ERROR_NONE) {
|
||||
LOG_E(TAG, "%s: failed to stop child device", device->name);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
}
|
||||
if (device_remove(data->child_device) != ERROR_NONE) {
|
||||
LOG_E(TAG, "%s: failed to remove child device", device->name);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
}
|
||||
check(device_destruct(data->child_device) == ERROR_NONE);
|
||||
}
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
}
|
||||
|
||||
if (data->child_config) {
|
||||
if (data->current_mode == GROVE_MODE_UART) {
|
||||
delete static_cast<Esp32UartConfig*>(data->child_config);
|
||||
} else if (data->current_mode == GROVE_MODE_I2C) {
|
||||
delete static_cast<Esp32I2cMasterConfig*>(data->child_config);
|
||||
}
|
||||
data->child_config = nullptr;
|
||||
}
|
||||
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
|
||||
data->current_mode = GROVE_MODE_DISABLED;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t start_child(Device* device, GroveMode mode) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
auto* data = GET_DATA(device);
|
||||
|
||||
if (mode == GROVE_MODE_DISABLED) {
|
||||
LOG_I(TAG, "%s: Grove port disabled", device->name);
|
||||
data->current_mode = GROVE_MODE_DISABLED;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
data->child_device = new(std::nothrow) Device();
|
||||
if (!data->child_device) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(data->child_device, 0, sizeof(Device));
|
||||
|
||||
size_t name_len = std::strlen(device->name) + 10;
|
||||
data->child_name = new(std::nothrow) char[name_len];
|
||||
if (!data->child_name) {
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
data->child_device->parent = device;
|
||||
const char* compatible = nullptr;
|
||||
|
||||
if (mode == GROVE_MODE_UART) {
|
||||
// Device name
|
||||
std::snprintf(data->child_name, name_len, "%s_uart", device->name);
|
||||
data->child_device->name = data->child_name;
|
||||
// Device config
|
||||
auto* uart_cfg = new(std::nothrow) struct Esp32UartConfig();
|
||||
if (!uart_cfg) {
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(uart_cfg, 0, sizeof(Esp32UartConfig));
|
||||
uart_cfg->port = config->uartPort;
|
||||
uart_cfg->pin_tx = config->pinSclTx;
|
||||
uart_cfg->pin_rx = config->pinSdaRx;
|
||||
uart_cfg->pin_cts = GPIO_PIN_SPEC_NONE;
|
||||
uart_cfg->pin_rts = GPIO_PIN_SPEC_NONE;
|
||||
data->child_config = uart_cfg;
|
||||
compatible = "espressif,esp32-uart";
|
||||
LOG_I(TAG, "%s: starting UART mode on port %d", device->name, (int)uart_cfg->port);
|
||||
} else if (mode == GROVE_MODE_I2C) {
|
||||
// Device name
|
||||
std::snprintf(data->child_name, name_len, "%s_i2c", device->name);
|
||||
data->child_device->name = data->child_name;
|
||||
// Device config
|
||||
auto* i2c_cfg = new (std::nothrow) struct Esp32I2cMasterConfig();
|
||||
if (!i2c_cfg) {
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
std::memset(i2c_cfg, 0, sizeof(Esp32I2cMasterConfig));
|
||||
i2c_cfg->port = static_cast<i2c_port_num_t>(config->i2cPort);
|
||||
i2c_cfg->clockFrequency = config->i2cClockFrequency;
|
||||
i2c_cfg->pinSda = config->pinSdaRx;
|
||||
i2c_cfg->pinScl = config->pinSclTx;
|
||||
// New driver seems to require pull-up setting
|
||||
i2c_cfg->pinSda.flags |= GPIO_FLAG_PULL_UP;
|
||||
i2c_cfg->pinScl.flags |= GPIO_FLAG_PULL_UP;
|
||||
i2c_cfg->clkSource = 0; // Default
|
||||
data->child_config = i2c_cfg;
|
||||
compatible = "espressif,esp32-i2c-master";
|
||||
LOG_I(TAG, "%s: starting I2C mode on port %d", device->name, (int)config->i2cPort);
|
||||
} else {
|
||||
LOG_E(TAG, "%s: unknown mode %d", device->name, mode);
|
||||
if (data->child_name != nullptr) {
|
||||
delete[] data->child_name;
|
||||
data->child_name = nullptr;
|
||||
}
|
||||
delete data->child_device;
|
||||
data->child_device = nullptr;
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
data->child_device->config = data->child_config;
|
||||
|
||||
error_t err = device_construct_add_start(data->child_device, compatible);
|
||||
if (err != ERROR_NONE) {
|
||||
LOG_E(TAG, "%s: failed to start child device: %d", device->name, err);
|
||||
stop_child(device);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->current_mode = mode;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t start_device(Device* device) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
auto* data = new(std::nothrow) Esp32GroveInternal();
|
||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||
device_set_driver_data(device, data);
|
||||
|
||||
if (start_child(device, config->defaultMode) != ERROR_NONE) {
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete data;
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop_device(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data) return ERROR_NONE;
|
||||
|
||||
stop_child(device);
|
||||
delete data;
|
||||
device_set_driver_data(device, nullptr);
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t esp32_grove_set_mode(Device* device, enum GroveMode mode) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->current_mode == mode) return ERROR_NONE;
|
||||
|
||||
error_t err = stop_child(device);
|
||||
if (err != ERROR_NONE) return err;
|
||||
|
||||
return start_child(device, mode);
|
||||
}
|
||||
|
||||
static error_t esp32_grove_get_mode(Device* device, enum GroveMode* mode) {
|
||||
auto* data = GET_DATA(device);
|
||||
*mode = data->current_mode;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static const GroveApi esp32_grove_api = {
|
||||
.set_mode = esp32_grove_set_mode,
|
||||
.get_mode = esp32_grove_get_mode
|
||||
};
|
||||
|
||||
extern Module platform_esp32_module;
|
||||
|
||||
Driver esp32_grove_driver = {
|
||||
.name = "esp32_grove",
|
||||
.compatible = (const char*[]) { "espressif,esp32-grove", nullptr },
|
||||
.start_device = start_device,
|
||||
.stop_device = stop_device,
|
||||
.api = &esp32_grove_api,
|
||||
.device_type = &GROVE_TYPE,
|
||||
.owner = &platform_esp32_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@@ -308,4 +308,8 @@ Driver esp32_i2c_master_driver = {
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
i2c_master_bus_handle_t esp32_i2c_master_get_bus_handle(Device* device) {
|
||||
return GET_DATA(device)->bus_handle;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -71,9 +71,7 @@ static error_t start_device(struct Device* device) {
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
.enum_filter_cb = nullptr,
|
||||
.fifo_settings_custom = {},
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
.peripheral_map = cfg->peripheral_map,
|
||||
#endif
|
||||
};
|
||||
|
||||
esp_err_t ret = usb_host_install(&host_cfg);
|
||||
|
||||
@@ -20,6 +20,7 @@ extern Driver esp32_sdmmc_driver;
|
||||
#endif
|
||||
extern Driver esp32_spi_driver;
|
||||
extern Driver esp32_uart_driver;
|
||||
extern Driver esp32_grove_driver;
|
||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
extern Driver esp32_bluetooth_driver;
|
||||
extern Driver esp32_ble_serial_driver;
|
||||
@@ -45,6 +46,7 @@ static error_t start() {
|
||||
#endif
|
||||
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);
|
||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
||||
@@ -84,6 +86,7 @@ static error_t stop() {
|
||||
#endif
|
||||
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);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user