Nuvoton
/
NuMaker-mbed-emWin-example
NuMaker emWin HMI
Embed:
(wiki syntax)
Show/hide line numbers
ts_calibrate.c
00001 /* 00002 * ts_calibrate.c 00003 * 00004 * Copyright (C) 2022 Nuvoton Technology 00005 * 00006 * 00007 */ 00008 #include <stdio.h> 00009 #include <stdlib.h> 00010 #include <string.h> 00011 #include "NuMicro.h" 00012 #include "GUI.h" 00013 #include "TouchPanel.h" 00014 00015 #define POINT_NUM 5 //7 00016 #define MAX_NUM 200 00017 00018 #define DIFF 5 00019 00020 typedef struct 00021 { 00022 int x; 00023 int y; 00024 } coordiante; 00025 00026 // physical.x, y is the coordinate of H/W for LCD. 00027 // logical x,y is the coordinate of GUI. 00028 coordiante physical[POINT_NUM], logical[POINT_NUM]; 00029 00030 // samples x, y for calibration. maximum number is adjustable MAX_NUM 00031 // the duration is at least 2 seconds for clicking down, and then release 00032 00033 int sampleX[MAX_NUM], sampleY[MAX_NUM]; 00034 /* 00035 // Binary linear equations are as follows, it is the key of solution. 00036 // logical.x = physical.x X A + physical.y X B + C 00037 // logical.y = physical.x X D + physical.y X E + F 00038 // Xl = A x Xp + B x Yp + C 00039 // Yl = D x Xp + E x Yp + F 00040 // We use Xp and Yp to be the multiple of the above equations, and obtain the following equations. 00041 // Xl = A x Xp + B x Yp + C 00042 // Xl x Xp = A x Xp x Xp + B x Yp x Xp + C x Xp 00043 // Xl x Yp = A x Xp x Yp + B x Yp x Yp + C x Yp 00044 // we obtain A, B, C from the above 3 equations, by accumulating the coordinates of 5 points. 00045 // Yl = D x Xp + E x Yp + F 00046 // Yl x Xp = D x Xp x Xp + E x Yp x Xp + F x Xp 00047 // Yl x Yp = D x Xp x Yp + E x Yp x Yp + F x Yp 00048 // we obtain D, E, F from the above 3 equations, by accumulating the coordinates of 5 points. 00049 // the value of calibration : A B C D E F (65536), 7 integers used, 1 integer reserved 00050 */ 00051 int cal_values[8]; 00052 00053 00054 int ts_writefile(void); 00055 int ts_readfile(void); 00056 int ts_calibrate(int xsize, int ysize); 00057 int ts_phy2log(int *logx, int *logy); 00058 00059 int DisplayFailStatus(int xsize, int ysize) 00060 { 00061 int i; 00062 00063 GUI_SetFont(&GUI_Font32_ASCII); 00064 GUI_SetTextMode(GUI_TM_XOR); 00065 00066 for (i=0; i<3; i++) 00067 { 00068 GUI_DispStringHCenterAt("Fail to calibrate", xsize / 2, ysize / 4 + 30); 00069 GUI_X_Delay(500); 00070 GUI_DispStringHCenterAt("Fail to calibrate", xsize / 2, ysize / 4 + 30); 00071 GUI_X_Delay(500); 00072 } 00073 00074 return -1; 00075 } 00076 00077 void write_cross(int x, int y) 00078 { 00079 GUI_DrawLine(x - 12, y, x - 2, y); 00080 GUI_DrawLine(x + 2, y, x + 12, y); 00081 GUI_DrawLine(x, y - 12, x, y - 2); 00082 GUI_DrawLine(x, y + 2, x, y + 12); 00083 GUI_DrawLine(x - 6, y - 12, x - 12, y - 12); 00084 GUI_DrawLine(x - 12, y - 12, x - 12, y - 6); 00085 GUI_DrawLine(x - 12, y + 6, x - 12, y + 12); 00086 GUI_DrawLine(x - 12, y + 12, x - 6, y + 12); 00087 GUI_DrawLine(x + 6, y + 12, x + 12, y + 12); 00088 GUI_DrawLine(x + 12, y + 12, x + 12, y + 6); 00089 GUI_DrawLine(x + 12, y - 6, x + 12, y - 12); 00090 GUI_DrawLine(x + 12, y - 12, x + 6, y - 12); 00091 } 00092 00093 static int compare_x(const void* arg1, const void *arg2) 00094 { 00095 int ret; 00096 ret = *(int *)arg1 -*(int *)arg2; 00097 if ( ret > 0 ) 00098 return 1; 00099 else if ( ret < 0 ) 00100 return -1; 00101 return 0; 00102 } 00103 00104 static int compare_y(const void* arg1, const void *arg2) 00105 { 00106 int ret; 00107 ret = *(int *)arg1 -*(int *)arg2; 00108 if ( ret > 0 ) 00109 return 1; 00110 else if ( ret < 0 ) 00111 return -1; 00112 return 0; 00113 } 00114 00115 int read_phy_xy(int *x, int *y) 00116 { 00117 00118 int number, middle; 00119 int phyx, phyy; 00120 00121 printf("read physical x, y\n"); 00122 again: 00123 while (1) 00124 { 00125 if ( Read_TouchPanel(&phyx, &phyy) > 0 ) 00126 { 00127 if ( (phyx < 0) || ( phyy < 0 ) ) 00128 continue; 00129 break; 00130 } 00131 } 00132 00133 // Delay 50 ms to wait HW ADC to be ready 00134 GUI_X_Delay(50); 00135 number = 0; 00136 while (1) 00137 { 00138 if ( Read_TouchPanel(&phyx, &phyy) > 0) 00139 { 00140 sampleX[number] = phyx; 00141 sampleY[number] = phyy; 00142 } 00143 else 00144 { 00145 break; 00146 } 00147 if ( number < MAX_NUM-1) 00148 number++; 00149 } 00150 00151 printf("Capture %d samples\n",number); 00152 00153 // pick the average value of the middle for the coordinate x, y 00154 middle = number/2; 00155 qsort(sampleX, number, sizeof(int), compare_x); 00156 *x = (sampleX[middle-1] + sampleX[middle]) / 2; 00157 00158 qsort(sampleY, number, sizeof(int), compare_y); 00159 *y = (sampleY[middle-1] + sampleY[middle]) / 2; 00160 00161 if ( number <= 10) 00162 goto again; 00163 00164 // >= DIFF, it means touch screen is not stable. stop the calibration 00165 if ( abs(sampleY[middle-1] - sampleY[middle]) >= DIFF ) 00166 return 0; 00167 if ( abs(sampleX[middle-1] - sampleX[middle]) >= DIFF ) 00168 return 0; 00169 return 1; 00170 } 00171 00172 int run_calibration(void) 00173 { 00174 int i, no; 00175 int sum_px, sum_py, sum_pxy, sum_square_px, sum_square_py, sum_lx, sum_lpx, sum_lpy, sum_ly; 00176 float deter, im11, im12, im13, im21, im22, im23, im31, im32, im33; 00177 00178 // logical.x = physical.x X A + physical.y X B + C 00179 // logical.y = physical.x X D + physical.y X E + F 00180 00181 // multiple physic.y and physic.y as follows 00182 // logical.x X physical.x = physical.x X A X physical.x+ physical.y X B X physical.x + C X physical.x 00183 // logical.x X physical.y = physical.x X A X physical.y+ physical.y X B X physical.y + C X physical.y 00184 // we can obtain the paramters A, B, C from 3 x 3 matrix 00185 // In the similiar method, we could also obtain the parameters D, E, F 00186 // logical.y X physical.x = physical.x X D X physical.x+ physical.y X E X physical.x + F X physical.x 00187 // logical.y X physical.y = physical.x X D X physical.y+ physical.y X E X physical.y + F X physical.y 00188 00189 cal_values[6] = 65536; 00190 sum_px = sum_py = sum_square_px = sum_square_py = sum_pxy = 0; 00191 00192 // Get sums of physical x, y for matrix 00193 00194 no = POINT_NUM; 00195 for(i=0; i<POINT_NUM; i++) 00196 { 00197 sum_px += physical[i].x; 00198 sum_py += physical[i].y; 00199 sum_square_px += (physical[i].x * physical[i].x); 00200 sum_square_py += (physical[i].y * physical[i].y); 00201 sum_pxy += (physical[i].x * physical[i].y); 00202 } 00203 // From 3x3 matix Z, ZX= Y, X, Y is a 3 x 1 matrix 00204 // deter is the determinant for 3 x 3 matix 00205 00206 im11 = (float)sum_pxy*sum_py - (float)sum_px*sum_square_py; 00207 im21 = (float)sum_px*sum_pxy - (float)sum_py*sum_square_px; 00208 im31= (float)sum_square_px*sum_square_py - (float)sum_pxy*sum_pxy; 00209 deter = im11*sum_px+im21*sum_py+im31*no; 00210 00211 if(deter < 0.01 && deter > -0.01) 00212 { 00213 printf("ts_calibrate: No inverse matrix \n"); 00214 return 0; 00215 } 00216 00217 // Get elements of inverse matrix as follows 00218 // im11 im12 im13 00219 // im21 im22 im23 00220 // im31 im32 im33 00221 im32 = im11 = im11/deter; 00222 im12 = (float)(no*sum_square_py - sum_py*sum_py)/deter; 00223 im22 = im13 = (float)(sum_px*sum_py - no*sum_pxy)/deter; 00224 im33 = im21 = im21/deter; 00225 im23 = (float)(no*sum_square_px - sum_px*sum_px)/deter; 00226 im31= im31/deter; 00227 00228 // Get sums of logical and physical for x calibration 00229 sum_lx = sum_lpx = sum_lpy = 0; 00230 for(i=0; i<POINT_NUM; i++) 00231 { 00232 sum_lx += logical[i].x; 00233 sum_lpx += (logical[i].x*physical[i].x); 00234 sum_lpy += (logical[i].x*physical[i].y); 00235 } 00236 00237 // get the calibration for A, B, C mapping cal_values[0], cal_values[1], cal_values[2] 00238 cal_values[0] = (int)((im11*sum_lx + im12*sum_lpx + im13*sum_lpy)* cal_values[6]); 00239 cal_values[1] = (int)((im21*sum_lx + im22*sum_lpx + im23*sum_lpy)* cal_values[6]); 00240 cal_values[2] = (int)((im31*sum_lx + im32*sum_lpx + im33*sum_lpy)* cal_values[6]); 00241 00242 // Get sums of logical and physical for y calibration 00243 sum_ly = sum_lpx = sum_lpy = 0; 00244 for(i=0; i<POINT_NUM; i++) 00245 { 00246 sum_ly += logical[i].y; 00247 sum_lpx += (logical[i].y*physical[i].x); 00248 sum_lpy += (logical[i].y*physical[i].y); 00249 } 00250 00251 // get the calibration for D, E, F mapping cal_values[3], cal_values[4], cal_values[5] 00252 cal_values[3] = (int)((im11*sum_ly + im12*sum_lpx + im13*sum_lpy)* cal_values[6]); 00253 cal_values[4] = (int)((im21*sum_ly + im22*sum_lpx + im23*sum_lpy)* cal_values[6]); 00254 cal_values[5] = (int)((im31*sum_ly + im32*sum_lpx + im33*sum_lpy)* cal_values[6]); 00255 00256 return 1; 00257 } 00258 00259 00260 int read_calib_sample(char *rect_name, int index, int logx, int logy) 00261 { 00262 int result; 00263 GUI_SetColor(GUI_WHITE); 00264 write_cross(logx, logy); 00265 result = read_phy_xy (&physical[index].x, &physical[index].y); 00266 GUI_SetColor(GUI_BLACK); 00267 write_cross(logx, logy); 00268 00269 logical[index].x = logx; 00270 logical[index].y = logy; 00271 00272 printf("%s : X = %4d Y = %4d\n", rect_name, physical[index].x, physical[index].y); 00273 return result; 00274 } 00275 00276 int ts_calibrate(int xsize, int ysize) 00277 { 00278 int result,d1, d2, d3; 00279 GUI_SetBkColor(GUI_BLACK); 00280 GUI_Clear(); 00281 00282 if ( xsize >= 800 ) // 800x480 00283 { 00284 GUI_SetFont(&GUI_Font24B_ASCII); 00285 d1 = -50; 00286 d2 = -20; 00287 d3 = 10; 00288 } 00289 else if ( xsize >= 480 ) // 480 x272 00290 { 00291 GUI_SetFont(&GUI_Font13B_ASCII); 00292 d1 = -50; 00293 d2 = -30; 00294 d3 = -10; 00295 } 00296 else 00297 { 00298 GUI_SetFont(&GUI_Font8_ASCII); 00299 d1 = -20; 00300 d2 = -10; 00301 d3 = 0; 00302 } 00303 00304 GUI_SetColor(GUI_RED); 00305 GUI_DispStringHCenterAt("Nuvoton's TS calibration utility", xsize / 2, ysize / 4 +d1); 00306 00307 GUI_SetColor(GUI_BLUE); 00308 GUI_DispStringHCenterAt("Touch crosshair to calibrate", xsize / 2, ysize / 4 +d2 ); 00309 00310 GUI_SetColor(GUI_GREEN); 00311 GUI_DispStringHCenterAt("Click down 2 seconds and release", xsize / 2, ysize / 4 + d3); 00312 00313 printf("xsize = %d, ysize = %d\n", xsize, ysize); 00314 00315 //GUI_SetColor(GUI_WHITE); 00316 //GUI_SetDrawMode(GUI_DRAWMODE_XOR); 00317 GUI_SetPenSize(1); 00318 00319 //Top left 00320 result = read_calib_sample ("Top left", 0, 40, 40); 00321 GUI_X_Delay(300); 00322 if ( result == 0 ) 00323 { 00324 return(DisplayFailStatus(xsize, ysize)); 00325 } 00326 00327 //Top right 00328 result = read_calib_sample ("Top right", 1, xsize - 40, 40); 00329 GUI_X_Delay(300); 00330 if ( result == 0 ) 00331 { 00332 return(DisplayFailStatus(xsize, ysize)); 00333 } 00334 00335 //Bottom right 00336 result = read_calib_sample ("Bottom right", 2, xsize - 40, ysize - 40); 00337 GUI_X_Delay(300); 00338 if ( result == 0 ) 00339 { 00340 return(DisplayFailStatus(xsize, ysize)); 00341 } 00342 00343 //Bottom left 00344 result = read_calib_sample ("Bottom left", 3, 40, ysize - 40); 00345 GUI_X_Delay(300); 00346 if ( result == 0 ) 00347 { 00348 return(DisplayFailStatus(xsize, ysize)); 00349 } 00350 00351 // Center 00352 result = read_calib_sample ("Center", 4, xsize / 2, ysize / 2); 00353 GUI_X_Delay(300); 00354 if ( result == 0 ) 00355 { 00356 return(DisplayFailStatus(xsize, ysize)); 00357 } 00358 00359 // After running API run_calibration, global variable cal_values is exported. 00360 if (run_calibration()) 00361 { 00362 printf("Calibration OK.\n"); 00363 result = 1; 00364 } 00365 else 00366 { 00367 printf("Calibration failed.\n"); 00368 result = -1; 00369 } 00370 #if 0 00371 printf("cal_values[0][0x%08X]\n", (unsigned int)cal_values[0]); 00372 printf("cal_values[1][0x%08X]\n", (unsigned int)cal_values[1]); 00373 printf("cal_values[2][0x%08X]\n", (unsigned int)cal_values[2]); 00374 printf("cal_values[3][0x%08X]\n", (unsigned int)cal_values[3]); 00375 printf("cal_values[4][0x%08X]\n", (unsigned int)cal_values[4]); 00376 printf("cal_values[5][0x%08X]\n", (unsigned int)cal_values[5]); 00377 printf("cal_values[6][0x%08X]\n", (unsigned int)cal_values[6]); 00378 #endif 00379 return result; 00380 } 00381 00382 // logical.x = physical.x X A + physical.y X B + C 00383 // logical.y = physical.x X D + physical.y X E + F 00384 int ts_phy2log(int *logx, int *logy) 00385 { 00386 int phyx,phyy; 00387 00388 phyx = *logx; 00389 phyy = *logy; 00390 *logx = ( phyx*cal_values[0] + phyy*cal_values[1] + cal_values[2] ) / cal_values[6]; 00391 *logy = ( phyx*cal_values[3]+ phyy*cal_values[4] + cal_values[5] ) / cal_values[6]; 00392 return 1; 00393 } 00394 00395 // write the calibration parameters into one file 00396 int ts_writefile(void) 00397 { 00398 #if 0 00399 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x00, cal_values[0]); 00400 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x04, cal_values[1]); 00401 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x08, cal_values[2]); 00402 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x0C, cal_values[3]); 00403 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x10, cal_values[4]); 00404 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x14, cal_values[5]); 00405 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x18, cal_values[6]); 00406 FMC_Write(__DEMO_TSFILE_ADDR__ + 0x1C, 0x55AAA55A); 00407 #endif 00408 return 0; 00409 } 00410 00411 int ts_readfile(void) 00412 { 00413 #if 0 00414 cal_values[0] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x00); 00415 cal_values[1] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x04); 00416 cal_values[2] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x08); 00417 cal_values[3] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x0C); 00418 cal_values[4] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x10); 00419 cal_values[5] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x14); 00420 cal_values[6] = FMC_Read(__DEMO_TSFILE_ADDR__ + 0x18); 00421 #endif 00422 return 0; 00423 } 00424 00425 void ts_init(void) 00426 { 00427 #if 0 00428 #ifdef __DEMO_160x128__ 00429 cal_values[0] = 0xFFFFFFEB; 00430 cal_values[1] = 0x00000D1D; 00431 cal_values[2] = 0xFFEE9924; 00432 cal_values[3] = 0x00000BF3; 00433 cal_values[4] = 0x00000004; 00434 cal_values[5] = 0xFFE8E0E6; 00435 cal_values[6] = 0x00010000; 00436 #else 00437 cal_values[0] = 0x00000050; 00438 cal_values[1] = 0x00001896; 00439 cal_values[2] = 0xFFC6AEB4; 00440 cal_values[3] = 0x00001404; 00441 cal_values[4] = 0xFFFFFFF5; 00442 cal_values[5] = 0xFFD1601B; 00443 cal_values[6] = 0x00010000; 00444 #endif 00445 #endif 00446 }
Generated on Mon Mar 4 2024 07:48:13 by 1.7.2