1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-12-30    Sundm75       first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <stdbool.h>
14 #include "drivers/dev_spi.h"
15 #include "ls1c.h"
16 #include "ls1c_gpio.h"
17 #include "ls1c_spi.h"
18 #include "drv_spi.h"
19 #include "touch.h"
20 
21 #ifdef XPT2046_USING_TOUCH
22 
23 #include <rtgui/calibration.h>
24 #include <rtgui/event.h>
25 #include <rtgui/kbddef.h>
26 #include <rtgui/rtgui_server.h>
27 #include <rtgui/rtgui_system.h>
28 
29 
30 //竖屏幕 不需要  _ILI_HORIZONTAL_DIRECTION_
31 //横屏幕 需要  _ILI_HORIZONTAL_DIRECTION_
32 
33 //#define _ILI_HORIZONTAL_DIRECTION_
34 
35 #if defined(_ILI_HORIZONTAL_DIRECTION_)
36 #define X_WIDTH 272
37 #define Y_WIDTH 480
38 #else
39 #define X_WIDTH 480
40 #define Y_WIDTH 272
41 #endif
42 /*
43 TOUCH INT: 84
44 */
45 #define IS_TOUCH_UP()     gpio_get(TOUCH_INT_PIN)
46 
47 #define led_gpio 52    // led1指示
48 
49 #define DUMMY                 0x00
50 
51 /*
52 7  6 - 4  3      2     1-0
53 s  A2-A0 MODE SER/DFR PD1-PD0
54 */
55 /* bit[1:0] power-down */
56 #define POWER_MODE0     (0) /* Power-Down Between Conversions. When */
57                             /* each conversion is finished, the converter */
58                             /* enters a low-power mode. At the start of the */
59                             /* next conversion, the device instantly powers up */
60                             /* to full power. There is no need for additional */
61                             /* delays to ensure full operation, and the very first */
62                             /* conversion is valid. The Y? switch is on when in */
63                             /* power-down.*/
64 #define POWER_MODE1     (1) /* Reference is off and ADC is on. */
65 #define POWER_MODE2     (2) /* Reference is on and ADC is off. */
66 #define POWER_MODE3     (3) /* Device is always powered. Reference is on and */
67                             /* ADC is on. */
68 /* bit[2] SER/DFR */
69 #define DIFFERENTIAL    (0<<2)
70 #define SINGLE_ENDED    (1<<2)
71 /* bit[3] mode */
72 #define MODE_12BIT      (0<<3)
73 #define MODE_8BIT       (1<<3)
74 /* bit[6:4] differential mode */
75 #define MEASURE_X       (((1<<2) | (0<<1) | (1<<0))<<4)
76 #define MEASURE_Y       (((0<<2) | (0<<1) | (1<<0))<<4)
77 #define MEASURE_Z1      (((0<<2) | (1<<1) | (1<<0))<<4)
78 #define MEASURE_Z2      (((1<<2) | (0<<1) | (0<<0))<<4)
79 /* bit[7] start */
80 #define START           (1<<7)
81 
82 /* X Y change. */
83 #define TOUCH_MSR_X     (START | MEASURE_X | MODE_12BIT | DIFFERENTIAL | POWER_MODE0)
84 #define TOUCH_MSR_Y     (START | MEASURE_Y | MODE_12BIT | DIFFERENTIAL | POWER_MODE0)
85 
86 
87 /* 以下定义XPT2046 的触摸屏位置*/
88 #if defined(_ILI_HORIZONTAL_DIRECTION_)
89 #define MIN_X_DEFAULT   2047
90 #define MAX_X_DEFAULT   47
91 #define MIN_Y_DEFAULT   102
92 #define MAX_Y_DEFAULT   1939
93 #else
94 #define MIN_X_DEFAULT   47
95 #define MAX_X_DEFAULT   2047
96 #define MIN_Y_DEFAULT   1939
97 #define MAX_Y_DEFAULT   102
98 #endif
99 
100 
101 
102 #define SAMP_CNT 8                              //the adc array size
103 #define SAMP_CNT_DIV2 4                         //the middle of the adc array
104 #define SH   10                                 // Valve value
105 
106 
107 /*宏定义 */
108 #define TOUCH_SPI_X                 SPI1
109 #define TOUCH_INT_PIN               84
110 #define TOUCH_CS_PIN                49
111 #define TOUCH_SCK_PIN               46
112 #define TOUCH_MISO_PIN              47
113 #define TOUCH_MOSI_PIN              48
114 
115 
116 /*创建结构体将需要用到的东西进行打包*/
117 struct rtgui_touch_device
118 {
119     struct rt_device parent;                    /* 用于注册设备*/
120 
121     rt_uint16_t x, y;                           /* 记录读取到的位置值  */
122 
123     rt_bool_t calibrating;                      /* 触摸校准标志 */
124     rt_touch_calibration_func_t calibration_func;/* 触摸函数 函数指针 */
125 
126     rt_uint16_t min_x, max_x;                   /* 校准后 X 方向最小 最大值 */
127     rt_uint16_t min_y, max_y;                   /* 校准后 Y 方向最小 最大值 */
128 
129     struct rt_spi_device * spi_device;          /* SPI 设备 用于通信 */
130     struct rt_event event;                       /* 事件同步,用于“笔中断” */
131 };
132 static struct rtgui_touch_device *touch = RT_NULL;
133 
touch_send_then_recv(struct rt_spi_device * device,const void * send_buf,rt_size_t send_length,void * recv_buf,rt_size_t recv_length)134 static rt_err_t  touch_send_then_recv(struct rt_spi_device *device,
135                                const void           *send_buf,
136                                rt_size_t             send_length,
137                                void                 *recv_buf,
138                                rt_size_t             recv_length)
139 {
140     rt_err_t result;
141     struct rt_spi_message message;
142     rt_uint8_t dummy[128] ;
143 
144     rt_memset(dummy, DUMMY, sizeof(dummy));
145 
146     RT_ASSERT(device != RT_NULL);
147     RT_ASSERT(device->bus != RT_NULL);
148 
149     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
150     if (result == RT_EOK)
151     {
152         if (device->bus->owner != device)
153         {
154             /* not the same owner as current, re-configure SPI bus */
155             result = device->bus->ops->configure(device, &device->config);
156             if (result == RT_EOK)
157             {
158                 /* set SPI bus owner */
159                 device->bus->owner = device;
160             }
161             else
162             {
163                 /* configure SPI bus failed */
164                 result = -RT_EIO;
165                 goto __exit;
166             }
167         }
168 
169         /* send data */
170         message.send_buf   = send_buf;
171         message.recv_buf   = RT_NULL;
172         message.length     = send_length;
173         message.cs_take    = 1;
174         message.cs_release = 0;
175         message.next       = RT_NULL;
176 
177         result = device->bus->ops->xfer(device, &message);
178         if (result == 0)
179         {
180             result = -RT_EIO;
181             goto __exit;
182         }
183 
184         /* recv data */
185         message.send_buf   = dummy;
186         message.recv_buf   = recv_buf;
187         message.length     = recv_length;
188         message.cs_take    = 0;
189         message.cs_release = 1;
190         message.next       = RT_NULL;
191 
192         result = device->bus->ops->xfer(device, &message);
193         if (result == 0)
194         {
195             result = -RT_EIO;
196             goto __exit;
197         }
198 
199         result = RT_EOK;
200     }
201     else
202     {
203         return -RT_EIO;
204     }
205 
206 __exit:
207     rt_mutex_release(&(device->bus->lock));
208 
209     return result;
210 }
211 
212 
rtgui_touch_calculate(void)213 static void rtgui_touch_calculate(void)
214 {
215     if (touch != RT_NULL)
216     {
217         /* read touch */
218         {
219             rt_uint8_t i, j, k, min;
220             rt_uint16_t temp;
221             rt_uint16_t tmpxy[2][SAMP_CNT];
222             rt_uint8_t send_buffer[1];
223             rt_uint8_t recv_buffer[2];
224             for(i=0; i<SAMP_CNT; i++)
225             {
226                 send_buffer[0] = TOUCH_MSR_X;
227           touch_send_then_recv(touch->spi_device, send_buffer, 1, recv_buffer, 2);
228                 rt_kprintf("touch x: %d ",(recv_buffer[0]*256|recv_buffer[1])>>4);
229 #if defined(_ILI_HORIZONTAL_DIRECTION_)
230                 tmpxy[1][i]  = (recv_buffer[0]<<8)|recv_buffer[1] ;
231                 tmpxy[1][i] >>= 4;
232 #else
233                 tmpxy[0][i]  = (recv_buffer[0]<<8)|recv_buffer[1] ;
234                 tmpxy[0][i] >>=4;
235 
236 #endif
237                 send_buffer[0] = TOUCH_MSR_Y;
238                 touch_send_then_recv(touch->spi_device, send_buffer, 1, recv_buffer, 2);
239           rt_kprintf("touch y: %d \n",(recv_buffer[0]*256|recv_buffer[1])>>4);
240 
241 #if defined(_ILI_HORIZONTAL_DIRECTION_)
242                 tmpxy[0][i]  = (recv_buffer[0]<<8)|recv_buffer[1] ;
243                 tmpxy[0][i] >>= 4;
244 #else
245                 tmpxy[1][i]  = (recv_buffer[0]<<8)|recv_buffer[1] ;
246                 tmpxy[1][i] >>= 4;
247 #endif
248             }
249             /*再次打开触摸中断*/
250             send_buffer[0] = 1 << 7;
251           touch_send_then_recv(touch->spi_device, send_buffer, 1, recv_buffer, 2);
252                 touch_send_then_recv(touch->spi_device, send_buffer, 1, recv_buffer, 2);
253             /* calculate average */
254             {
255                 rt_uint32_t total_x = 0;
256                 rt_uint32_t total_y = 0;
257                 for(k=0; k<2; k++)
258                 {
259                     // sorting the ADC value
260                     for(i=0; i<SAMP_CNT-1; i++)
261                     {
262                         min=i;
263                         for (j=i+1; j<SAMP_CNT; j++)
264                         {
265                             if (tmpxy[k][min] > tmpxy[k][j])
266                                 min=j;
267                         }
268                         temp = tmpxy[k][i];
269                         tmpxy[k][i] = tmpxy[k][min];
270                         tmpxy[k][min] = temp;
271                     }
272                     //check value for Valve value
273                     if((tmpxy[k][SAMP_CNT_DIV2+1]-tmpxy[k][SAMP_CNT_DIV2-2]) > SH)
274                     {
275                         return;
276                     }
277                 }
278                 total_x=tmpxy[0][SAMP_CNT_DIV2-2]+tmpxy[0][SAMP_CNT_DIV2-1]+tmpxy[0][SAMP_CNT_DIV2]+tmpxy[0][SAMP_CNT_DIV2+1];
279                 total_y=tmpxy[1][SAMP_CNT_DIV2-2]+tmpxy[1][SAMP_CNT_DIV2-1]+tmpxy[1][SAMP_CNT_DIV2]+tmpxy[1][SAMP_CNT_DIV2+1];
280                 //calculate average value
281                 touch->x=total_x>>2;
282                 touch->y=total_y>>2;
283                 rt_kprintf("touch->x:%d touch->y:%d\r\n", touch->x, touch->y);
284            } /* calculate average */
285         } /* read touch */
286 
287         /* if it's not in calibration status  */
288         /*触摸值缩放*/
289         if (touch->calibrating != RT_TRUE)
290         {
291             if (touch->max_x > touch->min_x)
292             {
293                 touch->x = (touch->x - touch->min_x) * X_WIDTH/(touch->max_x - touch->min_x);
294             }
295             else
296             {
297                 touch->x = (touch->min_x - touch->x) * X_WIDTH/(touch->min_x - touch->max_x);
298             }
299 
300             if (touch->max_y > touch->min_y)
301             {
302                 touch->y = (touch->y - touch->min_y) * Y_WIDTH /(touch->max_y - touch->min_y);
303             }
304             else
305             {
306                 touch->y = (touch->min_y - touch->y) * Y_WIDTH /(touch->min_y - touch->max_y);
307             }
308         }
309     }
310 }
311 #include "ls1c_regs.h"
312 #define TOUCH_INT_EN                __REG32(LS1C_INT4_EN)
touch_int_cmd(rt_bool_t NewState)313 rt_inline void touch_int_cmd(rt_bool_t NewState)
314 {
315     if(NewState == RT_TRUE)
316         {
317             //TOUCH_INT_EN |= (1<<(TOUCH_INT_PIN-64));
318             reg_set_one_bit(LS1C_INT4_EN, 1<<(TOUCH_INT_PIN-64));
319         }
320     else
321         {
322             //TOUCH_INT_EN &=(~ (1<<(TOUCH_INT_PIN-64)));
323             reg_clr_one_bit(LS1C_INT4_EN, 1<<(TOUCH_INT_PIN-64));
324         }
325 
326 }
327 
ls1c_touch_irqhandler(void)328 void ls1c_touch_irqhandler(void) /* TouchScreen */
329 {
330   if(gpio_get(TOUCH_INT_PIN)==0)
331   {
332     /* 触摸屏按下后操作 */
333     if (gpio_level_low == gpio_get(led_gpio))
334         gpio_set(led_gpio, gpio_level_high);
335     else
336         gpio_set(led_gpio, gpio_level_low);
337     touch_int_cmd(RT_FALSE);
338     rt_event_send(&touch->event, 1);
339   }
340 }
341 
342 /*管脚初始化,配置中断打开SPI1 CS0 设备*/
touch_init(void)343 rt_inline void touch_init(void)
344 {
345     unsigned int touch_int_gpio = TOUCH_INT_PIN;     // 触摸屏中断
346     int touch_irq = LS1C_GPIO_TO_IRQ(touch_int_gpio);
347 
348     // 初始化按键中断
349     gpio_set_irq_type(touch_int_gpio, IRQ_TYPE_EDGE_FALLING);
350     rt_hw_interrupt_install(touch_irq, ls1c_touch_irqhandler, RT_NULL, "touch");
351     rt_hw_interrupt_umask(touch_irq);
352     gpio_init(touch_int_gpio, gpio_mode_input);
353 
354     // 初始化led
355     gpio_init(led_gpio, gpio_mode_output);
356     gpio_set(led_gpio, gpio_level_high);
357 }
358 
359 
360 /* RT-Thread Device Interface */
rtgui_touch_init(rt_device_t dev)361 static rt_err_t rtgui_touch_init (rt_device_t dev)
362 {
363     rt_uint8_t send;
364     rt_uint8_t recv_buffer[2];
365     struct rtgui_touch_device * touch_device = (struct rtgui_touch_device *)dev;
366 
367     touch_init();
368     rt_kprintf("touch_init ...\n");
369     send = START | DIFFERENTIAL | POWER_MODE0;
370     touch_send_then_recv(touch->spi_device, &send, 1, recv_buffer, 2);
371 
372     return RT_EOK;
373 }
374 
rtgui_touch_control(rt_device_t dev,int cmd,void * args)375 static rt_err_t rtgui_touch_control (rt_device_t dev, int cmd, void *args)
376 {
377     switch (cmd)
378     {
379     case RT_TOUCH_CALIBRATION:
380         touch->calibrating = RT_TRUE;
381         touch->calibration_func = (rt_touch_calibration_func_t)args;
382         break;
383 
384     case RT_TOUCH_NORMAL:
385         touch->calibrating = RT_FALSE;
386         break;
387 
388     case RT_TOUCH_CALIBRATION_DATA:
389     {
390         struct calibration_data* data;
391         data = (struct calibration_data*) args;
392 
393         //update
394         touch->min_x = data->min_x;
395         touch->max_x = data->max_x;
396         touch->min_y = data->min_y;
397         touch->max_y = data->max_y;
398     }
399     break;
400     }
401 
402     return RT_EOK;
403 }
404 
_set_mouse_position(rt_uint32_t X,rt_uint32_t Y)405 void _set_mouse_position(rt_uint32_t X, rt_uint32_t Y)
406 {}
touch_thread_entry(void * parameter)407 static void touch_thread_entry(void *parameter)
408 {
409     rt_bool_t touch_down = RT_FALSE;
410     rt_uint32_t event_value;
411     struct rtgui_event_mouse emouse;
412     static struct _touch_previous
413     {
414         rt_uint32_t x;
415         rt_uint32_t y;
416     } touch_previous;
417 
418     RTGUI_EVENT_MOUSE_BUTTON_INIT(&emouse);
419     emouse.wid = RT_NULL;
420 
421     while(1)
422     {
423         /* 接收到触摸中断事件 */
424         if(rt_event_recv(&touch->event,
425                          1,
426                          RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
427                          100,
428                          &event_value)
429                 == RT_EOK)
430         {
431             while(1)
432             {
433                 if (IS_TOUCH_UP())
434                 {
435                     /* 触摸笔抬起 */
436                     /* touch up */
437                     emouse.button = (RTGUI_MOUSE_BUTTON_LEFT |RTGUI_MOUSE_BUTTON_UP);
438 
439                     /* use old value */
440                     emouse.x = touch->x;
441                     emouse.y = touch->y;
442 
443                     if(touch_down != RT_TRUE)
444                     {
445                         touch_int_cmd(RT_TRUE);
446                         break;
447                     }
448 
449                     if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
450                     {
451                         /* 触摸校准处理 */
452                         /* callback function */
453                         touch->calibration_func(emouse.x, emouse.y);
454 
455                     }
456                     else
457                     {
458                         /* 向ui发送触摸坐标 */
459                         rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
460                     }
461                     rt_kprintf("touch up: (%d, %d)\n", emouse.x, emouse.y);
462 
463                     /* clean */
464                     touch_previous.x = touch_previous.y = 0;
465                     touch_down = RT_FALSE;
466 
467                     touch_int_cmd(RT_TRUE);
468                     break;
469                 } /* touch up */
470                 else /* touch down or move */
471                 {
472                     if(touch_down == RT_FALSE)
473                     {
474                         rt_thread_delay(RT_TICK_PER_SECOND / 10);
475                     }
476                     else
477                     {
478                         rt_thread_delay(5);
479                     }
480 
481                     if(IS_TOUCH_UP()) continue;
482 
483                     /* calculation */
484                     rtgui_touch_calculate();
485 
486                     /* send mouse event */
487                     emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
488                     emouse.parent.sender = RT_NULL;
489 
490                     emouse.x = touch->x;
491                     emouse.y = touch->y;
492                     _set_mouse_position(emouse.x, emouse.y);
493                     /* 光标跟随 */
494                     /* init mouse button */
495                     emouse.button = (RTGUI_MOUSE_BUTTON_LEFT |RTGUI_MOUSE_BUTTON_DOWN);
496 
497                     /* send event to server */
498                     if (touch->calibrating != RT_TRUE)
499                     {
500 #define previous_keep      8
501                         /* filter. */
502                         if((touch_previous.x > touch->x + previous_keep)
503                             || (touch_previous.x < touch->x - previous_keep)
504                             || (touch_previous.y > touch->y + previous_keep)
505                             || (touch_previous.y < touch->y - previous_keep))
506                         {
507                             touch_previous.x = touch->x;
508                             touch_previous.y = touch->y;
509                             /* 向ui发送触摸坐标 */
510                             rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
511                             if(touch_down == RT_FALSE)
512                             {
513                                 touch_down = RT_TRUE;
514                                 rt_kprintf("touch down: (%d, %d)\n", emouse.x, emouse.y);
515                             }
516                             else
517                             {
518                                 rt_kprintf("touch motion: (%d, %d)\n", emouse.x, emouse.y);
519                             }
520                         }
521                     }
522                     else
523                     {
524                         touch_down = RT_TRUE;
525                     }
526                 } /* touch down or move */
527             } /* read touch */
528         } /* event recv */
529     } /* thread while(1) */
530 }
531 
532 
rtgui_touch_hw_init(const char * spi_device_name)533 rt_err_t rtgui_touch_hw_init(const char * spi_device_name)
534 {
535          rt_uint32_t arg[2];
536     struct rt_device * spi_device;
537         struct rt_thread * touch_thread;
538     rt_err_t err;
539 
540     rt_kprintf("spi1 cs0 start...\n");
541     spi_device = rt_device_find("spi10");
542     if(spi_device ==  RT_NULL)
543     {
544         rt_kprintf("Did not find spi1, exit thread....\n");
545         return;
546     }
547     err = rt_device_open(spi_device, RT_DEVICE_OFLAG_RDWR);
548     if(err != RT_EOK)
549     {
550         rt_kprintf("Open spi1 failed %08X, exit thread....\n", err);
551         return;
552     }
553 
554       /* config spi */
555       {
556           struct rt_spi_configuration cfg;
557           cfg.data_width = 8;
558           cfg.mode = RT_SPI_MODE_0;
559        cfg.max_hz  = 200 * 1000; /* 200K */
560         rt_spi_configure((struct rt_spi_device *)spi_device, &cfg);
561       }
562 
563     touch = (struct rtgui_touch_device*)rt_malloc (sizeof(struct rtgui_touch_device));
564     if (touch == RT_NULL) return -RT_ENOMEM; /* no memory yet */
565 
566     /* clear device structure */
567     rt_memset(&(touch->parent), 0, sizeof(struct rt_device));
568 
569     rt_event_init(&touch->event, "touch", RT_IPC_FLAG_FIFO);
570 
571     touch->spi_device = (struct rt_spi_device *)spi_device;
572     touch->calibrating = false;
573 
574     touch->min_x = MIN_X_DEFAULT;
575     touch->max_x = MAX_X_DEFAULT;
576     touch->min_y = MIN_Y_DEFAULT;
577     touch->max_y = MAX_Y_DEFAULT;
578 
579     /* init device structure */
580     touch->parent.type = RT_Device_Class_Miscellaneous;
581     touch->parent.init = rtgui_touch_init;
582     touch->parent.control = rtgui_touch_control;
583     touch->parent.user_data = RT_NULL;
584 
585     /* register touch device to RT-Thread */
586     rt_device_register(&(touch->parent), "touch", RT_DEVICE_FLAG_RDWR);
587 
588 
589     touch_thread = rt_thread_create("touch_thread",
590                                     touch_thread_entry, RT_NULL,
591                                     4096, RTGUI_SVR_THREAD_PRIORITY-1, 1);
592     if (touch_thread != RT_NULL) rt_thread_startup(touch_thread);
593 
594      rt_device_init((rt_device_t)touch);
595    return RT_EOK;
596 }
597 
598 #endif
599