00001
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include "em_device.h"
00038 #include "em_adc.h"
00039 #include "em_gpio.h"
00040 #include "em_cmu.h"
00041 #include "touch.h"
00042 #include "calibrate.h"
00043 #include "bsp.h"
00044 #ifndef TOUCH_WITHOUT_STORE
00045 #include "i2cdrv.h"
00046 #include "eeprom.h"
00047 #endif
00048
00050 #define CALIBRATION_MAGIC_NUMBER 0xCA71B4A7
00051 #define CALIBRATION_EEPROM_OFFSET 0x80
00052
00054
00055 #define ADC_X adcSingleInpCh1
00056 #define ADC_Y adcSingleInpCh4
00058
00059 #define TOUCH_X1 gpioPortD, 5
00060 #define TOUCH_X2 gpioPortD, 4
00061 #define TOUCH_Y1 gpioPortD, 3
00062 #define TOUCH_Y2 gpioPortD, 1
00065 typedef enum
00066 { TOUCH_INIT,
00067 TOUCH_CHECK_PRESS,
00068 TOUCH_MEASURE_X,
00069 TOUCH_MEASURE_Y } TOUCH_State_TypeDef;
00070
00073 static volatile TOUCH_State_TypeDef touch_state = TOUCH_INIT;
00074 static ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;
00075 volatile TOUCH_Pos_TypeDef newpos;
00076 volatile TOUCH_Pos_TypeDef current_pos;
00077 static TOUCH_Pos_TypeDef pos;
00078
00079 static void (*upcall)(TOUCH_Pos_TypeDef *) = 0;
00080
00081 uint32_t touch_ignore_move;
00085 MATRIX calibrationMatrix = { 103800, 2048, -8184704, -384, 102144, -16424640, 287650 };
00086
00088 #ifndef TOUCH_WITHOUT_STORE
00089
00105 static uint32_t touch_CountChecksum(uint32_t magic, uint32_t *data, uint32_t len)
00106 {
00107 unsigned long checksum = magic;
00108
00109 while (len--)
00110 {
00111 if (checksum & 0x80000000)
00112 {
00113 checksum <<= 1;
00114 checksum |= 1;
00115 }
00116 else checksum <<= 1;
00117 checksum += *data;
00118 data++;
00119 }
00120 return(checksum);
00121 }
00122
00124 static void touch_LoadCalibration(void)
00125 {
00126 I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
00127 uint32_t temp, checksum;
00128 int count;
00129 MATRIX new_matrix;
00130
00131
00132
00133 I2CDRV_Init(&i2cInit);
00134 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00135 count += EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &new_matrix, sizeof(new_matrix));
00136 if (count == sizeof(new_matrix) + 4)
00137 {
00138 if (temp == CALIBRATION_MAGIC_NUMBER)
00139 {
00140 checksum = touch_CountChecksum(temp, (uint32_t*) &new_matrix, sizeof(new_matrix) / 4);
00141 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(new_matrix), (uint8_t*) &temp, sizeof(temp));
00142 if (temp == checksum)
00143 {
00144 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00145 memcpy(&calibrationMatrix, &new_matrix, sizeof(calibrationMatrix));
00146 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00147 }
00148 }
00149 }
00150 }
00151
00153 static void touch_StoreCalibration(void)
00154 {
00155 int count;
00156 uint32_t temp = CALIBRATION_MAGIC_NUMBER, checksum;
00157 checksum = touch_CountChecksum(CALIBRATION_MAGIC_NUMBER, (uint32_t*) &calibrationMatrix, sizeof(calibrationMatrix) / 4);
00158 count = EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00159 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &calibrationMatrix, sizeof(calibrationMatrix));
00160 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(calibrationMatrix), (uint8_t*) &checksum, sizeof(checksum));
00161 }
00162 #endif
00163
00165
00172 void TOUCH_RecalculatePosition(volatile TOUCH_Pos_TypeDef *pos)
00173 {
00174 POINT old_pos, new_pos;
00175
00176 if (pos->pen)
00177 {
00178 old_pos.x = pos->adcx;
00179 old_pos.y = pos->adcy;
00180 if (getDisplayPoint(&new_pos, &old_pos, &calibrationMatrix) == OK)
00181 {
00182 if (new_pos.x >= 0) pos->x = new_pos.x;
00183 else pos->x = 0;
00184 if (new_pos.y >= 0) pos->y = new_pos.y;
00185 else pos->y = 0;
00186 }
00187 }
00188 else
00189 {
00190 pos->x = 0;
00191 pos->y = 0;
00192 }
00193 }
00194
00195
00199 void TOUCH_CallUpcall(void)
00200 {
00201 if (upcall)
00202 upcall((TOUCH_Pos_TypeDef*) ¤t_pos);
00203 }
00204
00205
00212 int TOUCH_StateChanged(void)
00213 {
00214 int result = 0;
00215 int diff, a, b;
00216 if (newpos.pen && !current_pos.pen) result = 1;
00217 a = current_pos.x;
00218 b = newpos.x;
00219 diff = a - b;
00220 if (abs(diff) > (int) touch_ignore_move) result = 1;
00221 a = current_pos.y;
00222 b = newpos.y;
00223 diff = a - b;
00224 if (abs(diff) > (int) touch_ignore_move) result = 1;
00225 return result;
00226 }
00227
00228
00233 void ADC0_IRQHandler(void)
00234 {
00235 switch (touch_state)
00236 {
00237 case TOUCH_INIT:
00238 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1);
00239 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00240 GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0);
00241 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00242 sInit.input = ADC_Y;
00243 sInit.reference = adcRefVDD;
00244 sInit.resolution = adcResOVS;
00245 sInit.acqTime = adcAcqTime128;
00246 if(GPIO_PinInGet(TOUCH_X2))
00247 {
00248 touch_state = TOUCH_MEASURE_Y;
00249 GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1);
00250 GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0);
00251 GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0);
00252 GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0);
00253 sInit.input = ADC_X;
00254 sInit.acqTime = adcAcqTime16;
00255 }
00256 ADC_InitSingle(ADC0, &sInit);
00257 break;
00258 case TOUCH_CHECK_PRESS:
00259 if( GPIO_PinInGet(TOUCH_X2) )
00260 {
00261 touch_state = TOUCH_MEASURE_Y;
00262 GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1);
00263 GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0);
00264 GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0);
00265 GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0);
00266 sInit.input = ADC_X;
00267 sInit.acqTime = adcAcqTime16;
00268 ADC_InitSingle(ADC0, &sInit);
00269 current_pos.pen = newpos.pen;
00270 TOUCH_RecalculatePosition(&newpos);
00271 if (newpos.pen)
00272 {
00273 int call_upcall = TOUCH_StateChanged();
00274 if (call_upcall)
00275 {
00276 current_pos.x = newpos.x;
00277 current_pos.y = newpos.y;
00278 }
00279 current_pos.adcx = newpos.adcx;
00280 current_pos.adcy = newpos.adcy;
00281 current_pos.pen = 1;
00282 if (call_upcall) TOUCH_CallUpcall();
00283 }
00284 newpos.pen = 1;
00285 }
00286 else
00287 {
00288 touch_state = TOUCH_INIT;
00289 newpos.pen = 0;
00290 current_pos.pen = 0;
00291 TOUCH_CallUpcall();
00292 }
00293 break;
00294 case TOUCH_MEASURE_Y:
00295 newpos.adcy = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00296 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 0);
00297 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00298 GPIO_PinModeSet(TOUCH_X1, gpioModeInput, 0);
00299 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00300 sInit.input = ADC_Y;
00301 ADC_InitSingle(ADC0, &sInit);
00302 touch_state = TOUCH_MEASURE_X;
00303 break;
00304 case TOUCH_MEASURE_X:
00305 newpos.adcx = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00306 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1);
00307 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00308 GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0);
00309 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00310 sInit.input = ADC_Y;
00311 ADC_InitSingle(ADC0, &sInit);
00312 touch_state = TOUCH_CHECK_PRESS;
00313 break;
00314 default: touch_state = TOUCH_INIT;
00315 }
00316 ADC_IntClear(ADC0, ADC_IF_SINGLE);
00317 ADC_Start(ADC0, adcStartSingle);
00318 }
00319
00320
00327 int TOUCH_IsBusy(void)
00328 {
00329 if( (touch_state == TOUCH_INIT) )
00330 {
00331 return GPIO_PinInGet(TOUCH_X2);
00332 }
00333
00334 if( (touch_state == TOUCH_CHECK_PRESS) )
00335 {
00336 return TOUCH_BUSY_CHECK;
00337 }
00338
00339 return(TOUCH_BUSY_SCAN);
00340 }
00341
00342
00349 void TOUCH_Init(TOUCH_Config_TypeDef *config)
00350 {
00351 ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
00352 #ifndef TOUCH_WITHOUT_STORE
00353 touch_LoadCalibration();
00354 #endif
00355 CMU_ClockEnable(cmuClock_ADC0, true);
00356 ADC_IntDisable(ADC0, _ADC_IF_MASK);
00357 init.prescale = ADC_PrescaleCalc(config->frequency, 0);
00358 touch_ignore_move = config->ignore;
00359 init.ovsRateSel = config->oversampling;
00360 ADC_Init(ADC0, &init);
00361 BSP_PeripheralAccess(BSP_TOUCH, true);
00362 sInit.input = ADC_Y;
00363 sInit.reference = adcRefVDD;
00364 sInit.resolution = adcResOVS;
00365 ADC_InitSingle(ADC0, &sInit);
00366 ADC_IntClear(ADC0, _ADC_IF_MASK);
00367 touch_state = TOUCH_INIT;
00368 NVIC_ClearPendingIRQ(ADC0_IRQn);
00369 NVIC_EnableIRQ(ADC0_IRQn);
00370 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00371 ADC_Start(ADC0, adcStartSingle);
00372 }
00373
00374
00381 TOUCH_Pos_TypeDef *TOUCH_GetPos(void)
00382 {
00383 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00384 pos.pen = current_pos.pen;
00385 pos.x = current_pos.x;
00386 pos.y = current_pos.y;
00387 pos.adcx = current_pos.adcx;
00388 pos.adcy = current_pos.adcy;
00389 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00390
00391 return &pos;
00392 }
00393
00394
00401 void TOUCH_RegisterUpcall(TOUCH_Upcall_TypeDef *new_upcall)
00402 {
00403 upcall = new_upcall;
00404 }
00405
00406
00407
00419 int TOUCH_CalibrationTable(POINT * displayPtr, POINT * screenPtr)
00420 {
00421 int result;
00422 result = setCalibrationMatrix(displayPtr, screenPtr, &calibrationMatrix);
00423 #ifndef TOUCH_WITHOUT_STORE
00424 if (result == OK)
00425 touch_StoreCalibration();
00426 #endif
00427 return(result);
00428 }