/**
 * 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]);
        }
        
    }
Exemple #2
0
//------------------------------------------------------------------------------
/// 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;
        }
    }
}
Exemple #3
0
/**
 * \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);
}
Exemple #4
0
//------------------------------------------------------------------------------
/// 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);
}