Tactility/Drivers/AXS5106/esp_lcd_touch_axs5106.c
Ken Van Hoeylandt 980b115f1d
Add board: Waveshare S3 Touch LCD 1.47 (#328)
Touch isn't working yet.
Fixed a SPI lock issue.
2025-09-12 23:45:37 +02:00

260 lines
8.2 KiB
C

#include <stdio.h>
#include "esp_lcd_touch_axs5106.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 "esp_lcd_panel_io.h"
#include "esp_lcd_touch.h"
static const char *TAG = "esp_lcd_touch_axs5106";
#define TOUCH_AXS5106_TOUCH_POINTS_REG (0X01)
#define TOUCH_AXS5106_TOUCH_P1_XH_REG (0x03)
#define TOUCH_AXS5106_TOUCH_P1_XL_REG (0x04)
#define TOUCH_AXS5106_TOUCH_P1_YH_REG (0x05)
#define TOUCH_AXS5106_TOUCH_P1_YL_REG (0x06)
#define TOUCH_AXS5106_TOUCH_ID_REG (0x08)
#define TOUCH_AXS5106_TOUCH_P2_XH_REG (0x09)
#define TOUCH_AXS5106_TOUCH_P2_XL_REG (0x0A)
#define TOUCH_AXS5106_TOUCH_P2_YH_REG (0x0B)
#define TOUCH_AXS5106_TOUCH_P2_YL_REG (0x0C)
/*******************************************************************************
* Function definitions
*******************************************************************************/
static esp_err_t esp_lcd_touch_axs5106_read_data(esp_lcd_touch_handle_t tp);
static bool esp_lcd_touch_axs5106_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_axs5106_del(esp_lcd_touch_handle_t tp);
/* I2C read */
static esp_err_t touch_axs5106_i2c_write(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len);
static esp_err_t touch_axs5106_i2c_read(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len);
/* AXS5106 init */
static esp_err_t touch_axs5106_init(esp_lcd_touch_handle_t tp);
/* AXS5106 reset */
static esp_err_t touch_axs5106_reset(esp_lcd_touch_handle_t tp);
esp_err_t esp_lcd_touch_new_i2c_axs5106(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);
/* Prepare main structure */
esp_lcd_touch_handle_t esp_lcd_touch_axs5106 = heap_caps_calloc(1, sizeof(esp_lcd_touch_t), MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(esp_lcd_touch_axs5106, ESP_ERR_NO_MEM, err, TAG, "no mem for AXS5106 controller");
/* Communication interface */
esp_lcd_touch_axs5106->io = io;
/* Only supported callbacks are set */
esp_lcd_touch_axs5106->read_data = esp_lcd_touch_axs5106_read_data;
esp_lcd_touch_axs5106->get_xy = esp_lcd_touch_axs5106_get_xy;
esp_lcd_touch_axs5106->del = esp_lcd_touch_axs5106_del;
/* Mutex */
esp_lcd_touch_axs5106->data.lock.owner = portMUX_FREE_VAL;
/* Save config */
memcpy(&esp_lcd_touch_axs5106->config, config, sizeof(esp_lcd_touch_config_t));
/* Prepare pin for touch interrupt */
if (esp_lcd_touch_axs5106->config.int_gpio_num != GPIO_NUM_NC)
{
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.intr_type = (esp_lcd_touch_axs5106->config.levels.interrupt ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE),
.pin_bit_mask = BIT64(esp_lcd_touch_axs5106->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_axs5106->config.interrupt_callback)
{
esp_lcd_touch_register_interrupt_callback(esp_lcd_touch_axs5106, esp_lcd_touch_axs5106->config.interrupt_callback);
}
}
/* Prepare pin for touch controller reset */
if (esp_lcd_touch_axs5106->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_axs5106->config.rst_gpio_num)};
ret = gpio_config(&rst_gpio_config);
ESP_GOTO_ON_ERROR(ret, err, TAG, "GPIO config failed");
}
/* Reset controller */
ret = touch_axs5106_reset(esp_lcd_touch_axs5106);
ESP_GOTO_ON_ERROR(ret, err, TAG, "AXS5106 reset failed");
/* Init controller */
ret = touch_axs5106_init(esp_lcd_touch_axs5106);
ESP_GOTO_ON_ERROR(ret, err, TAG, "AXS5106 init failed");
uint8_t data[3] = { 0 };
if (touch_axs5106_i2c_read(esp_lcd_touch_axs5106, TOUCH_AXS5106_TOUCH_ID_REG, data, 3) == ESP_OK) {
if (data[0] != 0x00) {
ESP_LOGI(TAG, "Read: %02x %02x %02x", data[0], data[1], data[2]);
} else {
ESP_LOGW(TAG, "Failed to read id: received zeroes");
}
} else {
ESP_LOGE(TAG, "Failed to read id: receive failed");
}
err:
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Error (0x%x)! Touch controller AXS5106 initialization failed!", ret);
if (esp_lcd_touch_axs5106)
{
esp_lcd_touch_axs5106_del(esp_lcd_touch_axs5106);
}
}
*out_touch = esp_lcd_touch_axs5106;
return ret;
}
static esp_err_t esp_lcd_touch_axs5106_read_data(esp_lcd_touch_handle_t tp)
{
uint8_t data[30] = {0};
size_t i = 0;
assert(tp != NULL);
esp_err_t err = touch_axs5106_i2c_read(tp, TOUCH_AXS5106_TOUCH_POINTS_REG, data, 14);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error: %s", esp_err_to_name(err));
uint8_t points = data[1];
points = points & 0x0F;
if (points == 0)
{
return ESP_OK;
}
/* Number of touched points */
points = (points > 2 ? 2 : points);
// err = touch_axs5106_i2c_read(tp, TOUCH_AXS5106_TOUCH_P1_XH_REG, 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].y = (((uint16_t)(data[4 + i * 6] & 0x0f)) << 8);
tp->data.coords[i].y |= data[5 + i * 6];
tp->data.coords[i].x = ((uint16_t)(data[2 + i * 6] & 0x0f)) << 8;
tp->data.coords[i].x |= data[3 + i * 6];
}
portEXIT_CRITICAL(&tp->data.lock);
return ESP_OK;
}
static bool esp_lcd_touch_axs5106_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_axs5106_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;
}
static esp_err_t touch_axs5106_i2c_write(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len)
{
assert(tp != NULL);
return esp_lcd_panel_io_tx_param(tp->io, reg, data, len);
}
static esp_err_t touch_axs5106_i2c_read(esp_lcd_touch_handle_t tp, uint8_t reg, uint8_t *data, uint8_t len)
{
assert(tp != NULL);
assert(data != NULL);
return esp_lcd_panel_io_rx_param(tp->io, reg, data, len);
}
static esp_err_t touch_axs5106_init(esp_lcd_touch_handle_t tp)
{
return ESP_OK;
}
static esp_err_t touch_axs5106_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;
}