drv_adc_touch.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**************************************************************************//**
  2. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-04-20 Wayne First version
  9. *
  10. ******************************************************************************/
  11. #include <rtconfig.h>
  12. #if defined(BSP_USING_ADC_TOUCH)
  13. #include "NuMicro.h"
  14. #include <rtdevice.h>
  15. #include "drv_adc.h"
  16. #include "touch.h"
  17. typedef struct
  18. {
  19. struct rt_touch_device dev;
  20. rt_uint32_t x_range;
  21. rt_uint32_t y_range;
  22. } nu_adc_touch;
  23. typedef nu_adc_touch *nu_adc_touch_t;
  24. static nu_adc_touch s_NuAdcTouch = {0};
  25. #define DEF_CALDATA_LENGTH 7
  26. static int cal_data_a[DEF_CALDATA_LENGTH] = { 13230, -66, -1161952, -85, 8600, -1636996, 65536 };
  27. static const int cal_zero[DEF_CALDATA_LENGTH] = { 1, 0, 0, 0, 1, 0, 1 };
  28. static void nu_adc_touch_cal(int *sumx, int *sumy)
  29. {
  30. int xtemp, ytemp;
  31. xtemp = *sumx;
  32. ytemp = *sumy;
  33. *sumx = (cal_data_a[2] +
  34. cal_data_a[0] * xtemp +
  35. cal_data_a[1] * ytemp) / cal_data_a[6];
  36. *sumy = (cal_data_a[5] +
  37. cal_data_a[3] * xtemp +
  38. cal_data_a[4] * ytemp) / cal_data_a[6];
  39. }
  40. static rt_size_t nu_adc_touch_readpoint(struct rt_touch_device *device, void *buf, rt_size_t read_num)
  41. {
  42. static int last_report_x = 0, last_report_y = 0;
  43. struct rt_touch_data *pPoint = (struct rt_touch_data *)buf;
  44. nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device;
  45. RT_ASSERT(device != RT_NULL);
  46. RT_ASSERT(buf != RT_NULL);
  47. int i;
  48. for (i = 0; i < read_num; i++)
  49. {
  50. int bufZ0 = 0, bufZ1 = 0;
  51. int sumx = 0, sumy = 0;
  52. pPoint[i].timestamp = rt_touch_get_ts();
  53. pPoint[i].track_id = 0;
  54. if (nu_adc_read_touch_xyz((uint16_t *)&sumx, (uint16_t *)&sumy, (uint16_t *)&bufZ0, (uint16_t *)&bufZ1, 1) != 1)
  55. break;
  56. if (bufZ0 == 0)
  57. {
  58. /* Workaround: In this case, x, y values are unstable. so, report last point's coordinate.*/
  59. pPoint[i].event = RT_TOUCH_EVENT_UP;
  60. pPoint[i].x_coordinate = last_report_x;
  61. pPoint[i].y_coordinate = last_report_y;
  62. }
  63. else
  64. {
  65. nu_adc_touch_cal(&sumx, &sumy);
  66. pPoint[i].event = RT_TOUCH_EVENT_DOWN;
  67. pPoint[i].x_coordinate = sumx;
  68. pPoint[i].y_coordinate = sumy;
  69. last_report_x = sumx;
  70. last_report_y = sumy;
  71. }
  72. bufZ0 = bufZ0 >> 3;
  73. pPoint[i].width = (bufZ0 > 255) ? 255 : bufZ0;
  74. //Limit max x, y coordinate if value is over its range.
  75. pPoint[i].x_coordinate = (pPoint[i].x_coordinate > psNuAdcTouch->x_range) ? psNuAdcTouch->x_range : pPoint[i].x_coordinate;
  76. pPoint[i].y_coordinate = (pPoint[i].y_coordinate > psNuAdcTouch->y_range) ? psNuAdcTouch->y_range : pPoint[i].y_coordinate;
  77. }
  78. return (rt_size_t)i;
  79. }
  80. static rt_err_t nu_adc_touch_control(struct rt_touch_device *device, int cmd, void *data)
  81. {
  82. nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device;
  83. RT_ASSERT(psNuAdcTouch != RT_NULL);
  84. switch (cmd)
  85. {
  86. case RT_TOUCH_CTRL_SET_X_RANGE: /* set x range */
  87. psNuAdcTouch->x_range = *((rt_int32_t *)data);
  88. break;
  89. case RT_TOUCH_CTRL_SET_Y_RANGE: /* set y range */
  90. psNuAdcTouch->y_range = *((rt_int32_t *)data);
  91. break;
  92. case RT_TOUCH_CTRL_ENABLE_INT: /* enable pen_down interrupt */
  93. nu_adc_touch_detect(RT_TRUE);
  94. break;
  95. case RT_TOUCH_CTRL_DISABLE_INT: /* disable pen_down interrupt */
  96. nu_adc_touch_detect(RT_FALSE);
  97. break;
  98. case RT_TOUCH_CTRL_POWER_ON: /* Touch Power On */
  99. return nu_adc_touch_enable(device);
  100. case RT_TOUCH_CTRL_POWER_OFF: /* Touch Power Off */
  101. return nu_adc_touch_disable();
  102. default:
  103. return -RT_ERROR;
  104. }
  105. return RT_EOK;
  106. }
  107. static struct rt_touch_ops touch_ops =
  108. {
  109. .touch_readpoint = nu_adc_touch_readpoint,
  110. .touch_control = nu_adc_touch_control,
  111. };
  112. void nu_adc_touch_update_caldata(int *psi32NewValue)
  113. {
  114. rt_memcpy(&cal_data_a[0], &psi32NewValue[0], sizeof(cal_data_a));
  115. }
  116. void nu_adc_touch_reset_caldata(int *psi32NewValue)
  117. {
  118. rt_memcpy(&cal_data_a[0], &cal_zero[0], sizeof(cal_data_a));
  119. }
  120. int rt_hw_adc_touch_init(void)
  121. {
  122. /* Register touch device */
  123. s_NuAdcTouch.dev.info.type = RT_TOUCH_TYPE_RESISTANCE;
  124. s_NuAdcTouch.dev.info.vendor = RT_TOUCH_VENDOR_UNKNOWN;
  125. s_NuAdcTouch.dev.info.point_num = 1;
  126. s_NuAdcTouch.dev.info.range_x = 800;
  127. s_NuAdcTouch.dev.info.range_x = 480;
  128. s_NuAdcTouch.dev.ops = &touch_ops;
  129. return (int)rt_hw_touch_register(&s_NuAdcTouch.dev, "adc_touch", RT_DEVICE_FLAG_INT_RX, RT_NULL);
  130. }
  131. INIT_DEVICE_EXPORT(rt_hw_adc_touch_init);
  132. static rt_thread_t adc_touch_thread = RT_NULL;
  133. static rt_sem_t adc_touch_sem = RT_NULL;
  134. static int adc_touch_worker_run = 0;
  135. static rt_err_t adc_touch_rx_callback(rt_device_t dev, rt_size_t size)
  136. {
  137. rt_sem_release(adc_touch_sem);
  138. return 0;
  139. }
  140. static void adc_touch_entry(void *parameter)
  141. {
  142. struct rt_touch_data touch_point;
  143. rt_err_t result;
  144. rt_device_t pdev = &s_NuAdcTouch.dev.parent;
  145. int max_range;
  146. adc_touch_sem = rt_sem_create("adc_touch_sem", 0, RT_IPC_FLAG_FIFO);
  147. RT_ASSERT(adc_touch_sem != RT_NULL);
  148. result = rt_device_open(pdev, RT_DEVICE_FLAG_INT_RX);
  149. RT_ASSERT(result == RT_EOK);
  150. result = rt_device_set_rx_indicate(pdev, adc_touch_rx_callback);
  151. RT_ASSERT(result == RT_EOK);
  152. max_range = 800;
  153. result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_X_RANGE, (void *)&max_range);
  154. RT_ASSERT(result == RT_EOK);
  155. max_range = 480;
  156. result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_Y_RANGE, (void *)&max_range);
  157. RT_ASSERT(result == RT_EOK);
  158. // nu_adc_touch_reset_caldata(int *psi32NewValue);
  159. // nu_adc_touch_update_caldata(int *psi32NewValue);
  160. result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_ON, RT_NULL);
  161. RT_ASSERT(result == RT_EOK);
  162. while (adc_touch_worker_run)
  163. {
  164. if ((-RT_ETIMEOUT == rt_sem_take(adc_touch_sem, rt_tick_from_millisecond(100))))
  165. continue;
  166. rt_memset(&touch_point, 0, sizeof(struct rt_touch_data));
  167. if (rt_device_read(pdev, 0, &touch_point, s_NuAdcTouch.dev.info.point_num) == s_NuAdcTouch.dev.info.point_num)
  168. {
  169. if (touch_point.event == RT_TOUCH_EVENT_DOWN
  170. || touch_point.event == RT_TOUCH_EVENT_UP
  171. || touch_point.event == RT_TOUCH_EVENT_MOVE)
  172. {
  173. #if defined(PKG_USING_LITTLEVGL2RTT)
  174. extern void littlevgl2rtt_send_input_event(rt_int16_t x, rt_int16_t y, rt_uint8_t state);
  175. littlevgl2rtt_send_input_event(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event);
  176. #endif
  177. #if defined(PKG_USING_NUEMWIN)
  178. extern void nuemwin_send_input_event(rt_int16_t x, rt_int16_t y, rt_uint8_t state);
  179. nuemwin_send_input_event(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event);
  180. #endif
  181. rt_kprintf("[%d-%d] id=%d width=%d x=%d y=%d\n",
  182. touch_point.timestamp,
  183. touch_point.event,
  184. touch_point.track_id,
  185. touch_point.width,
  186. touch_point.x_coordinate,
  187. touch_point.y_coordinate);
  188. }
  189. }
  190. }
  191. result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_OFF, RT_NULL);
  192. RT_ASSERT(result == RT_EOK);
  193. result = rt_device_close(pdev);
  194. RT_ASSERT(result == RT_EOK);
  195. }
  196. /* Support "nu_touch_start" command line in msh mode */
  197. static rt_err_t nu_touch_start(int argc, char **argv)
  198. {
  199. if (adc_touch_thread == RT_NULL)
  200. {
  201. adc_touch_thread = rt_thread_create("adc_touch_thread",
  202. adc_touch_entry,
  203. RT_NULL,
  204. 1024,
  205. 25,
  206. 5);
  207. adc_touch_worker_run = 1;
  208. if (adc_touch_thread != RT_NULL)
  209. rt_thread_startup(adc_touch_thread);
  210. }
  211. return 0;
  212. }
  213. MSH_CMD_EXPORT(nu_touch_start, e.g: start adc touch);
  214. /* Support "nu_touch_stop" command line in msh mode */
  215. static rt_err_t nu_touch_stop(int argc, char **argv)
  216. {
  217. adc_touch_worker_run = 0;
  218. adc_touch_thread = RT_NULL;
  219. return 0;
  220. }
  221. MSH_CMD_EXPORT(nu_touch_stop, e.g: stop adc touch);
  222. #endif //#if defined(BSP_USING_ADC_TOUCH)