## 简介
从以下官方的的开发板简介可知,板子配置了电容触摸接口。我们基于此硬件基础上验证触摸功能。
> D133CBV-QFN88-V1-2 是一款基于 D13x 芯片设计的人机交互应用开发板,配备 7 寸 LVDS 显示屏以及电容触摸屏,同时预留 MIPI 屏幕、电阻触摸屏接口。开发板集成了 USB 烧录、TF-Card 升级烧录、JTAG、串口打印等调试接口,方便调试开发。开发板集成 16MB NOR FLASH 并可兼容 NAND,同时引出 USB Host、CAN、RS485、SDIO WIFI、以太网、Speaker、数字 MIC、蜂鸣器等功能,预留 I2S、I2C、UART 等接口,方便用户快速进行技术预研与产品开发,满足用户对不同人机交互场景的开发需求。
硬件链接
从硬件原理图上可以看出电容触摸屏硬件上有四根PIN脚和MCU 连接。
对应连接关系如下:
PA8 I2C2_SDA
PA9 I2C2_SCL
PA10 RST
PA11 INT
通过 Menuconfig 开启如下touch GT911 配置开关即可将touch 驱动程序加入工程编译。
编译后下载运行终端输入list_device 命令发现系统的驱动设备中已经添加了touch 设备。
对应的驱动代码如下:
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-13 RiceChen the first version
* 2023-04-30 Geo modified for ArtInChip
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#define DBG_TAG "gt911"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "gt911.h"
static struct rt_i2c_client gt911_client;
static rt_uint8_t GT911_CFG_TBL[] = {
0x6b, 0x00, 0x04, 0x58, 0x02, 0x05, 0x0d, 0x00, 0x01, 0x0f, 0x28, 0x0f,
0x50, 0x32, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x8a, 0x2a, 0x0c, 0x45, 0x47, 0x0c, 0x08, 0x00, 0x00,
0x00, 0x40, 0x03, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
0x00, 0x00, 0x00, 0x28, 0x64, 0x94, 0xd5, 0x02, 0x07, 0x00, 0x00, 0x04,
0x95, 0x2c, 0x00, 0x8b, 0x34, 0x00, 0x82, 0x3f, 0x00, 0x7d, 0x4c, 0x00,
0x7a, 0x5b, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a,
0x08, 0x06, 0x04, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x24, 0x13, 0x12, 0x10, 0x0f,
0x0a, 0x08, 0x06, 0x04, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x79, 0x01,
};
static rt_err_t gt911_write_reg(struct rt_i2c_client *dev, rt_uint8_t *data,
rt_uint8_t len)
{
struct rt_i2c_msg msgs;
msgs.addr = dev->client_addr;
msgs.flags = RT_I2C_WR;
msgs.buf = data;
msgs.len = len;
if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1) {
return RT_EOK;
} else {
return -RT_ERROR;
}
}
static rt_err_t gt911_read_regs(struct rt_i2c_client *dev, rt_uint8_t *reg,
rt_uint8_t *data, rt_uint8_t len)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = dev->client_addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = reg;
msgs[0].len = GT911_REGITER_LEN;
msgs[1].addr = dev->client_addr;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = data;
msgs[1].len = len;
if (rt_i2c_transfer(dev->bus, msgs, 2) == 2) {
return RT_EOK;
} else {
return -RT_ERROR;
}
}
static rt_err_t gt911_get_product_id(struct rt_i2c_client *dev,
rt_uint8_t *data, rt_uint8_t len)
{
rt_uint8_t reg[2];
reg[0] = (rt_uint8_t)(GT911_PRODUCT_ID >> 8);
reg[1] = (rt_uint8_t)(GT911_PRODUCT_ID & 0xff);
if (gt911_read_regs(dev, reg, data, len) != RT_EOK) {
LOG_E("read id failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_get_info(struct rt_i2c_client *dev,
struct rt_touch_info *info)
{
rt_uint8_t reg[2];
rt_uint8_t out_info[7];
rt_uint8_t out_len = 7;
reg[0] = (rt_uint8_t)(GT911_CONFIG_REG >> 8);
reg[1] = (rt_uint8_t)(GT911_CONFIG_REG & 0xFF);
if (gt911_read_regs(dev, reg, out_info, out_len) != RT_EOK) {
LOG_E("read info failed");
return -RT_ERROR;
}
info->range_x = (out_info[2] << 8) | out_info[1];
info->range_y = (out_info[4] << 8) | out_info[3];
info->point_num = out_info[5] & 0x0f;
return RT_EOK;
}
#if 0
static rt_err_t gt911_soft_reset(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_COMMAND_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_COMMAND_REG & 0xFF);
buf[2] = 0x02;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("soft reset failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_soft_reset_finish(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_COMMAND_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_COMMAND_REG & 0xFF);
buf[2] = 0x00;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("soft reset failed");
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t gt911_set_irq_pin_int(struct rt_i2c_client *dev)
{
rt_uint8_t buf[3];
buf[0] = (rt_uint8_t)(GT911_MOD_SWT_REG >> 8);
buf[1] = (rt_uint8_t)(GT911_MOD_SWT_REG & 0xFF);
buf[2] = 0x01;
if (gt911_write_reg(dev, buf, 3) != RT_EOK) {
LOG_E("set up failed");
return -RT_ERROR;
}
return RT_EOK;
}
#endif
static int16_t pre_x[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static int16_t pre_y[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static int16_t pre_w[GT911_MAX_TOUCH] = { -1, -1, -1, -1, -1 };
static rt_uint8_t s_tp_dowm[GT911_MAX_TOUCH];
static struct rt_touch_data *read_data;
static void gt911_touch_up(void *buf, int8_t id)
{
read_data = (struct rt_touch_data *)buf;
if (s_tp_dowm[id] == 1) {
s_tp_dowm[id] = 0;
read_data[id].event = RT_TOUCH_EVENT_UP;
} else {
read_data[id].event = RT_TOUCH_EVENT_NONE;
}
read_data[id].timestamp = rt_touch_get_ts();
read_data[id].width = pre_w[id];
read_data[id].x_coordinate = pre_x[id];
read_data[id].y_coordinate = pre_y[id];
read_data[id].track_id = id;
pre_x[id] = -1;
pre_y[id] = -1;
pre_w[id] = -1;
}
static void gt911_touch_down(void *buf, int8_t id, int16_t x, int16_t y,
int16_t w)
{
read_data = (struct rt_touch_data *)buf;
if (s_tp_dowm[id] == 1) {
read_data[id].event = RT_TOUCH_EVENT_MOVE;
} else {
read_data[id].event = RT_TOUCH_EVENT_DOWN;
s_tp_dowm[id] = 1;
}
read_data[id].timestamp = rt_touch_get_ts();
read_data[id].width = w;
read_data[id].x_coordinate = x;
read_data[id].y_coordinate = y;
read_data[id].track_id = id;
pre_x[id] = x;
pre_y[id] = y;
pre_w[id] = w;
}
static rt_size_t gt911_read_point(struct rt_touch_device *touch, void *buf,
rt_size_t read_num)
{
rt_uint8_t point_status = 0;
rt_uint8_t touch_num = 0;
rt_uint8_t write_buf[3];
rt_uint8_t cmd[2];
rt_uint8_t read_buf[8 * GT911_MAX_TOUCH] = { 0 };
rt_uint8_t read_index;
int8_t read_id = 0;
int16_t input_x = 0;
int16_t input_y = 0;
int16_t input_w = 0;
static rt_uint8_t pre_touch = 0;
static int8_t pre_id[GT911_MAX_TOUCH] = { 0 };
rt_memset(buf, 0, sizeof(struct rt_touch_data) * read_num);
cmd[0] = (rt_uint8_t)((GT911_READ_STATUS >> 8) & 0xFF);
cmd[1] = (rt_uint8_t)(GT911_READ_STATUS & 0xFF);
if (gt911_read_regs(>911_client, cmd, &point_status, 1) != RT_EOK) {
LOG_D("read point failed\n");
read_num = 0;
goto exit_;
}
if (point_status == 0)
{
read_num = 0;
goto exit_;
}
if ((point_status & 0x80) == 0)
{
read_num = 0;
goto exit_;
}
touch_num = point_status & 0x0f;
if (touch_num > GT911_MAX_TOUCH)
{
read_num = 0;
goto exit_;
}
cmd[0] = (rt_uint8_t)((GT911_POINT1_REG >> 8) & 0xFF);
cmd[1] = (rt_uint8_t)(GT911_POINT1_REG & 0xFF);
if (gt911_read_regs(>911_client, cmd, read_buf,
read_num * GT911_POINT_INFO_NUM) != RT_EOK) {
LOG_D("read point failed\n");
read_num = 0;
goto exit_;
}
if (pre_touch > touch_num)
{
for (read_index = 0; read_index < pre_touch; read_index++) {
rt_uint8_t j;
for (j = 0; j < touch_num; j++)
{
read_id = read_buf[j * 8] & 0x0F;
if (pre_id[read_index] == read_id)
break;
if (j >= touch_num - 1) {
rt_uint8_t up_id;
up_id = pre_id[read_index];
gt911_touch_up(buf, up_id);
}
}
}
}
if (touch_num)
{
rt_uint8_t off_set;
for (read_index = 0; read_index < touch_num; read_index++) {
off_set = read_index * 8;
read_id = read_buf[off_set] & 0x0f;
pre_id[read_index] = read_id;
input_x =
read_buf[off_set + 1] | (read_buf[off_set + 2] << 8);
input_y =
read_buf[off_set + 3] | (read_buf[off_set + 4] << 8);
input_w =
read_buf[off_set + 5] | (read_buf[off_set + 6] << 8);
gt911_touch_down(buf, read_id, input_x, input_y, input_w);
}
} else if (pre_touch) {
for (read_index = 0; read_index < pre_touch; read_index++) {
gt911_touch_up(buf, pre_id[read_index]);
}
}
pre_touch = touch_num;
exit_:
write_buf[0] = (rt_uint8_t)((GT911_READ_STATUS >> 8) & 0xFF);
write_buf[1] = (rt_uint8_t)(GT911_READ_STATUS & 0xFF);
write_buf[2] = 0x00;
gt911_write_reg(>911_client, write_buf, 3);
return read_num;
}
static rt_err_t gt911_control(struct rt_touch_device *touch, int cmd, void *arg)
{
if (cmd == RT_TOUCH_CTRL_GET_ID) {
return gt911_get_product_id(>911_client, arg, 6);
}
if (cmd == RT_TOUCH_CTRL_GET_INFO) {
return gt911_get_info(>911_client, arg);
}
rt_uint8_t buf[4];
rt_uint8_t i = 0;
rt_uint8_t *config;
config =
(rt_uint8_t *)rt_calloc(1, sizeof(GT911_CFG_TBL) + GT911_REGITER_LEN);
if (config == RT_NULL) {
LOG_D("malloc config memory failed\n");
return -RT_ERROR;
}
config[0] = (rt_uint8_t)((GT911_CONFIG_REG >> 8) & 0xFF);
config[1] = (rt_uint8_t)(GT911_CONFIG_REG & 0xFF);
memcpy(&config[2], GT911_CFG_TBL, sizeof(GT911_CFG_TBL));
switch (cmd) {
case RT_TOUCH_CTRL_SET_X_RANGE: {
rt_uint16_t x_range;
x_range = *(rt_uint16_t *)arg;
config[4] = (rt_uint8_t)(x_range >> 8);
config[3] = (rt_uint8_t)(x_range & 0xff);
GT911_CFG_TBL[2] = config[4];
GT911_CFG_TBL[1] = config[3];
break;
}
case RT_TOUCH_CTRL_SET_Y_RANGE: {
rt_uint16_t y_range;
y_range = *(rt_uint16_t *)arg;
config[6] = (rt_uint8_t)(y_range >> 8);
config[5] = (rt_uint8_t)(y_range & 0xff);
GT911_CFG_TBL[4] = config[6];
GT911_CFG_TBL[3] = config[5];
break;
}
case RT_TOUCH_CTRL_SET_X_TO_Y: {
config[8] ^= (1 << 3);
break;
}
case RT_TOUCH_CTRL_SET_MODE: {
rt_uint16_t trig_type;
trig_type = *(rt_uint16_t *)arg;
switch (trig_type) {
case RT_DEVICE_FLAG_INT_RX:
config[8] &= 0xFC;
break;
case RT_DEVICE_FLAG_RDONLY:
config[8] &= 0xFC;
config[8] |= 0x02;
break;
default:
break;
}
break;
}
default: {
break;
}
}
if (gt911_write_reg(>911_client, config,
sizeof(GT911_CFG_TBL) + GT911_ADDR_LEN) != RT_EOK) {
LOG_D("send config failed");
return -1;
}
buf[0] = (rt_uint8_t)((GT911_CHECK_SUM >> 8) & 0xFF);
buf[1] = (rt_uint8_t)(GT911_CHECK_SUM & 0xFF);
buf[2] = 0;
for (i = GT911_ADDR_LEN; i < sizeof(GT911_CFG_TBL) + GT911_ADDR_LEN; i++) {
buf[GT911_ADDR_LEN] += config<i>;
}
buf[2] = (~buf[2]) + 1;
buf[3] = 1;
gt911_write_reg(>911_client, buf, 4);
rt_free(config);
return RT_EOK;
}
static struct rt_touch_ops gt911_touch_ops = {
.touch_readpoint = gt911_read_point,
.touch_control = gt911_control,
};
static int rt_hw_gt911_init(const char *name, struct rt_touch_config *cfg)
{
struct rt_touch_device *touch_device = RT_NULL;
touch_device =
(struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));
if (touch_device == RT_NULL) {
LOG_E("touch device malloc fail");
return -RT_ERROR;
}
rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);
rt_thread_delay(10);
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);
rt_pin_write(cfg->irq_pin.pin, PIN_LOW);
rt_thread_delay(2);
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);
rt_thread_delay(5);
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_INPUT);
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);
rt_pin_write(cfg->irq_pin.pin, PIN_LOW);
rt_thread_delay(50);
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_INPUT);
gt911_client.bus =
(struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
if (gt911_client.bus == RT_NULL) {
LOG_E("Can't find %s device", cfg->dev_name);
return -RT_ERROR;
}
if (rt_device_open((rt_device_t)gt911_client.bus, RT_DEVICE_FLAG_RDWR) !=
RT_EOK) {
LOG_E("open %s device failed", cfg->dev_name);
return -RT_ERROR;
}
gt911_client.client_addr = GT911_ADDRESS_HIGH;
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
touch_device->info.vendor = RT_TOUCH_VENDOR_GT;
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
touch_device->ops = >911_touch_ops;
if (RT_EOK != rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL)) {
LOG_E("touch device gt911 init failed !!!");
return -RT_ERROR;
}
LOG_I("touch device gt911 init success");
return RT_EOK;
}
static int rt_gt911_gpio_cfg()
{
unsigned int g, p;
long pin;
pin = drv_pin_get(GT911_RST_PIN);
g = GPIO_GROUP(pin);
p = GPIO_GROUP_PIN(pin);
hal_gpio_direction_input(g, p);
pin = drv_pin_get(GT911_INT_PIN);
g = GPIO_GROUP(pin);
p = GPIO_GROUP_PIN(pin);
hal_gpio_direction_input(g, p);
hal_gpio_set_irq_mode(g, p, 0);
return 0;
}
static int rt_hw_gt911_port(void)
{
struct rt_touch_config cfg;
rt_uint8_t rst_pin;
rt_gt911_gpio_cfg();
rst_pin = drv_pin_get(GT911_RST_PIN);
cfg.dev_name = GT911_I2C_CHAN;
cfg.irq_pin.pin = drv_pin_get(GT911_INT_PIN);
cfg.irq_pin.mode = PIN_MODE_INPUT;
cfg.user_data = &rst_pin;
rt_hw_gt911_init("gt911", &cfg);
return 0;
}
INIT_DEVICE_EXPORT(rt_hw_gt911_port);
驱动程序是配好了,我们使用example 的测试代码验证touch 功能,开启如下配置
对应的测试代码如下:
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-13 RiceChen the first version
* 2023-05-04 GeoDong modified for ArtInChip
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "gt911.h"
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
static rt_thread_t gt911_thread = RT_NULL;
static rt_sem_t gt911_sem = RT_NULL;
static rt_device_t dev = RT_NULL;
static struct rt_touch_data *read_data;
static struct rt_touch_info info;
static void gt911_entry(void *parameter)
{
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, &info);
read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * info.point_num);
while (1)
{
rt_sem_take(gt911_sem, RT_WAITING_FOREVER);
if (rt_device_read(dev, 0, read_data, info.point_num) == info.point_num)
{
for (rt_uint8_t i = 0; i < info.point_num; i++)
{
if (read_data<i>.event == RT_TOUCH_EVENT_DOWN || read_data<i>.event == RT_TOUCH_EVENT_MOVE)
{
rt_kprintf("%d %d %d %d %d\n", read_data<i>.track_id,
read_data<i>.x_coordinate,
read_data<i>.y_coordinate,
read_data<i>.timestamp,
read_data<i>.width);
}
}
}
rt_device_control(dev, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);
}
}
static rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
{
rt_sem_release(gt911_sem);
rt_device_control(dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
return 0;
}
static void test_gt911(void *parameter)
{
void *id;
dev = rt_device_find("gt911");
if (dev == RT_NULL)
{
rt_kprintf("can't find device:%s\n", "gt911");
return;
}
if (rt_device_open(dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
{
rt_kprintf("open device failed!");
return;
}
id = rt_malloc(sizeof(rt_uint8_t) * 8);
rt_device_control(dev, RT_TOUCH_CTRL_GET_ID, id);
rt_uint8_t * read_id = (rt_uint8_t *)id;
rt_kprintf("id = GT%d%d%d \n", read_id[0] - '0', read_id[1] - '0', read_id[2] - '0');
rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, id);
rt_kprintf("range_x = %d \n", (*(struct rt_touch_info*)id).range_x);
rt_kprintf("range_y = %d \n", (*(struct rt_touch_info*)id).range_y);
rt_kprintf("point_num = %d \n", (*(struct rt_touch_info*)id).point_num);
rt_free(id);
rt_device_set_rx_indicate(dev, rx_callback);
gt911_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
if (gt911_sem == RT_NULL)
{
rt_kprintf("create dynamic semaphore failed.\n");
return;
}
gt911_thread = rt_thread_create("gt911",
gt911_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
if (gt911_thread != RT_NULL)
rt_thread_startup(gt911_thread);
return;
}
MSH_CMD_EXPORT(test_gt911, test gt911 sample);
上述测试代码会会定义测试命令 test_gt911 启动测试线程,线程中读取设备节点数据,读取到按下事件打印对应的touch 数据。
功能验证
上报数据的格式如下:
struct rt_touch_data
{
rt_uint8_t event;
rt_uint8_t track_id;
rt_uint8_t width;
#ifdef AIC_RTP_DRV
rt_uint16_t pressure;
#endif
rt_uint16_t x_coordinate;
rt_uint16_t y_coordinate;
rt_tick_t timestamp;
};
对应打印输出如下
上述log对应的第二/三 对应的X/Y 坐标信息
从代码touch 上报信息信息的宏定义可以知道,TOUCH 支持多点信息上报,支持的最大数量为5
同时5个手指按下会上报多点触摸信息。