First commit with working display

This commit is contained in:
Ricardo LAP
2026-09-13 20:50:51 +00:00
parent a83af259b3
commit c54c68c899
6690 changed files with 1093387 additions and 2 deletions

View File

@@ -0,0 +1 @@
7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998

View File

@@ -0,0 +1 @@
.vscode

View File

@@ -0,0 +1,46 @@
# Change log for esp_lcd_touch_xpt2046
## v1.0.6 - new features
* Fixing interrupt mode via PR https://github.com/atanisoft/esp_lcd_touch_xpt2046/pull/11
## v1.0.5 - new features
* support for interrupt triggered wake-up for reading, thanks @ttt470!
## v1.0.4 - New features
* Add ability to read voltage level from Aux pin.
* Add ability to read temperature using the TEMP0 register (one point mode).
* Add ability to read temperature using the TEMP0 and TEMP1 registers (two point mode).
* Enable PENIRQ pin output when touched (if configured).
* Enable use of PENIRQ input to test for touch (if PENIRQ input pin configured).
* Allow leaving Vref permanently on (if configured). Increases power usage but reduces SPI transactions for temperature and voltage reads.
* Fixes battery voltage read (was scaled incorrectly).
* Fixes coordinate averaging (fix random bad clicks).
* Adjusts Vref voltage to reflect value in typical usage conditions.
## v1.0.3 - Minor Bug fixes
* Add new parameters to ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG macro based on IDF v5.1.2 and v5.1.3+.
## v1.0.2 - New features
* Set minimum version for esp_lcd_touch to 1.0.4.
* Add touch interrupt callback functionality.
* Add abilitty to read voltage level from vBat pin.
* Enable ADC during read of X/Y coords (Z already was enabled).
* Add IDF v5.1 esp_lcd_panel_io_spi_config_t updates.
* Fixing interrupt gpio pin reference during initialization.
## v1.0.1 - Bug fix release
* Fixing typo in configuration options.
* Removing usage of temporary array of coordinates.
* Adjustments to ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG for IDF v5.0-rc1.
* Add option to return raw coordinate data instead of converting to screen coordinates.
## v1.0.0 - Initial release
This release is the first revision of this component.

View File

@@ -0,0 +1 @@
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-05-21T14:04:59.865531+00:00", "files": [{"path": "esp_lcd_touch_xpt2046.c", "size": 14414, "hash": "b5923d99652b98771ad273bf26ab8d0fe9eec0912f8817818c8347427ae5540e"}, {"path": "CMakeLists.txt", "size": 156, "hash": "6860d27cc0e82589c8b145b30b4f35320e3feea9e033eebfa81eba2eebf4dcfa"}, {"path": "LICENSE", "size": 1069, "hash": "21a7c428a2b3cd90ac1f3c9c03ec3eea7d81f4ec01875ae0aa22a00d8cdbb74a"}, {"path": "CHANGELOG.md", "size": 1800, "hash": "e72bbb3371dd7d4509d403eeacb040016a8d7d32b6dc1c107c7f8071ccb7f66e"}, {"path": "idf_component.yml", "size": 339, "hash": "609077dfccdcda8c4151e3a03a2b757aa04aaafbbe02f9cb2dcd6a88eda89261"}, {"path": "README.md", "size": 4460, "hash": "e996d9678ce36350e267c18ad78d7834ae2e4bc426eee1aa63557aff06e1b39c"}, {"path": ".gitignore", "size": 7, "hash": "27bf025903b14c7d22e5415f78b31443828f0a7ecff34a2d7e722624550282d6"}, {"path": "Kconfig.projbuild", "size": 1821, "hash": "1619cadb78906a65020ddf3509d9cfc4a472b36e6195008ee49bc6373c818511"}, {"path": "include/esp_lcd_touch_xpt2046.h", "size": 9063, "hash": "32919e82cb73cb6b412d22c5dab527adb31ac0ee707252f382005573c97ceaf3"}]}

View File

@@ -0,0 +1,4 @@
idf_component_register(SRCS "esp_lcd_touch_xpt2046.c"
INCLUDE_DIRS "include"
REQUIRES "driver esp_lcd_touch")

View File

@@ -0,0 +1,44 @@
menu "XPT2046"
config XPT2046_Z_THRESHOLD
int "Minimum Z pressure threshold"
default 400
help
Touch pressure less than this value will be discarded as invalid
and no touch position data collected.
config XPT2046_INTERRUPT_MODE
bool "Enable Interrupt (PENIRQ) output"
default n
help
Also called Full Power Mode.
Enable this to configure the XPT2046 to output low on the PENIRQ output
if a touch is detected.
This mode uses more power when enabled.
Note that this signal goes low normally when a read is active.
config XPT2046_VREF_ON_MODE
bool "Keep internal Vref enabled"
default n
help
Enable this to keep the internal Vref enabled between conversions.
This uses slightly more power, but requires fewer transactions when
reading the battery voltage, aux voltage and temperature.
config XPT2046_CONVERT_ADC_TO_COORDS
bool "Convert touch coordinates to screen coordinates"
default y
help
When this option is enabled the raw ADC values will be converted from
0-4096 to 0-{screen width} or 0-{screen height}.
When this option is disabled the process_coordinates method will need
to be used to convert the raw ADC values into a screen coordinate.
config XPT2046_ENABLE_LOCKING
bool "Enable data structure locking"
default n
help
By enabling this option the XPT2046 driver will lock the touch position
data structures when reading values from the XPT2046 and when reading
position data via API.
WARNING: enabling this option may result in unintended crashes.
endmenu

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Mike Dunston
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,127 @@
# esp_lcd_touch driver for XPT2046 devices
Implementation of the XPT2046 Touch controller with esp_lcd_touch component.
| Touch controller | Communication interface | Component name | Link to datasheet |
| :------------: | :---------------------: | :------------: | :---------------: |
| XPT2046 | SPI | esp_lcd_touch_xpt2046 | [Specification](https://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) |
## Adding this component in your project
This package can be added to your project in two ways:
1. Using [Espressif's component service](https://components.espressif.com/) as:
```
dependencies:
atanisoft/esp_lcd_touch_xpt2046: "~1.0.0"
```
2. Using the git repository directly:
```
dependencies:
esp_lcd_touch_xpt2046:
git: https://github.com/atanisoft/esp_lcd_touch_xpt2046.git
```
For more information on the usage of the `idf_component.yml` file please refer to [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).
## Supported platforms
At this time testing is limited to ESP32 and ESP32-S3, other ESP32 variants should work but are not tested.
## Configuration options
`Kconfig.projbuild` contains a handful of options to allow customization of the XPT2046 interface:
* XPT2046_Z_THRESHOLD - This is the minimum ADC threshold to use for detecting touch points.
* XPT2046_INTERRUPT_MODE - This option enables / disables the PENIRQ output from the chip. If enabled (and the `int_gpio_num` is set) the driver can check for touch more efficiently by reading the input.
* XPT2046_VREF_ON_MODE - This option enables / disables keeping the internal Vref permanently enabled. This uses more power, but requires fewer SPI transactions when reading the battery voltage, aux voltage and temperature.
* XPT2046_CONVERT_ADC_TO_COORDS - This option enables / disables the conversion of raw ADC values into screen coordinates. When disabled it will be necessary to define the `process_coordinates` method in `esp_lcd_touch_config_t`. This can be useful for applying calibration or other offsets to adjust the screen coordinates.
* XPT2046_ENABLE_LOCKING - This option enables / disables the usage of critical sections to protect internal data structures. This has been seen to cause conflicts with other components at times.
## Example usage
### Initialization
```
esp_lcd_touch_handle_t tp = NULL;
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
esp_lcd_panel_io_spi_config_t tp_io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(TOUCH_CS_PIN);
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI2_HOST, &tp_io_config, &tp_io_handle));
esp_lcd_touch_config_t tp_cfg = {
.x_max = CONFIG_LCD_HRES,
.y_max = CONFIG_LCD_VRES,
.rst_gpio_num = -1,
.int_gpio_num = -1,
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
ESP_LOGI(TAG, "Initialize touch controller XPT2046");
ESP_ERROR_CHECK(esp_lcd_touch_new_spi_xpt2046(tp_io_handle, &tp_cfg, &tp));
```
### Updating touch point data
This will read new data from the touch controller and store it in SRAM. This method
should be called on a regular basis.
```
ESP_ERROR_CHECK(esp_lcd_touch_read_data(tp));
```
### Retrieving touch point(s)
This will retrieve the latest averaged touch point data from SRAM.
```
uint16_t x[1];
uint16_t y[1];
uint16_t strength[1];
uint8_t count = 0;
bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, x, y, strength, &count, 1);
```
### Integrating with LVGL
This driver can be integrated with LVGL using code similar to below:
```
void touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
uint16_t x[1];
uint16_t y[1];
uint16_t strength[1];
uint8_t count = 0;
// Update touch point data.
ESP_ERROR_CHECK(esp_lcd_touch_read_data(tp));
data->state = LV_INDEV_STATE_REL;
if (esp_lcd_touch_get_coordinates(tp, x, y, strength, &count, 1))
{
data->point.x = x[0];
data->point.y = y[0];
data->state = LV_INDEV_STATE_PR;
}
data->continue_reading = false;
}
void initialize_input()
{
lv_indev_drv_t indev_drv;
lv_indev_drv_init( &indev_drv );
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touch_driver_read;
lv_indev_drv_register( &indev_drv );
}
```

View File

@@ -0,0 +1,415 @@
/*
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
*
* SPDX-License-Identifier: MIT
*/
#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"
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_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));
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;
cfg.intr_type = (config->levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE);
// 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);
}
#if CONFIG_XPT2046_INTERRUPT_MODE
// Read a register to enable Low Power mode, which is required for interrupt to work.
uint8_t battery = 0;
ESP_GOTO_ON_ERROR(esp_lcd_panel_io_rx_param(handle->io, BATTERY, &battery, 1), err, TAG, "XPT2046 read error!");
#endif
}
err:
if (ret != ESP_OK)
{
if (handle)
{
xpt2046_del(handle);
handle = NULL;
}
}
*out_touch = handle;
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;
}

View File

@@ -0,0 +1,10 @@
dependencies:
esp_lcd_touch: '>=1.0.4'
idf: '>=4.4'
description: esp_lcd_touch driver for XPT2046 touch controllers.
repository: git://github.com/atanisoft/esp_lcd_touch_xpt2046.git
repository_info:
commit_sha: 05f4ecb82f19e4aa11b855a8e57539ba34e9629c
path: .
url: https://github.com/atanisoft/esp_lcd_touch_xpt2046
version: 1.0.6

View File

@@ -0,0 +1,222 @@
/*
* SPDX-FileCopyrightText: 2022 atanisoft (github.com/atanisoft)
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "esp_idf_version.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_panel_io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @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