First commit with working display
This commit is contained in:
@@ -0,0 +1 @@
|
||||
7e6381b67b6e487379118368b8e91624dc87036ef5734818de1db9eb35697998
|
||||
1
managed_components/atanisoft__esp_lcd_touch_xpt2046/.gitignore
vendored
Normal file
1
managed_components/atanisoft__esp_lcd_touch_xpt2046/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vscode
|
||||
@@ -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.
|
||||
@@ -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"}]}
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
idf_component_register(SRCS "esp_lcd_touch_xpt2046.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES "driver esp_lcd_touch")
|
||||
@@ -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
|
||||
21
managed_components/atanisoft__esp_lcd_touch_xpt2046/LICENSE
Normal file
21
managed_components/atanisoft__esp_lcd_touch_xpt2046/LICENSE
Normal 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.
|
||||
127
managed_components/atanisoft__esp_lcd_touch_xpt2046/README.md
Normal file
127
managed_components/atanisoft__esp_lcd_touch_xpt2046/README.md
Normal 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 );
|
||||
}
|
||||
|
||||
```
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user