1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2011, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
32 /*----------------------------------------------------------------------------
\r
34 *----------------------------------------------------------------------------*/
\r
36 /** \addtogroup tsd_module
\r
44 /*----------------------------------------------------------------------------
\r
46 *----------------------------------------------------------------------------*/
\r
48 /** Size in pixels of calibration points. */
\r
49 #define POINTS_SIZE 4
\r
50 /** Maximum difference in pixels between the test point and the measured point.
\r
52 #define POINTS_MAX_XERROR 10
\r
53 /** Maximum difference in pixels between the test point and the measured point.
\r
55 #define POINTS_MAX_YERROR 8
\r
57 /** Delay at the end of calibartion for result display (positive or negative) */
\r
58 #define DELAY_RESULT_DISPLAY 4000000
\r
60 /** Clear Strings on LCD */
\r
62 #define CLEAR_STRING() LCDD_Fill(COLOR_WHITE)
\r
64 #define CLEAR_STRING() \
\r
65 LCDD_DrawFilledRectangle(strX - 3*strW, strY, \
\r
66 strX + 20*strW, strY + 6*strH, COLOR_WHITE)
\r
69 /*----------------------------------------------------------------------------
\r
71 *----------------------------------------------------------------------------*/
\r
74 * Point used during the touchscreen calibration process.
\r
76 typedef struct _CalibrationPoint {
\r
78 /** Coordinate of point along the X-axis of the screen. */
\r
80 /** Coordinate of point along the Y-axis of the screen. */
\r
82 /** Calibration data of point. */
\r
87 /*----------------------------------------------------------------------------
\r
89 *----------------------------------------------------------------------------*/
\r
91 /** Calibration display title */
\r
92 static const char* strTitle = "LCD Calibration";
\r
94 /** indicates if the touch screen has been calibrated.
\r
95 If not, Callback functions are not called */
\r
96 static volatile uint8_t bCalibrationOk = 0;
\r
97 /** Slope for interpoling touchscreen measurements along the X-axis. */
\r
98 static int32_t xSlope;
\r
99 /** Slope for interpoling touchscreen measurements along the Y-axis. */
\r
100 static int32_t ySlope;
\r
102 /** Calibration points */
\r
103 static CalibrationPoint calibrationPoints[] = {
\r
105 /* Top-left corner calibration point */
\r
107 BOARD_LCD_WIDTH / 10,
\r
108 BOARD_LCD_HEIGHT / 10,
\r
111 /* Top-right corner calibration point */
\r
113 BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,
\r
114 BOARD_LCD_HEIGHT / 10,
\r
117 /* Bottom-right corner calibration point */
\r
119 BOARD_LCD_WIDTH - BOARD_LCD_WIDTH / 10,
\r
120 BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,
\r
123 /* Bottom-left corner calibration point */
\r
125 BOARD_LCD_WIDTH / 10,
\r
126 BOARD_LCD_HEIGHT - BOARD_LCD_HEIGHT / 10,
\r
132 static const CalibrationPoint testPoint = {
\r
133 BOARD_LCD_WIDTH / 2,
\r
134 BOARD_LCD_HEIGHT / 2,
\r
138 /*----------------------------------------------------------------------------
\r
139 * External functions
\r
140 *----------------------------------------------------------------------------*/
\r
142 /*----------------------------------------------------------------------------
\r
144 *----------------------------------------------------------------------------*/
\r
147 * Display a calibration point on the given buffer.
\r
148 * \param pPoint Calibration point to display.
\r
150 static void DrawCalibrationPoint(
\r
151 const CalibrationPoint *pPoint)
\r
153 LCDD_DrawFilledRectangle(pPoint->x - POINTS_SIZE / 2,
\r
154 pPoint->y - POINTS_SIZE / 2,
\r
155 pPoint->x + POINTS_SIZE,
\r
156 pPoint->y + POINTS_SIZE,
\r
161 * Clears a calibration point from the given buffer.
\r
162 * \param pLcdBuffer LCD buffer to draw on.
\r
163 * \param pPoint Calibration point to clear.
\r
165 static void ClearCalibrationPoint(
\r
166 const CalibrationPoint *pPoint)
\r
168 LCDD_DrawFilledRectangle(pPoint->x - POINTS_SIZE,
\r
169 pPoint->y - POINTS_SIZE,
\r
170 pPoint->x + POINTS_SIZE,
\r
171 pPoint->y + POINTS_SIZE,
\r
175 /*----------------------------------------------------------------------------
\r
176 * Exported functions
\r
177 *----------------------------------------------------------------------------*/
\r
180 * Indicates if the calibration of the touch screen is Ok
\r
181 * \return 1 calibration Ok, 0 if not
\r
183 uint8_t TSDCom_IsCalibrationOk(void)
\r
185 return bCalibrationOk;
\r
189 * Interpolates the provided raw measurements using the previously calculated
\r
190 * slope. The resulting x and y coordinates are stored in an array.
\r
191 * \param pData Raw measurement data, as returned by TSD_GetRawMeasurement().
\r
192 * \param pPoint Array in which x and y will be stored.
\r
194 void TSDCom_InterpolateMeasurement(const uint32_t *pData, uint32_t *pPoint)
\r
196 pPoint[0] = calibrationPoints[0].x
\r
197 - (((int32_t) calibrationPoints[0].data[0] - (int32_t) pData[0]) * 1024)
\r
200 pPoint[1] = calibrationPoints[0].y
\r
201 - (((int32_t) calibrationPoints[0].data[1] - (int32_t) pData[1]) * 1024)
\r
203 /* Is pPoint[0] negative ? */
\r
204 if(pPoint[0] & 0x80000000) pPoint[0] = 0;
\r
205 /* Is pPoint[0] bigger than the LCD width ? */
\r
206 if(pPoint[0] > BOARD_LCD_WIDTH) pPoint[0] = BOARD_LCD_WIDTH;
\r
207 /* Is pPoint[1] negative ? */
\r
208 if(pPoint[1] & 0x80000000) pPoint[1] = 0;
\r
209 /* Is pPoint[1] bigger than the LCD width ? */
\r
210 if(pPoint[1] > BOARD_LCD_HEIGHT) pPoint[1] = BOARD_LCD_HEIGHT;
\r
214 * Performs the calibration process using the provided buffer to display
\r
216 * \param pLcdBuffer LCD buffer to display.
\r
217 * \return True if calibration was successful; otherwise false.
\r
219 uint8_t TSDCom_Calibrate(void)
\r
221 uint32_t i; // to keep the tempo with gcc code optimisation
\r
222 int32_t slope1, slope2;
\r
223 CalibrationPoint measuredPoint;
\r
225 int32_t xDiff, yDiff;
\r
226 uint32_t strX = BOARD_LCD_WIDTH / 2 - 75, strY = 60;
\r
227 uint32_t strW, strH;
\r
229 LCDD_GetStringSize("P", &strW, &strH);
\r
230 /* Calibration setup */
\r
231 LCDD_Fill(COLOR_WHITE);
\r
232 LCDD_Flush_CurrentCanvas();
\r
233 LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);
\r
234 LCDD_Flush_CurrentCanvas();
\r
235 LCDD_DrawString(strX - 2*strW, strY + 3*strH,
\r
236 " Touch the dots to\ncalibrate the screen", COLOR_DARKBLUE);
\r
237 LCDD_Flush_CurrentCanvas();
\r
238 /* Calibration points */
\r
239 for (i = 0; i < 4; i++) {
\r
241 DrawCalibrationPoint(&calibrationPoints[i]);
\r
242 LCDD_Flush_CurrentCanvas();
\r
243 /* Wait for touch & end of conversion */
\r
244 TSD_WaitPenPressed();
\r
245 TSD_GetRawMeasurement(calibrationPoints[i].data);
\r
246 ClearCalibrationPoint(&calibrationPoints[i]);
\r
247 LCDD_Flush_CurrentCanvas();
\r
248 /* Wait for contact loss */
\r
249 TSD_WaitPenReleased();
\r
250 printf("P%d: (%d,%d)\n\r", (unsigned int)i, (unsigned int)calibrationPoints[i].data[0], (unsigned int)calibrationPoints[i].data[1]);
\r
253 /* Calculate slopes using the calibration data
\r
254 * Theory behind those calculations:
\r
255 * - We suppose the touchscreen measurements are linear, so the following equations are true (simple
\r
256 * linear regression) for any two 'a' and 'b' points of the screen:
\r
257 * dx = (a.data[0] - b.data[0]) / (a.x - b.x)
\r
258 * dy = (a.data[1] - b.data[1]) / (a.y - b.y)
\r
260 * - We calculate dx and dy (called xslope and yslope here) using the calibration points.
\r
262 * - We can then use dx and dy to infer the position of a point 'p' given the measurements performed
\r
263 * by the touchscreen ('c' is any of the calibration points):
\r
264 * dx = (p.data[0] - c.data[0]) / (p.x - c.x)
\r
265 * dy = (p.data[1] - c.data[1]) / (p.y - c.y)
\r
267 * p.x = c.x - (p.data[0] - c.data[0]) / dx
\r
268 * p.y = c.y - (p.data[1] - c.data[1]) / dy
\r
270 * - Since there are four calibration points, dx and dy can be calculated twice, so we average
\r
273 slope1 = ((int32_t) calibrationPoints[0].data[0]) - ((int32_t) calibrationPoints[1].data[0]);
\r
275 slope1 /= ((int32_t) calibrationPoints[0].x) - ((int32_t) calibrationPoints[1].x);
\r
276 slope2 = ((int32_t) calibrationPoints[2].data[0]) - ((int32_t) calibrationPoints[3].data[0]);
\r
278 slope2 /= ((int32_t) calibrationPoints[2].x) - ((int32_t) calibrationPoints[3].x);
\r
279 xSlope = (slope1 + slope2) / 2;
\r
281 slope1 = ((int32_t) calibrationPoints[0].data[1]) - ((int32_t) calibrationPoints[2].data[1]);
\r
283 slope1 /= ((int32_t) calibrationPoints[0].y) - ((int32_t) calibrationPoints[2].y);
\r
284 slope2 = ((int32_t) calibrationPoints[1].data[1]) - ((int32_t) calibrationPoints[3].data[1]);
\r
286 slope2 /= ((int32_t) calibrationPoints[1].y) - ((int32_t) calibrationPoints[3].y);
\r
287 ySlope = (slope1 + slope2) / 2;
\r
289 printf("Slope: %d, %d\n\r", (unsigned int)xSlope, (unsigned int)ySlope);
\r
293 LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);
\r
294 LCDD_DrawString(strX - 2*strW, strY + 3*strH,
\r
295 " Touch the point to\nvalidate calibration", COLOR_DARKBLUE);
\r
296 LCDD_Flush_CurrentCanvas();
\r
297 DrawCalibrationPoint(&testPoint);
\r
298 LCDD_Flush_CurrentCanvas();
\r
299 /* Wait for touch & end of conversion */
\r
300 TSD_WaitPenPressed();
\r
302 TSD_GetRawMeasurement(measuredPoint.data);
\r
303 TSDCom_InterpolateMeasurement(measuredPoint.data, (uint32_t *) &measuredPoint);
\r
304 DrawCalibrationPoint(&measuredPoint);
\r
305 LCDD_Flush_CurrentCanvas();
\r
306 /* Check resulting x and y */
\r
307 xDiff = (int32_t) measuredPoint.x - (int32_t) testPoint.x;
\r
308 yDiff = (int32_t) measuredPoint.y - (int32_t) testPoint.y;
\r
309 xOk = (xDiff >= -POINTS_MAX_XERROR) && (xDiff <= POINTS_MAX_XERROR);
\r
310 yOk = (yDiff >= -POINTS_MAX_YERROR) && (yDiff <= POINTS_MAX_YERROR);
\r
312 /* Wait for contact loss */
\r
313 TSD_WaitPenReleased();
\r
315 printf("TP: %d, %d -> %d, %d\n\r",
\r
316 (unsigned int)measuredPoint.data[0], (unsigned int)measuredPoint.data[1],
\r
317 (unsigned int)measuredPoint.x, (unsigned int)measuredPoint.y);
\r
319 /* Check calibration result */
\r
322 bCalibrationOk = 1;
\r
324 LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);
\r
325 LCDD_DrawString(strX + 3*strW, strY + 2*strH, "Success !", COLOR_GREEN);
\r
326 LCDD_Flush_CurrentCanvas();
\r
330 bCalibrationOk = 0;
\r
332 LCDD_DrawString(strX, strY, strTitle, COLOR_BLACK);
\r
333 LCDD_DrawString(strX + strW, strY + 2*strH, "Error too big", COLOR_RED);
\r
334 LCDD_Flush_CurrentCanvas();
\r
335 TRACE_WARNING("X %u, Y %u; Diff %d, %d\n\r",
\r
336 (unsigned int)(measuredPoint.x), (unsigned int)(measuredPoint.y), (unsigned int)xDiff, (unsigned int)yDiff);
\r
340 for (i = 0; i < DELAY_RESULT_DISPLAY; i++);
\r
341 LCDD_Flush_CurrentCanvas();
\r
342 return (xOk && yOk);
\r
346 * Read calibrate data to buffer.
\r
347 * \param pBuffer Data buffer.
\r
348 * \param size Size of data buffer in bytes.
\r
350 void TSDCom_ReadCalibrateData(void *pBuffer, uint32_t size)
\r
352 uint8_t *pDest = (uint8_t *)pBuffer;
\r
354 memcpy(pDest, (void const *)&bCalibrationOk, sizeof(bCalibrationOk));
\r
355 pDest += sizeof(bCalibrationOk);
\r
356 memcpy(pDest, &xSlope, sizeof(xSlope));
\r
357 pDest += sizeof(xSlope);
\r
358 memcpy(pDest, &ySlope, sizeof(ySlope));
\r
359 pDest += sizeof(ySlope);
\r
360 memcpy(pDest, &calibrationPoints[0].data, sizeof(calibrationPoints[0].data));
\r
361 pDest += sizeof(calibrationPoints[0].data);
\r
365 * Restore calibrate data with buffer data.
\r
366 * \param pBuffer Data buffer.
\r
367 * \param size Size of data buffer in bytes.
\r
369 void TSDCom_RestoreCalibrateData(void *pBuffer, uint32_t size)
\r
371 uint8_t *pSrc = (uint8_t *)pBuffer;
\r
373 memcpy((void *)&bCalibrationOk, pSrc, sizeof(bCalibrationOk));
\r
374 pSrc += sizeof(bCalibrationOk);
\r
375 memcpy(&xSlope, pSrc, sizeof(xSlope));
\r
376 pSrc += sizeof(xSlope);
\r
377 memcpy(&ySlope, pSrc, sizeof(ySlope));
\r
378 pSrc += sizeof(ySlope);
\r
379 memcpy(&calibrationPoints[0].data, pSrc, sizeof(calibrationPoints[0].data));
\r
380 pSrc += sizeof(calibrationPoints[0].data);
\r