NuMaker emWin HMI

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ts_calibrate.c Source File

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 }