Touch Equipment

Touch (touch chip) is an important part of human-computer interaction in UI design. A complete UI design should include input information and output information. Screen devices such as LCD are responsible for display output, while Touch devices are responsible for collecting contact information as information input.

Touch devices and hosts generally use the I2C bus protocol to exchange data, so a touch device is a standard I2C slave device. In order to improve the real-time performance of receiving touch data, touch chips will provide interrupt support. When a touch event (lift, press, move) occurs, an interrupt will be triggered to notify the MCU of a touch event. The host can read the touch point information through the interrupt callback function.

The communication connection between Touch device and host is shown in the figure below:

In order to facilitate the use of Touch devices, RT-Thread abstracts the Touch device driver framework and provides a unified operation interface to the upper layer to improve the reusability of the upper layer code.

  • Interface: standard device interface (open/close/read/control).

  • Working mode: Supports interrupt and polling modes.

  • Support reading multiple points of data

Click the Touch list to view the currently supported Touch types.

The application accesses the Touch device through the I/O device management interface provided by RT-Thread. The relevant interface is as follows:

function

describe

rt_device_find()

Find the device and get the device handle according to the Touch device name

rt_device_open()

Open the Touch device

rt_device_read()

Read contact data

rt_device_control()

Controlling Touch Devices

rt_device_set_rx_indicate()

Set the receiving callback function

rt_device_close()

Turn off your Touch device

The application obtains the device handle according to the Touch device name, and then can operate the Touch device. The device search function is as follows:

rt_device_t rt_device_find(const char* name);copymistakeCopy Success

parameter

describe

name

Touch device name

return

——

Device handle

If the corresponding device is found, the corresponding device handle will be returned.

RT_NULL

No corresponding device object was found

The usage examples are as follows:

#define TOUCH_DEVICE_NAME    "touch_gt"    /* Touch 设备名称 */

static rt_device_t touch_dev;             /* Touch 设备句柄 */
/* 根据设备名称查找 Touch 设备,获取设备句柄 */
touch_dev = rt_device_find(TOUCH_DEVICE_NAME);copymistakeCopy Success

Through the device handle, the application can open and close the device, and open the device through the following function:

rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);copymistakeCopy Success

parameter

describe

dev

Device handle

oflags

Device mode flags

return

——

RT_EOK

Device opened successfully

- RT_EBUSY

If the device registration parameter includes the RT_DEVICE_FLAG_STANDALONE parameter, the device will not be allowed to be opened repeatedly.

-RT_EINVAL

Unsupported open parameters

Other error codes

Device open failed

The oflags parameter supports the following parameters:

#define RT_DEVICE_FLAG_RDONLY       0x001     /* 标准设备的只读模式,对应 Touch 的轮询模式 */
#define RT_DEVICE_FLAG_INT_RX       0x100     /* 中断接收模式 */copymistakeCopy Success

There are two modes for receiving and sending data on the Touch device: interrupt mode and polling mode. When using, only one of these two modes can be selected . If the Touch opening parameter oflags does not specify the interrupt mode, the polling mode is used by default.

An example of using a Touch device in polling mode is as follows:

rt_device_open(touch_dev, RT_DEVICE_FLAG_RDONLY)copymistakeCopy Success

The following is an example of opening a Touch device in interrupt mode:

rt_device_open(touch_dev, RT_DEVICE_FLAG_INT_RX)copymistakeCopy Success

Through the command control word, the application can configure the Touch device through the following functions:

rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);copymistakeCopy Success

parameter

describe

dev

Device handle

cmd

Command control word, see below for details

arg

Control parameters, detailed description see below

return

——

RT_EOK

Function execution successful

-RT_ENOSYS

Execution failed, dev is empty

Other error codes

Execution failed

The cmd currently supports the following command control characters:

#define  RT_TOUCH_CTRL_GET_ID            (0)   /* 读设备ID */
#define  RT_TOUCH_CTRL_GET_INFO          (1)   /* 获取设备信息 */
#define  RT_TOUCH_CTRL_SET_MODE          (2)   /* 设置工作模式 */
#define  RT_TOUCH_CTRL_SET_X_RANGE       (3)   /* 设置 X 轴分辨率  */
#define  RT_TOUCH_CTRL_SET_Y_RANGE       (4)   /* 设置 Y 轴分辨率 */
#define  RT_TOUCH_CTRL_SET_X_TO_Y        (5)   /* 交换 X、Y 轴坐标 */
#define  RT_TOUCH_CTRL_DISABLE_INT       (6)   /* 失能中断 */
#define  RT_TOUCH_CTRL_ENABLE_INT        (7)   /* 使能中断 */copymistakeCopy Success

Read device ID

rt_uint8_t read_id[4];
rt_device_control(touch_dev, RT_TOUCH_CTRL_GET_ID, read_id);
LOG_I("id = %d %d %d %d \n", read_id[0] - '0', read_id[1] - '0', read_id[2] - '0', read_id[3] - '0');copymistakeCopy Success

Get device information

struct rt_touch_info info;
rt_device_control(touch_dev, RT_TOUCH_CTRL_GET_INFO, &info);
LOG_I("type       :%d", info.type);                       /* 类型:电容型/电阻型*/
LOG_I("vendor     :%s", info.vendor);                     /* 厂商 */
LOG_I("point_num  :%d", info.point_num);                  /* 支持的触点个数 */
LOG_I("range_x    :%d", info.range_x);                    /* X 轴分辨率 */
LOG_I("range_y    :%d", info.range_y);                    /* Y 轴分辨率*/copymistakeCopy Success

Set the working mode

/* 设置工作模式为中断模式 */
rt_device_control(touch_dev, RT_TOUCH_CTRL_SET_MODE, (void *)RT_DEVICE_FLAG_INT_RX);
/* 设置工作模式为轮询模式 */
rt_device_control(touch_dev, RT_TOUCH_CTRL_SET_MODE, (void *)RT_DEVICE_FLAG_RDONLY);copymistakeCopy Success

Set the X-axis range

Set the resolution of Touch X axis coordinates.

rt_uint16_t x = 400;
rt_device_control(touch_dev, RT_TOUCH_CTRL_SET_X_RANGE, &x);copymistakeCopy Success

Set the Y-axis range

Set the resolution of the Touch Y axis coordinates.

rt_uint16_t y = 400;
rt_device_control(touch_dev, RT_TOUCH_CTRL_SET_Y_RANGE, &y);copymistakeCopy Success

Swap the X and Y axis coordinates

rt_device_control(touch_dev, RT_TOUCH_CTRL_SET_X_TO_Y, RT_NULL);copymistakeCopy Success

Turn off Touch Turn off interruption

rt_device_control(touch_dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);copymistakeCopy Success

Enable Touch device interrupts

rt_device_control(touch_dev, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);copymistakeCopy Success

When using the interrupt mode to read the contact data, an interrupt will be triggered when a touch event occurs at the bottom layer. Since the speed of the interrupt trigger is greater than the speed of the Touch device reading (I2C reading data is generally slow), the interrupt needs to be turned off in the receiving callback function, and then the semaphore is released. In the contact information reading thread, the data will be read after the semaphore is requested, and the interrupt will be turned on after the data reading is completed. Note that the interrupt interface must be turned on and off in pairs. Turning on an interrupt once corresponds to turning off an interrupt once, so that the device can read data in normal interrupt mode.

The following function can be used to set the data receiving indication. When Touch receives data, it notifies the upper application thread that data has arrived:

rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));copymistakeCopy Success

parameter

describe

dev

Device handle

rx_ind

Callback function pointer

dev

Device handle (callback function parameter)

size

Buffer data size (callback function parameter)

return

——

RT_EOK

Set up for success

The callback function of this function is provided by the caller. If the Touch device is opened in interrupt receiving mode, when the Touch receives data and generates an interrupt, the callback function will be called and the Touch device handle will be placed in the dev parameter for the caller to obtain.

Contact information composition

struct rt_touch_data
{
    rt_uint8_t          event;
    rt_uint8_t          track_id;
    rt_uint8_t          width;
    rt_uint16_t         x_coordinate;
    rt_uint16_t         y_coordinate;
    rt_tick_t           timestamp;
};copymistakeCopy Success
  • event: touch event, including lift event, press event, and move event.

  • track_id: Each touch point has its own touch track. This data is used to save the touch track ID.

  • width: touch point width.

  • x_coordinate: X-axis coordinate of the touch point.

  • y_coordinate: Y-axis coordinate of the touch point.

  • timestamp: Touch event timestamp.

Read touch point information interface

The following interface can be called to read the touch point information:

rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);copymistakeCopy Success

parameter

describe

dev

Device handle

pos

Read data offset, this parameter is not used by Touch

buffer

Buffer pointer. The read data will be saved in the buffer.

size

The Touch device driver framework determines the number of touch points to be read based on this parameter.

return

——

The actual size of the data read

Returns the number of contact information read

0

You need to read the errno of the current thread to determine the error status

The code snippet for reading a touch point information is as follows:

struct rt_touch_data *read_data;
read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data));

if (rt_device_read(touch_dev, 0, read_data, 1) == 1)
{
    rt_kprintf("%d %d %d %d %d\n", read_data->track_id, read_data->x_coordinate, 
               read_data->y_coordinate, read_data->timestamp, read_data->width);
}copymistakeCopy Success

The code snippet for reading the five touch point information is as follows:

struct rt_touch_data *read_data;
read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * 5);

if (rt_device_read(dev, 0, read_data, 5) == 5)
{
    for (rt_uint8_t i = 0; i < 5; 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);
        }
    }
}copymistakeCopy Success

When the application completes the Touch operation, it can turn off the Touch device, which can be done through the following function:

rt_err_t rt_device_close(rt_device_t dev);copymistakeCopy Success

parameter

describe

dev

Device handle

return

——

RT_EOK

Shut down the device successfully

-RT_ERROR

The device has been completely shut down. You cannot shut down the device again.

Other error codes

Failed to shut down the device

Closing the device interface and opening the device interface must be used in pairs. Each time you open the device, you must close it once. Only in this way can the device be completely closed. Otherwise, the device will still be in an open state.

The specific usage of the Touch device interrupt method to read the touch information of five points can be referred to the following sample code. The main steps of the sample code are as follows:

  1. First look up the Touch settings to get the device handle.

  2. Open the Touch device in a way that interrupts receiving data.

  3. Set the interrupt receive callback.

  4. Create a thread and semaphore for reading Touch data, release the semaphore in the interrupt reception callback, keep requesting the semaphore in the data reception thread, and read the Touch data once the semaphore is requested.

static rt_thread_t  gt9147_thread = RT_NULL;
static rt_sem_t     gt9147_sem = RT_NULL;
static rt_device_t  dev = RT_NULL;
static struct       rt_touch_data *read_data;

/* 读取数据线程入口函数 */
static void gt9147_entry(void *parameter)
{
    struct rt_touch_data *read_data;
    read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * 5);

    while (1)
    {
        /* 请求信号量 */
        rt_sem_take(gt9147_sem, RT_WAITING_FOREVER);
        /* 读取五个点的触摸信息 */
        if (rt_device_read(dev, 0, read_data, 5) == 5)
        {
            for (rt_uint8_t i = 0; i < 5; 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_device_control(dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
    /* 释放信号量 */
    rt_sem_release(gt9147_sem);
    return 0;
}

static int gt9147_sample(void)
{
    /* 查找 Touch 设备 */
    dev = rt_device_find("touch");

    if (dev == RT_NULL)
    {
        rt_kprintf("can't find device:%s\n", "touch");
        return -1;
    }
    /* 以中断的方式打开设备 */
    if (rt_device_open(dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
    {
        rt_kprintf("open device failed!");
        return -1;
    }
    /* 设置接收回调 */
    rt_device_set_rx_indicate(dev, rx_callback);
    /* 创建信号量 */
    gt9147_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_PRIO);

    if (gt9147_sem == RT_NULL)
    {
        rt_kprintf("create dynamic semaphore failed.\n");
        return -1;
    }
    /* 创建读取数据线程 */
    gt9147_thread = rt_thread_create("thread1",
                                     gt9147_entry,
                                     RT_NULL,
                                     THREAD_STACK_SIZE,
                                     THREAD_PRIORITY,
                                     THREAD_TIMESLICE);
    /* 启动线程 */
    if (gt9147_thread != RT_NULL)
        rt_thread_startup(gt9147_thread);

    return 0;
}
MSH_CMD_EXPORT(gt9147_sample, gt9147 sample);
copymistakeCopy Success

Last updated

Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University