summaryrefslogtreecommitdiff
path: root/bsp/raspberry-pi/raspi4-32/driver/touch/drv_xpt2046.c
blob: 7dcb4805c6abea50bd174b986c9e56b27312a9ca (plain)
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author         Notes
 * 2020-11-08     bigmagic       first version
 */

#include <rtthread.h>
#include <rtdevice.h>

#include "drv_xpt2046.h"
//http://www.lcdwiki.com/MHS-3.5inch_RPi_Display

#define DBG_TAG "xpt2046"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

//XPT2046
#define     READ_X                (0xD0)
#define     READ_Y                (0x90)

#define     TFT_WIDTH             (320)
#define     TFT_HEIGHT            (480)
//freq
#define     TOUCH_SPI_MAX_FREQ    (10*1000)

#define     TP_IRQ_PIN            (17)
#define     TOUCH_DEVICE_NAME     ("spi0.1")

static struct rt_semaphore touch_ack;
static rt_touch_t touch_device = RT_NULL;

static rt_thread_t touch_tid = RT_NULL;
#define TOUCH_THREAD_STACK_SIZE     (1024)
#define TOUCH_THREAD_PRIORITY       (30)
#define TOUCH_THREAD_TIMESLICE      (10)

rt_uint8_t touch_flag = 0;
rt_uint16_t touch_x_val = 0;
rt_uint16_t touch_y_val = 0;

extern struct rt_semaphore lcd_spi_lock;
static void touch_read_x_y(void *dev, rt_uint16_t *x, rt_uint16_t *y)
{
    struct rt_spi_device *touch_dev = (struct rt_spi_device *)dev;
    struct rt_spi_message msg1,msg2,msg3,msg4;
    rt_uint16_t readx_val = 0,ready_val = 0;
    rt_uint8_t readx[2];
    rt_uint8_t ready[2];
    rt_sem_take(&lcd_spi_lock, RT_WAITING_FOREVER);

    int read_x_id = READ_X;
    int read_y_id = READ_Y;

    msg1.send_buf   = &read_x_id;
    msg1.recv_buf   = RT_NULL;
    msg1.length     = 1;
    msg1.cs_take    = 1;
    msg1.cs_release = 0;
    msg1.next       = &msg2;

    msg2.send_buf   = RT_NULL;
    msg2.recv_buf   = &readx[0];
    msg2.length     = 2;
    msg2.cs_take    = 0;
    msg2.cs_release = 0;
    msg2.next       = &msg3;

    msg3.send_buf   = &read_y_id;
    msg3.recv_buf   = RT_NULL;
    msg3.length     = 1;
    msg3.cs_take    = 0;
    msg3.cs_release = 0;
    msg3.next       = &msg4;

    msg4.send_buf   = RT_NULL;
    msg4.recv_buf   = &ready[0];
    msg4.length     = 2;
    msg4.cs_take    = 0;
    msg4.cs_release = 1;
    msg4.next       = RT_NULL;

    rt_spi_transfer_message(touch_dev, &msg1);

    readx_val = ((readx[0] << 8) | readx[1]) >> 4;
    ready_val = ((ready[0] << 8) | ready[1]) >> 4;

    rt_sem_release(&lcd_spi_lock);
    *x = readx_val;
    *y = ready_val;
}

/*
XPT2046:Width:320 High:480
no pressed:(0x800,0xfff)
---ETH----USB-----------------------
| (0x800,0x800)      (0xfff,0x800) |
|                                  |
| (0x800,0xFFF)      (0xfff,0xfff) |
------------------------------------
*/
#define XMIN 0x800
#define YMAX 0xfff
void read_tp(void *dev, rt_uint16_t *x, rt_uint16_t *y)
{
    struct rt_spi_device *touch_dev = (struct rt_spi_device *)dev;
    rt_uint8_t try = 0;
    uint16_t _y[5] = {0,0,0,0,0};
    uint16_t _x[5] = {0,0,0,0,0};
    uint16_t x_val = 0;
    uint16_t y_val = 0;
    uint16_t cur_x = 0;
    uint16_t cur_y = 0;
    int index = 0;

    while(1)
    {
        try = try + 1;
        touch_read_x_y(touch_dev, x, y);
        if((*x > XMIN) && (*y < YMAX))
        {
            _x[index] = *x;
            _y[index] = *y;
            index = index + 1;
        }
        if(index == 5)
        {
            break;
        }

        if(try > 10)
        {
            break;
        }
    }

    x_val = (_x[0] + _x[1] + _x[2] + _x[3]+ _x[4]) / index;
    y_val = (_y[0] + _y[1] + _y[2] + _y[3]+ _y[4]) / index;

    cur_x = (x_val - 0x800) * TFT_WIDTH / 0x800;
    cur_y = (y_val - 0x800) * TFT_HEIGHT / 0x800;

    if((cur_x < TFT_WIDTH) && (cur_y < TFT_HEIGHT))
    {
        *x = TFT_WIDTH - cur_x;
        *y = TFT_HEIGHT - cur_y;
    }
    else
    {
        *x = 0;
        *y = 0;
    }
}

static void touch_thread_entry(void *param)
{
    rt_uint16_t x,y;
    struct rt_spi_device *touch_dev;
    touch_dev = (struct rt_spi_device *)rt_device_find(TOUCH_DEVICE_NAME);
    touch_dev->config.max_hz = TOUCH_SPI_MAX_FREQ;
    if (!touch_dev)
    {
        rt_kprintf("no %s!\n", TOUCH_DEVICE_NAME);
    }

    while (1)
    {
        rt_sem_take(&touch_ack, RT_WAITING_FOREVER);
        read_tp(touch_dev, &x, &y);
        if((x!= 0) && (y !=0))
        {
            touch_x_val = x;
            touch_y_val = y;
            touch_flag = 1;
        }
        rt_pin_mode(TP_IRQ_PIN, PIN_MODE_INPUT_PULLUP);
    }
}

static void touch_readly(void *args)
{
    if(rt_pin_read(TP_IRQ_PIN) == PIN_LOW)
    {
        rt_pin_mode(TP_IRQ_PIN, PIN_MODE_OUTPUT);
        rt_pin_write(TP_IRQ_PIN,PIN_HIGH);
        rt_sem_release(&touch_ack);
    }
}

static rt_ssize_t xpt2046_read_point(struct rt_touch_device *touch, void *buf, rt_size_t read_num)
{
    rt_uint16_t* touchxy = (rt_uint16_t *)buf;
    if((read_num != 0) && (touch_flag == 1))
    {
        touchxy[0] = touch_x_val;
        touchxy[1] = touch_y_val;
        touch_flag = 0;
        return read_num;
    }
    else
    {
        return 0;
    }
}

static rt_err_t xpt2046_control(struct rt_touch_device *device, int cmd, void *data)
{
    return RT_EOK;
}

static struct rt_touch_ops touch_ops =
{
    .touch_readpoint = xpt2046_read_point,
    .touch_control = xpt2046_control,
};

static int hw_xpt2046_touch_init(void)
{
    //touch sem
    rt_sem_init(&touch_ack, "touch_ack", 0, RT_IPC_FLAG_FIFO);

    touch_tid = rt_thread_create("touch",
                            touch_thread_entry, RT_NULL,
                            TOUCH_THREAD_STACK_SIZE,
                            TOUCH_THREAD_PRIORITY, TOUCH_THREAD_TIMESLICE);
    if (touch_tid != RT_NULL)
        rt_thread_startup(touch_tid);

    rt_pin_mode(TP_IRQ_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(TP_IRQ_PIN, PIN_IRQ_MODE_LOW_LEVEL, touch_readly, RT_NULL);
    rt_pin_irq_enable(TP_IRQ_PIN, PIN_IRQ_ENABLE);

    touch_device = (rt_touch_t)rt_calloc(1, sizeof(struct rt_touch_device));

    if (touch_device == RT_NULL)
        return -RT_ERROR;

    /* register touch device */
    touch_device->info.type = RT_TOUCH_TYPE_RESISTANCE;
    touch_device->info.vendor = RT_TOUCH_VENDOR_UNKNOWN;
    //rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
    touch_device->ops = &touch_ops;

    rt_hw_touch_register(touch_device, "xpt2046", RT_DEVICE_FLAG_INT_RX, RT_NULL);

    return 0;
}
INIT_DEVICE_EXPORT(hw_xpt2046_touch_init);