New kernel drivers and more (#560)

- Added kernel base drivers for: display, pointer (touch, mouse, etc.), keyboard, adc, power supply and backlight
- Implement new kernel driver modules: `st7789-module` and `gt911-module`
- Implement ESP32 ADC "oneshot" kernel driver
- Implement ESP32  backlight kernel driver with ledc API
- Implemented `battery-sense` driver that allows for voltage measurement and creates a power supply child device
- Updated github actions
- Updated flash scripts
- Fix for esp32 legacy driver conflict with ADC
- Created separate `lilygo-tdeck` and `lilygo-tdeck-plus` devices
- Created `lilygo-module` with LilyGO kernel drivers
- Fix for intermittent errors in build related to code generation of `devicetree.c`
- `lvgl-module` can now map kernel drivers onto LVGL devices
- Created `KernelDisplayApp` as a mirror of `HalDisplayApp` (formerly `DisplayApp`)
- Removed `struct` and `enum` prefix in a lot of kernel driver cpp source files
- `lilygo-tdeck` and `lilygo-tdeck-plus` are now fully relying on kernel drivers and don't use any of the old HAL
This commit is contained in:
Ken Van Hoeylandt
2026-07-12 00:29:12 +02:00
committed by GitHub
parent c4406b24ba
commit 50c0a14a93
149 changed files with 5274 additions and 1266 deletions
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Apache-2.0
#include <esp_adc/adc_oneshot.h>
#include <tactility/error_esp32.h>
#include <tactility/driver.h>
#include <tactility/drivers/adc_controller.h>
#include <tactility/drivers/esp32_adc_oneshot.h>
#include <tactility/log.h>
#include <tactility/time.h>
#define TAG "esp32_adc_oneshot"
#define GET_CONFIG(device) ((Esp32AdcOneshotConfig*)device->config)
#define GET_HANDLE(device) ((adc_oneshot_unit_handle_t)device_get_driver_data(device))
static const Esp32AdcOneshotChannelConfig* find_channel_config(const Esp32AdcOneshotConfig* dts_config, uint8_t channel_index) {
if (channel_index >= dts_config->channel_count) {
return nullptr;
}
return &dts_config->channels[channel_index];
}
extern "C" {
static error_t read_raw(Device* device, uint8_t channel, int* out_raw, TickType_t timeout) {
if (xPortInIsrContext()) return ERROR_ISR_STATUS;
auto* dts_config = GET_CONFIG(device);
auto* channel_config = find_channel_config(dts_config, channel);
if (channel_config == nullptr) {
return ERROR_OUT_OF_RANGE;
}
esp_err_t esp_error = adc_oneshot_read(GET_HANDLE(device), channel_config->channel, out_raw);
if (esp_error != ESP_OK) {
LOG_E(TAG, "read(channel=%u) failed: %s", channel, esp_err_to_name(esp_error));
}
return esp_err_to_error(esp_error);
}
static error_t start(Device* device) {
LOG_I(TAG, "start %s", device->name);
auto* dts_config = GET_CONFIG(device);
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = dts_config->unit_id,
.clk_src = dts_config->clk_src,
.ulp_mode = dts_config->ulp_mode,
};
adc_oneshot_unit_handle_t handle;
esp_err_t esp_error = adc_oneshot_new_unit(&init_config, &handle);
if (esp_error != ESP_OK) {
LOG_E(TAG, "Failed to create ADC unit %d: %s", (int)dts_config->unit_id, esp_err_to_name(esp_error));
return ERROR_RESOURCE;
}
for (size_t i = 0; i < dts_config->channel_count; i++) {
const auto& channel_config = dts_config->channels[i];
adc_oneshot_chan_cfg_t chan_cfg = {
.atten = channel_config.atten,
.bitwidth = channel_config.bitwidth,
};
esp_error = adc_oneshot_config_channel(handle, channel_config.channel, &chan_cfg);
if (esp_error != ESP_OK) {
LOG_E(TAG, "Failed to configure channel %d: %s", (int)channel_config.channel, esp_err_to_name(esp_error));
adc_oneshot_del_unit(handle);
return ERROR_RESOURCE;
}
}
device_set_driver_data(device, handle);
return ERROR_NONE;
}
static error_t stop(Device* device) {
LOG_I(TAG, "stop %s", device->name);
esp_err_t esp_error = adc_oneshot_del_unit(GET_HANDLE(device));
if (esp_error != ESP_OK) {
LOG_E(TAG, "Deleting ADC unit failed: %s", esp_err_to_name(esp_error));
}
device_set_driver_data(device, nullptr);
return ERROR_NONE;
}
static constexpr AdcControllerApi ESP32_ADC_ONESHOT_API = {
.read_raw = read_raw
};
extern Module platform_esp32_module;
Driver esp32_adc_oneshot_driver = {
.name = "esp32_adc_oneshot",
.compatible = (const char*[]) { "espressif,esp32-adc-oneshot", nullptr },
.start_device = start,
.stop_device = stop,
.api = &ESP32_ADC_ONESHOT_API,
.device_type = &ADC_CONTROLLER_TYPE,
.owner = &platform_esp32_module,
.internal = nullptr
};
} // extern "C"
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/esp32_ledc_backlight.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/backlight.h>
#include <tactility/log.h>
#include <driver/ledc.h>
#include <esp_err.h>
#include <cstdlib>
#define TAG "Esp32LedcBacklight"
#define GET_CONFIG(device) (static_cast<const Esp32LedcBacklightConfig*>((device)->config))
struct Esp32LedcBacklightInternal {
uint8_t brightness;
};
// region Driver lifecycle
static error_t start(Device* device) {
const auto* config = GET_CONFIG(device);
ledc_timer_config_t timer_config = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_8_BIT,
.timer_num = config->ledc_timer,
.freq_hz = config->frequency_hz,
.clk_cfg = LEDC_AUTO_CLK,
.deconfigure = false,
};
if (ledc_timer_config(&timer_config) != ESP_OK) {
LOG_E(TAG, "Failed to configure LEDC timer");
return ERROR_RESOURCE;
}
ledc_channel_config_t channel_config = {
.gpio_num = (int)config->pin_backlight.pin,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = config->ledc_channel,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = config->ledc_timer,
.duty = config->brightness_range.min,
.hpoint = 0,
.sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD,
.flags = {
.output_invert = 0,
},
};
if (ledc_channel_config(&channel_config) != ESP_OK) {
LOG_E(TAG, "Failed to configure LEDC channel");
return ERROR_RESOURCE;
}
auto* internal = static_cast<Esp32LedcBacklightInternal*>(malloc(sizeof(Esp32LedcBacklightInternal)));
if (internal == nullptr) {
return ERROR_OUT_OF_MEMORY;
}
internal->brightness = config->brightness_range.min;
device_set_driver_data(device, internal);
backlight_set_brightness_default(device); // Allowed to fail, we don't care about the result
return ERROR_NONE;
}
static error_t stop(Device* device) {
backlight_set_brightness(device, 0); // Allowed to fail, we don't care about the result
auto* internal = static_cast<Esp32LedcBacklightInternal*>(device_get_driver_data(device));
free(internal);
return ERROR_NONE;
}
// endregion
// region BacklightApi
static error_t esp32_ledc_backlight_set_brightness(Device* device, uint8_t brightness) {
const auto* config = GET_CONFIG(device);
auto* internal = static_cast<Esp32LedcBacklightInternal*>(device_get_driver_data(device));
esp_err_t ret = ledc_set_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel, brightness);
if (ret == ESP_OK) {
ret = ledc_update_duty(LEDC_LOW_SPEED_MODE, config->ledc_channel);
}
if (ret != ESP_OK) {
LOG_E(TAG, "Failed to set brightness: %s", esp_err_to_name(ret));
return ERROR_RESOURCE;
}
internal->brightness = brightness;
return ERROR_NONE;
}
static error_t esp32_ledc_backlight_set_brightness_default(Device* device) {
return esp32_ledc_backlight_set_brightness(device, GET_CONFIG(device)->brightness_default);
}
static error_t esp32_ledc_backlight_get_brightness(Device* device, uint8_t* out_brightness) {
auto* internal = static_cast<Esp32LedcBacklightInternal*>(device_get_driver_data(device));
*out_brightness = internal->brightness;
return ERROR_NONE;
}
static uint8_t esp32_ledc_backlight_get_min_brightness(Device* device) {
return GET_CONFIG(device)->brightness_range.min;
}
static uint8_t esp32_ledc_backlight_get_max_brightness(Device* device) {
return GET_CONFIG(device)->brightness_range.max;
}
// endregion
static const BacklightApi esp32_ledc_backlight_api = {
.set_brightness = esp32_ledc_backlight_set_brightness,
.set_brightness_default = esp32_ledc_backlight_set_brightness_default,
.get_brightness = esp32_ledc_backlight_get_brightness,
.get_min_brightness = esp32_ledc_backlight_get_min_brightness,
.get_max_brightness = esp32_ledc_backlight_get_max_brightness,
};
extern Module platform_esp32_module;
Driver esp32_ledc_backlight_driver = {
.name = "esp32_ledc_backlight",
.compatible = (const char*[]) { "espressif,esp32-ledc-backlight", nullptr },
.start_device = start,
.stop_device = stop,
.api = &esp32_ledc_backlight_api,
.device_type = &BACKLIGHT_TYPE,
.owner = &platform_esp32_module,
.internal = nullptr
};