您的位置:首页 > 其它

Windows CE 触摸屏(TouchPanel)驱动简析(2)-DDSI函数-(基于WinCE5.0 SMDK2410 BSP的TouchPanel驱动)

2010-04-23 10:28 429 查看
接下来我们来看看具体的DDSI函数.
1.DdsiTouchPanelAttach和DdsiTouchPanelDetach
DLL entry进入或结束执行,这里不需要任何工作,直接返回0
LONG
DdsiTouchPanelAttach(VOID)
{
return(0);
}

LONG
DdsiTouchPanelDetach(VOID)
{
return(0);
}

2.DdsiTouchPanelEnable
DdsiTouchPanelEnable使能触摸屏并进行相应的初始化工作.
首先调用TSP_VirtualAlloc给寄存器(GPIO,ADC,INTR,PWM)分配虚拟地址空间.调用TSP_RegAlloc,而TSP_RegAlloc则调用VirtualAlloc和VirtualCopy进行分配虚拟地址.
TSP_VirtualAlloc:
PRIVATE BOOL
TSP_VirtualAlloc(VOID)
{
BOOL r = FALSE;

RETAILMSG(0,(TEXT("::: TSP_VirtualAlloc()/r/n")));

do
{
v_pIOPregs = (volatile S3C2410X_IOPORT_REG *)TSP_RegAlloc((PVOID)S3C2410X_BASE_REG_PA_IOPORT, sizeof(S3C2410X_IOPORT_REG));
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPreg: VirtualAlloc failed!/r/n")));
break;
}

v_pADCregs = (volatile S3C2410X_ADC_REG *)TSP_RegAlloc((PVOID)S3C2410X_BASE_REG_PA_ADC, sizeof(S3C2410X_ADC_REG));
if (v_pADCregs == NULL)
{
ERRORMSG(1,(TEXT("For ADCreg: VirtualAlloc failed!/r/n")));
break;
}

v_pINTregs = (volatile S3C2410X_INTR_REG *)TSP_RegAlloc((PVOID)S3C2410X_BASE_REG_PA_INTR, sizeof(S3C2410X_INTR_REG));
if (v_pADCregs == NULL)
{
ERRORMSG(1,(TEXT("For INTregs: VirtualAlloc failed!/r/n")));
break;
}

v_pPWMregs = (volatile S3C2410X_PWM_REG *)TSP_RegAlloc((PVOID)S3C2410X_BASE_REG_PA_PWM, sizeof(S3C2410X_PWM_REG));
if (v_pPWMregs == NULL)
{
ERRORMSG(1,(TEXT("For PWMregs: VirtualAlloc failed!/r/n")));
break;
}

r = TRUE;
} while (0);

if (!r)
{
TSP_VirtualFree();

RETAILMSG(0,(TEXT("::: TSP_VirtualAlloc() - Fail/r/n")));
}
else
{
RETAILMSG(0,(TEXT("::: TSP_VirtualAlloc() - Success/r/n")));
}

return (r);
}

TSP_RegAlloc:
PRIVATE PVOID
TSP_RegAlloc(PVOID addr, INT sz)
{
PVOID reg;

reg = (PVOID)VirtualAlloc(0, sz, MEM_RESERVE, PAGE_NOACCESS);

if (reg)
{
if (!VirtualCopy(reg, (PVOID)((UINT32)addr >> 8), sz, PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE ))
{
VirtualFree(reg, 0, MEM_RELEASE);
reg = NULL;
}
}

return (reg);
}

然和调用KernelIoControl来申请ADC和TIMER3的逻辑中断号,获得CPU的时钟,从而计算出给Timer3的分频值.
最后调用TSP_PowerOn来初始化GPIO,ADC,INTR,TIMER3寄存器.
关于具体寄存器引脚的含义可以参考s3c2410的datasheet.
TSP_PowerOn:
PRIVATE VOID
TSP_PowerOn(VOID)
{
RETAILMSG(0,(TEXT("::: TSP_PowerOn()/r/n")));
RETAILMSG(1,(TEXT("++TSP_PowerOn for GEC2410 TouchPanel/r/n")));

/* Use TSXM, TSXP, TSYM, TSYP			*/
v_pIOPregs->GPGCON |=  ((0x3 << 30) | (0x3 << 28) | (0x3 << 26) | (0x3 << 24));

v_pADCregs->ADCDLY = 50000;

v_pADCregs->ADCCON =    (1      << 14) |    /* A/D Converter Enable					*/
(ADCPRS <<  6) |    /* Prescaler Setting					*/
(0      <<  3) |    /* Analog Input Channel : 0				*/
(0      <<  2) |    /* Normal Operation Mode				*/
(0      <<  1) |    /* Disable Read Start					*/
(0      <<  0);     /* No Operation							*/

v_pADCregs->ADCTSC =    (0      <<  8) |    /* UD_Sen								*/
(1      <<  7) |    /* YMON  1 (YM = GND)					*/
(1      <<  6) |    /* nYPON 1 (YP Connected AIN
)		*/
(0      <<  5) |    /* XMON  0 (XM = Z)						*/
(1      <<  4) |    /* nXPON 1 (XP = AIN[7])				*/
(0      <<  3) |    /* Pull Up Disable						*/
(0      <<  2) |    /* Normal ADC Conversion Mode			*/
(3      <<  0);     /* Waiting Interrupt					*/

v_pINTregs->INTSUBMSK  &= ~(1<<IRQ_SUB_TC);

v_pPWMregs->TCFG1  &= ~(0xf << 12);     /* Timer3's Divider Value				*/
v_pPWMregs->TCFG1  |=  (0   << 12);     /* 1/2									*/
v_pPWMregs->TCNTB3  = g_timer3_sampleticks;       /* Interrupt Frequency					*/
}

DdsiTouchPanelEnable:
PUBLIC BOOL
DdsiTouchPanelEnable(VOID)
{
BOOL r;
UINT32 Irq;
PROCESSOR_INFO procInfo;

RETAILMSG(0, (TEXT("::: DdsiTouchPanelEnable()/r/n")));

r = TSP_VirtualAlloc();

// Obtain sysintr values from the OAL for the touch and touch changed interrupts.
//
Irq = IRQ_ADC;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &gIntrTouch, sizeof(UINT32), NULL))
{
RETAILMSG(1, (TEXT("ERROR: Failed to request the touch sysintr./r/n")));
gIntrTouch = SYSINTR_UNDEFINED;
return(FALSE);
}
Irq = IRQ_TIMER3;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(UINT32), &gIntrTouchChanged, sizeof(UINT32), NULL))
{
RETAILMSG(1, (TEXT("ERROR: Failed to request the touch changed sysintr./r/n")));
gIntrTouchChanged = SYSINTR_UNDEFINED;
return(FALSE);
}

// Get the processor's pclk frequency.
//
if (!KernelIoControl(IOCTL_PROCESSOR_INFORMATION, NULL, 0, &procInfo, sizeof(PROCESSOR_INFO), NULL))
{
DEBUGMSG(1, (TEXT("WARNING: Touch driver failed to obtain processor frequency - using default value(%d Hz)./r/n"), g_s3c2410_pclk));
}
else
{
g_s3c2410_pclk = procInfo.dwClockSpeed;
DEBUGMSG(1, (TEXT("INFO: Touch driver using processor frequency reported by the OAL (%d Hz)./r/n"), g_s3c2410_pclk));
}

// Compute the OS timer frequency and number of pen-down sampling ticks.
//
g_timer3_freq        = (g_s3c2410_pclk / TIMER3_DIVIDER);
g_timer3_sampleticks = (g_timer3_freq / TSP_SAMPLE_RATE_LOW);

if (r)
{
TSP_PowerOn();
}

return (r);
}

3.DdsiTouchPanelDisable
对应的就有DdsiTouchPanelDisable函数,将DdsiTouchPanelEnable申请的资源进行释放.屏蔽中断.
PUBLIC VOID
DdsiTouchPanelDisable(VOID)
{
RETAILMSG(0, (TEXT("::: DdsiTouchPanelDisable()/r/n")));
if (v_pADCregs)
{
TSP_PowerOff();
TSP_VirtualFree();
}
}

4.DdsiTouchPanelSetMode
DdsiTouchPanelSetMode用来设置触摸屏的采样率周期.函数传入TPSM_SAMPLERATE_LOW_ID或TPSM_SAMPLERATE_HIGH_ID来进行相应的设置.这里只有一个采样率周期,所以函数不做实际工作.
PUBLIC BOOL
DdsiTouchPanelSetMode(INT iIndex, LPVOID  lpInput)
{
BOOL  ReturnCode = FALSE;

RETAILMSG(0, (TEXT("::: DdsiTouchPanelSetMode()/r/n")));

switch ( iIndex )
{
case TPSM_SAMPLERATE_LOW_ID:
case TPSM_SAMPLERATE_HIGH_ID:
SetLastError( ERROR_SUCCESS );
ReturnCode = TRUE;
break;

default:
SetLastError( ERROR_INVALID_PARAMETER );
break;
}

return( ReturnCode );
}

5.DdsiTouchPanelPowerHandler
DdsiTouchPanelPowerHandler用来通知驱动系统正进入或离开挂起状态.
参数bOff为TRUE表明系统正在关闭, FALSE表明系统正在开启.
该函数调用TSP_PowerOff和TSP_PowerOn来处理关闭或开启状态.
TSP_PowerOn前面已经看到了,TSP_PowerOff如下,屏蔽了INT_TC触摸屏中断(这里定义为IRQ_SUB_TC):
TSP_PowerOff:
PRIVATE VOID
TSP_PowerOff(VOID)
{
RETAILMSG(0,(TEXT("::: TSP_PowerOff()/r/n")));

v_pINTregs->INTSUBMSK |= (1<<IRQ_SUB_TC);
}

DdsiTouchPanelPowerHandler:
PUBLIC VOID
DdsiTouchPanelPowerHandler(BOOL bOff)
{
RETAILMSG(0, (TEXT("::: DdsiTouchPanelPowerHandler()/r/n")));
if (bOff)
{
TSP_PowerOff();
}
else
{
TSP_PowerOn();
}
}

6.DdsiTouchPanelGetDeviceCaps
DdsiTouchPanelGetDeviceCaps用来查询触摸屏设备的性能参数.
iIndex可能为以下3个参数:
TPDC_SAMPLE_RATE_ID: 返回采样周期,这里TSP_SAMPLE_RATE_LOW,TSP_SAMPLE_RATE_HIGH,TSP_CurRate都为100,即一直使用同一个采样周期.
TPDC_CALIBRATION_POINT_ID:返回需要校准点的XY坐标.校准点坐标索引在PointNumber(lpOutput传递的结构成员).调用TSP_CalibrationPointGet来获得.这5个点分别位于四个角和中间,也就是我们调用触摸屏校准程序时会调用到的函数.
TPDC_CALIBRATION_POINT_COUNT_ID:返回用来校准触摸屏的校准点数目.这里的数目设置为5.
lpOutput传递iIndex值对应的结构.

TPDC_SAMPLE_RATE_IDPointer to a TPDC_SAMPLE_RATE structure.
TPDC_CALIBRATION_POINT_IDPointer to a TPDC_CALIBRATION_POINT structure.
TPDC_CALIBRATION_POINT_COUNT_IDPointer to a TPDC_CALIBRATION_POINT_COUNT structure.
CalibrationPointGet:
用来计算校准触摸屏时的5个校准点的位置:

PRIVATE BOOL
TSP_CalibrationPointGet(TPDC_CALIBRATION_POINT *pTCP)
{

INT32   cDisplayWidth  = pTCP->cDisplayWidth;
INT32   cDisplayHeight = pTCP->cDisplayHeight;

int CalibrationRadiusX = cDisplayWidth  / 20;
int CalibrationRadiusY = cDisplayHeight / 20;

switch (pTCP -> PointNumber)
{
case    0:
pTCP->CalibrationX = cDisplayWidth  / 2;
pTCP->CalibrationY = cDisplayHeight / 2;
break;

case    1:
pTCP->CalibrationX = CalibrationRadiusX * 2;
pTCP->CalibrationY = CalibrationRadiusY * 2;
break;

case    2:
pTCP->CalibrationX = CalibrationRadiusX * 2;
pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
break;

case    3:
pTCP->CalibrationX = cDisplayWidth  - CalibrationRadiusX * 2;
pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
break;

case    4:
pTCP->CalibrationX = cDisplayWidth - CalibrationRadiusX * 2;
pTCP->CalibrationY = CalibrationRadiusY * 2;
break;

default:
pTCP->CalibrationX = cDisplayWidth  / 2;
pTCP->CalibrationY = cDisplayHeight / 2;

SetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}

RETAILMSG(0, (TEXT("::: TSP_CalibrationPointGet()/r/n")));
RETAILMSG(0, (TEXT("cDisplayWidth        : %4X/r/n"), cDisplayWidth     ));
RETAILMSG(0, (TEXT("cDisplayHeight       : %4X/r/n"), cDisplayHeight    ));
RETAILMSG(0, (TEXT("CalibrationRadiusX   : %4d/r/n"), CalibrationRadiusX));
RETAILMSG(0, (TEXT("CalibrationRadiusY   : %4d/r/n"), CalibrationRadiusY));
RETAILMSG(0, (TEXT("pTCP -> PointNumber  : %4d/r/n"), pTCP->PointNumber));
RETAILMSG(0, (TEXT("pTCP -> CalibrationX : %4d/r/n"), pTCP->CalibrationX));
RETAILMSG(0, (TEXT("pTCP -> CalibrationY : %4d/r/n"), pTCP->CalibrationY));

return (TRUE);
}

DdsiTouchPanelGetDeviceCaps:
PUBLIC BOOL
DdsiTouchPanelGetDeviceCaps(INT iIndex, LPVOID  lpOutput)
{
RETAILMSG(0, (TEXT("::: DdsiTouchPanelGetDeviceCaps/r/n")));

if ( lpOutput == NULL )
{
ERRORMSG(1, (__TEXT("TouchPanelGetDeviceCaps: invalid parameter./r/n")));
SetLastError(ERROR_INVALID_PARAMETER);
DebugBreak();
return (FALSE);
}

switch ( iIndex )
{
case TPDC_SAMPLE_RATE_ID:
{
TPDC_SAMPLE_RATE    *pTSR = (TPDC_SAMPLE_RATE*)lpOutput;
RETAILMSG(0, (TEXT("TouchPanelGetDeviceCaps::TPDC_SAMPLE_RATE_ID/r/n")));

pTSR->SamplesPerSecondLow      = TSP_SAMPLE_RATE_LOW;
pTSR->SamplesPerSecondHigh     = TSP_SAMPLE_RATE_HIGH;
pTSR->CurrentSampleRateSetting = TSP_CurRate;
}
break;

case TPDC_CALIBRATION_POINT_COUNT_ID:
{
TPDC_CALIBRATION_POINT_COUNT *pTCPC = (TPDC_CALIBRATION_POINT_COUNT*)lpOutput;
RETAILMSG(0, (TEXT("TouchPanelGetDeviceCaps::TPDC_CALIBRATION_POINT_COUNT_ID/r/n")));

pTCPC->flags              = 0;
pTCPC->cCalibrationPoints = 5;
}
break;

case TPDC_CALIBRATION_POINT_ID:
RETAILMSG(0, (TEXT("TouchPanelGetDeviceCaps::TPDC_CALIBRATION_POINT_ID/r/n")));
return(TSP_CalibrationPointGet((TPDC_CALIBRATION_POINT*)lpOutput));

default:
ERRORMSG(1, (__TEXT("TouchPanelGetDeviceCaps: invalid parameter./r/n")));
SetLastError(ERROR_INVALID_PARAMETER);
DebugBreak();
return (FALSE);

}

return (TRUE);
}

7.DdsiTouchPanelGetPoint
返回最近查询点的信息,如坐标等.这个函数被TouchPanelpISR调用,而TouchPanelpISR就是触摸屏中断IST.在TouchPanelEnable中会进行中断线程IST的创建.TouchPanelpISR会等待hTouchPanelEvent事件的发生.hTouchPanelEvent关联了两个中断,触摸屏中断(INT_TC)和TIMER3中断.即触点中断和触点变化中断.当中断发生时,TouchPanelpISR调用DdsiTouchPanelGetPoint来获得采样点信息.
详情可参考tchmain.c(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/TOUCH/TCHMAIN)
代码及注释如下:
PUBLIC VOID
DdsiTouchPanelGetPoint(TOUCH_PANEL_SAMPLE_FLAGS * pTipStateFlags,
INT  * pUncalX,
INT  * pUncalY)
{
static INT x, y;

//DEBUGMSG(1, (TEXT("::: DdsiTouchPanelGetPoint()/r/n")));

if (v_pINTregs->SUBSRCPND & (1<<IRQ_SUB_TC))        /* SYSINTR_TOUCH Interrupt Case				*/
{   //触点中断(INT_TC)
*pTipStateFlags = TouchSampleValidFlag;
//读取ADC Conversion DATA Register, 1-Stylus down state 0-Stylus up state
if ( (v_pADCregs->ADCDAT0 & (1 << 15)) |
(v_pADCregs->ADCDAT1 & (1 << 15)) )
{
//Stylus up state
bTSP_DownFlag = FALSE;

DEBUGMSG(ZONE_TIPSTATE, (TEXT("up/r/n")));
//重新设置ADC TOUCH SCREEN CONTROL REGISTER
v_pADCregs->ADCTSC &= 0xff;
//读取上次的坐标值
*pUncalX = x;
*pUncalY = y;
//停止取样(停止Timer3 PWM)
TSP_SampleStop();
//停止取样后忽略TIMER3中断
/* At this point SYSINTR_TOUCH_CHANGED (timer3) interrupt could also be pending (and masked).
Since we do not care about the timer3 interrupt after calling TSP_SampleStop, signal it Done.
If we do not signal done and it was indeed pending and masked, IRQ_TIMER3 will not be unmasked
and won't fire again unless unmasked */
if (v_pINTregs->SRCPND & (1<<IRQ_TIMER3))
InterruptDone(gIntrTouchChanged);
}
else
{
//Stylus down state
bTSP_DownFlag = TRUE;
//读触摸屏AD数据
if (!TSP_GetXY(&x, &y))
*pTipStateFlags = TouchSampleIgnore;
//转换成LCD上的坐标
TSP_TransXY(&x, &y);

*pUncalX = x;
*pUncalY = y;

*pTipStateFlags |= TouchSampleDownFlag;

DEBUGMSG(ZONE_TIPSTATE, (TEXT("down %x %x/r/n"), x, y));
//启动Timer3 PWM
TSP_SampleStart();
}
//屏蔽触摸屏中断,清除中断标志
v_pINTregs->SUBSRCPND  =  (1<<IRQ_SUB_TC);
v_pINTregs->INTSUBMSK &= ~(1<<IRQ_SUB_TC);
//通知系统中断处理完成
InterruptDone(gIntrTouch);
}
else        /* SYSINTR_TOUCH_CHANGED Interrupt Case		*/
{
//		TSP_SampleStart();
//Timer3 PWM中断发生
if (bTSP_DownFlag)
{
//触摸笔还处于down状态
INT  tx, ty;
INT  dx, dy;
//读取触摸屏AD数据
if (!TSP_GetXY(&tx, &ty))
*pTipStateFlags = TouchSampleIgnore;
else
{   //读到的是坏数据,进行相应处理,如不能修正则忽略该数据
TSP_TransXY(&tx, &ty);
// insert by mostek@dstcorp.com
#define X_ERRV	0x3bf
#define Y_ERRV	0x4ff

// Subsequent info: If the ADC provides a bad reading, this catches it and
// skips over it. Instead, it should be fixed at the source
// so as not to provide a bad reading.

if ((tx == X_ERRV) || (ty == Y_ERRV))
{
tx = x;
ty = y;
}
// =================== mostek
dx = (tx > x) ? (tx - x) : (x - tx);
dy = (ty > y) ? (ty - y) : (y - ty);

if (dx > TSP_CHANGE || dy > TSP_CHANGE)
{
*pUncalX = x = tx;
*pUncalY = y = ty;

DEBUGMSG(ZONE_TIPSTATE, (TEXT("down-c-v %x %x/r/n"), x, y));

*pTipStateFlags = TouchSampleValidFlag | TouchSampleDownFlag;
}
else
{
*pUncalX = x;
*pUncalY = y;

DEBUGMSG(ZONE_TIPSTATE, (TEXT("down-c %x %x/r/n"), x, y));

*pTipStateFlags = TouchSampleIgnore;
}
}
}
else
{
*pTipStateFlags = TouchSampleIgnore;

TSP_SampleStop();
}

InterruptDone(gIntrTouchChanged);
}
}

TSP_GetXY:
TSP_GetXY从触摸屏的ADC寄存器读取触摸点数据,读4次计算平均值.
PRIVATE BOOL
TSP_GetXY(INT *px, INT *py)
{
INT i;
INT xsum, ysum;
INT x, y;
INT dx, dy;

xsum = ysum = 0;

for (i = 0; i < TSP_SAMPLE_NUM; i++)
{
v_pADCregs->ADCTSC =    (0      <<  8) |        /* UD_Sen								*/
(1      <<  7) |        /* YMON  1 (YM = GND)					*/
(1      <<  6) |        /* nYPON 1 (YP Connected AIN
)		*/
(0      <<  5) |        /* XMON  0 (XM = Z)						*/
(1      <<  4) |        /* nXPON 1 (XP = AIN[7])				*/
(1      <<  3) |        /* Pull Up Enable						*/
(1      <<  2) |        /* Auto ADC Conversion Mode				*/
(0      <<  0);         /* No Operation Mode					*/

v_pADCregs->ADCCON |= (1 << 0);             /* Start Auto conversion				*/

while (v_pADCregs->ADCCON & 0x1);               /* check if Enable_start is low			*/
while (!(v_pADCregs->ADCCON & (1 << 15)));      /* Check ECFLG							*/

x = (0x3ff & v_pADCregs->ADCDAT1);
y = 0x3ff - (0x3ff & v_pADCregs->ADCDAT0);

xsum += x;
ysum += y;
}

*px = xsum / TSP_SAMPLE_NUM;
*py = ysum / TSP_SAMPLE_NUM;

v_pADCregs->ADCTSC =    (1      <<  8) |            /* UD_Sen								*/
(1      <<  7) |            /* YMON  1 (YM = GND)					*/
(1      <<  6) |            /* nYPON 1 (YP Connected AIN
)		*/
(0      <<  5) |            /* XMON  0 (XM = Z)						*/
(1      <<  4) |            /* nXPON 1 (XP = AIN[7])				*/
(0      <<  3) |            /* Pull Up Disable						*/
(0      <<  2) |            /* Normal ADC Conversion Mode			*/
(3      <<  0);             /* Waiting Interrupt					*/

dx = (*px > x) ? (*px - x) : (x - *px);
dy = (*py > y) ? (*py - y) : (y - *py);

return((dx > TSP_INVALIDLIMIT || dy > TSP_INVALIDLIMIT) ? FALSE : TRUE);
}

TSP_TransXY:
PRIVATE void
TSP_TransXY(INT *px, INT *py)
{
*px = (*px - TSP_MINX) * TSP_LCDX / (TSP_MAXX - TSP_MINX);
*py = (*py - TSP_MINY) * TSP_LCDY / (TSP_MAXY - TSP_MINY);

if (*px  <        0) *px = 0;
if (*px >= TSP_LCDX) *px = TSP_LCDX - 1;

if (*py  <        0) *py = 0;
if (*py >= TSP_LCDY) *py = TSP_LCDY - 1;
}

读到的坐标数据最终交由MDD层的函数进行诸如最小二乘法的数学运算,这里就不仔细分析了,有兴趣可以参考tchmdd.lib和tch_cal.lib里的代码(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐