blob: 0cc92566674437efb98d0aab2f4b6974ac9e23b4 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <board.h>
#include <string.h>
#ifdef REG_ADC_TSMR
/** \addtogroup tsd_module
*@{
*/
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/** SWAP X & Y */
#define TS_XY_SWAP
/** Status that used for touchscreen */
#define TS_STATUSES ( ADC_ISR_PENS | ADC_ISR_PEN | ADC_ISR_NOPEN \
| ADC_ISR_XRDY | ADC_ISR_YRDY | ADC_ISR_PRDY )
/*----------------------------------------------------------------------------
* Local types
*----------------------------------------------------------------------------*/
/** X value is ready */
#define TS_X_RDY (1 << 0)
/** Y value is ready */
#define TS_Y_RDY (1 << 1)
/** Pressure value is ready */
#define TS_P_RDY (1 << 2)
/** Pen status */
#define TS_PEN_STAT (1 << 7)
/** All data is ready (X,Y & P) */
#define TS_DATA_RDY (TS_X_RDY|TS_Y_RDY|TS_P_RDY)
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/** Raw register value */
static uint32_t dwRaw[3];
/** Touchscreen data sampling results */
static uint32_t dwTsData[3];
/** Last Touchscreen sampling results */
static uint32_t dwLastTsData[3];
/** Touchscreen data ready */
static uint8_t bTsFlags = 0;
/*----------------------------------------------------------------------------
* External functions
*----------------------------------------------------------------------------*/
extern uint32_t TSD_GetRaw(uint32_t i);
/**
* Return raw register value.
*/
uint32_t TSD_GetRaw(uint32_t i)
{
return dwRaw[i];
}
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/**
* 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]);
}
}
}
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* Reads and store a touchscreen measurement in the provided array.
* The value stored are:
* - data[0] = XPOS * 1024 / XSCALE
* - data[1] = YPOS * 1024 / YSCALE
* \param pData Array where the measurements will be stored
*/
void TSD_GetRawMeasurement(uint32_t *pData)
{
Adc *pAdc = ADC;
uint32_t xr, yr;
#ifdef TS_XY_SWAP
yr = ADC_GetTsXPosition(pAdc);
xr = ADC_GetTsYPosition(pAdc);
#else
xr = ADC_GetTsXPosition(pAdc);
yr = ADC_GetTsYPosition(pAdc);
#endif
pData[0] = ((xr & ADC_XPOSR_XPOS_Msk) >> ADC_XPOSR_XPOS_Pos) * 1024 * 4;
pData[0] /= ((xr & ADC_XPOSR_XSCALE_Msk) >> ADC_XPOSR_XSCALE_Pos);
pData[1] = ((yr & ADC_YPOSR_YPOS_Msk) >> ADC_YPOSR_YPOS_Pos) * 1024 * 4;
pData[1] /= ((yr & ADC_YPOSR_YSCALE_Msk) >> ADC_YPOSR_YSCALE_Pos);
}
/**
* Wait pen pressed
*/
void TSD_WaitPenPressed(void)
{
Adc *pAdc = ADC;
uint8_t bFlags = 0;
uint32_t dwStatus;
/* Wait for touch & end of conversion */
while (1)
{
dwStatus = ADC_GetStatus(pAdc);
if (dwStatus & ADC_ISR_PEN) bFlags |= 8;
if (dwStatus & ADC_ISR_XRDY)bFlags |= 1;
if (dwStatus & ADC_ISR_YRDY)bFlags |= 2;
if (dwStatus & ADC_ISR_PRDY)bFlags |= 4;
if (bFlags == 0xF) break;
}
}
/**
* Wait pen released
*/
void TSD_WaitPenReleased(void)
{
Adc *pAdc = ADC;
/* Wait for contact loss */
while((ADC_GetStatus(pAdc) & ADC_ISR_NOPEN) == 0);
}
/**
* Initializes the touchscreen driver and starts the calibration process. When
* finished, the touchscreen is operational.
* The configuration is taken from the board.h of the device being compiled.
* Important: the LCD driver must have been initialized prior to calling this
* function.
*/
void TSD_Initialize(void)
{
Adc *pAdc = ADC;
bTsFlags = 0;
/* Configuration */
PMC_EnablePeripheral(ID_ADC);
ADC_SetClock(pAdc, BOARD_TOUCHSCREEN_ADCCLK, BOARD_MCK);
ADC_SetStartupTime(pAdc, BOARD_TOUCHSCREEN_STARTUP);
ADC_SetTrackingTime(pAdc, BOARD_TOUCHSCREEN_SHTIM);
ADC_SetTriggerPeriod(pAdc, 20000000); /* 20ms */
ADC_SetTsMode(pAdc, ADC_TSMR_TSMODE_4_WIRE);
ADC_SetTsAverage(pAdc, ADC_TSMR_TSAV_NO_FILTER);
ADC_SetTsPenDetect(pAdc, 1);
ADC_SetTsDebounce(pAdc, BOARD_TOUCHSCREEN_DEBOUNCE);
pAdc->ADC_MR &= ~(3<<28);
pAdc->ADC_ACR = 0x102;
}
/**
* Enable/Disable TSD capturing
*/
void TSD_Enable(uint8_t bEnDis)
{
Adc *pAdc = ADC;
if (bEnDis)
{
ADC_SetTsAverage(pAdc, ADC_TSMR_TSAV_NO_FILTER);
ADC_TsCalibration(pAdc);
ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_PEN_TRIG);
ADC_EnableIt(pAdc, ADC_IER_PEN);
}
else
{
ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_NO_TRIGGER);
ADC_DisableIt(pAdc, TS_STATUSES);
ADC_GetStatus(pAdc);
ADC_GetTsXPosition(pAdc);
ADC_GetTsYPosition(pAdc);
ADC_GetTsPressure(pAdc);
}
}
/**
* Do touchscreen calibration
* \param pLcdBuffer LCD buffer to use for displaying the calibration info.
* \return 1 if calibration is Ok, 0 else
*/
uint8_t TSD_Calibrate(void)
{
Adc *pAdc = ADC;
uint8_t ret = 0;
/* Calibration is done only once */
if(TSDCom_IsCalibrationOk()) return 1;
/* Disable touch */
TSD_Enable(0);
/* Enable capturing */
ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_PEN_TRIG);
/* Do calibration */
ret = TSDCom_Calibrate();
/* Configure interrupt generation
Do it only if the calibration is Ok. */
//TSD_Enable(ret);
return ret;
}
/**
* Reset/stop the touchscreen
*/
void TSD_DeInitialize(void)
{
Adc *pAdc = ADC;
/* Disable TS related interrupts */
ADC_DisableIt(pAdc, TS_STATUSES);
/* Disable Trigger */
ADC_SetTriggerMode(pAdc, ADC_TRGR_TRGMOD_NO_TRIGGER);
/* Disable TS mode */
ADC_SetTsMode(pAdc, ADC_TSMR_TSMODE_NONE);
bTsFlags = 0;
}
/**@}*/
#endif /* #ifdef REG_ADC_TSMR */