Snapshot of JC3636W518EN kit before demo folder cleanup

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
patriandClaude Opus 5.5 committed 2026-10-22 23:56:18 +02:00
commit 9ee85bfd86
1862 files changed
+668877

No files matched your search

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "CST816S.h"
static const char *TAG = "CST816S_CPP";
ESP_PanelTouch_CST816S::ESP_PanelTouch_CST816S(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_CST816S::ESP_PanelTouch_CST816S(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_CST816S::~ESP_PanelTouch_CST816S()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_CST816S::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_cst816s(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_cst816s.h"
#include "ESP_PanelTouch.h"
/**
* @brief CST816S touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_CST816S : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_CST816S(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_CST816S(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_CST816S() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,275 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "driver/gpio.h"
#include "ESP_PanelTouch.h"
static const char *TAG = "ESP_PanelTouch";
#define CALLBACK_DATA_DEFAULT() \
{ \
.tp_ptr = this, \
.user_data = NULL, \
}
ESP_PanelTouchPoint::ESP_PanelTouchPoint(void):
x(0),
y(0),
strength(0)
{
}
ESP_PanelTouchPoint::ESP_PanelTouchPoint(uint16_t x, uint16_t y, uint16_t strength):
x(x),
y(y),
strength(strength)
{
}
bool ESP_PanelTouchPoint::operator==(ESP_PanelTouchPoint p)
{
return ((p.x == x) && (p.y == y));
}
bool ESP_PanelTouchPoint::operator!=(ESP_PanelTouchPoint p)
{
return ((p.x != x) || (p.y != y));
}
ESP_PanelTouch::ESP_PanelTouch(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io, int int_io):
bus(bus),
config((esp_lcd_touch_config_t)ESP_PANEL_TOUCH_CONFIG_DEFAULT(width, height, rst_io, int_io)),
handle(NULL),
_swap_xy(false),
_mirror_x(false),
_mirror_y(false),
_tp_points_num(0),
_tp_buttons_state{0},
onTouchInterruptCallback(NULL),
_isr_sem(NULL),
callback_data(CALLBACK_DATA_DEFAULT())
{
if (int_io >= 0) {
config.interrupt_callback = onTouchInterrupt;
config.user_data = &callback_data;
}
}
ESP_PanelTouch::ESP_PanelTouch(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
bus(bus),
config(config),
handle(NULL),
_swap_xy(false),
_mirror_x(false),
_mirror_y(false),
_tp_points_num(0),
_tp_buttons_state{0},
onTouchInterruptCallback(NULL),
_isr_sem(NULL),
callback_data(CALLBACK_DATA_DEFAULT())
{
if ((config.int_gpio_num != GPIO_NUM_NC) && (config.interrupt_callback == NULL) && (config.user_data == NULL)) {
this->config.interrupt_callback = onTouchInterrupt;
this->config.user_data = &callback_data;
}
}
bool ESP_PanelTouch::attachInterruptCallback(std::function<bool (void *)> callback, void *user_data)
{
ESP_PANEL_CHECK_FALSE_RET((config.interrupt_callback == onTouchInterrupt), false, "Interruption is not enabled");
onTouchInterruptCallback = callback;
callback_data.user_data = user_data;
return true;
}
bool ESP_PanelTouch::init(void)
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (config.interrupt_callback == onTouchInterrupt) {
_isr_sem = xSemaphoreCreateBinary();
ESP_PANEL_CHECK_NULL_RET(_isr_sem, false, "Create semaphore failed");
ESP_LOGD(TAG, "Enable interruption");
} else {
ESP_LOGD(TAG, "Disable interruption");
}
return true;
}
bool ESP_PanelTouch::del(void)
{
ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_del(handle), false, "Delete touch panel failed");
ESP_LOGD(TAG, "Touch panel @%p deleted", handle);
handle = NULL;
return true;
}
bool ESP_PanelTouch::swapXY(bool en)
{
ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_set_swap_xy(handle, en), false, "Swap axes failed");
_swap_xy = en;
return true;
}
bool ESP_PanelTouch::mirrorX(bool en)
{
ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_set_mirror_x(handle, en), false, "Mirror X failed");
_mirror_x = en;
return true;
}
bool ESP_PanelTouch::mirrorY(bool en)
{
ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_set_mirror_y(handle, en), false, "Mirror Y failed");
_mirror_y = en;
return true;
}
bool ESP_PanelTouch::readRawData(uint8_t max_points_num, int timeout_ms)
{
ESP_PANEL_CHECK_NULL_RET(handle, false, "Invalid handle");
uint16_t x[CONFIG_ESP_LCD_TOUCH_MAX_POINTS] = {0};
uint16_t y[CONFIG_ESP_LCD_TOUCH_MAX_POINTS] = {0};
uint16_t strength[CONFIG_ESP_LCD_TOUCH_MAX_POINTS] = {0};
_tp_points_num = 0;
if (max_points_num > CONFIG_ESP_LCD_TOUCH_MAX_POINTS) {
max_points_num = CONFIG_ESP_LCD_TOUCH_MAX_POINTS;
ESP_LOGE(TAG, "The max points number out of range [%d/%d]", max_points_num, CONFIG_ESP_LCD_TOUCH_MAX_POINTS);
}
if (_isr_sem != NULL) {
BaseType_t timeout_ticks = (timeout_ms < 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
if (xSemaphoreTake(_isr_sem, timeout_ticks) != pdTRUE) {
ESP_LOGD(TAG, "Touch panel @%p wait for isr timeout", handle);
return true;
}
}
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_read_data(handle), false, "Read data failed");
esp_lcd_touch_get_coordinates(handle, x, y, strength, &_tp_points_num, max_points_num);
for (int i = 0; i < _tp_points_num; i++) {
_tp_points[i].x = x[i];
_tp_points[i].y = y[i];
_tp_points[i].strength = strength[i];
ESP_LOGD(TAG, "Touch panel @%p touched (%d, %d, %d)", handle, _tp_points[i].x, _tp_points[i].y,
_tp_points[i].strength);
}
return true;
}
int ESP_PanelTouch::getPoints(ESP_PanelTouchPoint points[], uint8_t num)
{
ESP_PANEL_CHECK_FALSE_RET((num == 0) || (points != NULL), -1, "Invalid points or num");
int i = 0;
for (; (i < num) && (i < _tp_points_num); i++) {
points[i] = _tp_points[i];
}
return i;
}
int ESP_PanelTouch::getButtonState(uint8_t n)
{
uint8_t button_state = 0;
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_get_button_state(handle, n, &button_state), -1, "Get button state failed");
return button_state;
}
int ESP_PanelTouch::readPoints(ESP_PanelTouchPoint points[], uint8_t num, int timeout_ms)
{
ESP_PANEL_CHECK_FALSE_RET(readRawData(num, timeout_ms), -1, "Read raw data failed");
return getPoints(points, num);
}
int ESP_PanelTouch::readButtonState(uint8_t n, int timeout_ms)
{
ESP_PANEL_CHECK_FALSE_RET(readRawData(0, timeout_ms), -1, "Read raw data failed");
return getButtonState(n);
}
bool ESP_PanelTouch::isInterruptEnabled(void)
{
return (config.interrupt_callback == onTouchInterrupt);
}
bool ESP_PanelTouch::getSwapXYFlag(void)
{
return _swap_xy;
}
bool ESP_PanelTouch::getMirrorXFlag(void)
{
return _mirror_x;
}
bool ESP_PanelTouch::getMirrorYFlag(void)
{
return _mirror_y;
}
esp_lcd_touch_handle_t ESP_PanelTouch::getHandle(void)
{
if (handle == NULL) {
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
ESP_LOGD(TAG, "Get invalid handle");
}
return handle;
}
ESP_PanelBus *ESP_PanelTouch::getBus(void)
{
if (bus == NULL) {
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
ESP_LOGD(TAG, "Get invalid bus");
}
return bus;
}
void ESP_PanelTouch::onTouchInterrupt(esp_lcd_touch_handle_t tp)
{
if ((tp == NULL) || (tp->config.user_data == NULL)) {
return;
}
ESP_PanelTouch *panel = (ESP_PanelTouch *)((ESP_PanelTouchCallbackData_t *)tp->config.user_data)->tp_ptr;
if (panel == NULL) {
return;
}
BaseType_t need_yield = pdFALSE;
if (panel->onTouchInterruptCallback != NULL) {
need_yield = panel->onTouchInterruptCallback(panel->callback_data.user_data) ? pdTRUE : need_yield;
}
if (panel->_isr_sem != NULL) {
xSemaphoreGiveFromISR(panel->_isr_sem, &need_yield);
}
if (need_yield == pdTRUE) {
portYIELD_FROM_ISR();
}
}
@@ -0,0 +1,297 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <functional>
#include "touch/base/esp_lcd_touch.h"
#include "bus/ESP_PanelBus.h"
/**
* @brief Touch device default configuration macro
*
*/
#define ESP_PANEL_TOUCH_CONFIG_DEFAULT(width, height, rst_io, int_io) \
{ \
.x_max = width, \
.y_max = height, \
.rst_gpio_num = (gpio_num_t)rst_io, \
.int_gpio_num = (gpio_num_t)int_io, \
.levels = { \
.reset = 0, \
.interrupt = 0, \
}, \
.flags = { \
.swap_xy = 0, \
.mirror_x = 0, \
.mirror_y = 0, \
}, \
.process_coordinates = NULL, \
.interrupt_callback = NULL, \
.user_data = NULL, \
}
/**
* @brief The class used for storing touch points
*
*/
class ESP_PanelTouchPoint {
public:
ESP_PanelTouchPoint();
ESP_PanelTouchPoint(uint16_t x, uint16_t y, uint16_t strength);
bool operator==(ESP_PanelTouchPoint p);
bool operator!=(ESP_PanelTouchPoint p);
uint16_t x;
uint16_t y;
uint16_t strength;
};
/**
* @brief The touch device objdec class
*
* @note This class is a base class for all Touchs. Due to it is a virtual class, users cannot use it directly
*/
class ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io, int int_io);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
virtual ~ESP_PanelTouch() = default;
/**
* @brief Attach a callback function, which will be called when the refreshing is finished
*
* @param callback The callback function
* @param user_data The user data which will be passed to the callback function
*
* @return true if success, otherwise false
*/
bool attachInterruptCallback(std::function<bool (void *)> callback, void *user_data = NULL);
/**
* @brief Initialize the touch device, the `begin()` function should be called after this function.
*
* @note This function intends to create a semaphore for the interrupt if the interrupt pin is set and the
* `interrupt_callback` is not used by the users. If successful, the driver will enable the functionality of
* blocking reads.
*
* @return true if success, otherwise false
*/
bool init(void);
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
virtual bool begin(void) = 0;
/**
* @brief Delete the touch device, release the resources
*
* @note This function should be called after `begin()`
* @note This function typically calls `esp_lcd_touch_del()` to delete the touch device
*
* @return true if success, otherwise false
*/
bool del(void);
/**
* @brief Swap the X and Y axis
*
* @note This function should be called after `begin()`
* @note This function typically calls `esp_lcd_touch_set_swap_xy()` to mirror the axises
*
* @param en true: enable, false: disable
*
* @return true if success, otherwise false
*/
bool swapXY(bool en);
/**
* @brief Mirror the X axis
*
* @note This function should be called after `begin()`
* @note This function typically calls `esp_lcd_touch_set_mirror_x()` to mirror the axis
*
* @param en true: enable, false: disable
*
* @return true if success, otherwise false
*/
bool mirrorX(bool en);
/**
* @brief Mirror the Y axis
*
* @note This function should be called after `begin()`
* @note This function typically calls `esp_lcd_touch_set_mirror_y()` to mirror the axis
*
* @param en true: enable, false: disable
*
* @return true if success, otherwise false
*/
bool mirrorY(bool en);
/**
* @brief Read the raw data from the touch device, then users should call `getPoints()` to get the points, or call
* `getButtonState()` to get the button state
*
* @note This function should be called after `begin()`
* @note This function typically calls `esp_lcd_touch_read_data()` and `esp_lcd_touch_get_coordinates()` to read
* the raw data
* @note If the interrupt pin is set, this function will be blocked until either the interrupt occurs or a timeout
* is triggered
*
* @param max_points_num The max number of the points to read
* @param timeout_ms The timeout of waiting for the interrupt, it is only used when the interrupt pin is set. Set to
* `-1` if waiting forever
*
* @return true if success, otherwise false
*/
bool readRawData(uint8_t max_points_num = CONFIG_ESP_LCD_TOUCH_MAX_POINTS, int timeout_ms = 0);
/**
* @brief Get the touch points. This function should be called immediately after the `readRawData()` function
*
* @note This function should be called after `begin()`
*
* @param points The buffer to store the points
* @param num The number of the points to read
*
* @return The number of the points read, `-1` if failed
*/
int getPoints(ESP_PanelTouchPoint points[], uint8_t num = 1);
/**
* @brief Get the button state. This function should be called immediately after the `readRawData()` function
*
* @note This function should be called after `begin()`
*
* @param index The index of the button
*
* @return The state of the button, `-1` if failed
*/
int getButtonState(uint8_t index = 0);
/**
* @brief Read the points from the touch device. This function is a combination of `readRawData()` and `getPoints()`
*
* @note This function should be called after `begin()`
* @note If the interrupt pin is set, this function will be blocked until either the interrupt occurs or a timeout
* is triggered
*
* @param points The buffer to store the points
* @param num The number of the points to read
* @param timeout_ms The timeout of waiting for the interrupt, it is only used when the interrupt pin is set. Set to
* `-1` if waiting forever
*
* @return The number of the points read, `-1` if failed
*/
int readPoints(ESP_PanelTouchPoint points[], uint8_t num = 1, int timeout_ms = 0);
/**
* @brief Read the button state from the touch device. This function is a combination of `readRawData()` and
* `getButtonState()`
*
* @note This function should be called after `begin()`
* @note If the interrupt pin is set, this function will be blocked until either the interrupt occurs or a timeout
* is triggered
*
* @param index The index of the button
* @param timeout_ms The timeout of waiting for the interrupt, it is only used when the interrupt pin is set. Set to
* `-1` if waiting forever
*
* @return The state of the button, `-1` if failed
*/
int readButtonState(uint8_t index = 0, int timeout_ms = 0);
/**
* @brief Check if the interrupt function is enabled
*
* @return true if enabled, otherwise false
*/
bool isInterruptEnabled(void);
/**
* @brief Get the flag of the X and Y axis swap
*
* @return true if swap, otherwise not swap
*/
bool getSwapXYFlag(void);
/**
* @brief Get the flag of the X axis mirror
*
* @return true if mirror, otherwise not mirror
*/
bool getMirrorXFlag(void);
/**
* @brief Get the flag of the Y axis mirror
*
* @return true if mirror, otherwise not mirror
*/
bool getMirrorYFlag(void);
/**
* @brief Get the panel handle of LCD device
*
* @return The handle of the LCD panel, or NULL if fail
*/
esp_lcd_touch_handle_t getHandle(void);
/**
* @brief Get the panel bus
*
* @return The pointer of the LCD Bus, or NULL if fail
*/
ESP_PanelBus *getBus(void);
protected:
ESP_PanelBus *bus;
esp_lcd_touch_config_t config;
esp_lcd_touch_handle_t handle;
private:
static void onTouchInterrupt(esp_lcd_touch_handle_t tp);
bool _swap_xy;
bool _mirror_x;
bool _mirror_y;
uint8_t _tp_points_num;
uint8_t _tp_buttons_state[CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS];
ESP_PanelTouchPoint _tp_points[CONFIG_ESP_LCD_TOUCH_MAX_POINTS];
std::function<bool (void *)> onTouchInterruptCallback;
SemaphoreHandle_t _isr_sem;
typedef struct {
void *tp_ptr;
void *user_data;
} ESP_PanelTouchCallbackData_t;
ESP_PanelTouchCallbackData_t callback_data;
};
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "FT5x06.h"
static const char *TAG = "FT5x06_CPP";
ESP_PanelTouch_FT5x06::ESP_PanelTouch_FT5x06(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_FT5x06::ESP_PanelTouch_FT5x06(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_FT5x06::~ESP_PanelTouch_FT5x06()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_FT5x06::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_ft5x06(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_ft5x06.h"
#include "ESP_PanelTouch.h"
/**
* @brief FT5x06 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_FT5x06 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_FT5x06(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_FT5x06(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_FT5x06() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "GT1151.h"
static const char *TAG = "GT1151_CPP";
ESP_PanelTouch_GT1151::ESP_PanelTouch_GT1151(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_GT1151::ESP_PanelTouch_GT1151(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_GT1151::~ESP_PanelTouch_GT1151()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_GT1151::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt1151(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_gt1151.h"
#include "ESP_PanelTouch.h"
/**
* @brief TT21100 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_GT1151 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_GT1151(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_GT1151(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_GT1151() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "GT911.h"
static const char *TAG = "GT911_CPP";
ESP_PanelTouch_GT911::ESP_PanelTouch_GT911(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_GT911::ESP_PanelTouch_GT911(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_GT911::~ESP_PanelTouch_GT911()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_GT911::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_gt911(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_gt911.h"
#include "ESP_PanelTouch.h"
/**
* @brief GT911 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_GT911 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_GT911(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_GT911(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_GT911() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,13 @@
# Touch Controllers
| **Name** | **Version** |
| -------------------------------------------------------------------------------------- | ----------- |
| [esp_lcd_touch](https://components.espressif.com/components/espressif/esp_lcd_touch) | 1.1.1 |
| [CST816S](https://components.espressif.com/components/espressif/esp_lcd_touch_cst816s) | 1.0.3 |
| [FT5x06](https://components.espressif.com/components/espressif/esp_lcd_touch_ft5x06) | 1.0.6 |
| [GT911](https://components.espressif.com/components/espressif/esp_lcd_touch_gt911) | 1.1.0 |
| [GT1151](https://components.espressif.com/components/espressif/esp_lcd_touch_gt1151) | 1.0.5~1 |
| ST1633 | 0.1.0 |
| [ST7123](https://components.espressif.com/components/espressif/esp_lcd_touch_st7123) | 0.0.1 |
| [TT21100](https://components.espressif.com/components/espressif/esp_lcd_touch_tt21100) | 1.1.0 |
| [XPT2046](https://components.espressif.com/components/atanisoft/esp_lcd_touch_xpt2046) | 1.0.4 |
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "ST1633.h"
static const char *TAG = "ST1633_CPP";
ESP_PanelTouch_ST1633::ESP_PanelTouch_ST1633(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_ST1633::ESP_PanelTouch_ST1633(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_ST1633::~ESP_PanelTouch_ST1633()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_ST1633::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st1633(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_st1633.h"
#include "ESP_PanelTouch.h"
/**
* @brief ST1633 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_ST1633 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_ST1633(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_ST1633(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_ST1633() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "ST7123.h"
static const char *TAG = "ST7123_CPP";
ESP_PanelTouch_ST7123::ESP_PanelTouch_ST7123(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_ST7123::ESP_PanelTouch_ST7123(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_ST7123::~ESP_PanelTouch_ST7123()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_ST7123::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_st7123(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_st7123.h"
#include "ESP_PanelTouch.h"
/**
* @brief ST7123 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_ST7123 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_ST7123(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_ST7123(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_ST7123() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "TT21100.h"
static const char *TAG = "TT21100_CPP";
ESP_PanelTouch_TT21100::ESP_PanelTouch_TT21100(ESP_PanelBus *bus, uint16_t width, uint16_t height,
int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_TT21100::ESP_PanelTouch_TT21100(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_TT21100::~ESP_PanelTouch_TT21100()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_TT21100::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_i2c_tt21100(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_tt21100.h"
#include "ESP_PanelTouch.h"
/**
* @brief TT21100 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_TT21100 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_TT21100(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_TT21100(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_TT21100() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include "XPT2046.h"
static const char *TAG = "XPT2046_CPP";
ESP_PanelTouch_XPT2046::ESP_PanelTouch_XPT2046(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io, int int_io):
ESP_PanelTouch(bus, width, height, rst_io, int_io)
{
}
ESP_PanelTouch_XPT2046::ESP_PanelTouch_XPT2046(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config):
ESP_PanelTouch(bus, config)
{
}
ESP_PanelTouch_XPT2046::~ESP_PanelTouch_XPT2046()
{
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
if (handle == NULL) {
goto end;
}
if (!del()) {
ESP_LOGE(TAG, "Delete device failed");
}
end:
ESP_LOGD(TAG, "Destroyed");
}
bool ESP_PanelTouch_XPT2046::begin(void)
{
ESP_PANEL_CHECK_NULL_RET(bus, false, "Invalid bus");
ESP_PANEL_CHECK_ERR_RET(esp_lcd_touch_new_spi_xpt2046(bus->getHandle(), &config, &handle), false, "New driver failed");
return true;
}
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "base/esp_lcd_touch_xpt2046.h"
#include "ESP_PanelTouch.h"
/**
* @brief XPT2046 touch device object class
*
* @note This class is a derived class of `ESP_PanelTouch`, user can use it directly
*/
class ESP_PanelTouch_XPT2046 : public ESP_PanelTouch {
public:
/**
* @brief Construct a new touch device in a simple way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param width The width of the touch screen
* @param height The height of the touch screen
* @param rst_io The reset pin of the touch screen, set to `-1` if not used
* @param int_io The interrupt pin of the touch screen, set to `-1` if not used
*/
ESP_PanelTouch_XPT2046(ESP_PanelBus *bus, uint16_t width, uint16_t height, int rst_io = -1, int int_io = -1);
/**
* @brief Construct a new touch device in a complex way, the `init()` function should be called after this function
*
* @param bus Pointer to panel bus
* @param config Touch device configuration
*/
ESP_PanelTouch_XPT2046(ESP_PanelBus *bus, const esp_lcd_touch_config_t &config);
/**
* @brief Destroy the LCD device
*
*/
~ESP_PanelTouch_XPT2046() override;
/**
* @brief Startup the touch device
*
* @return true if success, otherwise false
*/
bool begin(void) override;
};
@@ -0,0 +1,266 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_log.h"
#include "esp_lcd_touch.h"
static const char *TAG = "TP";
/*******************************************************************************
* Function definitions
*******************************************************************************/
/*******************************************************************************
* Local variables
*******************************************************************************/
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->enter_sleep == NULL) {
ESP_LOGE(TAG, "Sleep mode not supported!");
return ESP_FAIL;
} else {
return tp->enter_sleep(tp);
}
}
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->exit_sleep == NULL) {
ESP_LOGE(TAG, "Sleep mode not supported!");
return ESP_FAIL;
} else {
return tp->exit_sleep(tp);
}
}
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
assert(tp->read_data != NULL);
return tp->read_data(tp);
}
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
bool touched = false;
assert(tp != NULL);
assert(x != NULL);
assert(y != NULL);
assert(tp->get_xy != NULL);
touched = tp->get_xy(tp, x, y, strength, point_num, max_point_num);
if (!touched) {
return false;
}
/* Process coordinates by user */
if (tp->config.process_coordinates != NULL) {
tp->config.process_coordinates(tp, x, y, strength, point_num, max_point_num);
}
/* Software coordinates adjustment needed */
bool sw_adj_needed = ((tp->config.flags.mirror_x && (tp->set_mirror_x == NULL)) ||
(tp->config.flags.mirror_y && (tp->set_mirror_y == NULL)) ||
(tp->config.flags.swap_xy && (tp->set_swap_xy == NULL)));
/* Adjust all coordinates */
for (int i = 0; (sw_adj_needed && i < *point_num); i++) {
/* Mirror X coordinates (if not supported by HW) */
if (tp->config.flags.mirror_x && tp->set_mirror_x == NULL) {
x[i] = tp->config.x_max - x[i];
}
/* Mirror Y coordinates (if not supported by HW) */
if (tp->config.flags.mirror_y && tp->set_mirror_y == NULL) {
y[i] = tp->config.y_max - y[i];
}
/* Swap X and Y coordinates (if not supported by HW) */
if (tp->config.flags.swap_xy && tp->set_swap_xy == NULL) {
uint16_t tmp = x[i];
x[i] = y[i];
y[i] = tmp;
}
}
return touched;
}
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state)
{
assert(tp != NULL);
assert(state != NULL);
*state = 0;
if (tp->get_button_state) {
return tp->get_button_state(tp, n, state);
} else {
return ESP_ERR_NOT_SUPPORTED;
}
return ESP_OK;
}
#endif
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap)
{
assert(tp != NULL);
tp->config.flags.swap_xy = swap;
/* Is swap supported by HW? */
if (tp->set_swap_xy) {
return tp->set_swap_xy(tp, swap);
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap)
{
assert(tp != NULL);
assert(swap != NULL);
/* Is swap supported by HW? */
if (tp->get_swap_xy) {
return tp->get_swap_xy(tp, swap);
} else {
*swap = tp->config.flags.swap_xy;
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror)
{
assert(tp != NULL);
tp->config.flags.mirror_x = mirror;
/* Is mirror supported by HW? */
if (tp->set_mirror_x) {
return tp->set_mirror_x(tp, mirror);
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror)
{
assert(tp != NULL);
assert(mirror != NULL);
/* Is swap supported by HW? */
if (tp->get_mirror_x) {
return tp->get_mirror_x(tp, mirror);
} else {
*mirror = tp->config.flags.mirror_x;
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror)
{
assert(tp != NULL);
tp->config.flags.mirror_y = mirror;
/* Is mirror supported by HW? */
if (tp->set_mirror_y) {
return tp->set_mirror_y(tp, mirror);
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror)
{
assert(tp != NULL);
assert(mirror != NULL);
/* Is swap supported by HW? */
if (tp->get_mirror_y) {
return tp->get_mirror_y(tp, mirror);
} else {
*mirror = tp->config.flags.mirror_y;
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->del != NULL) {
return tp->del(tp);
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback)
{
esp_err_t ret = ESP_OK;
assert(tp != NULL);
/* Interrupt pin is not selected */
if (tp->config.int_gpio_num == GPIO_NUM_NC) {
return ESP_ERR_INVALID_ARG;
}
tp->config.interrupt_callback = callback;
if (callback != NULL) {
ret = gpio_install_isr_service(0);
/* ISR service can be installed from user before, then it returns invalid state */
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG, "GPIO ISR install failed");
return ret;
}
/* Add GPIO ISR handler */
ret = gpio_intr_enable(tp->config.int_gpio_num);
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
ret = gpio_isr_handler_add(tp->config.int_gpio_num, (gpio_isr_t)tp->config.interrupt_callback, tp);
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR install failed");
} else {
/* Remove GPIO ISR handler */
ret = gpio_isr_handler_remove(tp->config.int_gpio_num);
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR remove handler failed");
ret = gpio_intr_disable(tp->config.int_gpio_num);
ESP_RETURN_ON_ERROR(ret, TAG, "GPIO ISR disable failed");
}
return ESP_OK;
}
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data)
{
assert(tp != NULL);
tp->config.user_data = user_data;
return esp_lcd_touch_register_interrupt_callback(tp, callback);
}
@@ -0,0 +1,436 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch
*/
#pragma once
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "driver/gpio.h"
#include "esp_lcd_panel_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "ESP_Panel_Conf_Internal.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_VER_MAJOR (1)
#define ESP_LCD_TOUCH_VER_MINOR (1)
#define ESP_LCD_TOUCH_VER_PATCH (1)
#define CONFIG_ESP_LCD_TOUCH_MAX_POINTS (ESP_PANEL_TOUCH_MAX_POINTS)
#define CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS (ESP_PANEL_TOUCH_MAX_BUTTONS)
/**
* @brief Touch controller type
*
*/
typedef struct esp_lcd_touch_s esp_lcd_touch_t;
typedef esp_lcd_touch_t *esp_lcd_touch_handle_t;
/**
* @brief Touch controller interrupt callback type
*
*/
typedef void (*esp_lcd_touch_interrupt_callback_t)(esp_lcd_touch_handle_t tp);
/**
* @brief Touch Configuration Type
*
*/
typedef struct {
uint16_t x_max; /*!< X coordinates max (for mirroring) */
uint16_t y_max; /*!< Y coordinates max (for mirroring) */
gpio_num_t rst_gpio_num; /*!< GPIO number of reset pin */
gpio_num_t int_gpio_num; /*!< GPIO number of interrupt pin */
struct {
unsigned int reset: 1; /*!< Level of reset pin in reset */
unsigned int interrupt: 1;/*!< Active Level of interrupt pin */
} levels;
struct {
unsigned int swap_xy: 1; /*!< Swap X and Y after read coordinates */
unsigned int mirror_x: 1; /*!< Mirror X after read coordinates */
unsigned int mirror_y: 1; /*!< Mirror Y after read coordinates */
} flags;
/*!< User callback called after get coordinates from touch controller for apply user adjusting */
void (*process_coordinates)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
/*!< User callback called after the touch interrupt occured */
esp_lcd_touch_interrupt_callback_t interrupt_callback;
/*!< User data passed to callback */
void *user_data;
} esp_lcd_touch_config_t;
typedef struct {
uint8_t points; /*!< Count of touch points saved */
struct {
uint16_t x; /*!< X coordinate */
uint16_t y; /*!< Y coordinate */
uint16_t strength; /*!< Strength */
} coords[CONFIG_ESP_LCD_TOUCH_MAX_POINTS];
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
uint8_t buttons; /*!< Count of buttons states saved */
struct {
uint8_t status; /*!< Status of button */
} button[CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS];
#endif
portMUX_TYPE lock; /*!< Lock for read/write */
} esp_lcd_touch_data_t;
/**
* @brief Declare of Touch Type
*
*/
struct esp_lcd_touch_s {
/**
* @brief set touch controller into sleep mode
*
* @note This function is usually blocking.
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*enter_sleep)(esp_lcd_touch_handle_t tp);
/**
* @brief set touch controller into normal mode
*
* @note This function is usually blocking.
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*exit_sleep)(esp_lcd_touch_handle_t tp);
/**
* @brief Read data from touch controller (mandatory)
*
* @note This function is usually blocking.
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*read_data)(esp_lcd_touch_handle_t tp);
/**
* @brief Get coordinates from touch controller (mandatory)
*
* @param tp: Touch handler
* @param x: Array of X coordinates
* @param y: Array of Y coordinates
* @param strength: Array of strengths
* @param point_num: Count of points touched (equals with count of items in x and y array)
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
*
* @return
* - Returns true, when touched and coordinates readed. Otherwise returns false.
*/
bool (*get_xy)(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
/**
* @brief Get button state (optional)
*
* @param tp: Touch handler
* @param n: Button index
* @param state: Button state
*
* @return
* - Returns true, when touched and coordinates readed. Otherwise returns false.
*/
esp_err_t (*get_button_state)(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
#endif
/**
* @brief Swap X and Y after read coordinates (optional)
* If set, then not used SW swapping.
*
* @param tp: Touch handler
* @param swap: Set swap value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*set_swap_xy)(esp_lcd_touch_handle_t tp, bool swap);
/**
* @brief Are X and Y coordinates swapped (optional)
*
* @param tp: Touch handler
* @param swap: Get swap value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*get_swap_xy)(esp_lcd_touch_handle_t tp, bool *swap);
/**
* @brief Mirror X after read coordinates
* If set, then not used SW mirroring.
*
* @param tp: Touch handler
* @param mirror: Set X mirror value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*set_mirror_x)(esp_lcd_touch_handle_t tp, bool mirror);
/**
* @brief Is mirrored X (optional)
*
* @param tp: Touch handler
* @param mirror: Get X mirror value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*get_mirror_x)(esp_lcd_touch_handle_t tp, bool *mirror);
/**
* @brief Mirror Y after read coordinates
* If set, then not used SW mirroring.
*
* @param tp: Touch handler
* @param mirror: Set Y mirror value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*set_mirror_y)(esp_lcd_touch_handle_t tp, bool mirror);
/**
* @brief Is mirrored Y (optional)
*
* @param tp: Touch handler
* @param mirror: Get Y mirror value
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*get_mirror_y)(esp_lcd_touch_handle_t tp, bool *mirror);
/**
* @brief Delete Touch
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t (*del)(esp_lcd_touch_handle_t tp);
/**
* @brief Configuration structure
*/
esp_lcd_touch_config_t config;
/**
* @brief Communication interface
*/
esp_lcd_panel_io_handle_t io;
/**
* @brief Data structure
*/
esp_lcd_touch_data_t data;
};
/**
* @brief Read data from touch controller
*
* @note This function is usually blocking.
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG parameter error
* - ESP_FAIL sending command error, slave hasn't ACK the transfer
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode
* - ESP_ERR_TIMEOUT operation timeout because the bus is busy
*/
esp_err_t esp_lcd_touch_read_data(esp_lcd_touch_handle_t tp);
/**
* @brief Read coordinates from touch controller
*
* @param tp: Touch handler
* @param x: Array of X coordinates
* @param y: Array of Y coordinates
* @param strength: Array of the strengths (can be NULL)
* @param point_num: Count of points touched (equals with count of items in x and y array)
* @param max_point_num: Maximum count of touched points to return (equals with max size of x and y array)
*
* @return
* - Returns true, when touched and coordinates readed. Otherwise returns false.
*/
bool esp_lcd_touch_get_coordinates(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
/**
* @brief Get button state
*
* @param tp: Touch handler
* @param n: Button index
* @param state: Button state
*
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_SUPPORTED if this function is not supported by controller
* - ESP_ERR_INVALID_ARG if bad button index
*/
esp_err_t esp_lcd_touch_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
#endif
/**
* @brief Swap X and Y after read coordinates
*
* @param tp: Touch handler
* @param swap: Set swap value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_set_swap_xy(esp_lcd_touch_handle_t tp, bool swap);
/**
* @brief Are X and Y coordinates swapped
*
* @param tp: Touch handler
* @param swap: Get swap value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_get_swap_xy(esp_lcd_touch_handle_t tp, bool *swap);
/**
* @brief Mirror X after read coordinates
*
* @param tp: Touch handler
* @param mirror: Set X mirror value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_set_mirror_x(esp_lcd_touch_handle_t tp, bool mirror);
/**
* @brief Is mirrored X
*
* @param tp: Touch handler
* @param mirror: Get X mirror value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_get_mirror_x(esp_lcd_touch_handle_t tp, bool *mirror);
/**
* @brief Mirror Y after read coordinates
*
* @param tp: Touch handler
* @param mirror: Set Y mirror value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_set_mirror_y(esp_lcd_touch_handle_t tp, bool mirror);
/**
* @brief Is mirrored Y
*
* @param tp: Touch handler
* @param mirror: Get Y mirror value
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_get_mirror_y(esp_lcd_touch_handle_t tp, bool *mirror);
/**
* @brief Delete touch (free all allocated memory and restart HW)
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_del(esp_lcd_touch_handle_t tp);
/**
* @brief Register user callback called after the touch interrupt occured
*
* @param tp: Touch handler
* @param callback: Interrupt callback
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback);
/**
* @brief Register user callback called after the touch interrupt occured with user data
*
* @param tp: Touch handler
* @param callback: Interrupt callback
* @param user_data: User data passed to callback
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_lcd_touch_register_interrupt_callback_with_data(esp_lcd_touch_handle_t tp, esp_lcd_touch_interrupt_callback_t callback, void *user_data);
/**
* @brief Enter sleep mode
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if parameter is invalid
*/
esp_err_t esp_lcd_touch_enter_sleep(esp_lcd_touch_handle_t tp);
/**
* @brief Exit sleep mode
*
* @param tp: Touch handler
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if parameter is invalid
*/
esp_err_t esp_lcd_touch_exit_sleep(esp_lcd_touch_handle_t tp);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,196 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_cst816s.h"
#define POINT_NUM_MAX (1)
#define DATA_START_REG (0x02)
#define CHIP_ID_REG (0xA7)
static const char *TAG = "CST816S";
static esp_err_t read_data(esp_lcd_touch_handle_t tp);
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
static esp_err_t del(esp_lcd_touch_handle_t tp);
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
static esp_err_t reset(esp_lcd_touch_handle_t tp);
static esp_err_t read_id(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_i2c_cst816s(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "Invalid io");
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Invalid config");
ESP_RETURN_ON_FALSE(tp, ESP_ERR_INVALID_ARG, TAG, "Invalid touch handle");
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_err_t ret = ESP_OK;
esp_lcd_touch_handle_t cst816s = calloc(1, sizeof(esp_lcd_touch_t));
ESP_GOTO_ON_FALSE(cst816s, ESP_ERR_NO_MEM, err, TAG, "Touch handle malloc failed");
/* Communication interface */
cst816s->io = io;
/* Only supported callbacks are set */
cst816s->read_data = read_data;
cst816s->get_xy = get_xy;
cst816s->del = del;
/* Mutex */
cst816s->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&cst816s->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (cst816s->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (cst816s->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(cst816s->config.int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
/* Register interrupt callback */
if (cst816s->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(cst816s, cst816s->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (cst816s->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(cst816s->config.rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
}
/* Reset controller */
ESP_GOTO_ON_ERROR(reset(cst816s), err, TAG, "Reset failed");
/* Read product id */
ESP_GOTO_ON_ERROR(read_id(cst816s), err, TAG, "Read version failed");
*tp = cst816s;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_CST816S_VER_MAJOR, ESP_LCD_TOUCH_CST816S_VER_MINOR,
ESP_LCD_TOUCH_CST816S_VER_PATCH);
return ESP_OK;
err:
if (cst816s) {
del(cst816s);
}
ESP_LOGE(TAG, "Initialization failed!");
return ret;
}
static esp_err_t read_data(esp_lcd_touch_handle_t tp)
{
typedef struct {
uint8_t num;
uint8_t x_h : 4;
uint8_t : 4;
uint8_t x_l;
uint8_t y_h : 4;
uint8_t : 4;
uint8_t y_l;
} data_t;
data_t point;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, DATA_START_REG, (uint8_t *)&point, sizeof(data_t)), TAG, "I2C read failed");
portENTER_CRITICAL(&tp->data.lock);
point.num = (point.num > POINT_NUM_MAX ? POINT_NUM_MAX : point.num);
tp->data.points = point.num;
/* Fill all coordinates */
for (int i = 0; i < point.num; i++) {
tp->data.coords[i].x = point.x_h << 8 | point.x_l;
tp->data.coords[i].y = point.y_h << 8 | point.y_l;
}
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Invalidate */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
static esp_err_t del(esp_lcd_touch_handle_t tp)
{
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
}
/* Release memory */
free(tp);
return ESP_OK;
}
static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(200));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(200));
}
return ESP_OK;
}
static esp_err_t read_id(esp_lcd_touch_handle_t tp)
{
uint8_t id;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, CHIP_ID_REG, &id, 1), TAG, "I2C read failed");
ESP_LOGI(TAG, "IC id: %d", id);
return ESP_OK;
}
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
{
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "Invalid data");
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
}
@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch: CST816S
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_CST816S_VER_MAJOR (1)
#define ESP_LCD_TOUCH_CST816S_VER_MINOR (0)
#define ESP_LCD_TOUCH_CST816S_VER_PATCH (3)
/**
* @brief Create a new CST816S touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD panel IO handle, it should be created by `esp_lcd_new_panel_io_i2c()`
* @param config Touch panel configuration
* @param tp Touch panel handle
* @return
* - ESP_OK: on success
*/
esp_err_t esp_lcd_touch_new_i2c_cst816s(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp);
/**
* @brief I2C address of the CST816S controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS (0x15)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_CST816S_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 8, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,340 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_ft5x06.h"
static const char *TAG = "FT5x06";
/* Registers */
#define FT5x06_DEVICE_MODE (0x00)
#define FT5x06_GESTURE_ID (0x01)
#define FT5x06_TOUCH_POINTS (0x02)
#define FT5x06_TOUCH1_EV_FLAG (0x03)
#define FT5x06_TOUCH1_XH (0x03)
#define FT5x06_TOUCH1_XL (0x04)
#define FT5x06_TOUCH1_YH (0x05)
#define FT5x06_TOUCH1_YL (0x06)
#define FT5x06_TOUCH2_EV_FLAG (0x09)
#define FT5x06_TOUCH2_XH (0x09)
#define FT5x06_TOUCH2_XL (0x0A)
#define FT5x06_TOUCH2_YH (0x0B)
#define FT5x06_TOUCH2_YL (0x0C)
#define FT5x06_TOUCH3_EV_FLAG (0x0F)
#define FT5x06_TOUCH3_XH (0x0F)
#define FT5x06_TOUCH3_XL (0x10)
#define FT5x06_TOUCH3_YH (0x11)
#define FT5x06_TOUCH3_YL (0x12)
#define FT5x06_TOUCH4_EV_FLAG (0x15)
#define FT5x06_TOUCH4_XH (0x15)
#define FT5x06_TOUCH4_XL (0x16)
#define FT5x06_TOUCH4_YH (0x17)
#define FT5x06_TOUCH4_YL (0x18)
#define FT5x06_TOUCH5_EV_FLAG (0x1B)
#define FT5x06_TOUCH5_XH (0x1B)
#define FT5x06_TOUCH5_XL (0x1C)
#define FT5x06_TOUCH5_YH (0x1D)
#define FT5x06_TOUCH5_YL (0x1E)
#define FT5x06_ID_G_THGROUP (0x80)
#define FT5x06_ID_G_THPEAK (0x81)
#define FT5x06_ID_G_THCAL (0x82)
#define FT5x06_ID_G_THWATER (0x83)
#define FT5x06_ID_G_THTEMP (0x84)
#define FT5x06_ID_G_THDIFF (0x85)
#define FT5x06_ID_G_CTRL (0x86)
#define FT5x06_ID_G_TIME_ENTER_MONITOR (0x87)
#define FT5x06_ID_G_PERIODACTIVE (0x88)
#define FT5x06_ID_G_PERIODMONITOR (0x89)
#define FT5x06_ID_G_AUTO_CLB_MODE (0xA0)
#define FT5x06_ID_G_LIB_VERSION_H (0xA1)
#define FT5x06_ID_G_LIB_VERSION_L (0xA2)
#define FT5x06_ID_G_CIPHER (0xA3)
#define FT5x06_ID_G_MODE (0xA4)
#define FT5x06_ID_G_PMODE (0xA5)
#define FT5x06_ID_G_FIRMID (0xA6)
#define FT5x06_ID_G_STATE (0xA7)
#define FT5x06_ID_G_FT5201ID (0xA8)
#define FT5x06_ID_G_ERR (0xA9)
/*******************************************************************************
* Function definitions
*******************************************************************************/
static esp_err_t esp_lcd_touch_ft5x06_read_data(esp_lcd_touch_handle_t tp);
static bool esp_lcd_touch_ft5x06_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
static esp_err_t esp_lcd_touch_ft5x06_del(esp_lcd_touch_handle_t tp);
/* I2C read */
static esp_err_t touch_ft5x06_i2c_write(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t data);
static esp_err_t touch_ft5x06_i2c_read(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len);
/* FT5x06 init */
static esp_err_t touch_ft5x06_init(esp_lcd_touch_handle_t tp);
/* FT5x06 reset */
static esp_err_t touch_ft5x06_reset(esp_lcd_touch_handle_t tp);
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t esp_lcd_touch_new_i2c_ft5x06(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch)
{
esp_err_t ret = ESP_OK;
assert(config != NULL);
assert(out_touch != NULL);
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_lcd_touch_handle_t esp_lcd_touch_ft5x06 = heap_caps_calloc(1, sizeof(esp_lcd_touch_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(esp_lcd_touch_ft5x06, ESP_ERR_NO_MEM, err, TAG, "no mem for FT5x06 controller");
/* Communication interface */
esp_lcd_touch_ft5x06->io = io;
/* Only supported callbacks are set */
esp_lcd_touch_ft5x06->read_data = esp_lcd_touch_ft5x06_read_data;
esp_lcd_touch_ft5x06->get_xy = esp_lcd_touch_ft5x06_get_xy;
esp_lcd_touch_ft5x06->del = esp_lcd_touch_ft5x06_del;
/* Mutex */
esp_lcd_touch_ft5x06->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&esp_lcd_touch_ft5x06->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (esp_lcd_touch_ft5x06->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (esp_lcd_touch_ft5x06->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(esp_lcd_touch_ft5x06->config.int_gpio_num)
};
ret = gpio_config(&int_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
/* Register interrupt callback */
if (esp_lcd_touch_ft5x06->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_ft5x06, esp_lcd_touch_ft5x06->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (esp_lcd_touch_ft5x06->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(esp_lcd_touch_ft5x06->config.rst_gpio_num)
};
ret = gpio_config(&rst_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
}
/* Reset controller */
ret = touch_ft5x06_reset(esp_lcd_touch_ft5x06);
ESP_GOTO_ON_ERROR(ret, err, TAG, "FT5x06 reset failed");
/* Init controller */
ret = touch_ft5x06_init(esp_lcd_touch_ft5x06);
ESP_GOTO_ON_ERROR(ret, err, TAG, "FT5x06 init failed");
err:
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error (0x%x)! Touch controller FT5x06 initialization failed!", ret);
if (esp_lcd_touch_ft5x06) {
esp_lcd_touch_ft5x06_del(esp_lcd_touch_ft5x06);
}
return ret;
}
*out_touch = esp_lcd_touch_ft5x06;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_FT5x06_VER_MAJOR, ESP_LCD_TOUCH_FT5x06_VER_MINOR,
ESP_LCD_TOUCH_FT5x06_VER_PATCH);
return ret;
}
static esp_err_t esp_lcd_touch_ft5x06_read_data(esp_lcd_touch_handle_t tp)
{
esp_err_t err;
uint8_t data[30];
uint8_t points;
size_t i = 0;
assert(tp != NULL);
err = touch_ft5x06_i2c_read(tp, FT5x06_TOUCH_POINTS, &points, 1);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
if (points > 5 || points == 0) {
return ESP_OK;
}
/* Number of touched points */
points = (points > CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? CONFIG_ESP_LCD_TOUCH_MAX_POINTS : points);
err = touch_ft5x06_i2c_read(tp, FT5x06_TOUCH1_XH, data, 6 * points);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
portENTER_CRITICAL(&tp->data.lock);
/* Number of touched points */
tp->data.points = points;
/* Fill all coordinates */
for (i = 0; i < points; i++) {
tp->data.coords[i].x = (((uint16_t)data[(i * 6) + 0] & 0x0f) << 8) + data[(i * 6) + 1];
tp->data.coords[i].y = (((uint16_t)data[(i * 6) + 2] & 0x0f) << 8) + data[(i * 6) + 3];
}
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool esp_lcd_touch_ft5x06_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
assert(tp != NULL);
assert(x != NULL);
assert(y != NULL);
assert(point_num != NULL);
assert(max_point_num > 0);
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Invalidate */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
static esp_err_t esp_lcd_touch_ft5x06_del(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
/* Reset GPIO pin settings */
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
}
free(tp);
return ESP_OK;
}
/*******************************************************************************
* Private API function
*******************************************************************************/
static esp_err_t touch_ft5x06_init(esp_lcd_touch_handle_t tp)
{
esp_err_t ret = ESP_OK;
// Valid touching detect threshold
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THGROUP, 70);
// valid touching peak detect threshold
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THPEAK, 60);
// Touch focus threshold
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THCAL, 16);
// threshold when there is surface water
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THWATER, 60);
// threshold of temperature compensation
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THTEMP, 10);
// Touch difference threshold
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_THDIFF, 20);
// Delay to enter 'Monitor' status (s)
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_TIME_ENTER_MONITOR, 2);
// Period of 'Active' status (ms)
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_PERIODACTIVE, 12);
// Timer to enter 'idle' when in 'Monitor' (ms)
ret |= touch_ft5x06_i2c_write(tp, FT5x06_ID_G_PERIODMONITOR, 40);
return ret;
}
/* Reset controller */
static esp_err_t touch_ft5x06_reset(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t touch_ft5x06_i2c_write(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t data)
{
assert(tp != NULL);
// *INDENT-OFF*
/* Write data */
return esp_lcd_panel_io_tx_param(tp->io, reg, (uint8_t[]){data}, 1);
// *INDENT-ON*
}
static esp_err_t touch_ft5x06_i2c_read(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len)
{
assert(tp != NULL);
assert(data != NULL);
/* Read data */
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
}
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch: FT5x06
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_FT5x06_VER_MAJOR (1)
#define ESP_LCD_TOUCH_FT5x06_VER_MINOR (0)
#define ESP_LCD_TOUCH_FT5x06_VER_PATCH (6)
/**
* @brief Create a new FT5x06 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD/Touch panel IO handle
* @param config: Touch configuration
* @param out_touch: Touch instance handle
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if there is no memory for allocating main structure
*/
esp_err_t esp_lcd_touch_new_i2c_ft5x06(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch);
/**
* @brief I2C address of the FT5x06 controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS (0x38)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 8, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,253 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_gt1151.h"
static const char *TAG = "gt1151";
#define READ_XY_REG (0x814E)
#define PRODUCT_ID_REG (0x8140)
#define MAX_TOUCH_NUM (10)
/* Buffer Length = StatusReg(1) + TouchData(8 * TouchNum) + KeyValue(1) + Checksum(1) */
#define DATA_BUFF_LEN(touch_num) (1 + 8 * (touch_num) + 2)
#define IS_NUM_OR_CHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= '0' && (x) <= '9'))
static esp_err_t read_data(esp_lcd_touch_handle_t tp);
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
static esp_err_t del(esp_lcd_touch_handle_t tp);
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
static esp_err_t i2c_write_byte(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t data);
static esp_err_t reset(esp_lcd_touch_handle_t tp);
static esp_err_t read_product_id(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_i2c_gt1151(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "Invalid io");
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Invalid config");
ESP_RETURN_ON_FALSE(tp, ESP_ERR_INVALID_ARG, TAG, "Invalid touch handle");
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_err_t ret = ESP_OK;
esp_lcd_touch_handle_t gt1151 = calloc(1, sizeof(esp_lcd_touch_t));
ESP_GOTO_ON_FALSE(gt1151, ESP_ERR_NO_MEM, err, TAG, "Touch handle malloc failed");
/* Communication interface */
gt1151->io = io;
/* Only supported callbacks are set */
gt1151->read_data = read_data;
gt1151->get_xy = get_xy;
gt1151->del = del;
/* Mutex */
gt1151->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&gt1151->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (gt1151->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (gt1151->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(gt1151->config.int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
/* Register interrupt callback */
if (gt1151->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(gt1151, gt1151->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (gt1151->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(gt1151->config.rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
}
/* Reset controller */
ESP_GOTO_ON_ERROR(reset(gt1151), err, TAG, "Reset failed");
/* Read product id */
ESP_GOTO_ON_ERROR(read_product_id(gt1151), err, TAG, "Read product id failed");
*tp = gt1151;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_GT1151_VER_MAJOR, ESP_LCD_TOUCH_GT1151_VER_MINOR,
ESP_LCD_TOUCH_GT1151_VER_PATCH);
return ESP_OK;
err:
if (gt1151) {
del(gt1151);
}
ESP_LOGE(TAG, "Initialization failed!");
return ret;
}
static esp_err_t read_data(esp_lcd_touch_handle_t tp)
{
typedef struct {
uint8_t touch_id : 4;
uint8_t : 4;
uint16_t x;
uint16_t y;
uint16_t strength;
uint8_t useless;
} __attribute__((packed)) touch_record_t;
typedef struct {
uint8_t touch_cnt : 4;
uint8_t : 4;
touch_record_t touch_record[0];
} __attribute__((packed)) touch_report_t;
uint8_t touch_cnt;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, READ_XY_REG, &touch_cnt, sizeof(touch_cnt)), TAG, "I2C read failed!");
touch_cnt &= 0x0f;
/* Any touch data? */
if (touch_cnt > MAX_TOUCH_NUM || touch_cnt == 0) {
i2c_write_byte(tp, READ_XY_REG, 0);
return ESP_OK;
}
uint8_t buf[DATA_BUFF_LEN(MAX_TOUCH_NUM)];
/* Read all points */
ESP_RETURN_ON_ERROR( i2c_read_bytes(tp, READ_XY_REG, buf, DATA_BUFF_LEN(touch_cnt)), TAG, "I2C read failed");
/* Clear all */
i2c_write_byte(tp, READ_XY_REG, 0);
/* Caculate checksum */
uint8_t checksum = 0;
for (int i = 0; i < DATA_BUFF_LEN(touch_cnt); i++) {
checksum += buf[i];
}
ESP_RETURN_ON_FALSE(!checksum, ESP_ERR_INVALID_CRC, TAG, "Checksum error");
touch_report_t *touch_report = (touch_report_t *)buf;
portENTER_CRITICAL(&tp->data.lock);
/* Expect Number of touched points */
touch_cnt = (touch_cnt > CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? CONFIG_ESP_LCD_TOUCH_MAX_POINTS : touch_cnt);
tp->data.points = touch_cnt;
/* Fill all coordinates */
for (int i = 0; i < touch_cnt; i++) {
tp->data.coords[i].x = touch_report->touch_record[i].x;
tp->data.coords[i].y = touch_report->touch_record[i].y;
tp->data.coords[i].strength = touch_report->touch_record[i].strength;
}
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Invalidate */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
static esp_err_t del(esp_lcd_touch_handle_t tp)
{
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
}
/* Release memory */
free(tp);
return ESP_OK;
}
static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t read_product_id(esp_lcd_touch_handle_t tp)
{
uint8_t buf[11] = {0};
uint8_t checksum = 0;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, PRODUCT_ID_REG, buf, sizeof(buf)), TAG, "I2C read failed");
for (int i = 0; i < sizeof(buf); i++) {
checksum += buf[i];
}
/* First 3 bytes must be number or char, and sensor id != 0xFF */
ESP_RETURN_ON_FALSE(checksum, ESP_ERR_INVALID_CRC, TAG, "Checksum error");
ESP_RETURN_ON_FALSE(
IS_NUM_OR_CHAR(buf[0]) && IS_NUM_OR_CHAR(buf[1]) && IS_NUM_OR_CHAR(buf[2]) && buf[10] != 0xFF,
ESP_ERR_INVALID_CRC, TAG, "Product id format error");
uint32_t mask_id, patch_id, sensor_id;
char product_id[5] = {0};
mask_id = (uint32_t) ((buf[7] << 16) | (buf[8] << 8) | buf[9]);
patch_id = (uint32_t) ((buf[4] << 16) | (buf[5] << 8) | buf[6]);
memcpy(product_id, buf, 4);
sensor_id = buf[10] & 0x0F;
ESP_LOGI(
TAG, "IC version: GT%s_%06" PRIX32 "(Patch)_%04" PRIX32 "(Mask)_%02" PRIX32 "(SensorID)",
product_id, patch_id, mask_id >> 8, sensor_id);
return ESP_OK;
}
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
{
ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "Invalid data");
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
}
static esp_err_t i2c_write_byte(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t data)
{
// *INDENT-OFF*
return esp_lcd_panel_io_tx_param(tp->io, reg, (uint8_t[]){data}, 1);
// *INDENT-ON*
}
@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch: GT1151
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_GT1151_VER_MAJOR (1)
#define ESP_LCD_TOUCH_GT1151_VER_MINOR (0)
#define ESP_LCD_TOUCH_GT1151_VER_PATCH (5)
/**
* @brief Create a new GT1151 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD panel IO handle, it should be created by `esp_lcd_new_panel_io_i2c()`
* @param config Touch panel configuration
* @param tp Touch panel handle
* @return
* - ESP_OK: on success
*/
esp_err_t esp_lcd_touch_new_i2c_gt1151(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp);
/**
* @brief I2C address of the GT1151 controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS (0x14)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_GT1151_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT1151_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 16, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,388 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_gt911.h"
static const char *TAG = "GT911";
/* GT911 registers */
#define ESP_LCD_TOUCH_GT911_READ_KEY_REG (0x8093)
#define ESP_LCD_TOUCH_GT911_READ_XY_REG (0x814E)
#define ESP_LCD_TOUCH_GT911_CONFIG_REG (0x8047)
#define ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG (0x8140)
#define ESP_LCD_TOUCH_GT911_ENTER_SLEEP (0x8040)
/* GT911 support key num */
#define ESP_GT911_TOUCH_MAX_BUTTONS (4)
/*******************************************************************************
* Function definitions
*******************************************************************************/
static esp_err_t esp_lcd_touch_gt911_read_data(esp_lcd_touch_handle_t tp);
static bool esp_lcd_touch_gt911_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
static esp_err_t esp_lcd_touch_gt911_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
#endif
static esp_err_t esp_lcd_touch_gt911_del(esp_lcd_touch_handle_t tp);
/* I2C read/write */
static esp_err_t touch_gt911_i2c_read(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
static esp_err_t touch_gt911_i2c_write(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t data);
/* GT911 reset */
static esp_err_t touch_gt911_reset(esp_lcd_touch_handle_t tp);
/* Read status and config register */
static esp_err_t touch_gt911_read_cfg(esp_lcd_touch_handle_t tp);
/* GT911 enter/exit sleep mode */
static esp_err_t esp_lcd_touch_gt911_enter_sleep(esp_lcd_touch_handle_t tp);
static esp_err_t esp_lcd_touch_gt911_exit_sleep(esp_lcd_touch_handle_t tp);
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t esp_lcd_touch_new_i2c_gt911(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch)
{
esp_err_t ret = ESP_OK;
assert(io != NULL);
assert(config != NULL);
assert(out_touch != NULL);
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_lcd_touch_handle_t esp_lcd_touch_gt911 = heap_caps_calloc(1, sizeof(esp_lcd_touch_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(esp_lcd_touch_gt911, ESP_ERR_NO_MEM, err, TAG, "no mem for GT911 controller");
/* Communication interface */
esp_lcd_touch_gt911->io = io;
/* Only supported callbacks are set */
esp_lcd_touch_gt911->read_data = esp_lcd_touch_gt911_read_data;
esp_lcd_touch_gt911->get_xy = esp_lcd_touch_gt911_get_xy;
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
esp_lcd_touch_gt911->get_button_state = esp_lcd_touch_gt911_get_button_state;
#endif
esp_lcd_touch_gt911->del = esp_lcd_touch_gt911_del;
esp_lcd_touch_gt911->enter_sleep = esp_lcd_touch_gt911_enter_sleep;
esp_lcd_touch_gt911->exit_sleep = esp_lcd_touch_gt911_exit_sleep;
/* Mutex */
esp_lcd_touch_gt911->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&esp_lcd_touch_gt911->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (esp_lcd_touch_gt911->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (esp_lcd_touch_gt911->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(esp_lcd_touch_gt911->config.int_gpio_num)
};
ret = gpio_config(&int_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
/* Register interrupt callback */
if (esp_lcd_touch_gt911->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_gt911, esp_lcd_touch_gt911->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (esp_lcd_touch_gt911->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(esp_lcd_touch_gt911->config.rst_gpio_num)
};
ret = gpio_config(&rst_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
}
/* Reset controller */
ret = touch_gt911_reset(esp_lcd_touch_gt911);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GT911 reset failed");
/* Read status and config info */
ret = touch_gt911_read_cfg(esp_lcd_touch_gt911);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GT911 init failed");
err:
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error (0x%x)! Touch controller GT911 initialization failed!", ret);
if (esp_lcd_touch_gt911) {
esp_lcd_touch_gt911_del(esp_lcd_touch_gt911);
}
return ret;
}
*out_touch = esp_lcd_touch_gt911;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_GT911_VER_MAJOR, ESP_LCD_TOUCH_GT911_VER_MINOR,
ESP_LCD_TOUCH_GT911_VER_PATCH);
return ret;
}
static esp_err_t esp_lcd_touch_gt911_enter_sleep(esp_lcd_touch_handle_t tp)
{
esp_err_t err = touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_ENTER_SLEEP, 0x05);
ESP_RETURN_ON_ERROR(err, TAG, "Enter Sleep failed!");
return ESP_OK;
}
static esp_err_t esp_lcd_touch_gt911_exit_sleep(esp_lcd_touch_handle_t tp)
{
esp_err_t ret;
esp_lcd_touch_handle_t esp_lcd_touch_gt911 = tp;
if (esp_lcd_touch_gt911->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config_high = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(esp_lcd_touch_gt911->config.int_gpio_num)
};
ret = gpio_config(&int_gpio_config_high);
ESP_RETURN_ON_ERROR(ret, TAG, "High GPIO config failed");
gpio_set_level(esp_lcd_touch_gt911->config.int_gpio_num, 1);
vTaskDelay(pdMS_TO_TICKS(5));
const gpio_config_t int_gpio_config_float = {
.mode = GPIO_MODE_OUTPUT_OD,
.pin_bit_mask = BIT64(esp_lcd_touch_gt911->config.int_gpio_num)
};
ret = gpio_config(&int_gpio_config_float);
ESP_RETURN_ON_ERROR(ret, TAG, "Float GPIO config failed");
}
return ESP_OK;
}
static esp_err_t esp_lcd_touch_gt911_read_data(esp_lcd_touch_handle_t tp)
{
esp_err_t err;
uint8_t buf[41];
uint8_t touch_cnt = 0;
uint8_t clear = 0;
size_t i = 0;
assert(tp != NULL);
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, buf, 1);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Any touch data? */
if ((buf[0] & 0x80) == 0x00) {
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
} else if ((buf[0] & 0x10) == 0x10) {
/* Read all keys */
uint8_t key_max = ((ESP_GT911_TOUCH_MAX_BUTTONS < CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS) ? \
(ESP_GT911_TOUCH_MAX_BUTTONS) : (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS));
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_KEY_REG, &buf[0], key_max);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Clear all */
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
ESP_RETURN_ON_ERROR(err, TAG, "I2C write error!");
portENTER_CRITICAL(&tp->data.lock);
/* Buttons count */
tp->data.buttons = key_max;
for (i = 0; i < key_max; i++) {
tp->data.button[i].status = buf[0] ? 1 : 0;
}
portEXIT_CRITICAL(&tp->data.lock);
#endif
} else if ((buf[0] & 0x80) == 0x80) {
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
portENTER_CRITICAL(&tp->data.lock);
for (i = 0; i < CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS; i++) {
tp->data.button[i].status = 0;
}
portEXIT_CRITICAL(&tp->data.lock);
#endif
/* Count of touched points */
touch_cnt = buf[0] & 0x0f;
if (touch_cnt > 5 || touch_cnt == 0) {
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
return ESP_OK;
}
/* Read all points */
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG + 1, &buf[1], touch_cnt * 8);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Clear all */
err = touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
portENTER_CRITICAL(&tp->data.lock);
/* Number of touched points */
touch_cnt = (touch_cnt > CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? CONFIG_ESP_LCD_TOUCH_MAX_POINTS : touch_cnt);
tp->data.points = touch_cnt;
/* Fill all coordinates */
for (i = 0; i < touch_cnt; i++) {
tp->data.coords[i].x = ((uint16_t)buf[(i * 8) + 3] << 8) + buf[(i * 8) + 2];
tp->data.coords[i].y = (((uint16_t)buf[(i * 8) + 5] << 8) + buf[(i * 8) + 4]);
tp->data.coords[i].strength = (((uint16_t)buf[(i * 8) + 7] << 8) + buf[(i * 8) + 6]);
}
portEXIT_CRITICAL(&tp->data.lock);
}
return ESP_OK;
}
static bool esp_lcd_touch_gt911_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
assert(tp != NULL);
assert(x != NULL);
assert(y != NULL);
assert(point_num != NULL);
assert(max_point_num > 0);
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Invalidate */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
static esp_err_t esp_lcd_touch_gt911_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state)
{
esp_err_t err = ESP_OK;
assert(tp != NULL);
assert(state != NULL);
*state = 0;
portENTER_CRITICAL(&tp->data.lock);
if (n > tp->data.buttons) {
err = ESP_ERR_INVALID_ARG;
} else {
*state = tp->data.button[n].status;
}
portEXIT_CRITICAL(&tp->data.lock);
return err;
}
#endif
static esp_err_t esp_lcd_touch_gt911_del(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
/* Reset GPIO pin settings */
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
}
free(tp);
return ESP_OK;
}
/*******************************************************************************
* Private API function
*******************************************************************************/
/* Reset controller */
static esp_err_t touch_gt911_reset(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t touch_gt911_read_cfg(esp_lcd_touch_handle_t tp)
{
uint8_t buf[4];
assert(tp != NULL);
ESP_RETURN_ON_ERROR(touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG, (uint8_t *)&buf[0], 3), TAG, "GT911 read error!");
ESP_RETURN_ON_ERROR(touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_CONFIG_REG, (uint8_t *)&buf[3], 1), TAG, "GT911 read error!");
ESP_LOGI(TAG, "TouchPad_ID:0x%02x,0x%02x,0x%02x", buf[0], buf[1], buf[2]);
ESP_LOGI(TAG, "TouchPad_Config_Version:%d", buf[3]);
return ESP_OK;
}
static esp_err_t touch_gt911_i2c_read(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
{
assert(tp != NULL);
assert(data != NULL);
/* Read data */
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
}
static esp_err_t touch_gt911_i2c_write(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t data)
{
assert(tp != NULL);
// *INDENT-OFF*
/* Write data */
return esp_lcd_panel_io_tx_param(tp->io, reg, (uint8_t[]){data}, 1);
// *INDENT-ON*
}
@@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch: GT911
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_GT911_VER_MAJOR (1)
#define ESP_LCD_TOUCH_GT911_VER_MINOR (1)
#define ESP_LCD_TOUCH_GT911_VER_PATCH (0)
/**
* @brief Create a new GT911 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD/Touch panel IO handle
* @param config: Touch configuration
* @param out_touch: Touch instance handle
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if there is no memory for allocating main structure
*/
esp_err_t esp_lcd_touch_new_i2c_gt911(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch);
/**
* @brief I2C address of the GT911 controller
*
* @note When power-on detects low level of the interrupt gpio, address is 0x5D.
* @note Interrupt gpio is high level, address is 0x14.
*
*/
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS (0x5D)
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP (0x14)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 16, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,239 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/param.h>
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_st1633.h"
#define FW_VERSION_REG (0x00)
#define XY_RES_H_REG (0x04)
#define FW_REVISION_REG (0x0C)
#define ADVANCED_INFO_REG (0x10)
#define MAX_TOUCH_NUM (10)
#define MAX_READ_TOUCH_NUM (MAX(MAX_TOUCH_NUM, CONFIG_ESP_LCD_TOUCH_MAX_POINTS))
static const char *TAG = "ST1633";
static esp_err_t read_data(esp_lcd_touch_handle_t tp);
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
static esp_err_t del(esp_lcd_touch_handle_t tp);
static esp_err_t reset(esp_lcd_touch_handle_t tp);
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
static esp_err_t read_fw_info(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_i2c_st1633(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "Invalid io");
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Invalid config");
ESP_RETURN_ON_FALSE(tp, ESP_ERR_INVALID_ARG, TAG, "Invalid touch handle");
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_err_t ret = ESP_OK;
esp_lcd_touch_handle_t st1633 = (esp_lcd_touch_handle_t)calloc(1, sizeof(esp_lcd_touch_t));
ESP_GOTO_ON_FALSE(st1633, ESP_ERR_NO_MEM, err, TAG, "Touch handle malloc failed");
/* Communication interface */
st1633->io = io;
/* Only supported callbacks are set */
st1633->read_data = read_data;
st1633->get_xy = get_xy;
st1633->del = del;
/* Mutex */
st1633->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&st1633->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (config->int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (config->levels.interrupt) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE,
.pin_bit_mask = BIT64(config->int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
/* Register interrupt callback */
if (config->interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(st1633, config->interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (config->rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(config->rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
}
/* Reset controller */
ESP_GOTO_ON_ERROR(reset(st1633), err, TAG, "Reset failed");
ESP_GOTO_ON_ERROR(read_fw_info(st1633), err, TAG, "Read version failed");
ESP_LOGI(TAG, "Touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_ST1633_VER_MAJOR,
ESP_LCD_TOUCH_ST1633_VER_MINOR, ESP_LCD_TOUCH_ST1633_VER_PATCH);
*tp = st1633;
return ESP_OK;
err:
if (st1633) {
del(st1633);
}
ESP_LOGE(TAG, "Initialization failed!");
return ret;
}
static esp_err_t read_data(esp_lcd_touch_handle_t tp)
{
typedef struct {
uint8_t y_h: 3;
uint8_t reserved_3: 1;
uint8_t x_h: 3;
uint8_t valid: 1;
uint8_t x_l;
uint8_t y_l;
uint8_t reserved_24_31;
} xy_coord_t;
typedef struct {
uint8_t gesture_type: 4;
uint8_t reserved_4: 1;
uint8_t water_flag: 1;
uint8_t prox_flag: 1;
uint8_t reserved_7: 1;
uint8_t keys;
xy_coord_t xy_coord[MAX_READ_TOUCH_NUM];
} tp_report_t;
static_assert((sizeof(xy_coord_t) == 4) && (sizeof(tp_report_t) == 42), "Invalid size of tp xy_coord_t or_report_t");
tp_report_t tp_report = { 0 };
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, ADVANCED_INFO_REG, (uint8_t *)&tp_report, sizeof(tp_report)), TAG, "Read advanced info failed");
uint16_t x = 0;
uint16_t y = 0;
portENTER_CRITICAL(&tp->data.lock);
int j = 0;
/* Fill all coordinates */
for (int i = 0; i < MAX_READ_TOUCH_NUM; i++) {
x = (((uint16_t)tp_report.xy_coord[i].x_h) << 8) | tp_report.xy_coord[i].x_l;
y = (((uint16_t)tp_report.xy_coord[i].y_h) << 8) | tp_report.xy_coord[i].y_l;
if (((x == 0) && (y == 0)) || (x > tp->config.x_max) || (y > tp->config.y_max)) {
continue;
}
tp->data.coords[j].x = x;
tp->data.coords[j].y = y;
j++;
}
/* Expect Number of touched points */
tp->data.points = j;
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Clear available touch points count */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
static esp_err_t del(esp_lcd_touch_handle_t tp)
{
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
}
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
/* Release memory */
free(tp);
return ESP_OK;
}
static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
{
ESP_RETURN_ON_FALSE((len == 0) || (data != NULL), ESP_ERR_INVALID_ARG, TAG, "Invalid data");
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(tp->io, reg, data, len), TAG, "Read param failed");
return ESP_OK;
}
static esp_err_t read_fw_info(esp_lcd_touch_handle_t tp)
{
uint8_t version = 0;
uint8_t revision[4] = { 0 };
struct {
uint8_t y_res_h: 3;
uint8_t reserved_3: 1;
uint8_t x_res_h: 3;
uint8_t reserved_7: 1;
uint8_t x_res_l;
uint8_t y_res_l;
} xy_res;
static_assert(sizeof(xy_res) == 3, "Invalid size of info");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, FW_VERSION_REG, &version, 1), TAG, "Read version failed");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, FW_REVISION_REG, (uint8_t *)&revision[0], sizeof(revision)), TAG, "Read revision failed");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, XY_RES_H_REG, (uint8_t *)&xy_res, sizeof(xy_res)), TAG, "Read XY Resolution failed");
ESP_LOGI(TAG, "Firmware version: %d(%d.%d.%d.%d), Max.X: %d, Max.Y: %d", version, revision[3], revision[2],
revision[1], revision[0], (((uint16_t)xy_res.x_res_h) << 8) | xy_res.x_res_l,
(((uint16_t)xy_res.y_res_h) << 8) | xy_res.y_res_l);
return ESP_OK;
}
@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_ST1633_VER_MAJOR (0)
#define ESP_LCD_TOUCH_ST1633_VER_MINOR (1)
#define ESP_LCD_TOUCH_ST1633_VER_PATCH (0)
/**
* @brief Create a new ST1633 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD panel IO handle, it should be created by `esp_lcd_new_panel_io_i2c()`
* @param config Touch panel configuration
* @param tp Touch panel handle
* @return
* - ESP_OK: on success
*/
esp_err_t esp_lcd_touch_new_i2c_st1633(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp);
/**
* @brief I2C address of the ST1633 controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_ST1633_ADDRESS (0x55)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_ST1633_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_ST1633_ADDRESS, \
.control_phase_bytes = 1, \
.lcd_cmd_bits = 8, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,241 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/param.h>
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_st7123.h"
#define FW_VERSION_REG (0x0000)
#define FW_REVISION_REG (0x000C)
#define MAX_X_COORD_H_REG (0x0005)
#define MAX_X_COORD_L_REG (0x0006)
#define MAX_Y_COORD_H_REG (0x0007)
#define MAX_Y_COORD_L_REG (0x0008)
#define MAX_TOUCHES_REG (0x0009)
#define REPORT_COORD_0_REG (0x0014)
static const char *TAG = "ST7123";
static esp_err_t read_data(esp_lcd_touch_handle_t tp);
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
static esp_err_t del(esp_lcd_touch_handle_t tp);
static esp_err_t reset(esp_lcd_touch_handle_t tp);
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len);
static esp_err_t read_fw_info(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_i2c_st7123(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "Invalid io");
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "Invalid config");
ESP_RETURN_ON_FALSE(tp, ESP_ERR_INVALID_ARG, TAG, "Invalid touch handle");
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_err_t ret = ESP_OK;
esp_lcd_touch_handle_t st7123 = (esp_lcd_touch_handle_t)calloc(1, sizeof(esp_lcd_touch_t));
ESP_GOTO_ON_FALSE(st7123, ESP_ERR_NO_MEM, err, TAG, "Touch handle malloc failed");
/* Communication interface */
st7123->io = io;
/* Only supported callbacks are set */
st7123->read_data = read_data;
st7123->get_xy = get_xy;
st7123->del = del;
/* Mutex */
st7123->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&st7123->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (config->int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (config->levels.interrupt) ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE,
.pin_bit_mask = BIT64(config->int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
/* Register interrupt callback */
if (config->interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(st7123, config->interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (config->rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(config->rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
}
/* Reset controller */
ESP_GOTO_ON_ERROR(reset(st7123), err, TAG, "Reset failed");
ESP_GOTO_ON_ERROR(read_fw_info(st7123), err, TAG, "Read version failed");
ESP_LOGI(TAG, "Touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_ST7123_VER_MAJOR,
ESP_LCD_TOUCH_ST7123_VER_MINOR, ESP_LCD_TOUCH_ST7123_VER_PATCH);
*tp = st7123;
return ESP_OK;
err:
if (st7123) {
del(st7123);
}
ESP_LOGE(TAG, "Initialization failed!");
return ret;
}
static esp_err_t read_data(esp_lcd_touch_handle_t tp)
{
typedef struct {
uint8_t x_h: 6;
uint8_t reserved_6: 1;
uint8_t valid: 1;
uint8_t x_l;
uint8_t y_h;
uint8_t y_l;
uint8_t area;
uint8_t intensity;
uint8_t reserved_49_55;
} touch_report_t;
typedef struct {
uint8_t reserved_0_1: 2;
uint8_t with_prox: 1;
uint8_t with_coord: 1;
uint8_t prox_status: 3;
uint8_t rst_chip: 1;
} adv_info_t;
touch_report_t touch_report[10];
adv_info_t adv_info = { 0 };
uint8_t max_touches = 0;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, 0x0010, (uint8_t *)&adv_info, 1), TAG, "Read advanced info failed");
if (adv_info.with_coord) {
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, MAX_TOUCHES_REG, &max_touches, 1), TAG, "Read max touches failed");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, REPORT_COORD_0_REG, (uint8_t *)&touch_report[0],
sizeof(touch_report_t) * max_touches), TAG, "Read report failed");
}
portENTER_CRITICAL(&tp->data.lock);
/* Fill all coordinates */
int j = 0;
for (int i = 0; (i < max_touches) && (j < CONFIG_ESP_LCD_TOUCH_MAX_POINTS); i++) {
if (!touch_report[i].valid) {
continue;
}
tp->data.coords[j].x = touch_report[i].x_h << 8 | touch_report[i].x_l;
tp->data.coords[j].y = touch_report[i].y_h << 8 | touch_report[i].y_l;
tp->data.coords[j++].strength = touch_report[i].area;
}
/* Expect Number of touched points */
tp->data.points = j;
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Clear available touch points count */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
static esp_err_t del(esp_lcd_touch_handle_t tp)
{
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
}
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
/* Release memory */
free(tp);
return ESP_OK;
}
static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t i2c_read_bytes(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint8_t len)
{
ESP_RETURN_ON_FALSE((len == 0) || (data != NULL), ESP_ERR_INVALID_ARG, TAG, "Invalid data");
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(tp->io, reg, data, len), TAG, "Read param failed");
return ESP_OK;
}
static esp_err_t read_fw_info(esp_lcd_touch_handle_t tp)
{
uint8_t version = 0;
uint8_t revision[4] = { 0 };
struct {
uint8_t max_x_h;
uint8_t max_x_l;
uint8_t max_y_h;
uint8_t max_y_l;
uint8_t max_touches;
} info;
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, FW_VERSION_REG, &version, 1), TAG, "Read version failed");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, FW_REVISION_REG, (uint8_t *)&revision[0], 4), TAG, "Read revision failed");
ESP_RETURN_ON_ERROR(i2c_read_bytes(tp, MAX_X_COORD_H_REG, (uint8_t *)&info, sizeof(info)), TAG, "Read info failed");
ESP_LOGI(TAG, "Firmware version: %d(%d.%d.%d.%d), Max.X: %d, Max.Y: %d, Max.Touchs: %d",
version, revision[0], revision[1], revision[2], revision[3], ((uint16_t)info.max_x_h << 8) | info.max_x_l,
((uint16_t)info.max_y_h << 8) | info.max_y_l, info.max_touches);
return ESP_OK;
}
@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_ST7123_VER_MAJOR (0)
#define ESP_LCD_TOUCH_ST7123_VER_MINOR (0)
#define ESP_LCD_TOUCH_ST7123_VER_PATCH (1)
/**
* @brief Create a new ST7123 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD panel IO handle, it should be created by `esp_lcd_new_panel_io_i2c()`
* @param config Touch panel configuration
* @param tp Touch panel handle
* @return
* - ESP_OK: on success
*/
esp_err_t esp_lcd_touch_new_i2c_st7123(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *tp);
/**
* @brief I2C address of the ST7123 controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_ST7123_ADDRESS (0x55)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_ST7123_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_ST7123_ADDRESS, \
.control_phase_bytes = 1, \
.lcd_cmd_bits = 16, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,369 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ESP_PanelLog.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_tt21100.h"
static const char *TAG = "TT21100";
#define ESP_LCD_TOUCH_TT21100_MAX_DATA_LEN (7+CONFIG_ESP_LCD_TOUCH_MAX_POINTS*10) /* 7 Header + (Points * 10 data bytes) */
/*******************************************************************************
* Function definitions
*******************************************************************************/
static esp_err_t esp_lcd_touch_tt21100_read_data(esp_lcd_touch_handle_t tp);
static bool esp_lcd_touch_tt21100_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
static esp_err_t esp_lcd_touch_tt21100_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
#endif
static esp_err_t esp_lcd_touch_tt21100_del(esp_lcd_touch_handle_t tp);
/* I2C read */
static esp_err_t touch_tt21100_i2c_read(esp_lcd_touch_handle_t tp, uint8_t *data, uint8_t len);
/* TT21100 reset */
static esp_err_t touch_tt21100_reset(esp_lcd_touch_handle_t tp);
/* TT21100 write */
static esp_err_t touch_tt21100_i2c_write(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint16_t len);
static esp_err_t esp_lcd_touch_tt21100_enter_sleep(esp_lcd_touch_handle_t tp);
static esp_err_t esp_lcd_touch_tt21100_exit_sleep(esp_lcd_touch_handle_t tp);
/*******************************************************************************
* Public API functions
*******************************************************************************/
esp_err_t esp_lcd_touch_new_i2c_tt21100(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch)
{
esp_err_t ret = ESP_OK;
assert(config != NULL);
assert(out_touch != NULL);
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
/* Prepare main structure */
esp_lcd_touch_handle_t esp_lcd_touch_tt21100 = heap_caps_calloc(1, sizeof(esp_lcd_touch_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(esp_lcd_touch_tt21100, ESP_ERR_NO_MEM, err, TAG, "no mem for TT21100 controller");
/* Communication interface */
esp_lcd_touch_tt21100->io = io;
/* Only supported callbacks are set */
esp_lcd_touch_tt21100->read_data = esp_lcd_touch_tt21100_read_data;
esp_lcd_touch_tt21100->get_xy = esp_lcd_touch_tt21100_get_xy;
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
esp_lcd_touch_tt21100->get_button_state = esp_lcd_touch_tt21100_get_button_state;
#endif
esp_lcd_touch_tt21100->del = esp_lcd_touch_tt21100_del;
esp_lcd_touch_tt21100->enter_sleep = esp_lcd_touch_tt21100_enter_sleep;
esp_lcd_touch_tt21100->exit_sleep = esp_lcd_touch_tt21100_exit_sleep;
/* Mutex */
esp_lcd_touch_tt21100->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&esp_lcd_touch_tt21100->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (esp_lcd_touch_tt21100->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (esp_lcd_touch_tt21100->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(esp_lcd_touch_tt21100->config.int_gpio_num)
};
ret = gpio_config(&int_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
/* Register interrupt callback */
if (esp_lcd_touch_tt21100->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_tt21100, esp_lcd_touch_tt21100->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (esp_lcd_touch_tt21100->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = BIT64(esp_lcd_touch_tt21100->config.rst_gpio_num)
};
ret = gpio_config(&rst_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
}
/* Reset controller */
ret = touch_tt21100_reset(esp_lcd_touch_tt21100);
ESP_GOTO_ON_ERROR(ret, err, TAG, "TT21100 reset failed");
/* Initial read */
ret = esp_lcd_touch_tt21100_read_data(esp_lcd_touch_tt21100);
ESP_GOTO_ON_ERROR(ret, err, TAG, "TT21100 init failed");
err:
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error (0x%x)! Touch controller TT21100 initialization failed!", ret);
if (esp_lcd_touch_tt21100) {
esp_lcd_touch_tt21100_del(esp_lcd_touch_tt21100);
}
return ret;
}
*out_touch = esp_lcd_touch_tt21100;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_TT21100_VER_MAJOR, ESP_LCD_TOUCH_TT21100_VER_MINOR,
ESP_LCD_TOUCH_TT21100_VER_PATCH);
return ret;
}
static esp_err_t esp_lcd_touch_tt21100_enter_sleep(esp_lcd_touch_handle_t tp)
{
uint8_t power_save_cmd[2] = {0x01, 0x08};
esp_err_t err = touch_tt21100_i2c_write(tp, 0x0500, power_save_cmd, sizeof(power_save_cmd));
ESP_RETURN_ON_ERROR(err, TAG, "Enter Sleep failed!");
return ESP_OK;
}
static esp_err_t esp_lcd_touch_tt21100_exit_sleep(esp_lcd_touch_handle_t tp)
{
uint8_t power_save_cmd[2] = {0x00, 0x08};
esp_err_t err = touch_tt21100_i2c_write(tp, 0x0500, power_save_cmd, sizeof(power_save_cmd));
ESP_RETURN_ON_ERROR(err, TAG, "Exit Sleep failed!");
return ESP_OK;
}
static esp_err_t esp_lcd_touch_tt21100_read_data(esp_lcd_touch_handle_t tp)
{
typedef struct {
uint8_t : 5;
uint8_t touch_type: 3;
uint8_t tip: 1;
uint8_t event_id: 2;
uint8_t touch_id: 5;
uint16_t x;
uint16_t y;
uint8_t pressure;
uint16_t major_axis_length;
uint8_t orientation;
} __attribute__((packed)) touch_record_struct_t;
typedef struct {
uint16_t data_len;
uint8_t report_id;
uint16_t time_stamp;
uint8_t : 2;
uint8_t large_object : 1;
uint8_t record_num : 5;
uint8_t report_counter: 2;
uint8_t : 3;
uint8_t noise_efect: 3;
touch_record_struct_t touch_record[0];
} __attribute__((packed)) touch_report_struct_t;
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
typedef struct {
uint16_t length; /*!< Always 14(0x000E) */
uint8_t report_id; /*!< Always 03h */
uint16_t time_stamp; /*!< Number in units of 100 us */
uint8_t btn_val; /*!< Only use bit[0..3] */
uint16_t btn_signal[4];
} __attribute__((packed)) button_record_struct_t;
#endif
touch_report_struct_t *p_report_data = NULL;
touch_record_struct_t *p_touch_data = NULL;
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
button_record_struct_t *p_btn_data = NULL;
#endif
esp_err_t err;
static uint16_t data_len;
static uint8_t data[ESP_LCD_TOUCH_TT21100_MAX_DATA_LEN];
uint8_t tp_num = 0;
size_t i = 0;
assert(tp != NULL);
/* Get report data length */
err = touch_tt21100_i2c_read(tp, (uint8_t *)&data_len, sizeof(data_len));
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Read report data if length */
if (data_len > 0 && data_len < sizeof(data)) {
touch_tt21100_i2c_read(tp, data, data_len);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
portENTER_CRITICAL(&tp->data.lock);
if (data_len == 14) {
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
/* Button event */
p_btn_data = (button_record_struct_t *) data;
/* Buttons count */
tp->data.buttons = (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS < 4 ? CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS : 4);
for (i = 0; i < tp->data.buttons; i++) {
tp->data.button[i].status = p_btn_data->btn_signal[i];
}
// ESP_LOGD(TAG, "Len : %04Xh. ID : %02Xh. Time : %5u. Val : [%u] - [%04X][%04X][%04X][%04X]",
// p_btn_data->length, p_btn_data->report_id, p_btn_data->time_stamp, p_btn_data->btn_val,
// p_btn_data->btn_signal[0], p_btn_data->btn_signal[1], p_btn_data->btn_signal[2], p_btn_data->btn_signal[3]);
#endif
} else if (data_len >= 7) {
/* Touch point event */
p_report_data = (touch_report_struct_t *) data;
tp_num = (data_len - sizeof(touch_report_struct_t)) / sizeof(touch_record_struct_t);
/* Number of touched points */
tp_num = (tp_num > CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? CONFIG_ESP_LCD_TOUCH_MAX_POINTS : tp_num);
tp->data.points = tp_num;
/* Fill all coordinates */
for (i = 0; i < tp_num; i++) {
p_touch_data = &p_report_data->touch_record[i];
tp->data.coords[i].x = p_touch_data->x;
tp->data.coords[i].y = p_touch_data->y;
tp->data.coords[i].strength = p_touch_data->pressure;
// ESP_LOGD(TAG, "(%zu) [%3u][%3u]", i, p_touch_data->x, p_touch_data->y);
}
}
portEXIT_CRITICAL(&tp->data.lock);
}
return ESP_OK;
}
static bool esp_lcd_touch_tt21100_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num)
{
assert(tp != NULL);
assert(x != NULL);
assert(y != NULL);
assert(point_num != NULL);
assert(max_point_num > 0);
portENTER_CRITICAL(&tp->data.lock);
/* Count of points */
*point_num = (tp->data.points > max_point_num ? max_point_num : tp->data.points);
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
/* Invalidate */
tp->data.points = 0;
portEXIT_CRITICAL(&tp->data.lock);
return (*point_num > 0);
}
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
static esp_err_t esp_lcd_touch_tt21100_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state)
{
esp_err_t err = ESP_OK;
assert(tp != NULL);
assert(state != NULL);
*state = 0;
portENTER_CRITICAL(&tp->data.lock);
if (n > tp->data.buttons) {
err = ESP_ERR_INVALID_ARG;
} else {
*state = tp->data.button[n].status;
}
portEXIT_CRITICAL(&tp->data.lock);
return err;
}
#endif
static esp_err_t esp_lcd_touch_tt21100_del(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
/* Reset GPIO pin settings */
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
if (tp->config.interrupt_callback) {
gpio_isr_handler_remove(tp->config.int_gpio_num);
}
}
/* Reset GPIO pin settings */
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.rst_gpio_num);
}
free(tp);
return ESP_OK;
}
/*******************************************************************************
* Private API function
*******************************************************************************/
/* Reset controller */
static esp_err_t touch_tt21100_reset(esp_lcd_touch_handle_t tp)
{
assert(tp != NULL);
if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level error!");
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
static esp_err_t touch_tt21100_i2c_read(esp_lcd_touch_handle_t tp, uint8_t *data, uint8_t len)
{
assert(tp != NULL);
assert(data != NULL);
/* Read data */
return esp_lcd_panel_io_rx_param(tp->io, -1, data, len);
}
static esp_err_t touch_tt21100_i2c_write(esp_lcd_touch_handle_t tp, uint16_t reg, uint8_t *data, uint16_t len)
{
assert(tp != NULL);
assert(data != NULL);
return esp_lcd_panel_io_tx_param(tp->io, reg, data, len);
}
@@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ESP LCD touch: TT21100
*/
#pragma once
#include "esp_lcd_touch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_TT21100_VER_MAJOR (1)
#define ESP_LCD_TOUCH_TT21100_VER_MINOR (1)
#define ESP_LCD_TOUCH_TT21100_VER_PATCH (6)
/**
* @brief Create a new TT21100 touch driver
*
* @note The I2C communication should be initialized before use this function.
*
* @param io LCD/Touch panel IO handle
* @param config: Touch configuration
* @param out_touch: Touch instance handle
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if there is no memory for allocating main structure
*/
esp_err_t esp_lcd_touch_new_i2c_tt21100(const esp_lcd_panel_io_handle_t io, const esp_lcd_touch_config_t *config, esp_lcd_touch_handle_t *out_touch);
/**
* @brief I2C address of the TT21100 controller
*
*/
#define ESP_LCD_TOUCH_IO_I2C_TT21100_ADDRESS (0x24)
/**
* @brief Touch IO configuration structure
*
*/
#define ESP_LCD_TOUCH_IO_I2C_TT21100_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_TT21100_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 16, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,395 @@
/*
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
*/
#include "ESP_PanelLog.h"
#include <driver/gpio.h>
#include <esp_check.h>
#include <esp_err.h>
#include <esp_lcd_panel_io.h>
#include <esp_rom_gpio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
// This must be included after FreeRTOS includes due to missing include
// for portMUX_TYPE
#include "esp_lcd_touch.h"
#include <memory.h>
#include "sdkconfig.h"
#include "esp_lcd_touch_xpt2046.h"
static const char *TAG = "xpt2046";
#ifdef CONFIG_XPT2046_INTERRUPT_MODE
#define XPT2046_PD0_BIT (0x00)
#else
#define XPT2046_PD0_BIT (0x01)
#endif
#ifdef CONFIG_XPT2046_VREF_ON_MODE
#define XPT2046_PD1_BIT (0x02)
#else
#define XPT2046_PD1_BIT (0x00)
#endif
#define XPT2046_PD_BITS (XPT2046_PD1_BIT | XPT2046_PD0_BIT)
enum xpt2046_registers {
// START ADDR MODE SER/ VREF ADC (PENIRQ)
// 12/8b DFR INT/EXT ENA
Z_VALUE_1 = 0xB0 | XPT2046_PD_BITS, // 1 011 0 0 X X
Z_VALUE_2 = 0xC0 | XPT2046_PD_BITS, // 1 100 0 0 X X
Y_POSITION = 0x90 | XPT2046_PD_BITS, // 1 001 0 0 X X
X_POSITION = 0xD0 | XPT2046_PD_BITS, // 1 101 0 0 X X
BATTERY = 0xA6 | XPT2046_PD_BITS, // 1 010 0 1 1 X
AUX_IN = 0xE6 | XPT2046_PD_BITS, // 1 110 0 1 1 X
TEMP0 = 0x86 | XPT2046_PD_BITS, // 1 000 0 1 1 X
TEMP1 = 0xF6 | XPT2046_PD_BITS, // 1 111 0 1 1 X
};
#if CONFIG_XPT2046_ENABLE_LOCKING
#define XPT2046_LOCK(lock) portENTER_CRITICAL(lock)
#define XPT2046_UNLOCK(lock) portEXIT_CRITICAL(lock)
#else
#define XPT2046_LOCK(lock)
#define XPT2046_UNLOCK(lock)
#endif
static const uint16_t XPT2046_ADC_LIMIT = 4096;
// refer the TSC2046 datasheet https://www.ti.com/lit/ds/symlink/tsc2046.pdf rev F 2008
// TEMP0 reads approx 599.5 mV at 25C (Refer p8 TEMP0 diode voltage vs Vcc chart)
// Vref is approx 2.507V = 2507mV at moderate temperatures (refer p8 Vref vs Temperature chart)
// counts@25C = TEMP0_mV / Vref_mv * XPT2046_ADC_LIMIT
static const float XPT2046_TEMP0_COUNTS_AT_25C = (599.5 / 2507 * XPT2046_ADC_LIMIT);
static esp_err_t xpt2046_read_data(esp_lcd_touch_handle_t tp);
static bool xpt2046_get_xy(esp_lcd_touch_handle_t tp,
uint16_t *x, uint16_t *y,
uint16_t *strength,
uint8_t *point_num,
uint8_t max_point_num);
static esp_err_t xpt2046_del(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_spi_xpt2046(const esp_lcd_panel_io_handle_t io,
const esp_lcd_touch_config_t *config,
esp_lcd_touch_handle_t *out_touch)
{
esp_err_t ret = ESP_OK;
esp_lcd_touch_handle_t handle = NULL;
ESP_PANEL_ENABLE_TAG_DEBUG_LOG();
ESP_GOTO_ON_FALSE(io, ESP_ERR_INVALID_ARG, err, TAG,
"esp_lcd_panel_io_handle_t must not be NULL");
ESP_GOTO_ON_FALSE(config, ESP_ERR_INVALID_ARG, err, TAG,
"esp_lcd_touch_config_t must not be NULL");
handle = (esp_lcd_touch_handle_t)calloc(1, sizeof(esp_lcd_touch_t));
ESP_GOTO_ON_FALSE(handle, ESP_ERR_NO_MEM, err, TAG,
"No memory available for XPT2046 state");
handle->io = io;
handle->read_data = xpt2046_read_data;
handle->get_xy = xpt2046_get_xy;
handle->del = xpt2046_del;
handle->data.lock.owner = portMUX_FREE_VAL;
memcpy(&handle->config, config, sizeof(esp_lcd_touch_config_t));
// this is not yet supported by esp_lcd_touch.
if (config->int_gpio_num != GPIO_NUM_NC) {
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->int_gpio_num),
ESP_ERR_INVALID_ARG, err, TAG, "Invalid GPIO Interrupt Pin");
gpio_config_t cfg;
memset(&cfg, 0, sizeof(gpio_config_t));
esp_rom_gpio_pad_select_gpio(config->int_gpio_num);
cfg.pin_bit_mask = BIT64(config->int_gpio_num);
cfg.mode = GPIO_MODE_INPUT;
// If the user has provided a callback routine for the interrupt enable
// the interrupt mode on the negative edge.
if (config->interrupt_callback) {
cfg.intr_type = GPIO_INTR_NEGEDGE;
}
ESP_GOTO_ON_ERROR(gpio_config(&cfg), err, TAG,
"Configure GPIO for Interrupt failed");
// Connect the user interrupt callback routine.
if (config->interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(handle, config->interrupt_callback);
}
}
err:
if (ret != ESP_OK) {
if (handle) {
xpt2046_del(handle);
handle = NULL;
}
}
*out_touch = handle;
ESP_LOGI(TAG, "LCD touch panel create success, version: %d.%d.%d", ESP_LCD_TOUCH_XPT2046_VER_MAJOR,
ESP_LCD_TOUCH_XPT2046_VER_MINOR, ESP_LCD_TOUCH_XPT2046_VER_PATCH);
return ret;
}
static esp_err_t xpt2046_del(esp_lcd_touch_handle_t tp)
{
if (tp != NULL) {
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
gpio_reset_pin(tp->config.int_gpio_num);
}
}
free(tp);
return ESP_OK;
}
static inline esp_err_t xpt2046_read_register(esp_lcd_touch_handle_t tp, uint8_t reg, uint16_t *value)
{
uint8_t buf[2] = {0, 0};
ESP_RETURN_ON_ERROR(esp_lcd_panel_io_rx_param(tp->io, reg, buf, 2), TAG, "XPT2046 read error!");
*value = ((buf[0] << 8) | (buf[1]));
return ESP_OK;
}
static esp_err_t xpt2046_read_data(esp_lcd_touch_handle_t tp)
{
uint16_t z1 = 0, z2 = 0, z = 0;
uint32_t x = 0, y = 0;
uint8_t point_count = 0;
#ifdef CONFIG_XPT2046_INTERRUPT_MODE
if (tp->config.int_gpio_num != GPIO_NUM_NC) {
// Check the PENIRQ pin to see if there is a touch
if (gpio_get_level(tp->config.int_gpio_num)) {
XPT2046_LOCK(&tp->data.lock);
tp->data.coords[0].x = 0;
tp->data.coords[0].y = 0;
tp->data.coords[0].strength = 0;
tp->data.points = 0;
XPT2046_UNLOCK(&tp->data.lock);
return ESP_OK;
}
}
#endif
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Z_VALUE_1, &z1), TAG, "XPT2046 read error!");
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Z_VALUE_2, &z2), TAG, "XPT2046 read error!");
// Convert the received values into a Z value.
z = (z1 >> 3) + (XPT2046_ADC_LIMIT - (z2 >> 3));
// If the Z (pressure) exceeds the threshold it is likely the user has
// pressed the screen, read in and average the positions.
if (z >= CONFIG_XPT2046_Z_THRESHOLD) {
uint16_t discard_buf = 0;
// read and discard a value as it is usually not reliable.
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, X_POSITION, &discard_buf),
TAG, "XPT2046 read error!");
for (uint8_t idx = 0; idx < CONFIG_ESP_LCD_TOUCH_MAX_POINTS; idx++) {
uint16_t x_temp = 0;
uint16_t y_temp = 0;
// Read X position and convert returned data to 12bit value
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, X_POSITION, &x_temp),
TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit position
x_temp >>= 3;
// Read Y position and convert returned data to 12bit value
ESP_RETURN_ON_ERROR(xpt2046_read_register(tp, Y_POSITION, &y_temp),
TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit position
y_temp >>= 3;
// Test if the readings are valid (50 < reading < max - 50)
if ((x_temp >= 50) && (x_temp <= XPT2046_ADC_LIMIT - 50) && (y_temp >= 50) && (y_temp <= XPT2046_ADC_LIMIT - 50)) {
#if CONFIG_XPT2046_CONVERT_ADC_TO_COORDS
// Convert the raw ADC value into a screen coordinate and store it
// for averaging.
x += ((x_temp / (double)XPT2046_ADC_LIMIT) * tp->config.x_max);
y += ((y_temp / (double)XPT2046_ADC_LIMIT) * tp->config.y_max);
#else
// store the raw ADC values and let the user convert them to screen
// coordinates.
x += x_temp;
y += y_temp;
#endif // CONFIG_XPT2046_CONVERT_ADC_TO_COORDS
point_count++;
}
}
// Check we had enough valid values
const int minimum_count = (1 == CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? 1 : CONFIG_ESP_LCD_TOUCH_MAX_POINTS / 2);
if (point_count >= minimum_count) {
// Average the accumulated coordinate data points.
x /= point_count;
y /= point_count;
point_count = 1;
} else {
z = 0;
point_count = 0;
}
}
XPT2046_LOCK(&tp->data.lock);
tp->data.coords[0].x = x;
tp->data.coords[0].y = y;
tp->data.coords[0].strength = z;
tp->data.points = point_count;
XPT2046_UNLOCK(&tp->data.lock);
return ESP_OK;
}
static bool xpt2046_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y,
uint16_t *strength, uint8_t *point_num,
uint8_t max_point_num)
{
XPT2046_LOCK(&tp->data.lock);
// Determine how many touch points that are available.
if (tp->data.points > max_point_num) {
*point_num = max_point_num;
} else {
*point_num = tp->data.points;
}
for (size_t i = 0; i < *point_num; i++) {
x[i] = tp->data.coords[i].x;
y[i] = tp->data.coords[i].y;
if (strength) {
strength[i] = tp->data.coords[i].strength;
}
}
// Invalidate stored touch data.
tp->data.points = 0;
XPT2046_UNLOCK(&tp->data.lock);
if (*point_num) {
ESP_LOGD(TAG, "Touch point: %dx%d", x[0], y[0]);
} else {
ESP_LOGV(TAG, "No touch points");
}
return (*point_num > 0);
}
esp_err_t esp_lcd_touch_xpt2046_read_battery_level(const esp_lcd_touch_handle_t handle, float *output)
{
uint16_t level;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, BATTERY, &level), TAG, "XPT2046 read error!");
#endif
// Read the battery voltage
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, BATTERY, &level), TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit value
level >>= 3;
// battery voltage is reported as 1/4 the actual voltage due to logic in
// the chip.
*output = level * 4.0;
// adjust for internal vref of 2.5v
*output *= 2.507f;
// adjust for ADC bit count
*output /= 4096.0f;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// Final read is to turn the Vref off
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &level), TAG, "XPT2046 read error!");
#endif
return ESP_OK;
}
esp_err_t esp_lcd_touch_xpt2046_read_aux_level(const esp_lcd_touch_handle_t handle, float *output)
{
uint16_t level;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, AUX_IN, &level), TAG, "XPT2046 read error!");
#endif
// Read the aux input voltage
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, AUX_IN, &level), TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit value
level >>= 3;
*output = level;
// adjust for internal vref of 2.5v
*output *= 2.507f;
// adjust for ADC bit count
*output /= 4096.0f;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// Final read is to turn on the ADC and the Vref off
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &level), TAG, "XPT2046 read error!");
#endif
return ESP_OK;
}
esp_err_t esp_lcd_touch_xpt2046_read_temp0_level(const esp_lcd_touch_handle_t handle, float *output)
{
uint16_t temp0;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
#endif
// Read the temp0 value
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit value
temp0 >>= 3;
*output = temp0;
// Convert to temperature in degrees C
*output = (XPT2046_TEMP0_COUNTS_AT_25C - *output) * (2.507 / 4096.0) / 0.0021 + 25.0;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// Final read is to turn on the ADC and the Vref off
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &temp0), TAG, "XPT2046 read error!");
#endif
return ESP_OK;
}
esp_err_t esp_lcd_touch_xpt2046_read_temp1_level(const esp_lcd_touch_handle_t handle, float *output)
{
uint16_t temp0;
uint16_t temp1;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// First read is to turn on the Vref, so it has extra time to stabilise before we read it for real
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
#endif
// Read the temp0 value
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP0, &temp0), TAG, "XPT2046 read error!");
// Read the temp1 value
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, TEMP1, &temp1), TAG, "XPT2046 read error!");
// drop lowest three bits to convert to 12-bit value
temp0 >>= 3;
temp1 >>= 3;
*output = temp1 - temp0;
*output = *output * 1000.0 * (2.507 / 4096.0) * 2.573 - 273.0;
#ifndef CONFIG_XPT2046_VREF_ON_MODE
// Final read is to turn on the ADC and the Vref off
ESP_RETURN_ON_ERROR(xpt2046_read_register(handle, Z_VALUE_1, &temp0), TAG, "XPT2046 read error!");
#endif
return ESP_OK;
}
@@ -0,0 +1,235 @@
/*
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
*/
#pragma once
#include "esp_idf_version.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_panel_io.h"
#include "ESP_Panel_Conf_Internal.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_LCD_TOUCH_XPT2046_VER_MAJOR (1)
#define ESP_LCD_TOUCH_XPT2046_VER_MINOR (0)
#define ESP_LCD_TOUCH_XPT2046_VER_PATCH (4)
#define CONFIG_XPT2046_Z_THRESHOLD (ESP_PANEL_TOUCH_XPT2046_Z_THRESHOLD)
#define CONFIG_XPT2046_INTERRUPT_MODE (ESP_PANEL_TOUCH_XPT2046_INTERRUPT_MODE)
#define CONFIG_XPT2046_VREF_ON_MODE (ESP_PANEL_TOUCH_XPT2046_XPT2046_VREF_ON_MODE)
#define CONFIG_XPT2046_CONVERT_ADC_TO_COORDS (ESP_PANEL_TOUCH_XPT2046_CONVERT_ADC_TO_COORDS)
/**
* @brief Recommended clock for SPI read of the XPT2046
*
*/
#define ESP_LCD_TOUCH_SPI_CLOCK_HZ (1 * 1000 * 1000)
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)
/**
* @brief Communication SPI device IO structure
*
*/
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
{ \
.cs_gpio_num = (gpio_num_t)touch_cs, \
.dc_gpio_num = GPIO_NUM_NC, \
.spi_mode = 0, \
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
.trans_queue_depth = 3, \
.on_color_trans_done = NULL, \
.user_ctx = NULL, \
.lcd_cmd_bits = 8, \
.lcd_param_bits = 8, \
.flags = \
{ \
.dc_as_cmd_phase = 0, \
.dc_low_on_data = 0, \
.octal_mode = 0, \
.lsb_first = 0 \
} \
}
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,0)
/**
* @brief Communication SPI device IO structure
*
*/
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
{ \
.cs_gpio_num = (gpio_num_t)touch_cs, \
.dc_gpio_num = GPIO_NUM_NC, \
.spi_mode = 0, \
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
.trans_queue_depth = 3, \
.on_color_trans_done = NULL, \
.user_ctx = NULL, \
.lcd_cmd_bits = 8, \
.lcd_param_bits = 8, \
.flags = \
{ \
.dc_low_on_data = 0, \
.octal_mode = 0, \
.lsb_first = 0 \
} \
}
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,2)
/**
* @brief Communication SPI device IO structure
*
*/
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
{ \
.cs_gpio_num = (gpio_num_t)touch_cs, \
.dc_gpio_num = GPIO_NUM_NC, \
.spi_mode = 0, \
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
.trans_queue_depth = 3, \
.on_color_trans_done = NULL, \
.user_ctx = NULL, \
.lcd_cmd_bits = 8, \
.lcd_param_bits = 8, \
.flags = \
{ \
.dc_low_on_data = 0, \
.octal_mode = 0, \
.sio_mode = 0, \
.lsb_first = 0, \
.cs_high_active = 0 \
} \
}
#elif ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,1,3)
/**
* @brief Communication SPI device IO structure
*
*/
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
{ \
.cs_gpio_num = (gpio_num_t)touch_cs, \
.dc_gpio_num = GPIO_NUM_NC, \
.spi_mode = 0, \
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
.trans_queue_depth = 3, \
.on_color_trans_done = NULL, \
.user_ctx = NULL, \
.lcd_cmd_bits = 8, \
.lcd_param_bits = 8, \
.flags = \
{ \
.dc_low_on_data = 0, \
.octal_mode = 0, \
.quad_mode = 0, \
.sio_mode = 0, \
.lsb_first = 0, \
.cs_high_active = 0 \
} \
}
#else
/**
* @brief Communication SPI device IO structure
*
*/
#define ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(touch_cs) \
{ \
.cs_gpio_num = (gpio_num_t)touch_cs, \
.dc_gpio_num = GPIO_NUM_NC, \
.spi_mode = 0, \
.pclk_hz = ESP_LCD_TOUCH_SPI_CLOCK_HZ, \
.trans_queue_depth = 3, \
.on_color_trans_done = NULL, \
.user_ctx = NULL, \
.lcd_cmd_bits = 8, \
.lcd_param_bits = 8, \
.flags = \
{ \
.dc_high_on_cmd = 0, \
.dc_low_on_data = 0, \
.dc_low_on_param = 0, \
.octal_mode = 0, \
.quad_mode = 0, \
.sio_mode = 0, \
.lsb_first = 0, \
.cs_high_active = 0 \
} \
}
#endif // IDF v5.1.3
/**
* @brief Create a new XPT2046 touch driver
*
* @note The SPI communication should be initialized before use this function.
*
* @param io: LCD/Touch panel IO handle.
* @param config: Touch configuration.
* @param out_touch: XPT2046 instance handle.
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if there is insufficient memory for allocating main structure.
* - ESP_ERR_INVALID_ARG if @param io or @param config are null.
*/
esp_err_t esp_lcd_touch_new_spi_xpt2046(const esp_lcd_panel_io_handle_t io,
const esp_lcd_touch_config_t *config,
esp_lcd_touch_handle_t *out_touch);
/**
* @brief Reads the voltage from the v-bat pin of the XPT2046.
*
* @param handle: XPT2046 instance handle.
* @param out_level: Approximate voltage read in from the v-bat pin.
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*
* @note The v-bat pin has a voltage range of 0.0 to 6.0 volts.
*/
esp_err_t esp_lcd_touch_xpt2046_read_battery_level(const esp_lcd_touch_handle_t handle, float *out_level);
/**
* @brief Reads the voltage from the aux pin of the XPT2046.
*
* @param handle: XPT2046 instance handle.
* @param out_level: Approximate voltage read in from the aux pin.
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*
* @note The aux pin has a voltage range of 0.0 to 2.5 volts.
*/
esp_err_t esp_lcd_touch_xpt2046_read_aux_level(const esp_lcd_touch_handle_t handle, float *out_level);
/**
* @brief Reads the temperature from the XPT2046 using a one-point reading.
* High precision (0.3 degrees C) but low accuracy requires a
* calibration offset for accurate results.
*
* @param handle: XPT2046 instance handle.
* @param out_level: Approximate tempreature of the TSC2046 in degrees C
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t esp_lcd_touch_xpt2046_read_temp0_level(const esp_lcd_touch_handle_t handle, float *output);
/**
* @brief Reads the temperature from the XPT2046 using a two-point reading.
* Low precision (1.6 degrees C) but high accuracy requires no calibration.
*
* @param handle: XPT2046 instance handle.
* @param out_level: Approximate tempreature of the TSC2046 in degrees C
* @return
* - ESP_OK on success, otherwise returns ESP_ERR_xxx
*/
esp_err_t esp_lcd_touch_xpt2046_read_temp1_level(const esp_lcd_touch_handle_t handle, float *output);
#ifdef __cplusplus
}
#endif