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 "i2cdrv.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 gpioPortD, 5
00042 #define TOUCH_X2 gpioPortD, 4
00043 #define TOUCH_Y1 gpioPortD, 3
00044 #define TOUCH_Y2 gpioPortD, 1
00047 typedef enum
00048 { TOUCH_INIT,
00049 TOUCH_CHECK_PRESS,
00050 TOUCH_MEASURE_X,
00051 TOUCH_MEASURE_Y } TOUCH_State_TypeDef;
00052
00055 static volatile TOUCH_State_TypeDef touch_state = TOUCH_INIT;
00056 static ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;
00057 volatile TOUCH_Pos_TypeDef newpos;
00058 volatile TOUCH_Pos_TypeDef current_pos;
00059 static TOUCH_Pos_TypeDef pos;
00060
00061 static void (*upcall)(TOUCH_Pos_TypeDef *) = 0;
00062
00063 uint32_t touch_ignore_move;
00067 MATRIX calibrationMatrix = { 103800, 2048, -8184704, -384, 102144, -16424640, 287650 };
00068
00070 #ifndef TOUCH_WITHOUT_STORE
00071
00087 static uint32_t touch_CountChecksum(uint32_t magic, uint32_t *data, uint32_t len)
00088 {
00089 unsigned long checksum = magic;
00090
00091 while (len--)
00092 {
00093 if (checksum & 0x80000000)
00094 {
00095 checksum <<= 1;
00096 checksum |= 1;
00097 }
00098 else checksum <<= 1;
00099 checksum += *data;
00100 data++;
00101 }
00102 return(checksum);
00103 }
00104
00106 static void touch_LoadCalibration(void)
00107 {
00108 I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
00109 uint32_t temp, checksum;
00110 int count;
00111 MATRIX new_matrix;
00112
00113
00114
00115 I2CDRV_Init(&i2cInit);
00116 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00117 count += EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &new_matrix, sizeof(new_matrix));
00118 if (count == sizeof(new_matrix) + 4)
00119 {
00120 if (temp == CALIBRATION_MAGIC_NUMBER)
00121 {
00122 checksum = touch_CountChecksum(temp, (uint32_t*) &new_matrix, sizeof(new_matrix) / 4);
00123 count = EEPROM_Read(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(new_matrix), (uint8_t*) &temp, sizeof(temp));
00124 if (temp == checksum)
00125 {
00126 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00127 memcpy(&calibrationMatrix, &new_matrix, sizeof(calibrationMatrix));
00128 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00129 }
00130 }
00131 }
00132 }
00133
00135 static void touch_StoreCalibration(void)
00136 {
00137 int count;
00138 uint32_t temp = CALIBRATION_MAGIC_NUMBER, checksum;
00139 checksum = touch_CountChecksum(CALIBRATION_MAGIC_NUMBER, (uint32_t*) &calibrationMatrix, sizeof(calibrationMatrix) / 4);
00140 count = EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET, (uint8_t*) &temp, sizeof(temp));
00141 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4, (uint8_t*) &calibrationMatrix, sizeof(calibrationMatrix));
00142 count += EEPROM_Write(I2C0, EEPROM_DVK_ADDR, CALIBRATION_EEPROM_OFFSET + 4 + sizeof(calibrationMatrix), (uint8_t*) &checksum, sizeof(checksum));
00143 }
00144 #endif
00145
00147
00154 void TOUCH_RecalculatePosition(volatile TOUCH_Pos_TypeDef *pos)
00155 {
00156 POINT old_pos, new_pos;
00157
00158 if (pos->pen)
00159 {
00160 old_pos.x = pos->adcx;
00161 old_pos.y = pos->adcy;
00162 if (getDisplayPoint(&new_pos, &old_pos, &calibrationMatrix) == OK)
00163 {
00164 if (new_pos.x >= 0) pos->x = new_pos.x;
00165 else pos->x = 0;
00166 if (new_pos.y >= 0) pos->y = new_pos.y;
00167 else pos->y = 0;
00168 }
00169 }
00170 else
00171 {
00172 pos->x = 0;
00173 pos->y = 0;
00174 }
00175 }
00176
00177
00181 void TOUCH_CallUpcall(void)
00182 {
00183 if (upcall)
00184 upcall((TOUCH_Pos_TypeDef*) ¤t_pos);
00185 }
00186
00187
00194 int TOUCH_StateChanged(void)
00195 {
00196 int result = 0;
00197 int diff, a, b;
00198 if (newpos.pen && !current_pos.pen) result = 1;
00199 a = current_pos.x;
00200 b = newpos.x;
00201 diff = a - b;
00202 if (abs(diff) > (int) touch_ignore_move) result = 1;
00203 a = current_pos.y;
00204 b = newpos.y;
00205 diff = a - b;
00206 if (abs(diff) > (int) touch_ignore_move) result = 1;
00207 return result;
00208 }
00209
00210
00215 void ADC0_IRQHandler(void)
00216 {
00217 switch (touch_state)
00218 {
00219 case TOUCH_INIT:
00220 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1);
00221 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00222 GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0);
00223 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00224 sInit.input = ADC_Y;
00225 sInit.reference = adcRefVDD;
00226 sInit.resolution = adcResOVS;
00227 sInit.acqTime = adcAcqTime128;
00228 if(GPIO_PinInGet(TOUCH_X2))
00229 {
00230 touch_state = TOUCH_MEASURE_Y;
00231 GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1);
00232 GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0);
00233 GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0);
00234 GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0);
00235 sInit.input = ADC_X;
00236 sInit.acqTime = adcAcqTime16;
00237 }
00238 ADC_InitSingle(ADC0, &sInit);
00239 break;
00240 case TOUCH_CHECK_PRESS:
00241 if( GPIO_PinInGet(TOUCH_X2) )
00242 {
00243 touch_state = TOUCH_MEASURE_Y;
00244 GPIO_PinModeSet(TOUCH_X1, gpioModePushPull, 1);
00245 GPIO_PinModeSet(TOUCH_X2, gpioModePushPull, 0);
00246 GPIO_PinModeSet(TOUCH_Y1, gpioModeInput, 0);
00247 GPIO_PinModeSet(TOUCH_Y2, gpioModeInput, 0);
00248 sInit.input = ADC_X;
00249 sInit.acqTime = adcAcqTime16;
00250 ADC_InitSingle(ADC0, &sInit);
00251 current_pos.pen = newpos.pen;
00252 TOUCH_RecalculatePosition(&newpos);
00253 if (newpos.pen)
00254 {
00255 int call_upcall = TOUCH_StateChanged();
00256 if (call_upcall)
00257 {
00258 current_pos.x = newpos.x;
00259 current_pos.y = newpos.y;
00260 }
00261 current_pos.adcx = newpos.adcx;
00262 current_pos.adcy = newpos.adcy;
00263 current_pos.pen = 1;
00264 if (call_upcall) TOUCH_CallUpcall();
00265 }
00266 newpos.pen = 1;
00267 }
00268 else
00269 {
00270 touch_state = TOUCH_INIT;
00271 newpos.pen = 0;
00272 current_pos.pen = 0;
00273 TOUCH_CallUpcall();
00274 }
00275 break;
00276 case TOUCH_MEASURE_Y:
00277 newpos.adcy = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00278 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 0);
00279 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00280 GPIO_PinModeSet(TOUCH_X1, gpioModeInput, 0);
00281 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00282 sInit.input = ADC_Y;
00283 ADC_InitSingle(ADC0, &sInit);
00284 touch_state = TOUCH_MEASURE_X;
00285 break;
00286 case TOUCH_MEASURE_X:
00287 newpos.adcx = (ADC_DataSingleGet(ADC0) + 31) >> 6;
00288 GPIO_PinModeSet(TOUCH_Y1, gpioModePushPull, 1);
00289 GPIO_PinModeSet(TOUCH_Y2, gpioModePushPull, 1);
00290 GPIO_PinModeSet(TOUCH_X1, gpioModeInputPullFilter , 0);
00291 GPIO_PinModeSet(TOUCH_X2, gpioModeInput, 0);
00292 sInit.input = ADC_Y;
00293 ADC_InitSingle(ADC0, &sInit);
00294 touch_state = TOUCH_CHECK_PRESS;
00295 break;
00296 default: touch_state = TOUCH_INIT;
00297 }
00298 ADC_IntClear(ADC0, ADC_IF_SINGLE);
00299 ADC_Start(ADC0, adcStartSingle);
00300 }
00301
00302
00309 int TOUCH_IsBusy(void)
00310 {
00311 if( (touch_state == TOUCH_INIT) )
00312 {
00313 return GPIO_PinInGet(TOUCH_X2);
00314 }
00315
00316 if( (touch_state == TOUCH_CHECK_PRESS) )
00317 {
00318 return TOUCH_BUSY_CHECK;
00319 }
00320
00321 return(TOUCH_BUSY_SCAN);
00322 }
00323
00324
00331 void TOUCH_Init(TOUCH_Config_TypeDef *config)
00332 {
00333 ADC_Init_TypeDef init = ADC_INIT_DEFAULT;
00334 #ifndef TOUCH_WITHOUT_STORE
00335 touch_LoadCalibration();
00336 #endif
00337 CMU_ClockEnable(cmuClock_ADC0, true);
00338 ADC_IntDisable(ADC0, _ADC_IF_MASK);
00339 init.prescale = ADC_PrescaleCalc(config->frequency, 0);
00340 touch_ignore_move = config->ignore;
00341 init.ovsRateSel = config->oversampling;
00342 ADC_Init(ADC0, &init);
00343 BSP_PeripheralAccess(BSP_TOUCH, true);
00344 sInit.input = ADC_Y;
00345 sInit.reference = adcRefVDD;
00346 sInit.resolution = adcResOVS;
00347 ADC_InitSingle(ADC0, &sInit);
00348 ADC_IntClear(ADC0, _ADC_IF_MASK);
00349 touch_state = TOUCH_INIT;
00350 NVIC_ClearPendingIRQ(ADC0_IRQn);
00351 NVIC_EnableIRQ(ADC0_IRQn);
00352 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00353 ADC_Start(ADC0, adcStartSingle);
00354 }
00355
00356
00363 TOUCH_Pos_TypeDef *TOUCH_GetPos(void)
00364 {
00365 ADC_IntDisable(ADC0, ADC_IF_SINGLE);
00366 pos.pen = current_pos.pen;
00367 pos.x = current_pos.x;
00368 pos.y = current_pos.y;
00369 pos.adcx = current_pos.adcx;
00370 pos.adcy = current_pos.adcy;
00371 ADC_IntEnable(ADC0, ADC_IF_SINGLE);
00372
00373 return &pos;
00374 }
00375
00376
00383 void TOUCH_RegisterUpcall(TOUCH_Upcall_TypeDef *new_upcall)
00384 {
00385 upcall = new_upcall;
00386 }
00387
00388
00389
00401 int TOUCH_CalibrationTable(POINT * displayPtr, POINT * screenPtr)
00402 {
00403 int result;
00404 result = setCalibrationMatrix(displayPtr, screenPtr, &calibrationMatrix);
00405 #ifndef TOUCH_WITHOUT_STORE
00406 if (result == OK)
00407 touch_StoreCalibration();
00408 #endif
00409 return(result);
00410 }