2440/2416/6410/S5PV210之wince+android系统驱动开发者

等待新发生的事情

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

2440 5.0BSP触摸屏驱动学习(作者:wogoyixikexie@gliet)

//-----------------------------------------------------------------------------------------------------------

// 日期:2009年3月14日11:49:48

// 作者:wogoyixikexie@gliet

// 版权:桂林电子科技大学一系科协wogoyixikexie@gliet

// 最后修改:2009年3月17日10:20:39

//-----------------------------------------------------------------------------------------------------------     

     以前曾经看过一下子触摸屏驱动,但是那时候火候不到,现在老大叫我看,并且写一篇博客,现在我就边看边写吧。

     曾经在nasiry看到touch.dll是这样生成的。

 

touch.dll生成过程
有意思的是tchmdd.lib则比较特殊,在OAK的lib文件夹中居然找不到这个文件,而在项目文件的OAK目录下该文件确是存在的,也就是说该文件在CESYSGEN的过程中产生。根据该链接库提供的接口来看,可以猜测该lib应当由另外几个零散的lib组成,这些链接库的source文件夹在OAK\COMMON\Drivers\Touch目录下。后来在PUBLIC\COMMON\CESYSGEN下的makefile文件内找到如下内容

tchmdd::

        @set TARGETTYPE=LIBRARY

        @set TARGETNAME=$@

        @set RELEASETYPE=OAK

        @set TARGETLIBS=

!IFDEF SYSGEN_TRANSCRIBER

        @set SOURCELIBS=$(SG_INPUT_LIB)\tchmain.lib $(SG_INPUT_LIB)\tch_trns.lib

        echo touch includes transcriber hooks

!ELSE

        @set SOURCELIBS=$(SG_INPUT_LIB)\tchmain.lib $(SG_INPUT_LIB)\tchbasic.lib

        echo touch is minimal

!ENDIF

确定了Tchmdd.lib的内容就是tchmain.lib+ tch_trns.lib或tchbasic.lib.因为tchmdd需要通过专门的Nmake指令完成生成的动作,所以在Touch驱动目录下都会有一个bat文件用于产生tchmdd.lib文件用于后面的链接库。

之所以需要将tchmdd.lib设定为这种方式生成,而不直接产生可以猜测为不同的编译条件下DDI的接口不同(见第一部分),所以通过这里来选择不同的DDI接口实现。

这样一来Touch驱动就分成两种不同的类型了:

1.       不使用扩展DDI接口的Touch驱动

2.       在TRANSCRIBER编译条件下产生的带扩展的Touch驱动。

 

     哈哈,现在看看我的2440 touch到底用了什么代码,首先找到TOUCH.def文件,内容如下:

 

LIBRARY  TOUCH

EXPORTS
 STDAPI(TouchPanelGetDeviceCaps, 8);
 STDAPI(TouchPanelEnable,4);
 STDAPI(TouchPanelDisable,0);
 STDAPI(TouchPanelSetMode, 8);
 STDAPI(TouchPanelReadCalibrationPoint, 8);
 STDAPI(TouchPanelReadCalibrationAbort, 0);
 STDAPI(TouchPanelSetCalibration, 20);
 STDAPI(TouchPanelCalibrateAPoint, 16);
 STDAPI(TouchPanelPowerHandler, 4);
; @CESYSGEN IF WCESHELLFE_MODULES_MSTRANSCRIBER || SHELLW_MODULES_TRANSCRIBER
 TouchReset
 TouchRegisterWindow
 TouchUnregisterWindow
 TouchSetValue
 TouchGetValue
 TouchCreateEvent
 TouchGetFocusWnd
 TouchGetLastTouchFocusWnd
 TouchGetQueuePtr
; @CESYSGEN ENDIF 

 

     很明显,这个DEF文件也受控制了,现在使用dumbin看看touch.dll到底导出了什么函数就可以知道用了什么库了。

 

     由此可以看出,触摸屏驱动使用了非扩展方案。现在开始分析代码。

     MDD层:

     1.TouchPanelEnable

     该函数首先调用TouchPanelpAttach函数,(在TouchPanelpAttach里面又调用和坐标校正相关的TouchPanelSetCalibration函数);DdsiTouchPanelEnable(在PDD中实现)以及初始化触摸屏驱动的按下弹起、滑动两个线程。

     2.TouchPanelDisable

     该函数调用DdsiTouchPanelDisable(PDD实现——释放触摸屏驱动占用的队内存以及禁止pen up/down中断)以及SetEvent一些事件。

     3.TouchPanelGetDeviceCaps

     该函数为DDI接口函数。用于查询触摸屏设备支持的具体功能。

调用到的DDSI函数为

DdsiTouchPanelGetDeviceCaps

该函数动作为

(1).       通过DDSI函数查询相应的信息

(2).       当查询屏幕坐标信息时保存屏幕信息,供后面程序映射屏幕坐标

4.TouchPanelSetMode

该函数根据switch语句设置一些优先级采样相关的东西

 5.TouchPanelReadCalibrationPoint

该函数主要是读入Common.reg的注册表,但是我对这个注册表的作用还不是很明白。——了解的告知小弟一声。

[HKEY_LOCAL_MACHINE\SYSTEM\GWE]
    "ActivityEvent"="PowerManager/ActivityTimer/UserActivity"

dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\GWE", 0, 0, &hk);

dwStatus = RegQueryValueEx(hk, L"ActivityEvent", NULL, &dwType, (LPBYTE) szEventPath, &dwSize);

hevActivity = OpenEvent(EVENT_ALL_ACCESS, FALSE, szEventPath);——不理解的是这里了。

 6.TouchPanelReadCalibrationAbort

   该函数在效验取消的时候被调用。仅仅设置状态位和事件后返回。

   

   7.  TouchPanelSetCalibration

   该函数是校准相关的东西,我的数学太烂了,看了代码不知道怎么回事。现在暂时放弃,以后有空再研究了。

   8.TouchPanelCalibrateAPoint

   该函数用于校正坐标,使用的公式貌似是最小二乘法,数学忘记了,真是后悔以前没有学好。就贴个代码吧。

 

     最后一个MDD函数 TouchPanelPowerHandler

     该函数调用PDD的DdsiTouchPanelPowerHandler函数实现功能。

     PDD层:

     一、TSP_VirtualFree(VOID); TSP_VirtualAlloc(VOID);

     上面两个函数分别是释放和获得wince系统的堆内存

     二、TSP_SampleStart

     采样开始,利用PWM定时器3

     三、TSP_SampleStop

     停止采样,关闭定时器

     四、TSP_PowerOn

     该函数初始化AD、定时器,以及消除INT_TC Touch screen interrupt屏蔽

     五、TSP_PowerOff

     屏蔽INT_TC Touch screen interrupt

     六、TSP_CalibrationPointGet

     该函数是用来计算五个点的校正坐标的,我们在校正笔针的时候会调用到这个函数

     七、TSP_TransXY

     该函数为作比较转换函数,被DdsiTouchPanelGetPoint函数调用。对于里面的写法我不懂,TSP_MINXTSP_MINy的值到底是根据什么来取的?我记得触摸屏驱动和LCD大小是无关的,以前我修改屏幕不同的LCD驱动的时候并没有修改触摸屏就可以用了,这个值到底是怎么搞的呢?也没有相关资料说明真是难以理解的。

     八、TSP_GetXY

     该函数是读入的X、Y坐标AD值,这个值是连续采样四次(如果要精准,估计加大采样次数即可);被DdsiTouchPanelGetPoint调用

     九、DdsiTouchPanelGetDeviceCaps

     该函数是一些触摸屏参数设置,采样率等;还有就是点号,校正点的坐标计算等。

     十、DdsiTouchPanelSetMode

     参数设置

     十一、DdsiTouchPanelEnable

     该函数用来申请触摸屏用到相关两个中断,不过它的一些写法让人有点费解Irq[0]=-1;Irq[1]=OAL_INTR_FORCE_STATIC;Irq[2]=IRQ_ADC;不知道它为何要这样写。

     十二、DdsiTouchPanelDisable

     该函数释放对内存等资源。

     十三、DdsiTouchPanelAttachDdsiTouchPanelDetach

     两函数没有任何动作。

     十四、DdsiTouchPanelPowerHandler

     根绝条件是执行TSP_PowerOffTSP_PowerOn

     十五、DdsiTouchPanelGetPoint

     两个中断的线程函数,被TouchPanelpISR函数调用——TouchPanelpISR是在TouchPanelEnable函数创建的线程

补充:

     (1)触摸屏中断申请

     我感觉触摸屏的中断有点奇怪,首次看到这样的写法。(触摸屏的两个中断是绑定同一个线程的,是个经典例子)

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

     KernelIoControl的第二个参数是指向一个buf的指针,IRQ数组是如何得到处理的呢?在OALIntrRequestSysIntr函数中有

if (
        g_oalIrq2SysIntr[irq] == SYSINTR_UNDEFINED ||
        (flags & OAL_INTR_FORCE_STATIC) != 0
    ) {
        g_oalIrq2SysIntr[irq] = sysIntr;
    }

     以前看OALIntrRequestSysIntr都只是看函数名称,没有看它带的参数,现在要好好看看

UINT32 OALIntrRequestSysIntr(UINT32 count, const UINT32 *pIrqs, UINT32 flags)
count *pIrqs  flags都有它的作用。

     后来在CSDN请教LinHanLao前辈,得到了满意的回复:

aIrqs[0] = -1;

// Using -1 indicates we are not using the legacy calling convention. 

     关于OAL_INTR_FORCE_STATIC的详细解释在PB帮助文档有说明。

     (2)触摸屏中断线程

     触摸屏涉及两个中断,一个是按下,弹起笔针,另外一个是笔针滑动中断;他们分别是由INT_TC和Timer3实现的。非常有趣的是这两个中断绑定同一个线程(在CSDN有人问过,现在终于亲自看到了(*^__^*) 嘻嘻……),任何一个中断产生都能启动线程。

     弹起、按下笔针中断很容易理解,但是这个滑动却是比较牛,在产生按下动作之后,是通过定时器采样,然后计算亮点的差值来做的,不过我对笔针的框选动作始终不理解,还有触摸屏驱动是如何被应用程序调用的呢?我们如何自己写校验算法呢?毕竟他不是流驱动。以后到CSDN发帖求助吧,这篇博客完之前贴一下它的中断的关键代码。

 

  

/* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */
/* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */

 

PUBLIC VOID
DdsiTouchPanelGetPoint(TOUCH_PANEL_SAMPLE_FLAGS * pTipStateFlags,
        INT * pUncalX,
        INT * pUncalY)
{
 static INT x, y;
 //INT_TC Touch screen interrupt (pen up/down) INT_ADC
 if (v_pINTregs->SUBSRCPND & (1<<IRQ_SUB_TC))  /* SYSINTR_TOUCH Interrupt Case*/
 {
  *pTipStateFlags = TouchSampleValidFlag;

  if ( (v_pADCregs->ADCDAT0 & (1 << 15)) |
    (v_pADCregs->ADCDAT1 & (1 << 15)) )
  {
   bTSP_DownFlag = FALSE;

   DEBUGMSG(ZONE_TIPSTATE, (TEXT("up\r\n")));

   v_pADCregs->ADCTSC &= 0xff;

   *pUncalX = x;
   *pUncalY = y;

   TSP_SampleStop();
  }
  else
  {
   bTSP_DownFlag = TRUE;

   if (!TSP_GetXY(&x, &y))
    *pTipStateFlags = TouchSampleIgnore;

   TSP_TransXY(&x, &y);

   *pUncalX = x;
   *pUncalY = y;

   *pTipStateFlags |= TouchSampleDownFlag;

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

   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();
  
  if (bTSP_DownFlag)
  {
   INT  tx, ty;
   INT  dx, dy;

   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

    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);
 }
}


 


 

相关文章参考:http://topic.csdn.net/u/20081215/16/3ae65482-c8ea-4e09-a725-89a9255eb60f.html

                    http://blog.csdn.net/gooogleman/archive/2009/03/14/3990238.aspx

 


/*++

Routine Description:

    Convert uncalibrated points to calibrated points.


Autodoc Information:

    @doc INTERNAL DRIVERS MDD TOUCH_DRIVER
    @func VOID | TouchPanelCalibrateAPoint |
    Convert uncalibrated points to calibrated points.

    @comm
    The transform coefficients are already in vCalcParam.<nl>


    @devnote
    Note that there is a *4 hiding in the calculations of X and
    Y.  This is a means of providing sub-pixel accuracy to GWE,
    which will theoretically help improve accuracy in inking. It
    would be nice if this multiplier were defined in a .h file
    by gwe, but it isn't.  So make very sure that this value
    agrees with the divisor used by gwe in touch.cpp.
--*/


void
TouchPanelCalibrateAPoint(
    INT32   UncalX,     //@PARM The uncalibrated X coordinate
    INT32   UncalY,     //@PARM The uncalibrated Y coordinate
    INT32   *pCalX,     //@PARM The calibrated X coordinate
    INT32   *pCalY      //@PARM The calibrated Y coordinate
    )
{
    INT32   x, y;

    if ( !v_Calibrated ){
        *pCalX = UncalX;
        *pCalY = UncalY;
        return;
    }
     //
     // Note the *4 in the expression below.  This is a kludge
     // perpetrated on behalf of gwe.  It provides a form of
     // sub-pixel accuracy desirable for inking
     //
    x = (v_CalcParam.a1 * UncalX + v_CalcParam.b1 * UncalY +
         v_CalcParam.c1) * 4 / v_CalcParam.delta;
    y = (v_CalcParam.a2 * UncalX + v_CalcParam.b2 * UncalY +
         v_CalcParam.c2) * 4 / v_CalcParam.delta;
    if ( x < 0 ){
        x = 0;
    }

    if ( y < 0 ){
        y = 0;
    }

    *pCalX = x;
    *pCalY = y;
}

posted on 2010-11-05 10:45  gooogleman  阅读(352)  评论(0编辑  收藏  举报