00001
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include "em_device.h"
00020 #include "em_adc.h"
00021 #include "em_gpio.h"
00022 #include "em_cmu.h"
00023 #include "touch.h"
00024 #include "calibrate.h"
00025 #include "bsp.h"
00026 #ifndef TOUCH_WITHOUT_STORE
00027 #include "i2cspm.h"
00028 #include "eeprom.h"
00029 #endif
00030
00032 #define CALIBRATION_MAGIC_NUMBER 0xCA71B4A7
00033 #define CALIBRATION_EEPROM_OFFSET 0x80
00034
00036
00037 #define ADC_X adcSingleInpCh1
00038 #define ADC_Y adcSingleInpCh4
00040
00041 #define TOUCH_X1_PORT gpioPortD
00042 #define TOUCH_X1_PIN 5
00043 #define TOUCH_X2_PORT gpioPortD
00044 #define TOUCH_X2_PIN 4
00045 #define TOUCH_Y1_PORT gpioPortD
00046 #define TOUCH_Y1_PIN 3
00047 #define TOUCH_Y2_PORT gpioPortD
00048 #define TOUCH_Y2_PIN 1
00051 typedef enum
00052 { TOUCH_INIT,
00053 TOUCH_CHECK_PRESS,
00054 TOUCH_MEASURE_X,
00055 TOUCH_MEASURE_Y } TOUCH_State_TypeDef;
00056
00059 static volatile TOUCH_State_TypeDef touch_state = TOUCH_INIT;
00060 static ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;
00061 volatile TOUCH_Pos_TypeDef newpos;
00062 volatile TOUCH_Pos_TypeDef current_pos;
00063 static TOUCH_Pos_TypeDef pos;
00064
00065 static void (*upcall)(TOUCH_Pos_TypeDef *) = 0;
00066
00067 uint32_t touch_ignore_move;
00071 MATRIX calibrationMatrix = { 103800, 2048, -8184704, -384, 102144, -16424640, 287650 };
00072
00074 #ifndef TOUCH_WITHOUT_STORE
00075
00091 static uint32_t touch_CountChecksum(uint32_t magic, uint32_t *data, uint32_t len)
00092 {
00093 unsigned long checksum = magic;
00094
00095 while (len--)
00096 {
00097 if (checksum & 0x80000000)
00098 {
00099 checksum <<= 1;
00100 checksum |= 1;
00101 }
00102 else checksum <<= 1;
00103 checksum += *data;
00104 data++;
00105 }
00106 return(checksum);
00107 }
00108
00110 static void touch_LoadCalibration(void)
00111 {
00112 I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;
00113 uint32_t temp, checksum;
00114 int count;
00115 MATRIX new_matrix;
00116
00117 #if !defined( BSP_STK )
00118 BSP_PeripheralAccess(BSP_I2C, true);
00119 #endif
00120
00121
00122
00123
00124 I2CSPM_Init(&i2cInit);
00125 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00126 count += EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &new_matrix, sizeof(new_matrix));
00127 if (count == sizeof(new_matrix) + 4)
00128 {
00129 if (temp == CALIBRATION_MAGIC_NUMBER)
00130 {
00131 checksum = touch_CountChecksum(temp, (uint32_t*) &new_matrix, sizeof(new_matrix) / 4);
00132 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(new_matrix), (uint8_t*) &temp, sizeof(temp));
00133 if (temp == checksum)
00134 {
00135 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00136 memcpy(&calibrationMatrix, &new_matrix, sizeof(calibrationMatrix));
00137 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00138 }
00139 }
00140 }
00141 }
00142
00144 static void touch_StoreCalibration(void)
00145 {
00146 int count;
00147 uint32_t temp = CALIBRATION_MAGIC_NUMBER, checksum;
00148 checksum = touch_CountChecksum(CALIBRATION_MAGIC_NUMBER, (uint32_t*) &calibrationMatrix, sizeof(calibrationMatrix) / 4);
00149 count = EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00150 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &calibrationMatrix, sizeof(calibrationMatrix));
00151 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(calibrationMatrix), (uint8_t*) &checksum, sizeof(checksum));
00152 }
00153 #endif
00154
00156
00163 void TOUCH_RecalculatePosition(volatile TOUCH_Pos_TypeDef *pos)
00164 {
00165 POINT old_pos, new_pos;
00166
00167 if (pos->pen)
00168 {
00169 old_pos.x = pos->adcx;
00170 old_pos.y = pos->adcy;
00171 if (getDisplayPoint(&new_pos, &old_pos, &calibrationMatrix) == OK)
00172 {
00173 if (new_pos.x >= 0) pos->x = new_pos.x;
00174 else pos->x = 0;
00175 if (new_pos.y >= 0) pos->y = new_pos.y;
00176 else pos->y = 0;
00177 }
00178 }
00179 else
00180 {
00181 pos->x = 0;
00182 pos->y = 0;
00183 }
00184 }
00185
00186
00190 void TOUCH_CallUpcall(void)
00191 {
00192 if (upcall)
00193 upcall((TOUCH_Pos_TypeDef*) ¤t_pos);
00194 }
00195
00196
00203 int TOUCH_StateChanged(void)
00204 {
00205 int result = 0;
00206 int diff, a, b;
00207 if (newpos.pen && !current_pos.pen) result = 1;
00208 a = current_pos.x;
00209 b = newpos.x;
00210 diff = a - b;
00211 if (abs(diff) > (int) touch_ignore_move) result = 1;
00212 a = current_pos.y;
00213 b = newpos.y;
00214 diff = a - b;
00215 if (abs(diff) > (int) touch_ignore_move) result = 1;
00216 return result;
00217 }
00218
00219
00224 void ADC0_IRQHandler(void)
00225 {
00226 switch (touch_state)
00227 {
00228 case TOUCH_INIT:
00229 GPIO_PinModeSet(TOUCH_Y1_PORT, TOUCH_Y1_PIN, gpioModePushPull, 1);
00230 GPIO_PinModeSet(TOUCH_Y2_PORT, TOUCH_Y2_PIN, gpioModePushPull, 1);
00231 GPIO_PinModeSet(TOUCH_X1_PORT, TOUCH_X1_PIN, gpioModeInputPullFilter , 0);
00232 GPIO_PinModeSet(TOUCH_X2_PORT, TOUCH_X2_PIN, gpioModeInput, 0);
00233 sInit.input = ADC_Y;
00234 sInit.reference = adcRefVDD;
00235 sInit.resolution = adcResOVS;
00236 sInit.acqTime = adcAcqTime128;
00237 if(GPIO_PinInGet(TOUCH_X2_PORT, TOUCH_X2_PIN))
00238 {
00239 touch_state = TOUCH_MEASURE_Y;
00240 GPIO_PinModeSet(TOUCH_X1_PORT, TOUCH_X1_PIN, gpioModePushPull, 1);
00241 GPIO_PinModeSet(TOUCH_X2_PORT, TOUCH_X2_PIN, gpioModePushPull, 0);
00242 GPIO_PinModeSet(TOUCH_Y1_PORT, TOUCH_Y1_PIN, gpioModeInput, 0);
00243 GPIO_PinModeSet(TOUCH_Y2_PORT, TOUCH_Y2_PIN, gpioModeInput, 0);
00244 sInit.input = ADC_X;
00245 sInit.acqTime = adcAcqTime16;
00246 }
00247 ADC_InitSingle(ADC0, &sInit);
00248 break;
00249 case TOUCH_CHECK_PRESS:
00250 if( GPIO_PinInGet(TOUCH_X2_PORT, TOUCH_X2_PIN) )
00251 {
00252 touch_state = TOUCH_MEASURE_Y;
00253 GPIO_PinModeSet(TOUCH_X1_PORT, TOUCH_X1_PIN, gpioModePushPull, 1);
00254 GPIO_PinModeSet(TOUCH_X2_PORT, TOUCH_X2_PIN, gpioModePushPull, 0);
00255 GPIO_PinModeSet(TOUCH_Y1_PORT, TOUCH_Y1_PIN, gpioModeInput, 0);
00256 GPIO_PinModeSet(TOUCH_Y2_PORT, TOUCH_Y2_PIN, gpioModeInput, 0);
00257 sInit.input = ADC_X;
00258 sInit.acqTime = adcAcqTime16;
00259 ADC_InitSingle(ADC0, &sInit);
00260 current_pos.pen = newpos.pen;
00261 TOUCH_RecalculatePosition(&newpos);
00262 if (newpos.pen)
00263 {
00264 int call_upcall = TOUCH_StateChanged();
00265 if (call_upcall)
00266 {
00267 current_pos.x = newpos.x;
00268 current_pos.y = newpos.y;
00269 }
00270 current_pos.adcx = newpos.adcx;
00271 current_pos.adcy = newpos.adcy;
00272 current_pos.pen = 1;
00273 if (call_upcall) TOUCH_CallUpcall();
00274 }
00275 newpos.pen = 1;
00276 }
00277 else
00278 {
00279 touch_state = TOUCH_INIT;
00280 newpos.pen = 0;
00281 current_pos.pen = 0;
00282 TOUCH_CallUpcall();
00283 }
00284 break;
00285 case TOUCH_MEASURE_Y:
00286 newpos.adcy = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00287 GPIO_PinModeSet(TOUCH_Y1_PORT, TOUCH_Y1_PIN, gpioModePushPull, 0);
00288 GPIO_PinModeSet(TOUCH_Y2_PORT, TOUCH_Y2_PIN, gpioModePushPull, 1);
00289 GPIO_PinModeSet(TOUCH_X1_PORT, TOUCH_X1_PIN, gpioModeInput, 0);
00290 GPIO_PinModeSet(TOUCH_X2_PORT, TOUCH_X2_PIN, gpioModeInput, 0);
00291 sInit.input = ADC_Y;
00292 ADC_InitSingle(ADC0, &sInit);
00293 touch_state = TOUCH_MEASURE_X;
00294 break;
00295 case TOUCH_MEASURE_X:
00296 newpos.adcx = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00297 GPIO_PinModeSet(TOUCH_Y1_PORT, TOUCH_Y1_PIN, gpioModePushPull, 1);
00298 GPIO_PinModeSet(TOUCH_Y2_PORT, TOUCH_Y2_PIN, gpioModePushPull, 1);
00299 GPIO_PinModeSet(TOUCH_X1_PORT, TOUCH_X1_PIN, gpioModeInputPullFilter , 0);
00300 GPIO_PinModeSet(TOUCH_X2_PORT, TOUCH_X2_PIN, gpioModeInput, 0);
00301 sInit.input = ADC_Y;
00302 ADC_InitSingle(ADC0, &sInit);
00303 touch_state = TOUCH_CHECK_PRESS;
00304 break;
00305 default: touch_state = TOUCH_INIT;
00306 }
00307 ADC_IntClear(ADC0, ADC_IF_SINGLE);
00308 ADC_Start(ADC0, adcStartSingle);
00309 }
00310
00311
00318 int TOUCH_IsBusy(void)
00319 {
00320 if( (touch_state == TOUCH_INIT) )
00321 {
00322 return GPIO_PinInGet(TOUCH_X2_PORT, TOUCH_X2_PIN);
00323 }
00324
00325 if( (touch_state == TOUCH_CHECK_PRESS) )
00326 {
00327 return TOUCH_BUSY_CHECK;
00328 }
00329
00330 return(TOUCH_BUSY_SCAN);
00331 }
00332
00333
00340 void TOUCH_Init(TOUCH_Config_TypeDef *config)
00341 {
00342 ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
00343 #ifndef TOUCH_WITHOUT_STORE
00344 touch_LoadCalibration();
00345 #endif
00346 CMU_ClockEnable(cmuClock_ADC0, true);
00347 ADC_IntDisable(ADC0, _ADC_IF_MASK);
00348 init.prescale = ADC_PrescaleCalc(config->frequency, 0);
00349 touch_ignore_move = config->ignore;
00350 init.ovsRateSel = config->oversampling;
00351 ADC_Init(ADC0, &init);
00352 BSP_PeripheralAccess(BSP_TOUCH, true);
00353 sInit.input = ADC_Y;
00354 sInit.reference = adcRefVDD;
00355 sInit.resolution = adcResOVS;
00356 ADC_InitSingle(ADC0, &sInit);
00357 ADC_IntClear(ADC0, _ADC_IF_MASK);
00358 touch_state = TOUCH_INIT;
00359 NVIC_ClearPendingIRQ(ADC0_IRQn);
00360 NVIC_EnableIRQ(ADC0_IRQn);
00361 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00362 ADC_Start(ADC0, adcStartSingle);
00363 }
00364
00365
00372 TOUCH_Pos_TypeDef *TOUCH_GetPos(void)
00373 {
00374 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00375 pos.pen = current_pos.pen;
00376 pos.x = current_pos.x;
00377 pos.y = current_pos.y;
00378 pos.adcx = current_pos.adcx;
00379 pos.adcy = current_pos.adcy;
00380 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00381
00382 return &pos;
00383 }
00384
00385
00392 void TOUCH_RegisterUpcall(TOUCH_Upcall_TypeDef *new_upcall)
00393 {
00394 upcall = new_upcall;
00395 }
00396
00397
00398
00410 int TOUCH_CalibrationTable(POINT * displayPtr, POINT * screenPtr)
00411 {
00412 int result;
00413 result = setCalibrationMatrix(displayPtr, screenPtr, &calibrationMatrix);
00414 #ifndef TOUCH_WITHOUT_STORE
00415 if (result == OK)
00416 touch_StoreCalibration();
00417 #endif
00418 return(result);
00419 }