mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-25 21:48:54 +00:00
V1.0.5
This commit is contained in:
374
bsp/peripheral/touch/st16xx/src/st16xx.c
Normal file
374
bsp/peripheral/touch/st16xx/src/st16xx.c
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Notes
|
||||
* 2024-04-19 the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtdbg.h>
|
||||
#include "st16xx.h"
|
||||
|
||||
static struct rt_i2c_client *st16xx_client;
|
||||
|
||||
/**
|
||||
* @brief st16xx_write_regs
|
||||
*
|
||||
* @param reg register to be written
|
||||
* @param buf buf to be written
|
||||
* @param len buf len
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static rt_err_t st16xx_write_regs(struct rt_i2c_client *dev, rt_uint8_t write_len,
|
||||
rt_uint8_t *write_data)
|
||||
{
|
||||
struct rt_i2c_msg msgs;
|
||||
|
||||
msgs.addr = dev->client_addr;
|
||||
msgs.flags = RT_I2C_WR;
|
||||
msgs.buf = write_data;
|
||||
msgs.len = write_len;
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1) {
|
||||
return RT_EOK;
|
||||
} else {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief st16xx_read_regs
|
||||
*
|
||||
* @param reg register to be read
|
||||
* @param buf read data
|
||||
* @param len read len
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static rt_err_t st16xx_read_regs(struct rt_i2c_client *dev, rt_uint8_t *cmd_buf, rt_uint8_t cmd_len,
|
||||
rt_uint8_t read_len, rt_uint8_t *read_buf)
|
||||
{
|
||||
struct rt_i2c_msg msgs[2];
|
||||
|
||||
msgs[0].addr = dev->client_addr;
|
||||
msgs[0].flags = RT_I2C_WR;
|
||||
msgs[0].buf = cmd_buf;
|
||||
msgs[0].len = cmd_len;
|
||||
|
||||
msgs[1].addr = dev->client_addr;
|
||||
msgs[1].flags = RT_I2C_RD;
|
||||
msgs[1].buf = read_buf;
|
||||
msgs[1].len = read_len;
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, msgs, 2) == 2) {
|
||||
return RT_EOK;
|
||||
} else {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function read the product id
|
||||
*
|
||||
* @param dev the pointer of device driver structure
|
||||
* @param reg the register
|
||||
* @param read data len
|
||||
* @param read data pointer
|
||||
*
|
||||
* @return the read status, RT_EOK reprensents read the value of the register successfully.
|
||||
*/
|
||||
static rt_err_t st16xx_get_product_id(struct rt_i2c_client *dev,
|
||||
rt_uint8_t read_len, rt_uint8_t *read_data)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t st16xx_get_info(struct rt_i2c_client *dev, struct rt_touch_info *info)
|
||||
{
|
||||
rt_uint8_t read_buf[4] = {0};
|
||||
rt_uint8_t cmd_buf[2];
|
||||
|
||||
cmd_buf[0] = ST16XX_RESOLUTION_REG;
|
||||
/* read point num is read_num */
|
||||
if (st16xx_read_regs(st16xx_client, cmd_buf, 1, 3, read_buf) != RT_EOK) {
|
||||
LOG_I("read resolution info failed\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
info->range_x = (read_buf[0] & 0x70) << 4 | read_buf[1]; /* x */
|
||||
info->range_y = (read_buf[0] & 0x07) << 8 | read_buf[2]; /* y */
|
||||
|
||||
cmd_buf[0] = ST16XX_CONTACTS_NUM_REG;
|
||||
/* read point num is read_num */
|
||||
if (st16xx_read_regs(st16xx_client, cmd_buf, 1, 1, read_buf) != RT_EOK) {
|
||||
LOG_I("read contacts info failed\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
info->point_num = read_buf[0];
|
||||
info->type = RT_TOUCH_TYPE_CAPACITANCE;
|
||||
info->vendor = RT_TOUCH_VENDOR_UNKNOWN;
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
}
|
||||
|
||||
static rt_err_t st16xx_soft_reset(struct rt_i2c_client *dev)
|
||||
{
|
||||
rt_uint8_t buf[2];
|
||||
|
||||
buf[0] = (rt_uint8_t)(ST16XX_RESET_REG);
|
||||
/* reset ic and disable multi-touch*/
|
||||
buf[1] = 0x41;
|
||||
|
||||
if (st16xx_write_regs(dev, 2, buf) != RT_EOK) {
|
||||
LOG_D("soft reset st1633i failed\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t st16xx_control(struct rt_touch_device *device, int cmd, void *data)
|
||||
{
|
||||
if (cmd == RT_TOUCH_CTRL_GET_ID) {
|
||||
return st16xx_get_product_id(st16xx_client, 6, data);
|
||||
}
|
||||
|
||||
if (cmd == RT_TOUCH_CTRL_GET_INFO) {
|
||||
return st16xx_get_info(st16xx_client, data);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int16_t pre_x[ST16XX_MAX_TOUCH] = {-1, -1, -1, -1, -1};
|
||||
static int16_t pre_y[ST16XX_MAX_TOUCH] = {-1, -1, -1, -1, -1};
|
||||
static int16_t pre_w[ST16XX_MAX_TOUCH] = {-1, -1, -1, -1, -1};
|
||||
static rt_uint8_t s_tp_dowm[ST16XX_MAX_TOUCH];
|
||||
static struct rt_touch_data *read_data;
|
||||
|
||||
static void st16xx_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; /* last point is none */
|
||||
pre_y[id] = -1;
|
||||
pre_w[id] = -1;
|
||||
}
|
||||
|
||||
static void st16xx_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; /* save last point */
|
||||
pre_y[id] = y;
|
||||
pre_w[id] = w;
|
||||
}
|
||||
|
||||
static rt_size_t st16xx_read_points(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 cmd[2];
|
||||
rt_uint8_t read_buf[(ST16XX_POINT_INFO_NUM * ST16XX_MAX_TOUCH) + 2] = {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[ST16XX_MAX_TOUCH] = {0};
|
||||
/* point status register */
|
||||
cmd[0] = (ST16XX_STATUS_REG);
|
||||
if (st16xx_read_regs(st16xx_client, cmd, 1, 1, &point_status) != RT_EOK) {
|
||||
LOG_I("read point failed\n");
|
||||
read_num = 0;
|
||||
goto exit_;
|
||||
}
|
||||
|
||||
if ((point_status & 0x0f) == 0x02) { /* error code */
|
||||
read_num = 0;
|
||||
LOG_I("Touch error: %d\n",point_status & 0x0f);
|
||||
goto exit_;
|
||||
}
|
||||
|
||||
cmd[0] = ST16XX_CONTACTS_NUM_REG;
|
||||
st16xx_read_regs(st16xx_client, cmd, 1, 1, &touch_num);
|
||||
if (touch_num > ST16XX_MAX_TOUCH) { /* point num is not correct */
|
||||
read_num = 0;
|
||||
LOG_I("Set contact num: %d,Get contact num: %d\n",ST16XX_MAX_TOUCH,point_status);
|
||||
goto exit_;
|
||||
}
|
||||
|
||||
cmd[0] = (ST16XX_KEY_REG);
|
||||
/* read point num is read_num */
|
||||
if (st16xx_read_regs(st16xx_client, cmd, 1,
|
||||
read_num * ST16XX_POINT_INFO_NUM, read_buf) != RT_EOK) {
|
||||
LOG_I("read point failed\n");
|
||||
read_num = 0;
|
||||
goto exit_;
|
||||
}
|
||||
|
||||
if(touch_num) { /* point down */
|
||||
rt_uint8_t off_set;
|
||||
for (read_index = 0; read_index < 1; read_index++) {
|
||||
off_set = read_index * 4;
|
||||
read_id = read_buf[off_set];
|
||||
pre_id[read_index] = read_id;
|
||||
if (read_buf[off_set + 1] & 0x80) { //touch data valid detect
|
||||
input_x = (read_buf[off_set + 1] & 0x70) << 4 | read_buf[off_set + 2]; /* x */
|
||||
input_y = (read_buf[off_set + 1] & 0x07) << 8 | read_buf[off_set + 3]; /* y */
|
||||
if (input_y)
|
||||
input_w = 4; /* size */
|
||||
st16xx_touch_down(buf, read_id, input_x, input_y, input_w);
|
||||
}
|
||||
}
|
||||
}
|
||||
pre_touch = (read_buf[1] & 0x80);
|
||||
for (read_index = 0; read_index < 1; read_index++) {
|
||||
if (!pre_touch) {
|
||||
st16xx_touch_up(buf, pre_id[read_index]);
|
||||
}
|
||||
}
|
||||
|
||||
exit_:
|
||||
return read_num;
|
||||
}
|
||||
|
||||
static struct rt_touch_ops touch_ops = {
|
||||
.touch_readpoint = st16xx_read_points,
|
||||
.touch_control = st16xx_control,
|
||||
};
|
||||
|
||||
static int rt_st16xx_gpio_cfg()
|
||||
{
|
||||
unsigned int g, p;
|
||||
long pin;
|
||||
|
||||
// RST
|
||||
pin = drv_pin_get(ST16XX_RESET_PIN);
|
||||
g = GPIO_GROUP(pin);
|
||||
p = GPIO_GROUP_PIN(pin);
|
||||
hal_gpio_direction_input(g, p);
|
||||
|
||||
// INT
|
||||
pin = drv_pin_get(ST16XX_IRQ_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tp init
|
||||
*
|
||||
*/
|
||||
int rt_hw_st16xx_init(const char *name, struct rt_touch_config *cfg)
|
||||
{
|
||||
rt_touch_t touch_device = RT_NULL;
|
||||
rt_uint8_t cmd_buf[2];
|
||||
|
||||
touch_device = (rt_touch_t)rt_calloc(1, sizeof(struct rt_touch_device));
|
||||
if (touch_device == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_INPUT_PULLDOWN);
|
||||
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_mdelay(2);
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);
|
||||
rt_thread_mdelay(5);
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
/* interface bus */
|
||||
st16xx_client = (struct rt_i2c_client *)rt_calloc(1, sizeof(struct rt_i2c_client));
|
||||
st16xx_client->bus = (struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
|
||||
|
||||
if (st16xx_client->bus == RT_NULL) {
|
||||
LOG_I("Can't find device\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
if (rt_device_open((rt_device_t)st16xx_client->bus, RT_DEVICE_FLAG_RDWR) != RT_EOK) {
|
||||
LOG_I("open device failed\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
st16xx_client->client_addr = ST16XX_ADDR;
|
||||
st16xx_soft_reset(st16xx_client); //Reset IC
|
||||
//Disable idle mode
|
||||
cmd_buf[0] = ST16XX_TIMOUT_REG;
|
||||
cmd_buf[1] = 0xff;
|
||||
if (st16xx_write_regs(st16xx_client, 2, cmd_buf) != RT_EOK) {
|
||||
LOG_I("st1633i set idle mode failed\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* register touch device */
|
||||
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
|
||||
touch_device->info.vendor = RT_TOUCH_VENDOR_UNKNOWN;
|
||||
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
|
||||
touch_device->ops = &touch_ops;
|
||||
|
||||
if (RT_EOK != rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL)) {
|
||||
LOG_E("touch device st16xx init failed !!!");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
LOG_I("touch device st16xx init success\n");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int rt_hw_st16xx_port(void)
|
||||
{
|
||||
struct rt_touch_config cfg;
|
||||
rt_uint8_t rst_pin;
|
||||
|
||||
rt_st16xx_gpio_cfg();
|
||||
|
||||
rst_pin = drv_pin_get(ST16XX_RESET_PIN);
|
||||
cfg.dev_name = ST16XX_I2C_CHAN;
|
||||
cfg.irq_pin.pin = drv_pin_get(ST16XX_IRQ_PIN);
|
||||
cfg.irq_pin.mode = PIN_MODE_INPUT;
|
||||
cfg.user_data = &rst_pin;
|
||||
|
||||
rt_hw_st16xx_init("st16xx", &cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_DEVICE_EXPORT(rt_hw_st16xx_port);
|
||||
Reference in New Issue
Block a user