/** * Interrupt handler for the TouchScreen. * Handles pen press, pen move and pen release events * by invoking three callback functions. */ void TSD_Handler(uint32_t dwAdcStatus) { Adc *pAdc = ADC; uint32_t status; /* TSADC status */ status = dwAdcStatus; status &= /*ADC_GetItMask(pAdc) &*/ TS_STATUSES; if (status == 0) return; /* Pen released */ if (status & ADC_ISR_NOPEN) { if ((bTsFlags & TS_PEN_STAT) == 0) { /* Register last data */ memcpy(dwLastTsData, dwTsData, sizeof(dwTsData)); /* Invoke PenReleased callback */ if (TSDCom_IsCalibrationOk()) TSD_PenReleased(dwTsData[0], dwTsData[1]); } bTsFlags = 0; /* Stop periodic trigger & enable pen */ ADC_SetTsAverage(pAdc, ADC_TSMR_TSAV_NO_FILTER); ADC_SetTsDebounce(pAdc, BOARD_TOUCHSCREEN_DEBOUNCE); ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_PEN_TRIG); /* Disable pen release detect */ ADC_DisableIt(pAdc, ADC_IDR_NOPEN); /* Enable pen press detect */ ADC_EnableIt(pAdc, ADC_IER_PEN); } /* Pen pressed */ else if (status & ADC_ISR_PEN) { bTsFlags |= TS_PEN_STAT; /* Configure for peripdic trigger */ ADC_SetTsAverage(pAdc, ADC_TSMR_TSAV_AVG8CONV); ADC_SetTsDebounce(pAdc, 300); /* 300ns */ ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_PERIOD_TRIG); /* Disable pen press detect */ ADC_DisableIt(pAdc, ADC_IDR_PEN); /* Enable pen release detect */ ADC_EnableIt(pAdc, ADC_IER_NOPEN|ADC_IER_XRDY|ADC_IER_YRDY|ADC_IER_PRDY); } else if (status & ADC_ISR_PENS) { /* X */ if (status & ADC_ISR_XRDY) { bTsFlags |= TS_X_RDY; } /* Y */ if (status & ADC_ISR_YRDY) { bTsFlags |= TS_Y_RDY; } /* P: (X/1024)*[(Z2/Z1)-1] */ if (status & ADC_ISR_PRDY) { bTsFlags |= TS_P_RDY; } } /* X,Y,P are ready */ if ((bTsFlags & TS_DATA_RDY) == TS_DATA_RDY) { uint32_t xpos, z2, z1; bTsFlags &= ~TS_DATA_RDY; /* Get X,Y */ TSD_GetRawMeasurement(dwRaw); /* Interprate X,Y */ TSDCom_InterpolateMeasurement(dwRaw, dwTsData); /* Get P: Rp = Rxp*(Xpos/1024)*[(Z2/Z1)-1] */ dwRaw[2] = ADC_GetTsPressure(pAdc); #ifdef TS_XY_SWAP xpos = (dwRaw[1]); #else xpos = (dwRaw[0]); #endif xpos = (xpos & ADC_XPOSR_XPOS_Msk) >> ADC_XPOSR_XPOS_Pos; z2 = (dwRaw[2] & ADC_PRESSR_Z2_Msk) >> ADC_PRESSR_Z2_Pos; z1 = (dwRaw[2] & ADC_PRESSR_Z1_Msk) >> ADC_PRESSR_Z1_Pos; dwTsData[2] = (xpos) * (z2 - z1) / z1; /* PenPress */ if (bTsFlags & TS_PEN_STAT) { bTsFlags &= ~TS_PEN_STAT; /* Invoke PenPress callback */ if (TSDCom_IsCalibrationOk()) TSD_PenPressed(dwTsData[0], dwTsData[1], dwTsData[2]); } /* Periodic if data change invoke callback */ if (dwTsData[0] != dwLastTsData[0] || dwTsData[1] != dwLastTsData[1] || dwTsData[2] != dwLastTsData[2] ) { /* Register last data */ memcpy(dwLastTsData, dwTsData, sizeof(dwTsData)); /* Invoke PenMoved callback */ if (TSDCom_IsCalibrationOk()) TSD_PenMoved(dwTsData[0], dwTsData[1], dwTsData[2]); } }
//------------------------------------------------------------------------------ /// Interrupt handler for the TSADC. Handles pen press, pen move and pen release /// events by invoking three callback functions. //------------------------------------------------------------------------------ static void InterruptHandler(void) { unsigned int status; unsigned int data[2]; static unsigned int newPoint[2]; static unsigned int point[2]; static unsigned char report = 0; // Retrieve TADC status // Bug fix: two step operation so IAR doesn't complain that the order of // volatile access is unspecified. status = AT91C_BASE_TSADC->TSADC_SR; status &= AT91C_BASE_TSADC->TSADC_IMR; // Pen release if ((status & AT91C_TSADC_NOCNT) == AT91C_TSADC_NOCNT) { // Invoke PenReleased callback if(TSDCom_IsCalibrationOk()) { TSD_PenReleased(point[0], point[1]); } // Stop periodic trigger mode TSADCC_SetDebounceTime(BOARD_TOUCHSCREEN_DEBOUNCE); AT91C_BASE_TSADC->TSADC_IDR = AT91C_TSADC_EOC3 | AT91C_TSADC_NOCNT; TSADCC_SetTriggerMode(AT91C_TSADC_TRGMOD_PENDET_TRIGGER); TSD_GetRawMeasurement(data); // Clear data registers AT91C_BASE_TSADC->TSADC_SR; AT91C_BASE_TSADC->TSADC_IER = AT91C_TSADC_PENCNT; } // Pen press else if ((status & AT91C_TSADC_PENCNT) == AT91C_TSADC_PENCNT) { // Invoke PenPressed callback with (x,y) coordinates while ((AT91C_BASE_TSADC->TSADC_SR & AT91C_TSADC_EOC3) != AT91C_TSADC_EOC3); TSD_GetRawMeasurement(data); TSDCom_InterpolateMeasurement(data, point); // Invoke PenPressed callback if(TSDCom_IsCalibrationOk()) { TSD_PenPressed(point[0], point[1]); } // Configure TSADC for periodic trigger TSADCC_SetDebounceTime(10); // 1ns AT91C_BASE_TSADC->TSADC_IER = AT91C_TSADC_EOC3 | AT91C_TSADC_NOCNT; AT91C_BASE_TSADC->TSADC_IDR = AT91C_TSADC_PENCNT; TSADCC_SetTriggerPeriod(10000000); // 10ms TSADCC_SetTriggerMode(AT91C_TSADC_TRGMOD_PERIODIC_TRIGGER); report = 0; } // Pen move else if ((status & AT91C_TSADC_EOC3) == AT91C_TSADC_EOC3) { // Invoke callback with LAST value measured // Explanation: the very last value that will be measured (just as the // pen is released) might be corrupted and there is no way to know. So // we just discard it. if (report) { memcpy(point, newPoint, sizeof(newPoint)); // Invoke PenMoved callback if(TSDCom_IsCalibrationOk()) { TSD_PenMoved(point[0], point[1]); } report = 0; } TSD_GetRawMeasurement(data); TSDCom_InterpolateMeasurement(data, newPoint); if ((newPoint[0] != point[0]) || (newPoint[1] != point[1])) { report = 1; } } }
/** * \brief Performs the calibration process using the provided buffer to display * information. * * \return True if calibration was successful; otherwise false. */ uint8_t TSDCom_Calibrate(void) { volatile uint32_t i; /* to keep the tempo with gcc code optimisation */ int32_t slope1, slope2; CalibrationPoint measuredPoint; uint8_t xOk, yOk; int32_t xDiff, yDiff; /* Calibration setup */ LCDD_Fill(COLOR_WHITE); LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK); LCDD_DrawString(1, 140, (uint8_t *)"Touch the dots to\ncalibrate the screen", COLOR_DARKBLUE); /* Calibration points */ for (i=0; i < 4; i++) { DrawCalibrationPoint(&calibrationPoints[i]); /* Wait for touch & end of conversion */ TSD_WaitPenPressed(); TSD_GetRawMeasurement(calibrationPoints[i].data); ClearCalibrationPoint(&calibrationPoints[i]); /* Wait for contact loss */ TSD_WaitPenReleased(); } /** * Calculate slopes using the calibration data * Theory behind those calculations: * - We suppose the touchscreen measurements are linear, so the following equations are true (simple * linear regression) for any two 'a' and 'b' points of the screen: * dx = (a.data[0] - b.data[0]) / (a.x - b.x) * dy = (a.data[1] - b.data[1]) / (a.y - b.y) * * - We calculate dx and dy (called xslope and yslope here) using the calibration points. * * - We can then use dx and dy to infer the position of a point 'p' given the measurements performed * by the touchscreen ('c' is any of the calibration points): * dx = (p.data[0] - c.data[0]) / (p.x - c.x) * dy = (p.data[1] - c.data[1]) / (p.y - c.y) * Thus: * p.x = c.x - (p.data[0] - c.data[0]) / dx * p.y = c.y - (p.data[1] - c.data[1]) / dy * * - Since there are four calibration points, dx and dy can be calculated twice, so we average * the two values. */ slope1 = ((int32_t) calibrationPoints[0].data[0]) - ((int32_t) calibrationPoints[1].data[0]); slope1 *= 1024; slope1 /= ((int32_t) calibrationPoints[0].x) - ((int32_t) calibrationPoints[1].x); slope2 = ((int32_t) calibrationPoints[2].data[0]) - ((int32_t) calibrationPoints[3].data[0]); slope2 *= 1024; slope2 /= ((int32_t) calibrationPoints[2].x) - ((int32_t) calibrationPoints[3].x); xSlope = (slope1 + slope2) / 2; slope1 = ((int32_t) calibrationPoints[0].data[1]) - ((int32_t) calibrationPoints[2].data[1]); slope1 *= 1024; slope1 /= ((int32_t) calibrationPoints[0].y) - ((int32_t) calibrationPoints[2].y); slope2 = ((int32_t) calibrationPoints[1].data[1]) - ((int32_t) calibrationPoints[3].data[1]); slope2 *= 1024; slope2 /= ((int32_t) calibrationPoints[1].y) - ((int32_t) calibrationPoints[3].y); ySlope = (slope1 + slope2) / 2; /* Test point */ LCDD_Fill(0xFFFFFF); LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK); LCDD_DrawString(1, 100, (uint8_t *)" Touch the point to\nvalidate calibration", COLOR_DARKBLUE); DrawCalibrationPoint(&testPoint); /* Wait for touch & end of conversion */ TSD_WaitPenPressed(); TSD_GetRawMeasurement(measuredPoint.data); TSDCom_InterpolateMeasurement(measuredPoint.data, (uint32_t *) &measuredPoint); DrawCalibrationPoint(&measuredPoint); /* Check resulting x and y */ xDiff = (int32_t) measuredPoint.x - (int32_t) testPoint.x; yDiff = (int32_t) measuredPoint.y - (int32_t) testPoint.y; xOk = (xDiff >= -POINTS_MAX_ERROR) && (xDiff <= POINTS_MAX_ERROR); yOk = (yDiff >= -POINTS_MAX_ERROR) && (yDiff <= POINTS_MAX_ERROR); /* Wait for contact loss */ TSD_WaitPenReleased(); /* Check calibration result */ if (xOk && yOk) { bCalibrationOk = 1; LCDD_Fill(COLOR_WHITE); LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK); LCDD_DrawString(80, 140, (uint8_t *)"Success !", COLOR_GREEN); } else { bCalibrationOk = 0; LCDD_Fill(COLOR_WHITE); LCDD_DrawString(30, 50, (uint8_t *)"LCD calibration", COLOR_BLACK); LCDD_DrawString(40, 140, (uint8_t *)"Error too big", COLOR_RED); } /* Slight delay */ for (i = 0; i < DELAY_RESULT_DISPLAY; i++); return (xOk && yOk); }
//------------------------------------------------------------------------------ /// Performs the calibration process using the provided buffer to display /// information. /// \param pLcdBuffer LCD buffer to display. /// \return True if calibration was successful; otherwise false. //------------------------------------------------------------------------------ unsigned char TSDCom_Calibrate(void *pLcdBuffer) { #ifdef AT91C_ID_LCDC void *pOldLcdBuffer; #endif volatile unsigned int i; // to keep the tempo with gcc code optimisation signed int slope1, slope2; CalibrationPoint measuredPoint; unsigned char xOk, yOk; signed int xDiff, yDiff; // Calibration setup LCDD_Fill(pLcdBuffer, COLOR_WHITE); LCDD_DrawString(pLcdBuffer, 30, 50, "LCD calibration", COLOR_BLACK); LCDD_DrawString(pLcdBuffer, 1, 100, " Touch the dots to\ncalibrate the screen", COLOR_DARKBLUE); #ifdef AT91C_ID_LCDC pOldLcdBuffer = LCDD_DisplayBuffer(pLcdBuffer); #endif // Calibration points for (i=0; i < 4; i++) { DrawCalibrationPoint(pLcdBuffer, &calibrationPoints[i]); // Wait for touch & end of conversion TSD_WaitPenPressed(); TSD_GetRawMeasurement(calibrationPoints[i].data); ClearCalibrationPoint(pLcdBuffer, &calibrationPoints[i]); // Wait for contact loss TSD_WaitPenReleased(); } // Calculate slopes using the calibration data // Theory behind those calculations: // - We suppose the touchscreen measurements are linear, so the following equations are true (simple // linear regression) for any two 'a' and 'b' points of the screen: // dx = (a.data[0] - b.data[0]) / (a.x - b.x) // dy = (a.data[1] - b.data[1]) / (a.y - b.y) // // - We calculate dx and dy (called xslope and yslope here) using the calibration points. // // - We can then use dx and dy to infer the position of a point 'p' given the measurements performed // by the touchscreen ('c' is any of the calibration points): // dx = (p.data[0] - c.data[0]) / (p.x - c.x) // dy = (p.data[1] - c.data[1]) / (p.y - c.y) // Thus: // p.x = c.x - (p.data[0] - c.data[0]) / dx // p.y = c.y - (p.data[1] - c.data[1]) / dy // // - Since there are four calibration points, dx and dy can be calculated twice, so we average // the two values. slope1 = ((signed int) calibrationPoints[0].data[0]) - ((signed int) calibrationPoints[1].data[0]); slope1 *= 1024; slope1 /= ((signed int) calibrationPoints[0].x) - ((signed int) calibrationPoints[1].x); slope2 = ((signed int) calibrationPoints[2].data[0]) - ((signed int) calibrationPoints[3].data[0]); slope2 *= 1024; slope2 /= ((signed int) calibrationPoints[2].x) - ((signed int) calibrationPoints[3].x); xSlope = (slope1 + slope2) / 2; slope1 = ((signed int) calibrationPoints[0].data[1]) - ((signed int) calibrationPoints[2].data[1]); slope1 *= 1024; slope1 /= ((signed int) calibrationPoints[0].y) - ((signed int) calibrationPoints[2].y); slope2 = ((signed int) calibrationPoints[1].data[1]) - ((signed int) calibrationPoints[3].data[1]); slope2 *= 1024; slope2 /= ((signed int) calibrationPoints[1].y) - ((signed int) calibrationPoints[3].y); ySlope = (slope1 + slope2) / 2; // Test point LCDD_Fill(pLcdBuffer, 0xFFFFFF); LCDD_DrawString(pLcdBuffer, 30, 50, "LCD calibration", COLOR_BLACK); LCDD_DrawString(pLcdBuffer, 1, 100, " Touch the point to\nvalidate calibration", COLOR_DARKBLUE); DrawCalibrationPoint(pLcdBuffer, &testPoint); // Wait for touch & end of conversion TSD_WaitPenPressed(); TSD_GetRawMeasurement(measuredPoint.data); TSDCom_InterpolateMeasurement(measuredPoint.data, (unsigned int *) &measuredPoint); DrawCalibrationPoint(pLcdBuffer, &measuredPoint); // Check resulting x and y xDiff = (signed int) measuredPoint.x - (signed int) testPoint.x; yDiff = (signed int) measuredPoint.y - (signed int) testPoint.y; xOk = (xDiff >= -POINTS_MAX_ERROR) && (xDiff <= POINTS_MAX_ERROR); yOk = (yDiff >= -POINTS_MAX_ERROR) && (yDiff <= POINTS_MAX_ERROR); // Wait for contact loss TSD_WaitPenReleased(); // Check calibration result if (xOk && yOk) { bCalibrationOk = 1; LCDD_Fill(pLcdBuffer, COLOR_WHITE); LCDD_DrawString(pLcdBuffer, 30, 50, "LCD calibration", COLOR_BLACK); LCDD_DrawString(pLcdBuffer, 80, 100, "Success !", COLOR_GREEN); } else { bCalibrationOk = 0; LCDD_Fill(pLcdBuffer, COLOR_WHITE); LCDD_DrawString(pLcdBuffer, 30, 50, "LCD calibration", COLOR_BLACK); LCDD_DrawString(pLcdBuffer, 40, 100, "Error too big", COLOR_RED); } // Slight delay for (i = 0; i < DELAY_RESULT_DISPLAY; i++); #ifdef AT91C_ID_LCDC // Restore old LCD buffer LCDD_DisplayBuffer(pOldLcdBuffer); #endif return (xOk && yOk); }