Compare commits

...

3 Commits

Author SHA1 Message Date
Ken Van Hoeylandt
026532b1f0 Update SDK in GitHub Actions 2026-09-10 18:06:34 +02:00
Ken Van Hoeylandt
d9399e3311 Fix for findOrCreateDirectoryInternal() 2026-09-10 17:58:51 +02:00
Ken Van Hoeylandt
4cb0882ee7 Driver migrations 2026-09-10 17:58:38 +02:00
25 changed files with 155 additions and 157 deletions

View File

@ -20,7 +20,7 @@ runs:
- name: 'Build'
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: v5.5.2
esp_idf_version: v6.1
target: ${{ inputs.arch }}
path: './'
- name: 'Release'

View File

@ -21,14 +21,14 @@ runs:
uses: espressif/esp-idf-ci-action@v1
with:
# NOTE: Update with ESP-IDF!
esp_idf_version: v5.5.2
esp_idf_version: v6.1
target: ${{ inputs.arch }}
path: './'
- name: 'Release'
shell: bash
env:
# NOTE: Update with ESP-IDF!
ESP_IDF_VERSION: '5.5.2'
ESP_IDF_VERSION: '6.1'
run: python Buildscripts/release-sdk-esp32.py release/TactilitySDK
- name: 'Test Integration Prep'
shell: bash
@ -41,7 +41,7 @@ runs:
- name: 'Test Integration'
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: v5.5.2
esp_idf_version: v6.1
target: ${{ inputs.arch }}
command: export TACTILITY_SDK_PATH=../../test_sdk && cd Tests/SdkIntegration && python tactility.py build -a ${{ inputs.arch }} --local-sdk
- name: 'Upload Artifact'

View File

@ -2,5 +2,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
REQUIRES TactilityKernel driver
REQUIRES TactilityKernel driver esp_driver_gpio
)

View File

@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "source"
REQUIRES TactilityKernel driver
REQUIRES TactilityKernel driver esp_driver_gpio
)

View File

@ -5,7 +5,6 @@
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
@ -39,14 +38,10 @@ static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
auto* parent_driver = device_get_driver(parent);
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) {
auto port = static_cast<const Esp32I2cConfig*>(parent->config)->port;
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle);
}
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) {
auto bus = esp32_i2c_master_get_bus_handle(parent);
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent);
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle);
return esp_lcd_new_panel_io_i2c(bus, &io_config, out_handle);
}
LOG_E(TAG, "Unsupported I2C driver");

View File

@ -5,7 +5,6 @@
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/i2c_controller.h>
@ -71,14 +70,10 @@ static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
auto* parent_driver = device_get_driver(parent);
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) {
auto port = static_cast<const Esp32I2cConfig*>(parent->config)->port;
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle);
}
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) {
auto bus = esp32_i2c_master_get_bus_handle(parent);
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent);
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle);
return esp_lcd_new_panel_io_i2c(bus, &io_config, out_handle);
}
LOG_E(TAG, "Unsupported I2C driver");

View File

@ -6,7 +6,6 @@
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
@ -73,14 +72,10 @@ static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_FT6x36_CONFIG();
auto* parent_driver = device_get_driver(parent);
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) {
auto port = static_cast<const Esp32I2cConfig*>(parent->config)->port;
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle);
}
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) {
auto bus = esp32_i2c_master_get_bus_handle(parent);
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent);
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle);
return esp_lcd_new_panel_io_i2c(bus, &io_config, out_handle);
}
LOG_E(TAG, "Unsupported I2C driver");

View File

@ -72,8 +72,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -104,13 +104,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// GC9A01's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
ret = esp_lcd_new_panel_gc9a01(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -129,8 +129,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -164,14 +164,14 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
// Always -1: pulse_reset() handles the physical pin itself (see its comment for why), and
// esp_lcd_panel_reset() below falls back to a SWRESET command when this is -1.
.reset_gpio_num = -1,
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.flags = { .reset_active_high = config->reset_active_high },
// Always NC: pulse_reset() handles the physical pin itself (see its comment for why), and
// esp_lcd_panel_reset() below falls back to a SWRESET command when this is NC.
.reset_gpio_num = GPIO_NUM_NC,
.vendor_config = nullptr,
.flags = { .reset_active_high = config->reset_active_high },
};
ret = esp_lcd_new_panel_ili9341(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -77,8 +77,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -109,13 +109,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// ILI9488's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
// Unlike st7789/ili9341, ili9488 needs an internal conversion buffer: over SPI the

View File

@ -251,13 +251,13 @@ static error_t start(Device* device) {
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// ILI9881C's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
if (esp_lcd_new_panel_ili9881c(internal->io_handle, &panel_config, &internal->panel_handle) != ESP_OK) {
@ -355,7 +355,7 @@ static error_t start(Device* device) {
xSemaphoreGive(internal->color_trans_done_semaphore);
esp_lcd_dpi_panel_event_callbacks_t callbacks = {};
callbacks.on_refresh_done = on_refresh_done;
callbacks.on_frame_buf_complete = on_refresh_done;
callbacks.on_color_trans_done = on_color_trans_done;
if (esp_lcd_dpi_panel_register_event_callbacks(internal->panel_handle, &callbacks, internal) != ESP_OK) {
LOG_E(TAG, "Failed to register panel event callbacks");

View File

@ -221,13 +221,13 @@ static error_t start(Device* device) {
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// JD9165's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
if (esp_lcd_new_panel_jd9165(internal->io_handle, &panel_config, &internal->panel_handle) != ESP_OK) {
@ -310,7 +310,7 @@ static error_t start(Device* device) {
}
esp_lcd_dpi_panel_event_callbacks_t callbacks = {};
callbacks.on_refresh_done = on_refresh_done;
callbacks.on_frame_buf_complete = on_refresh_done;
if (esp_lcd_dpi_panel_register_event_callbacks(internal->panel_handle, &callbacks, internal) != ESP_OK) {
LOG_E(TAG, "Failed to register panel event callbacks");
vSemaphoreDelete(internal->frame_complete_semaphore);

View File

@ -76,7 +76,7 @@ esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color space");
break;
}
#else
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
switch (panel_dev_config->rgb_endian)
{
case LCD_RGB_ENDIAN_RGB:
@ -89,6 +89,19 @@ esp_err_t esp_lcd_new_panel_jd9853(const esp_lcd_panel_io_handle_t io, const esp
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb endian");
break;
}
#else
switch (panel_dev_config->rgb_ele_order)
{
case LCD_RGB_ELEMENT_ORDER_RGB:
jd9853->madctl_val = 0;
break;
case LCD_RGB_ELEMENT_ORDER_BGR:
jd9853->madctl_val |= LCD_CMD_BGR_BIT;
break;
default:
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported rgb element order");
break;
}
#endif
switch (panel_dev_config->bits_per_pixel)

View File

@ -78,8 +78,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -115,13 +115,13 @@ static error_t start(Device* device) {
};
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// JD9853's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
ret = esp_lcd_new_panel_jd9853(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -70,6 +70,14 @@ static int pin_or_unused(const GpioPinSpec& pin) {
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(pin.pin);
}
static lcd_color_format_t color_format_from_bpp(uint8_t bits_per_pixel) {
switch (bits_per_pixel) {
case 16: return LCD_COLOR_FMT_RGB565;
case 24: return LCD_COLOR_FMT_RGB888;
default: return static_cast<lcd_color_format_t>(0);
}
}
// Pulses the panel's own driver-IC reset line, if configured. Transient: the descriptor is
// released immediately after, since nothing else needs to touch this pin afterward.
static error_t perform_hardware_reset(const RgbDisplayConfig* config) {
@ -166,33 +174,35 @@ static error_t start(Device* device) {
}
},
.data_width = config->data_width,
.bits_per_pixel = config->bits_per_pixel,
.in_color_format = color_format_from_bpp(config->bits_per_pixel),
.num_fbs = config->num_fbs,
.bounce_buffer_size_px = config->bounce_buffer_size_px,
.sram_trans_align = config->sram_trans_align,
.psram_trans_align = config->psram_trans_align,
.hsync_gpio_num = pin_or_unused(config->pin_hsync),
.vsync_gpio_num = pin_or_unused(config->pin_vsync),
.de_gpio_num = pin_or_unused(config->pin_de),
.pclk_gpio_num = pin_or_unused(config->pin_pclk),
.disp_gpio_num = pin_or_unused(config->pin_disp),
// No device configures sram-trans-align/psram-trans-align differently from their YAML
// defaults (8/64), so the single dma_burst_size that replaced both can just take the
// larger (PSRAM) alignment - safe for SRAM-only allocations too, just less tightly packed.
.dma_burst_size = config->psram_trans_align,
.hsync_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_hsync)),
.vsync_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_vsync)),
.de_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_de)),
.pclk_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_pclk)),
.disp_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_disp)),
.data_gpio_nums = {
pin_or_unused(config->pin_data0),
pin_or_unused(config->pin_data1),
pin_or_unused(config->pin_data2),
pin_or_unused(config->pin_data3),
pin_or_unused(config->pin_data4),
pin_or_unused(config->pin_data5),
pin_or_unused(config->pin_data6),
pin_or_unused(config->pin_data7),
pin_or_unused(config->pin_data8),
pin_or_unused(config->pin_data9),
pin_or_unused(config->pin_data10),
pin_or_unused(config->pin_data11),
pin_or_unused(config->pin_data12),
pin_or_unused(config->pin_data13),
pin_or_unused(config->pin_data14),
pin_or_unused(config->pin_data15),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data0)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data1)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data2)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data3)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data4)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data5)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data6)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data7)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data8)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data9)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data10)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data11)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data12)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data13)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data14)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data15)),
},
.flags = {
.disp_active_low = config->disp_active_low,
@ -209,7 +219,7 @@ static error_t start(Device* device) {
// marked unused rather than left as the aggregate-init default of 0 (which would look like
// "GPIO0 is wired to this line").
for (size_t i = 16; i < sizeof(panel_config.data_gpio_nums) / sizeof(panel_config.data_gpio_nums[0]); i++) {
panel_config.data_gpio_nums[i] = -1;
panel_config.data_gpio_nums[i] = GPIO_NUM_NC;
}
esp_err_t ret = esp_lcd_new_rgb_panel(&panel_config, &internal->panel_handle);

View File

@ -6,7 +6,6 @@
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/display.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/error.h>
@ -52,28 +51,24 @@ static esp_err_t create_io_handle(Device* parent, uint8_t address, esp_lcd_panel
// with, unlike the multi-byte-per-command SPI/QSPI panels elsewhere in this repo.
esp_lcd_panel_io_i2c_config_t io_config = {
.dev_addr = address,
.on_color_trans_done = nullptr,
.user_ctx = nullptr,
.scl_speed_hz = 0,
.control_phase_bytes = 1,
.dc_bit_offset = 6,
.lcd_cmd_bits = 0,
.lcd_param_bits = 0,
.on_color_trans_done = nullptr,
.user_ctx = nullptr,
.flags = {
.dc_low_on_data = false,
.disable_control_phase = false,
},
.scl_speed_hz = 0,
};
auto* parent_driver = device_get_driver(parent);
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) {
auto port = static_cast<const Esp32I2cConfig*>(parent->config)->port;
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle);
}
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) {
auto bus = esp32_i2c_master_get_bus_handle(parent);
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent);
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle);
return esp_lcd_new_panel_io_i2c(bus, &io_config, out_handle);
}
LOG_E(TAG, "Unsupported I2C driver");
@ -164,15 +159,14 @@ static error_t start(Device* device) {
.height = static_cast<uint8_t>(config->vertical_resolution),
};
// color_space (not rgb_ele_order): this deprecated union member is the only one whose type
// can express ESP_LCD_COLOR_SPACE_MONOCHROME - rgb_ele_order's own enum only covers RGB/BGR.
// No rgb_ele_order set: the built-in ssd1306 vendor driver is monochrome and never reads it
// (only bits_per_pixel, checked to be exactly 1 - see esp_lcd_panel_ssd1306.c).
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = -1, // always -1: reset is handled manually above, not by the panel itself
.color_space = ESP_LCD_COLOR_SPACE_MONOCHROME,
.data_endian = LCD_RGB_DATA_ENDIAN_BIG,
.bits_per_pixel = 1,
.flags = { .reset_active_high = false },
.reset_gpio_num = GPIO_NUM_NC, // reset is handled manually above, not by the panel itself
.vendor_config = &ssd1306_config,
.flags = { .reset_active_high = false },
};
if (esp_lcd_new_panel_ssd1306(internal->io_handle, &panel_config, &internal->panel_handle) != ESP_OK) {

View File

@ -250,13 +250,13 @@ static error_t start(Device* device) {
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// ST7121's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
if (esp_lcd_new_panel_st7121(internal->io_handle, &panel_config, &internal->panel_handle) != ESP_OK) {
@ -354,7 +354,7 @@ static error_t start(Device* device) {
xSemaphoreGive(internal->color_trans_done_semaphore);
esp_lcd_dpi_panel_event_callbacks_t callbacks = {};
callbacks.on_refresh_done = on_refresh_done;
callbacks.on_frame_buf_complete = on_refresh_done;
callbacks.on_color_trans_done = on_color_trans_done;
if (esp_lcd_dpi_panel_register_event_callbacks(internal->panel_handle, &callbacks, internal) != ESP_OK) {
LOG_E(TAG, "Failed to register panel event callbacks");

View File

@ -250,13 +250,13 @@ static error_t start(Device* device) {
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// ST7123's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
if (esp_lcd_new_panel_st7123(internal->io_handle, &panel_config, &internal->panel_handle) != ESP_OK) {
@ -354,7 +354,7 @@ static error_t start(Device* device) {
xSemaphoreGive(internal->color_trans_done_semaphore);
esp_lcd_dpi_panel_event_callbacks_t callbacks = {};
callbacks.on_refresh_done = on_refresh_done;
callbacks.on_frame_buf_complete = on_refresh_done;
callbacks.on_color_trans_done = on_color_trans_done;
if (esp_lcd_dpi_panel_register_event_callbacks(internal->panel_handle, &callbacks, internal) != ESP_OK) {
LOG_E(TAG, "Failed to register panel event callbacks");

View File

@ -5,7 +5,6 @@
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/esp32_i2c.h>
#include <tactility/drivers/esp32_i2c_master.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/drivers/pointer.h>
@ -39,14 +38,10 @@ static esp_err_t create_io_handle(Device* parent, esp_lcd_panel_io_handle_t* out
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_ST7123_CONFIG();
auto* parent_driver = device_get_driver(parent);
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c")) {
auto port = static_cast<const Esp32I2cConfig*>(parent->config)->port;
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, out_handle);
}
if (driver_is_compatible(parent_driver, "espressif,esp32-i2c-master")) {
auto bus = esp32_i2c_master_get_bus_handle(parent);
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(parent);
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, out_handle);
return esp_lcd_new_panel_io_i2c(bus, &io_config, out_handle);
}
LOG_E(TAG, "Unsupported I2C driver");

View File

@ -69,6 +69,14 @@ static int pin_or_unused(const GpioPinSpec& pin) {
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(pin.pin);
}
static lcd_color_format_t color_format_from_bpp(uint8_t bits_per_pixel) {
switch (bits_per_pixel) {
case 16: return LCD_COLOR_FMT_RGB565;
case 24: return LCD_COLOR_FMT_RGB888;
default: return static_cast<lcd_color_format_t>(0);
}
}
// Unpacks the devicetree's flat [cmd, data_len, delay_ms, data_len bytes...] encoding (produced
// by the devicetree compiler's "array" property type - see init-sequence in
// bindings/sitronix,st7701.yaml) into a heap-allocated st7701_lcd_init_cmd_t array. Each entry's
@ -177,33 +185,35 @@ static error_t start(Device* device) {
}
},
.data_width = config->data_width,
.bits_per_pixel = config->bits_per_pixel,
.in_color_format = color_format_from_bpp(config->bits_per_pixel),
.num_fbs = config->num_fbs,
.bounce_buffer_size_px = config->bounce_buffer_size_px,
.sram_trans_align = config->sram_trans_align,
.psram_trans_align = config->psram_trans_align,
.hsync_gpio_num = pin_or_unused(config->pin_hsync),
.vsync_gpio_num = pin_or_unused(config->pin_vsync),
.de_gpio_num = pin_or_unused(config->pin_de),
.pclk_gpio_num = pin_or_unused(config->pin_pclk),
.disp_gpio_num = pin_or_unused(config->pin_disp),
// No device configures sram-trans-align/psram-trans-align differently from their YAML
// defaults (8/64), so the single dma_burst_size that replaced both can just take the
// larger (PSRAM) alignment - safe for SRAM-only allocations too, just less tightly packed.
.dma_burst_size = config->psram_trans_align,
.hsync_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_hsync)),
.vsync_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_vsync)),
.de_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_de)),
.pclk_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_pclk)),
.disp_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_disp)),
.data_gpio_nums = {
pin_or_unused(config->pin_data0),
pin_or_unused(config->pin_data1),
pin_or_unused(config->pin_data2),
pin_or_unused(config->pin_data3),
pin_or_unused(config->pin_data4),
pin_or_unused(config->pin_data5),
pin_or_unused(config->pin_data6),
pin_or_unused(config->pin_data7),
pin_or_unused(config->pin_data8),
pin_or_unused(config->pin_data9),
pin_or_unused(config->pin_data10),
pin_or_unused(config->pin_data11),
pin_or_unused(config->pin_data12),
pin_or_unused(config->pin_data13),
pin_or_unused(config->pin_data14),
pin_or_unused(config->pin_data15),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data0)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data1)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data2)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data3)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data4)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data5)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data6)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data7)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data8)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data9)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data10)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data11)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data12)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data13)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data14)),
static_cast<gpio_num_t>(pin_or_unused(config->pin_data15)),
},
.flags = {
.disp_active_low = config->disp_active_low,
@ -219,7 +229,7 @@ static error_t start(Device* device) {
// more data lines than that, the tail of the array must be explicitly marked unused rather
// than left as the aggregate-init default of 0 (which would look like "GPIO0 is wired here").
for (size_t i = 16; i < sizeof(rgb_config.data_gpio_nums) / sizeof(rgb_config.data_gpio_nums[0]); i++) {
rgb_config.data_gpio_nums[i] = -1;
rgb_config.data_gpio_nums[i] = GPIO_NUM_NC;
}
st7701_vendor_config_t vendor_config = {
@ -234,13 +244,13 @@ static error_t start(Device* device) {
};
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = &vendor_config,
// ST7701's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = &vendor_config,
};
ret = esp_lcd_new_panel_st7701(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -83,8 +83,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -115,13 +115,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// ST7735's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
ret = esp_lcd_new_panel_st7735(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -113,7 +113,7 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
.on_color_trans_done = on_color_trans_done,
@ -144,13 +144,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// ST7789's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
ret = esp_lcd_new_panel_st7789(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -81,7 +81,7 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
.on_color_trans_done = on_color_trans_done,
@ -112,13 +112,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// ST7796's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
ret = esp_lcd_new_panel_st7796(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -83,8 +83,8 @@ static error_t start(Device* device) {
}
esp_lcd_panel_io_spi_config_t io_config = {
.cs_gpio_num = pin_or_unused(cs_pin),
.dc_gpio_num = pin_or_unused(config->pin_dc),
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
.dc_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_dc)),
.spi_mode = 0,
.pclk_hz = config->pixel_clock_hz,
.trans_queue_depth = config->transaction_queue_depth,
@ -115,13 +115,13 @@ static error_t start(Device* device) {
}
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = pin_or_unused(config->pin_reset),
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = config->bits_per_pixel,
.reset_gpio_num = static_cast<gpio_num_t>(pin_or_unused(config->pin_reset)),
.vendor_config = nullptr,
// ST7796's reset line is fixed active-low in hardware.
.flags = { .reset_active_high = false },
.vendor_config = nullptr,
};
ret = esp_lcd_new_panel_st7796(internal->io_handle, &panel_config, &internal->panel_handle);

View File

@ -186,25 +186,16 @@ bool writeString(const std::string& filepath, const std::string& content) {
return true;
}
static bool findOrCreateDirectoryInternal(std::string path, mode_t mode) {
static bool findOrCreateDirectoryInternal(const std::string& path, mode_t mode) {
// Checked before creating, not after: on the SD card's mount root, the FATFS VFS's mkdir()
// doesn't fail with EEXIST for an already-mounted root (it returns some other errno), so an
// mkdir-first/errno-check approach never recognizes it as already there.
struct stat dir_stat;
if (mkdir(path.c_str(), mode) == 0) {
return true;
if (stat(path.c_str(), &dir_stat) == 0) {
return S_ISDIR(dir_stat.st_mode);
}
if (errno != EEXIST) {
return false;
}
if (stat(path.c_str(), &dir_stat) != 0) {
return false;
}
if (!S_ISDIR(dir_stat.st_mode)) {
return false;
}
return true;
return mkdir(path.c_str(), mode) == 0;
}
std::string getLastPathSegment(const std::string& path) {