-
Notifications
You must be signed in to change notification settings - Fork 77
/
esp_lcd_touch_cst816s.c
184 lines (157 loc) · 5.84 KB
/
esp_lcd_touch_cst816s.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#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"
#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");
/* 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,
.pin_bit_mask = BIT64(cst816s->config.int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
}
/* 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,
.intr_type = GPIO_INTR_NEGEDGE,
.pin_bit_mask = BIT64(cst816s->config.rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
/* Register interrupt callback */
if (cst816s->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(cst816s, cst816s->config.interrupt_callback);
}
}
/* 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;
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.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_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);
}