comparison packages/devs/touch/arm/aaed2000/current/src/aaed2000_ts.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children d2c90368aeef
comparison
equal deleted inserted replaced
207:74c807ddde34 208:e0c0827131d1
1 //==========================================================================
2 //
3 // aaed2000_ts.c
4 //
5 // Touchscreen driver for the Agilent aaed2000
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s): gthomas
44 // Contributors: gthomas
45 // Date: 2002-03-05
46 // Purpose:
47 // Description: Touchscreen driver for Agilent AAED2000
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53
54 #include <pkgconf/devs_touch_aaed2000.h>
55
56 #include <cyg/kernel/kapi.h>
57 #include <cyg/hal/hal_io.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/drv_api.h>
60 #include <cyg/hal/hal_intr.h>
61 #include <cyg/hal/aaed2000.h>
62 #include <cyg/infra/cyg_type.h>
63 #include <cyg/infra/cyg_ass.h>
64 #include <cyg/infra/diag.h>
65
66 #include <cyg/fileio/fileio.h> // For select() functionality
67 static cyg_selinfo ts_select_info;
68 static cyg_bool ts_select_active;
69
70 #include <cyg/io/devtab.h>
71
72 /* ADS7846 flags */
73 #define ADS_START (1 << 7)
74 #define ADS_MEASURE_Y (0x01 << 4)
75 #define ADS_MEASURE_X (0x05 << 4)
76 #define ADS_MODE_12_BIT 0
77 #define ADS_PD0 0
78
79 // Misc constants
80 #define TS_INT (1<<0)
81 #define X_THRESHOLD 0x80
82 #define Y_THRESHOLD 0x80
83
84 // Functions in this module
85
86 static Cyg_ErrNo ts_read(cyg_io_handle_t handle,
87 void *buffer,
88 cyg_uint32 *len);
89 static cyg_bool ts_select(cyg_io_handle_t handle,
90 cyg_uint32 which,
91 cyg_addrword_t info);
92 static Cyg_ErrNo ts_set_config(cyg_io_handle_t handle,
93 cyg_uint32 key,
94 const void *buffer,
95 cyg_uint32 *len);
96 static Cyg_ErrNo ts_get_config(cyg_io_handle_t handle,
97 cyg_uint32 key,
98 void *buffer,
99 cyg_uint32 *len);
100 static bool ts_init(struct cyg_devtab_entry *tab);
101 static Cyg_ErrNo ts_lookup(struct cyg_devtab_entry **tab,
102 struct cyg_devtab_entry *st,
103 const char *name);
104
105 CHAR_DEVIO_TABLE(aaed2000_ts_handlers,
106 NULL, // Unsupported write() function
107 ts_read,
108 ts_select,
109 ts_get_config,
110 ts_set_config);
111
112 CHAR_DEVTAB_ENTRY(aaed2000_ts_device,
113 CYGDAT_DEVS_TOUCH_AAED2000_NAME,
114 NULL, // Base device name
115 &aaed2000_ts_handlers,
116 ts_init,
117 ts_lookup,
118 NULL); // Private data pointer
119
120 struct _event {
121 short button_state;
122 short xPos, yPos;
123 short _unused;
124 };
125 #define MAX_EVENTS CYGNUM_DEVS_TOUCH_AAED2000_EVENT_BUFFER_SIZE
126 static int num_events;
127 static int _event_put, _event_get;
128 static struct _event _events[MAX_EVENTS];
129
130 static bool _is_open = false;
131 #ifdef DEBUG_RAW_EVENTS
132 static unsigned char _ts_buf[512];
133 static int _ts_buf_ptr = 0;
134 #endif
135
136 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
137 static char ts_scan_stack[STACK_SIZE];
138 static cyg_thread ts_scan_thread_data;
139 static cyg_handle_t ts_scan_thread_handle;
140 #define SCAN_FREQ 20 // Hz
141 //#define SCAN_FREQ 5 // Hz
142 #define SCAN_DELAY ((1000/SCAN_FREQ)/10)
143
144
145 typedef struct {
146 short min;
147 short max;
148 short span;
149 } bounds;
150
151 static bounds xBounds = {1024, 0, 1024};
152 static bounds yBounds = {1024, 0, 1024};
153
154 static Cyg_ErrNo
155 ts_read(cyg_io_handle_t handle,
156 void *buffer,
157 cyg_uint32 *len)
158 {
159 struct _event *ev;
160 int tot = *len;
161 unsigned char *bp = (unsigned char *)buffer;
162
163 cyg_scheduler_lock(); // Prevent interaction with DSR code
164 while (tot >= sizeof(struct _event)) {
165 if (num_events > 0) {
166 ev = &_events[_event_get++];
167 if (_event_get == MAX_EVENTS) {
168 _event_get = 0;
169 }
170 // Self calibrate
171 if (ev->xPos > xBounds.max) xBounds.max = ev->xPos;
172 if (ev->xPos < xBounds.min) xBounds.min = ev->xPos;
173 if (ev->yPos > yBounds.max) yBounds.max = ev->yPos;
174 if (ev->yPos < yBounds.min) yBounds.min = ev->yPos;
175 if ((xBounds.span = xBounds.max - xBounds.min) <= 1) {
176 xBounds.span = 1;
177 }
178 if ((yBounds.span = yBounds.max - yBounds.min) <= 1) {
179 yBounds.span = 1;
180 }
181 // Scale values - done here so these potentially lengthy
182 // operations take place outside of interrupt processing
183 #ifdef DEBUG
184 diag_printf("Raw[%d,%d], X[%d,%d,%d], Y[%d,%d,%d]",
185 ev->xPos, ev->yPos,
186 xBounds.max, xBounds.min, xBounds.span,
187 yBounds.max, yBounds.min, yBounds.span);
188 #endif
189 ev->xPos = 640 - (((xBounds.max - ev->xPos) * 640) / xBounds.span);
190 ev->yPos = 480 - (((yBounds.max - ev->yPos) * 480) / yBounds.span);
191 #ifdef DEBUG
192 diag_printf(", Cooked[%d,%d]\n",
193 ev->xPos, ev->yPos);
194 #endif
195 memcpy(bp, ev, sizeof(*ev));
196 bp += sizeof(*ev);
197 tot -= sizeof(*ev);
198 num_events--;
199 } else {
200 break; // No more events
201 }
202 }
203 cyg_scheduler_unlock(); // Allow DSRs again
204 *len -= tot;
205 return ENOERR;
206 }
207
208 static cyg_bool
209 ts_select(cyg_io_handle_t handle,
210 cyg_uint32 which,
211 cyg_addrword_t info)
212 {
213 if (which == CYG_FREAD) {
214 cyg_scheduler_lock(); // Prevent interaction with DSR code
215 if (num_events > 0) {
216 cyg_scheduler_unlock(); // Reallow interaction with DSR code
217 return true;
218 }
219 if (!ts_select_active) {
220 ts_select_active = true;
221 cyg_selrecord(info, &ts_select_info);
222 }
223 cyg_scheduler_unlock(); // Reallow interaction with DSR code
224 }
225 return false;
226 }
227
228 static Cyg_ErrNo
229 ts_set_config(cyg_io_handle_t handle,
230 cyg_uint32 key,
231 const void *buffer,
232 cyg_uint32 *len)
233 {
234 return EINVAL;
235 }
236
237 static Cyg_ErrNo
238 ts_get_config(cyg_io_handle_t handle,
239 cyg_uint32 key,
240 void *buffer,
241 cyg_uint32 *len)
242 {
243 return EINVAL;
244 }
245
246 static bool
247 ts_init(struct cyg_devtab_entry *tab)
248 {
249 cyg_uint32 _dummy;
250
251 // Initialize SSP interface
252 #if 0
253 while (*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) {
254 _dummy = *(volatile cyg_uint32 *)AAEC_SSP_DR; // Drain FIFO
255 }
256 #endif
257 *(volatile cyg_uint32 *)AAEC_SSP_CR0 =
258 (1 << AAEC_SSP_CR0_SSE) | // SSP enable
259 (37 << AAEC_SSP_CR0_SCR) | // Serial clock rate
260 (AAEC_SSP_CR0_FRF_NAT << AAEC_SSP_CR0_FRF) | // MicroWire
261 ((12-1) << AAEC_SSP_CR0_SIZE); // 12 bit words
262 *(volatile cyg_uint32 *)AAEC_SSP_CR1 =
263 (1 << AAEC_SSP_CR1_FEN); // Enable FIFO
264 *(volatile cyg_uint32 *)AAEC_SSP_CPSR = 2; // Clock prescale
265 *(volatile cyg_uint32 *)AAEC_PFDDR &= ~(1<<0); // TS uses port F bit 0
266 cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_TS);
267 cyg_selinit(&ts_select_info);
268 return true;
269 }
270
271 static cyg_uint32
272 read_ts(int axis)
273 {
274 cyg_uint32 res;
275
276 *(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT | ADS_PD0);
277 *(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT);
278 // Wait for data
279 while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0);
280 res = *(volatile cyg_uint32 *)AAEC_SSP_DR; // ignore first datum
281 // Wait for data
282 while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0);
283 res = *(volatile cyg_uint32 *)AAEC_SSP_DR;
284 return res;
285 }
286
287 static void
288 ts_scan(cyg_addrword_t param)
289 {
290 short lastX, lastY;
291 short x, y;
292 struct _event *ev;
293 bool pen_down;
294
295 diag_printf("Touch Screen thread started\n");
296 // Discard the first sample - it's always 0
297 x = read_ts(ADS_MEASURE_X);
298 y = read_ts(ADS_MEASURE_Y);
299 lastX = lastY = -1;
300 pen_down = false;
301 while (true) {
302 cyg_thread_delay(SCAN_DELAY);
303 if ((*(volatile cyg_uint32 *)AAEC_PFDR & TS_INT) == 0) {
304 // Pen is down
305 x = read_ts(ADS_MEASURE_X);
306 y = read_ts(ADS_MEASURE_Y);
307 // diag_printf("X = %x, Y = %x\n", x, y);
308 if ((x < X_THRESHOLD) || (y < Y_THRESHOLD)) {
309 // Ignore 'bad' samples
310 continue;
311 }
312 lastX = x; lastY = y;
313 pen_down = true;
314 } else {
315 if (pen_down) {
316 // Capture first 'up' event
317 pen_down = false;
318 x = lastX;
319 y = lastY;
320 } else {
321 continue; // Nothing new to report
322 }
323 }
324 if (num_events < MAX_EVENTS) {
325 num_events++;
326 ev = &_events[_event_put++];
327 if (_event_put == MAX_EVENTS) {
328 _event_put = 0;
329 }
330 ev->button_state = pen_down ? 0x04 : 0x00;
331 ev->xPos = x;
332 ev->yPos = y;
333 if (ts_select_active) {
334 ts_select_active = false;
335 cyg_selwakeup(&ts_select_info);
336 }
337 }
338 #ifdef DEBUG_RAW_EVENTS
339 memcpy(&_ts_buf[_ts_buf_ptr], pkt->data, 8);
340 _ts_buf_ptr += 8;
341 if (_ts_buf_ptr == 512) {
342 diag_printf("TS handler\n");
343 diag_dump_buf(_ts_buf, 512);
344 _ts_buf_ptr = 0;
345 }
346 #endif
347 }
348 }
349
350 static Cyg_ErrNo
351 ts_lookup(struct cyg_devtab_entry **tab,
352 struct cyg_devtab_entry *st,
353 const char *name)
354 {
355 if (!_is_open) {
356 _is_open = true;
357 cyg_thread_create(1, // Priority
358 ts_scan, // entry
359 0, // entry parameter
360 "Touch Screen scan", // Name
361 &ts_scan_stack[0], // Stack
362 STACK_SIZE, // Size
363 &ts_scan_thread_handle, // Handle
364 &ts_scan_thread_data // Thread data structure
365 );
366 cyg_thread_resume(ts_scan_thread_handle); // Start it
367 }
368 return ENOERR;
369 }