??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩精品无码久久久久久,久久婷婷国产剧情内射白浆,欧美粉嫩小泬久久久久久久http://m.shnenglu.com/tdweng/category/16105.htmlzh-cnWed, 10 Apr 2013 01:12:26 GMTWed, 10 Apr 2013 01:12:26 GMT60WinCE6.0的EBOOT概要 http://m.shnenglu.com/tdweng/articles/141765.html心羽心羽Mon, 14 Mar 2011 02:34:00 GMThttp://m.shnenglu.com/tdweng/articles/141765.htmlhttp://m.shnenglu.com/tdweng/comments/141765.htmlhttp://m.shnenglu.com/tdweng/articles/141765.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/141765.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/141765.htmlwince博客 http://www.cnblogs.com/we-hjb

 

Z个新的硬件设备定?/font>WinCE6.0操作pȝQ一般需要完成以下几个主要步骤:

1.       针对特定的硬件设备创建板U支持包(Board Support Package~写?/span>BSP)Q?/span>BSP必须包括BOOTLOADER?/span>OEM适配?/span>(OEM Adaptation Layer~写?/span>OAL)和一些必要的驱动?/span>

2.       利用创徏?/span>BSPQ定制一个系l设?/span>(OS Design)。即通过VS2005创徏一?/span>Platform Builder的工E。该工程可编译生最l的q行时映像文ӞRum-time ImageQ?/span>

3.       针对板上的外围设备创建相关驱动,q添加到BSP中?/span>

4.       通过创徏子工E和Catalog Items的方式,修改OS Design?/span>

5.       ~译OS DesignQ下载编译得到的q行时映像文件到目标讑֤。此Ӟ可通过q程调试工具q行调试?/span>

6.       在完成所有的调试工作之后Q导q行时映像对应的SDK(Software Development Kit)Q应用程序的开发h员可Z?/span>SDK~写该设备的应用E序?/span>

       可以看出Q在整个WinCE操作pȝ的移植过E中Q?/span>BSP的移植是最基础也是最关键的一步。而创?/span>BSP的过E主要包括以下几个内容:

1.       创徏BOOTLOADER?/span>BOOTLOADER在开发的q程中用于下载操作系l映像文件?/span>

2.       创徏OAL?/span>OAL最l被链接到内核映像文Ӟ它主要完成硬件的初始化和理?/span>

3.       创徏讑֤驱动。设备驱动是板上外围讑֤的Y件支持?/span>

4.       修改q行时映像的配置文g。配|文件主要包?/span>BIB?/span>REG{文件?/span>

BOOTLOADER的主要作用是操作系l运行时映像加蝲到内存,q蟩转到OS的启动程序处。它的这一作用跟前一介l的NBOOT的作用完全一致?/span>BOOTLOADER获取q行时映像(一般对应的文g名ؓNKQ一般有两种Ҏ。它可以通过有线q接的方式象|络(Ethernet)?/span>USB或串口从外部下蝲NK。它也可以从本地的存储器(Flash?/span>Hard Disk)中加?/span>NK。通常Q?/span>BOOTLOADER通过Ethernet下蝲操作pȝ映像故将其称?/span>EBOOT。在开发的q程中?/span>EBOOTQ可以提高开发效率。通过使用EBOOTQ你可以很快速的下蝲NK到目标设备中。而利?/span>Flash~程工具或者是通过JTAG下蝲则很慢。在一些品最l发布时Q?/span>EBOOT是可以去掉的Q但也有一些则必须包括BOOTLOADERQ像X86的^台就是如此?/span>

xQ我们已l了解了EBOOT的主要功能,Z实现q些功能Q?/span>EBOOT必须完成以下工作Q?/span>

1.       初始?/span>MCU。包括初始化MCU的相兛_存器、中断、看门狗、系l时钟、内存和MMU。前面几跟NBOOT基本一_但这里增加了?/span>MMU的初始化?/span>

2.       在完成所有的初始化工作之后,调用BootloaderMain()。这个函数的定义?/span>WinCE6.0中对应的文g?/span>C:"WINCE600"PLATFORM"COMMON"SRC"COMMON"BOOT"BLCOMMON"blcommon.c

3.       BootloaderMain()主要依次调用以下几个函数Q?/span>OEMDebugInit()?/span>OEMPlatformInitQ)?/span>OEMPreDownloadQ)?/span>OEMLaunchQ)Q而这些函数必ȝEBOOT的代码来实现?/span>

4.       最l蟩转到OAL.exe?/span>StartUp处,q而启?/span>WinCE操作pȝ?/span>

整个程如下图所C:           

      

     EBOOT的代码可参考C:"WINCE600"PLATFORM"DEVICEEMULATOR"SRC"BOOTLOADER"EBOOT目录。这里针对S3C2410的EBOOT做几点说明。前一介lNBOOT加蝲EBOOT的方法时提到QNBOOT必须EBOOT攑֜内存中指定的位置Q这个位|是由EBOOT的来军_的。具体的Q在EBOOT中的体现是boot.bib里的内存配置Q如下图所C?

     

     NBOOT加蝲EBOOT到内存的地址必须与此地址对应。由于在NBOOT中没有?/span>MMUQ所?/span>NBOOT使用的实际地址应该?/span>0x30021000Q否则系l将不能正常启动。第二点Q如果没有采?/span>NBOOT加蝲EBOOT的方法,而是?/span>EBOOT直接存储?/span>NOR Flash中,此时必须?/span>EBOOT的代码中实现自加载的q程Q即?/span>NOR Flash中的EBOOT全部加蝲?/span>RAM中,q执行,实现代码如下:


;------------------------------------------------------------------------------
;   Copy boot loader to memory

        ands    r9, pc, #
0xFF000000     ; see if we are in flash or in ram
        bne     
%f20                    ; go ahead if we are already in ram

        ; This 
is the loop that perform copying.
        ldr     r0, 
= 0x21000           ; offset into the RAM 
        add     r0, r0, #PHYBASE        ; add physical 
base
        mov     r1, r0                  ; (r1) copy destination
        ldr     r2, 
=0x0                ; (r2) flash started at physical address 0
        ldr     r3, 
=0x10000            ; counter (0x40000/4)
10      ldr     r4, [r2], #4
        str     r4, [r1], #
4
        subs    r3, r3, #
1
        bne     
%b10

        ; Restart from the RAM position after copying.
        mov pc, r0
        nop
        nop
        nop

        ; Shouldn
't get here.
        b       .
      EBOOT在实现必备功能的前提下,我们q可以扩展其功能Q譬如说初始?/span>LCDQƈ昄特定的启动画面,昄加蝲映像的进度等?/span>
      本文_略的介l了WinCE6.0?/span>EBOOT的内容,但没有涉及具体的代码实现Q相关代码可以参考目?/span>C:"WINCE600"PLATFORM"DEVICEEMULATOR"SRC"BOOTLOADER"EBOOT。ȝ来说Q?/span>EBOOT的核心功能就是引导操作系l映像?/span>


心羽 2011-03-14 10:34 发表评论
]]>
Q{QWindows CE下访问物理内存的一些方法!Q?http://m.shnenglu.com/tdweng/articles/140929.html心羽心羽Tue, 01 Mar 2011 09:37:00 GMThttp://m.shnenglu.com/tdweng/articles/140929.htmlhttp://m.shnenglu.com/tdweng/comments/140929.htmlhttp://m.shnenglu.com/tdweng/articles/140929.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140929.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140929.html1.VirtualAlloc用来在进E的虚拟地址I间中保留(reserve)或者提?commit)c在保留时以64KB为粒度,即保留空间以64K为单位。而提交虚拟地址Ӟ则以?典型大小?KB)为单位?br>
2.VirtualCopy用来l定一块物理内存到当前q程虚拟地址I间。参数里的lpvSrc既可以是内核D늚虚拟地址也可以是物理地址(用page_physical来标?。同时要注意lpvSrc的右UM否?br>
3.使用VirtualAlloc要包含Winbase.h;使用VirtualCopy时要包含plfuncs.h.两者都要链接coredll.lib.

4.在CE5.0之前,使用VirtualAlloc获得的虚拟地址I间分ؓ两种情Ş:
(1)大小?MB以下?位于调用q程的虚拟空间中;
(2)大小大于2MB?位于用户态的׃n地址I间?0x42000000-0x7E000000 )


1. 如果copy的物理地址?12M范围内,那么׃静态映的存在QlpvSrc可以为静态映的虚拟地址Q也可以为物理地址。采用后者需要指定page_physicalQ同时lpvSrc右移8位?
2. 如果copy的物理地址?12M范围外,那么׃微Y的如下规?#8220;
VirtualCopy also supports the PAGE_PHYSICAL flag. You must set this flag when you are mapping physical memory that resides beyond 512 MB, that is, physical memory with an address above 0x1FFFFFFF.”
lpvSrc只能为物理地址Q同旉要右U?br>
只要讄了PAGE_PHYSICAL 为真Q那么就需要把lpvSrc右移8?/span>

嵌入式设备与桌面
PC的一个显著不同是它的应用E序中通常需要直接访问某一D늉理内存,q在驱动E序中对物理内存的访问尤为重要,其是像ARM体系l构下,I/O端口也被映射成某一个物理内存地址。因此,与桌面版?/span>Windows相比Q?/span>Windows CE提供了相对简单的物理内存讉K方式。无论是驱动E序q是应用E序都可以通过API讉K某一D늉理内存?/span>

Windows CE的有些函C需要用到物理内存结构体PHYSICAL_ADDRESSQ?/span> Windows CE?/span>ceddk.h中定义了PHYSICAL_ADDRESSQ它其实?/span>LARGE_INTEGERcdQ其定义如下Q?/span>

// in ceddk.h

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

// in winnt.h

typedef union _LARGE_INTEGER{

 struct{

    DWORD LowPart;

    LONG HighPart;

 };

 LONGLONG QuadPart;

} LARGE_INTEGER;

可见Q?/span>Windows CE中用64?/span>Bit来代表物理地址Q对于大多数32位的CPU而言Q只需要把它的HighPart讄?/span>0可以了?/span>

如果要直接访问某一个地址的物理内存,Windows CE提供?/span>VirtualAlloc()?/span>VirtualCopy()函数Q?/span>VirtualAlloc负责在虚拟内存空间内保留一D虚拟内存,?/span>VirtualCopy负责把一D늉理内存和虚拟内存l定Q这P最l对物理内存的访问还是通过虚拟地址q行。它们的声明如下Q?/span>

// 甌虚拟内存

LPVOID VirtualAlloc(

 LPVOID lpAddress,     // 希望的虚拟内存v始地址

 DWORD dwSize,             // 以字节ؓ单位的大?/span>

 DWORD flAllocationType,  // 甌cdQ分?/span>Reserve?/span>Commit

 DWORD flProtect           // 讉K权限

);

// 把物理内存绑定到虚拟地址I间

BOOL VirtualCopy(

 LPVOID lpvDest,           // 虚拟内存的目标地址

 LPVOID lpvSrc,            // 物理内存地址

 DWORD cbSize,             // 要绑定的大小

 DWORD fdwProtect          // 讉K权限

);

VirtualAlloc对虚拟内存的甌分ؓ两步Q保?/span>MEM_RESERVE和提?/span>MEM_COMMIT。其?/span>MEM_RESERVE只是在进E的虚拟地址I间内保留一D,q不分配实际的物理内存,因此保留的虚拟内存ƈ不能被应用程序直接用?/span>MEM_COMMIT阶段才真正的拟内存分配物理内存?/span>

下面的代码显CZ如何使用VirtualAlloc?/span>VirtualCopy来访问物理内存。因?/span>VirtualCopy负责把一D늉理内存和虚拟内存l定Q所?/span>VirtualAlloc的时候只需要对内存保留Q没有必要提交?/span>

FpDriverGlobals =

(PDRIVER_GLOBALS) VirtualAlloc(

    0,

    DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE,

    MEM_RESERVE,

    PAGE_NOACCESS);

 if (FpDriverGlobals == NULL) {

    ERRORMSG(DRIVER_ERROR_MSG, (TEXT(" VirtualAlloc failed!\r\n")));

    return;

 }

 else {

    if (!VirtualCopy(

    (PVOID)FpDriverGlobals,

    (PVOID)(DRIVER_GLOBALS_PHYSICAL_MEMORY_START),

    DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE,

    (PAGE_READWRITE | PAGE_NOCACHE))) {

       ERRORMSG(DRIVER_ERROR_MSG, (TEXT("VirtualCopy failed!\r\n")));

       return;

    }

 }

CEDDKq提供了函数MmMapIoSpace用来把一D늉理内存直接映到虚拟内存。此函数的原形如下:

PVOID MmMapIoSpace(

 PHYSICAL_ADDRESS PhysicalAddress, // 起始物理地址

 ULONG NumberOfBytes,                  // 要映的字节?/span>

 BOOLEAN CacheEnable                   // 是否~存

);

其实Q?/span>MmMapIoSpace函数内部也是调用VirtualAlloc?/span>VirtualCopy函数来实现物理地址到虚拟地址的映的?/span>MmMapIoSpace函数的原代码是公开的,我们可以?/span>%_WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\CEDDK\DDK_MAP\ddk_map.c得到。从MmMapIoSpace的实现我们也可以看出VirtualAlloc?/span>VirtualCopy的用法:

PVOID MmMapIoSpace (

    IN PHYSICAL_ADDRESS PhysicalAddress,

    IN ULONG NumberOfBytes,

    IN BOOLEAN CacheEnable

    )

{

PVOID pVirtualAddress; ULONGLONG SourcePhys;

ULONG SourceSize; BOOL bSuccess;

 

    SourcePhys = PhysicalAddress.QuadPart & ~(PAGE_SIZE - 1);

    SourceSize = NumberOfBytes + (PhysicalAddress.LowPart & (PAGE_SIZE - 1));

 

    pVirtualAddress = VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS);

    if (pVirtualAddress != NULL)

    {

        bSuccess = VirtualCopy(

            pVirtualAddress, (PVOID)(SourcePhys >> 8), SourceSize,

            PAGE_PHYSICAL | PAGE_READWRITE | (CacheEnable ? 0 : PAGE_NOCACHE));

 

        if (bSuccess) {

            (ULONG)pVirtualAddress += PhysicalAddress.LowPart & (PAGE_SIZE - 1);

        }

        else {

            VirtualFree(pVirtualAddress, 0, MEM_RELEASE);

            pVirtualAddress = NULL;

        }

    }

    return pVirtualAddress;

}

此外Q?/span>Windows CEq供?/span>AllocPhysMem函数?/span>FreePhysMem函数Q用来申请和释放一D连l的物理内存。函数可以保证申L物理内存是连l的Q如果函数成功,会返回虚拟内存的句柄和物理内存的起始地址。这对于DMA讑֤ؓ有用。在q里׃详细介绍了,读者可以参?/span>Windows CE的联机文?/span>



心羽 2011-03-01 17:37 发表评论
]]>
wince~译q程http://m.shnenglu.com/tdweng/articles/140919.html心羽心羽Tue, 01 Mar 2011 08:53:00 GMThttp://m.shnenglu.com/tdweng/articles/140919.htmlhttp://m.shnenglu.com/tdweng/comments/140919.htmlhttp://m.shnenglu.com/tdweng/articles/140919.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140919.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140919.html在WinCEpȝ中,当我们完成了相关的开发和pȝ定制工作以后Q会~译WinCEpȝQ最后生成NK.bin和NK.nb0。我现在用WinCE6.0在自qPC上面~译一ơ用?9?6U?有一天无聊,测了一?。下面介l一下WinCEpȝ的编译过E,大致分ؓ4个阶D:~译阶段(Compile phase)Q系l生阶D?Sysgen phase)Q文件拷贝阶D?Release copy phase)和生成映像阶D?Make Run-time image phase)?/p>

q程如图Q?/p>

从图中可以看出,整个~译都是通过调用Blddemo.bat来实现的Q实际上也是q样Q编译WinCE是用Blddemo.batQ只不过后面可以跟不同的参数。编译阶D和pȝ产生阶段由Cebuild.bat完成Q文件拷贝阶D는Buildrel.bat完成Q最后的生成映像阶段由Makeimg.exe完成。下面介l一下各个阶Dc?/p>

1. ~译阶段(Compile phase)

q个q程指对WinCE路径下的Private和Public目录q行~译Q将里面的源代码~译成库文g{,q个q程可能会花费几个小时。除非改动了Private或Public目录下的源码Q否则是不需要编译的。一般我们编译自q工程的时候,不需要这个步骤?/p>

2. pȝ产生阶段(Sysgen phase)

在这个过E中Q系l会Ҏ你在PB中Catalog中的选项Q删除和讄相应的SYSGEN环境变量Q链接相应的静态库Q过滤头文gQؓSDK创徏所需的导入库Q同时还会ؓWinCEpȝ创徏一些配|文件。最后会~译当前的BSP和应用程序?/p>

3. 文g拯阶段(Release Copy phase)

拯所有所需的文件到工程的release目录下面Q主要是前面pȝ产生阶段所产生的所有文件?/p>

4. 生成映像阶段(Make run-time image phase)

该过E首先调用cenlscmp.exeҎ国际语系与地定生成wince.nls文g。然后调用Fmerge.exe合ƈ一些配|文Ӟ合ƈ所有bib文g为ce.bibQ合q所有的reg文g为Reginit.iniQ合q所有的dat文g为Initobj.datQ合q所有的db文g为Initdb.ini。之后调用Regcomp.exe压羃reginit.ini为default.fdf。根据LOCAL环境变量的设|调用Res2exe.exe更新所有的dllQexe和cpl文g中的资源文gQ主要是更新其中的语a部分。再调用Txt2ucde.exe转换所有ASCII码字W串为UNICODE。最后调用Romimage.exe合ƈ所有文件ؓNK.bin?/p>

在整个编译过E中有时会遇到编译错误,q个可以通过察看Build.logQBuild.err和Build.wrn文g来分析问题,q三个文件应该是位于”\WINCE600”目录下面。编译错误可能在不同的编译阶D生,我们也可以根据这一Ҏ分析问题?/p>

一般在pȝ产生阶段(Sysgen phase)出现错误很可能是׃丢失lg或文仉成的,q时候Build.log会提供更多信息帮助分析问题。在q个阶段产生错误Q很可能是由于在当前工程中添加或者删除WinCElg造成的,其中有些lg的更Ҏ需要进?#8221;clean sysgen”的,而不能只使用”sysgen”命o。所以我的徏议是每次d或删除组仉?#8221;clean sysgen”?/p>

如上面介l系l生阶D?Sysgen phase)也会~译BSP和部分应用。所以如果错误出现在pȝ产生阶段的编译过E中Q一般一U可能就是你的代码有语法错误Q当然这U错误很好查。还有一U可能出现的错误是连接错误,有可能是丢失了lib库文件或者链接错了库文gQ也有可能是调用了错误的API函数Q还有就是设|了错误的环境变量,q些查v来相对困难一炏V?/p>

如果错误产生在文件拷贝阶D?Release copy phase)Q一U常见的问题是和硬盘驱动器有关Q检查一下release目录所在磁盘的盘I间?/p>

如果问题出现在生成映像阶D?Make run-time image phase)Q根据编译的输出H口的输Z息判断问题出在哪个子阶段。一U可能是你的bib文g或者reg文g中存在语法错误导致合q文件时出错Q还有就是注意你的image的大是否超q了config.bib文g中的讑֮Q还有就是可能丢׃某个或者某些文Ӟq些丢失的文件很可能是由于在前面的编译过E中出现错误D的?/p>

当然Q也有时候会遇到一些奇怪的问题Q这些问题可能是׃没有正确的安装WinCE造成的,比如在安装WinCE的时候,路径中不要有中文或者空格或者其他比较奇怪的字符。补丁要按照序来打Q要不也可能会出现问题?/p>

 

本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/FLandY1982/archive/2009/12/04/4941120.aspx



心羽 2011-03-01 16:53 发表评论
]]>
WINCE串口驱动MDD层代码简单分?http://m.shnenglu.com/tdweng/articles/140916.html心羽心羽Tue, 01 Mar 2011 08:16:00 GMThttp://m.shnenglu.com/tdweng/articles/140916.htmlhttp://m.shnenglu.com/tdweng/comments/140916.htmlhttp://m.shnenglu.com/tdweng/articles/140916.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140916.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140916.htmlhttp://blog.csdn.net/FLandY1982/archive/2009/12/24/5070059.aspx

心羽 2011-03-01 16:16 发表评论
]]>
WINCE串口驱动PDD层代码简单分?http://m.shnenglu.com/tdweng/articles/140915.html心羽心羽Tue, 01 Mar 2011 08:13:00 GMThttp://m.shnenglu.com/tdweng/articles/140915.htmlhttp://m.shnenglu.com/tdweng/comments/140915.htmlhttp://m.shnenglu.com/tdweng/articles/140915.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140915.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140915.html阅读全文

心羽 2011-03-01 16:13 发表评论
]]>
WinCE下Touch Panel驱动介绍http://m.shnenglu.com/tdweng/articles/140894.html心羽心羽Tue, 01 Mar 2011 03:51:00 GMThttp://m.shnenglu.com/tdweng/articles/140894.htmlhttp://m.shnenglu.com/tdweng/comments/140894.htmlhttp://m.shnenglu.com/tdweng/articles/140894.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140894.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140894.htmlWinCE中的Touch Panel驱动是由GWES模块来管理的QTouch Panel驱动接收用户的触怿息,q将其{换ؓ屏幕上的坐标信息Q传lGWES模块。在WinCE中,Touch Panel驱动是分层的Q分为MDD层和PDD层,q和其他WinCE讑֤驱动是一L。MDD层由微Y提供Q用户只需要实现MDD和PDD层间的DDSI函数可以了。如?span style="FONT-SIZE: small">

 


    WinCE中的GWES模块负责加蝲和管理Touch Panel驱动QTouch Panel的MDD层向上提供DDI接口QPDD层是针对g的实玎ͼ对MDD层提供DDSI接口?/p>

 

  WinCE中的GWES模块负责加蝲和管理Touch Panel驱动QTouch Panel的MDD层向上提供DDI接口QPDD层是针对g的实玎ͼ对MDD层提供DDSI接口?/p>

 

1 Touch Panel驱动中的数据l构

(1) TOUCH_PANEL_SAMPLE_FLAGS

用于描述一个采L的信息,q些信息被定义在一个枚丄构中Q?/p>

               enum enumTouchPanelSampleFlags {

                 TouchSampleValidFlag = 0x01,

                 TouchSampleDownFlag = 0x02,

                 TouchSampleIsCalibratedFlag = 0x04,

                 TouchSamplePreviousDownFlag = 0x08,

                 TouchSampleIgnore = 0x10,

                 TouchSampleMouse = 0x40000000

               };

               TouchSampleValidFlagQ一个有效的采样?/p>

               TouchSampleDownFlagQ第一ơ按触摸屏时Q返回该flag

               TouchSampleIsCalibratedFlagQ采Lx和y坐标g需要再被校验了

               TouchSamplePreviousDownFlagQ表CZ一ơ采L态是按在触摸屏上

               TouchSampleIgnoreQ忽略这ơ采样?/p>

               TouchSampleMouseQ预?/p>

 

(2) TPDC_CALIBRATION_POINT

用于描述一个校验点的相关信息,l构如下Q?/p>

               struct TPDC_CALIBRATION_POINT {

                 INT PointNumber;

                 INT cDisplayWidth;

                 INT cDisplayHeight;

                 INT CalibrationX;

                 INT CalibrationY;

               };

               PointNumberQ校验点索引|用于描述校验点在LCD上的位置

                                                0Q中?/p>

                                                1Q左?/p>

                                                2Q左?/p>

                                                3Q右?/p>

                                                4Q右?/p>

               cDisplayWidthQ显C的宽度

               cDisplayHeightQ显C的高度

               CalibrationXQ校验点的x坐标?/p>

               CalibrationYQ校验点的y坐标?/p>

 

(3) TPDC_CALIBRATION_POINT_COUNT

用于描述需要校验的点的个数Q结构如下:

               struct TPDC_CALIBRATION_POINT_COUNT {

                  DDI_TOUCH_PANEL_CALIBRATION_FLAGS flags;

                  INT cCalibrationPoints;

               };

               flagsQ一般ؓ0

               cCalibrationPointsQ需要校验的点的个数Q一般是5

 

(4) gIntrTouch和gIntrTouchChanged

q是两个被MDD层用到的中断Q需要在PDD层中定义Q如下:

                        DWORD gIntrTouch        = SYSINTR_NOP;

DWORD gIntrTouchChanged = SYSINTR_NOP;

gIntrTouch用于描述触摸屏中断,要和g的触摸屏中断相关联?/p>

gIntrTouchChanged用于在触摸屏按下后,每隔一D|间进行一ơ采P应该和硬件的一个定时器中断相关联?/p>

q两个值应该在DdsiTouchPanelEnable(..)函数中和g中断兌Qƈ在函数DdsiTouchPanelGetPoint(..)中根据情冉|除相应的中断?/p>

 

2 MDD层API

        MDDZ层导出所需的Touch Panel驱动接口函数Q上层通过q些函数可以完成对Touch Panel的操作,下面会介l这些函数的功能?/p>

(1) BOOL TouchPanelEnable(PFN_TOUCH_PANEL_CALLBACK pfnCallback):

使能Touch Panel讑֤Q用于初始化Touch Panel?/p>

       pfnCallbackQ指向处理Touch Panel事g的回调函?/p>

 

(2) Void TouchPanelDisable(void):

用Touch Panel讑֤?/p>

 

(3) BOOL TouchPanelGetDeviceCaps(INT iIndex, LPVOID lpOutput )Q?/p>

获得Touch Panel讑֤的相关信息?/p>

       iIndexQ烦引?/p>

                        TPDC_SAMPLE_RATE_IDQ采L信息

                        TPDC_CALIBRATION_POINT_COUNT_IDQ采L个数信息

                        TPDC_CALIBRATION_POINT_IDQ采L坐标信息

            lpOutputQ指向一个内存区域,用于存放获得的相关信?/p>

 

(4) VOID TouchPanelCalibrateAPoint(INT32 UncalX, INT32 UncalY, INT32* pCalX, INT32* pCalY)Q?/p>

输入的未经q校验的坐标信息转换成校验后的坐标信息?/p>

       UncalXQ输入的X坐标

               UncalYQ输入的Y坐标

       pCalXQ校验后的X坐标

       pCalYQ?校验后的Y坐标

 

(5) VOID TouchPanelPowerHandler(BOOL bOff)Q?/p>

Touch Panel的电源控制函数?/p>

       bOffQTRUE表示关闭甉|QFALSE表示打开甉|

 

(6) BOOL TouchPanelReadCalibrationPoint(INT* pRawX, INT* pRawY)Q?/p>

获得Touch Panel的坐标?/p>

       pRawXQ触摸屏的X坐标

       PRawYQ触摸屏的Y坐标

 

(7) VOID TouchPanelReadCalibrationAbort(void)Q?/p>

l止当前的校验?/p>

 

(8) VOID TouchPanelSetCalibration(INT32 cCalibrationPoints, INT32* pScreenXBuffer, INT32* pScreenYBuffer, INT32* pUncalXBuffer, INT32* pUncalYBuffer)Q?/p>

校验函数。通过一l实际的触摸屏上采集的点坐标和相应的屏幕坐标计算校验pL。具体公式如下:

        Sx =  A1*Tx + B1*Ty + C1

      Sy =  A2*Tx + B2*Ty + C2

   q里是通过昄屏坐标和采样的触摸屏坐标计算A1,B1,C1,A2,B2,C2?/p>

       cCalibrationPointsQ校验点的个?/p>

       pScreenXBufferQ一l显C屏上的X坐标

               pScreenYBufferQ一l显C屏上的Y坐标

               pUncalXBufferQ一l触摸屏上采LX坐标

               pUncalYBufferQ一l触摸屏上采LY坐标

 

(9) BOOL TouchPanelSetMode(INT iIndex, LPVOID lpInput)Q?/p>

讄Touch Panel的工作模式?/p>

               iIndexQ烦引模?/p>

                                    TPSM_SAMPLERATE_HIGHQ设|高采样?/p>

                                    TPSM_SAMPLERATE_LOWQ设|低采样?/p>

                                    TPSM_PRIORITY_HIGH_IDQ设|触摸屏的IST为高优先U?/p>

                                    TPSM_PRIORITY_NORMAL_IDQ设|IST为正怼先

               lpInputQ指向一块内存,其中包含相关信息?/p>

 

3 PDD层API

(1) LONG DdsiTouchPanelAttach(void)Q?/p>

该函数在Touch Panel驱动的Dll被加载的时候调?/p>

 

(2) LONG DdsiTouchPanelDettach(void)Q?/p>

该函数在Touch Panel驱动的Dll被卸载的时候调?/p>

 

(3) BOOL DdsiTouchPanelEnable(void)Q?/p>

打开Touch Panel甉|q做初始化。一般会在这里初始化一些信息,打开Touch Panel讑֤甉|q做初始化?/p>

 

(4) VOID DdsiTouchPanelDisable(void)Q?/p>

关闭Touch Panel讑֤。关闭Touch Panel甉|q放资源?/p>

 

(5) BOOL DdsiTouchPanelGetDeviceCaps(ULONG iIndex, LPVOID lpOutput)Q?/p>

查询Touch Panel讑֤的相关信?/p>

               iIndexQ查询的索引?/p>

                   TPDC_SAMPLE_RATE_IDQ查询采L信息

                   TPDC_CALIBRATION_POINT_IDQ查询需要校验的点的坐标

                   TPDC_CALIBRATION_POINT_COUNT_IDQ查询用于校验的点的个数

          lpOutputQ根据iIndex值分别指向相关的信息

 

(6) void DdsiTouchPanelGetPoint(TOUCH_PANEL_SAMPLE_FLAGS pTipState, PLONG pUnCalX, PLONG pUnCalY)Q?/p>

获得Touch Panel上被按下的点的状态和坐标?/p>

               pTipStateQ当前触摸点的状态,比如无效点,有效点,被按下的点等?/p>

               pUnCalXQ触摸点的X坐标

               pUnCalYQ触摸点的Y坐标

 

(7) VOID DdsiTouchPanelPowerHandler(BOOL bOff)Q?/p>

讄Touch Panel的电源状态?/p>

               bOffQTRUE表示关闭甉|QFALSE表示打开甉|

 

(8) BOOL DdsiTouchPanelSetMode(ULONG iIndex, LPVOID lpInput)Q?/p>

讄Touch Panel工作模式?/p>

               iIndexQ模式烦?/p>

                        TPSM_SAMPLERATE_HIGH_IDQ高采样?/p>

                        TPSM_SAMPLERATE_LOW_IDQ低采样?/p>

               lpInputQ指向包含相关信息的内存

 

4 注册表设|?/p>

对于Touch Panel驱动来说Q有些注册表Ҏ需要配|的。具体如下:

“InputConfig”QWinCEpȝ输入配置?/p>

Bit0表示键盘输入

Bit1表示Touch Panel输入

                                    Bit2表示g按键输入

“DeviceName”QTouch Panel驱动的名字?/p>

“MaxCalError”QTouch Panel的精度配置?/p>

“CalibrationData”QTouch Panel的校验倹{第一ơ启动WinCE后,需要通过WinCE的触摸屏校验E序对Touch Panelq行校验。校验完成后Q校验g被写入注册表里面?/p>

 

下面是关于Touch Panel的注册表配置的例子:

[HKEY_LOCAL_MACHINE\ControlPanel]

                "InputConfig"=dword:3    ;3 => keybd and touch screen

[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\TOUCH]

                "DriverName"="touch.dll"

                "MaxCalError"=dword:8

                "CalibrationData"="446,671 36,191 38,1179 856,1161 862,169 "

 

个h觉得Q要x好的理解Touch Panel驱动Q还是需要去读读代码Q基于WinCE6.0下,可以参?\WINCE600\PLATFORM\H4SAMPLE\SRC\DRIVERS\TOUCH"下面的驱动,Zq个驱动开发自q驱动会比较方ѝ?/p>

 

 

 

 

 

 

 

Windows CE下触摸屏驱动实现的分?br>Analysis of Touch Panel Driver Realization Based on Windows CE OS

刘林?    ??

Liu,LinHui1    Zhang,Fen2

Q? 长沙理工大学能源与动力工E学院,湖南 长沙Q?10077Q? 华中U技大学机械U学与工E学院,湖北 武汉Q?30074Q?/p>

摘要Q本文介l了Windows CE操作pȝ的触摸屏驱动E序模型Q详l阐q嵌入式pȝ中电d触摸屏的Windows CE驱动E序的设计和实现Ҏ?/p>

关键词:触摸屏,Windows CE

中图分类PTP316

文献标识码:A

AbstractQThis article introduced touch panel driver model of Windows CE operating system, and elaborated the driver design and the realization method of resistance-type touch panel based on an embedded system which take Windows CE as operating system.

KeywordQTouch PanelQWindows CE

1. 前言
触摸屏是嵌入式设备中常用的计机输入讑֤Q它可操作单直观,Zh都会使用Q这一Ҏ论是键盘q是鼠标都无法与其相比。在手机、PDA{手持品及公共服务讑֤中大量采用触摸屏。触摸屏分ؓ电阻式、电容式、表面声波式{多U,电阻式触摸屏是目前应用比较广泛的一U,有四Uѝ五Uѝ七U等几种。本文将分析Windows CE操作pȝ下的触摸屏驱动程序模型及实现Ҏ?/p>

2. Windows CE触摸屏驱动程序模?br>在Windows CE操作pȝ中触摸屏驱动是一U分层驱动。其驱动模型如图1所C。上层是模型讑֤驱动E序QModel Device Driver, MDDQ,下层是依赖^台的驱动E序QPlatform Dependent Driver, PDDQ。MDD通常无需修改直接使用QMDD链接PDD层ƈ定义它希望调用的函数接口Q设备驱动程序提供器接口QDevice Driver Service Provider Interface, DDSIQ。同时MDD把不同的函数集提供给操作pȝQ这些函数叫做设备驱动程序接口(Device Driver Interface, DDIQ,q部分ؓ也就是我们通常驱动需要实现的部分?/p>

3 Windows CE的触摸屏驱动E序接口

Windows CE的触摸屏驱动链接了tch_cal.lib和tchmdd.lib两个静态链接库。触摸屏驱动由GWES加蝲QGWES通过DDI调用驱动E序获取讑֤状态,讄驱动功能{,而驱动本w通过DDSI直接获得g信息来确定当前触摸屏的状态?/p>

Windows CE触摸屏驱动要求的DDI接口包括QTouchPanelGetDeviceCaps、TouchPanelEnable、TouchPanelDisable、TouchPanelSetMode、TouchPanelReadCalibrationPoint、TouchPanelReadCalibrationAbort、TouchPanelSetCalibration、TouchPanelCalibrateAPoint、TouchPanelPowerHandler?/p>

Windows CE触摸屏驱动要求的DDSI接口包括QDdsiTouchPanelAttach、DdsiTouchPanelDetach、DdsiTouchPanelDisable、DdsiTouchPanelEnable、DdsiTouchPanelGetDeviceCaps、DdsiTouchPanelGetPoint、DdsiTouchPanelPowerHandler?/p>

4 Windows CE的触摸屏数据采集
Windows CE触摸屏驱动程序采用中断方式对触摸W的按下状态进行检,如果到触摸W按下将产生中断q触发一个事仉知一个工作线E开始采集数据。同Ӟ驱动打开一个硬件定时器Q只要检到触摸W仍然在按下状态将定时触发同一个事仉知工作U程采集数据Q直到触摸笔抬v后关闭该定时器,q新检按下状态。驱动中采用了触摸屏中断以及定时器中断两个中断源Q不仅可以监控触摸笔按下和抬L态,而且可以触摸笔按下时的拖动轨迹?/p>

触摸屏驱动在初始化过E调用TouchPanelEnable函数使能触摸屏。该函数调用的DDSI函数为:DdsiTouchPanelEnable和DdsiTouchPanelDisable。该函数实现如下 内容Q?/p>

1) 创徏事ghTouchPanelEvent和hCalibrationSampleAvailable。hTouchPanelEvent事g在正常状态下当有触摸W按下或者按下后需要定旉集数据时被触发。而hCalibrationSampleAvailable事g在校准状态下当有校准数据输入时被触发Q?/p>

2) 查ƈ初始化所需的中断gIntrTouchQ触摸屏中断Q和gIntrTouchChangedQ定时器中断Q,q将中断gIntrTouch、gIntrTouchChanged兌C件hTouchPanelEvent。当gIntrTouchQgIntrTouchChanged中断产生时将触发hTouchPanelEvent事gQ?/p>

3) 创徏一个ISRU程TouchPanelpISR。TouchPanelpISR用于{待和处理触摸屏事ghTouchPanelEventQ它是整个驱动程序中唯一的事件源?/p>

TouchPanelpISR函数是实现触摸屏数据采集关键函数Q它实现的内容ؓQ?/p>

1) {待循环Q用于接收hTouchPanelEvent事gQƈ构成函数的主体;

2) 通过调用DdsiTouchPanelGetPoint函数获取当前触摸屏位|和状态信息;

3) 在获取有效数据且在校准状态下Q收集ƈ提交按下的位|信息;

4) 在正常状态下Q校准数据,q检查校准后数据的有效性;

5) 最后调用由GWES传入的回调函敎ͼ提交位置信息和状态信息?/p>

因此Q在触摸屏驱动程序中DdsiTouchPanelEnable、DdsiTouchPanelDisable和DdsiTouchPanelGetPoint三个DDSI接口函数是驱动实现的关键所在?/p>

在DdsiTouchPanelEnable和DdsiTouchPanelDisable函数中分别打开和关闭触摸屏gQ这两个函数其实可以不真正操作硬Ӟ而只是实现Y件上的控Ӟ但是Z降低功耗最好在DdsiTouchPanelDisable中将触摸屏控制器甉|关闭q在DdsiTouchPanelEnable函数中打开?/p>

在DdsiTouchPanelGetPoint函数中实现对触摸屏数据的采样。从上面的分析得知MDD通过hTouchPanelEvent和hCalibrationSampleAvailable事g控制采样Q这两个事g被触发都调用该函数。而这两个事g触发条g有两个:

1) 触摸W按下时产生触摸屏中断gIntrTouch时触发;

2) 触摸W按下后Q定时器被打开Q定时器定时生中断gIntrTouchChangedQƈ触发事gQ直到触摸笔抬v为止?/p>

因此该函C仅需要对触摸屏数据采P而且需要对触发条gq行状态控Ӟ其流E如?所C。图中定义了三个变量Q它们分别ؓQ?/p>

1) TouchIrq为静态变量或全局变量Q且初始gؓTRUEQ该变量必须在触摸屏按下q生触摸屏中断时设|ؓFALSEQ?/p>

2) InterruptType为静态变量或全局变量Q且初始gؓSYSINTR_NOPQ当在处理触摸屏中断时设|ؓSYSINTR_TOUCHQ在处理定时器中断时讄为SYSINTR_TOUCH_CHANGEDQ其余设|ؓSYSINTR_NOPQ且在处理完毕后必须其作ؓ参数传入InterruptDone函数以清除中断;

3) g_NextExpectedInterrupt为静态变量或全局变量Q该变量表示下一个希望生的中断Q初始状态ؓPEN_DOWNQ也是触摸W在抬v状态,因此希望下一个生的中断为PEN_DOWN。当触摸屏中断生以及定时器中断产生时该变量为PEN_UP_OR_TIMERQ也是下一个可能生的状态ؓ触摸W抬L态或者触摸笔按下但定时器中断产生?/p>

DdsiTouchPanelGetPoint函数一开始从触摸W抬L态开始执行,此时TouchIrq{于TRUE。如果此时触摸笔按下Q将讄TouchIrq为FALSEQ表C本ơ采h׃触摸屏中断生ƈ讄下一ơ调用由定时器生。然后设|InterruptType状态ؓSYSINTR_TOUCHQ接着开始采集数据ƈ讄g_NextExpectedInterrupt变量为PEN_UP_OR_TIMERQ表CZ一ơ生的中断为定时器中断。接着判断在触摸笔按下状态(g_NextExpectedInterrupt{于PEN_UP_OR_TIMERQ下触摸W是否抬P如果抬v则设|g_NextExpectedInterrupt为PEN_DOWN恢复到抬L态。最后通过InterruptType作ؓ参数传入InterruptDone函数以清除中断。当触摸W按下,q生定时器中断ӞTouchIrq{于FALSEQ此时InterruptType被设|ؓSYSINTR_TOUCH_CHANGEDQ其余的动作基本和上面的程一致?/p>


5 Windows CE下的触摸屏校?br>电阻触摸屏需要校准。应用程序需要一些参考|以便接收到的触摸屏坐标数据转换成高层Y件所需的屏q坐标。理x况下校准E序只要在品初ơ加甉|试过E中q行一ơ就可以了,参考D存储在非易失性存储器中。在理想情况下只需两组原始数据Q即在屏q对角读取的最和最大倹{而在实际应用中,因ؓ许多电阻触摸屏存在显著的非线性,因此如果在最和最大g间简单的插入位置数gD驱动E序非常的不_?/p>

在Windows CE中通过在函数DdsiTouchPanelGetDeviceCaps 中设|校准点的个敎ͼ在TouchDriverCalibrationPointGet中获取每个校准点的屏q坐标。常用的校准Ҏ量ؓ5。校准UI在校准点坐标处相应昄一个十字叉Q用户需要精地在该十字叉位|按下触摸屏Q驱动通过TouchPanelReadCalibrationPoint函数d相应的触摸屏坐标|然后开始下一个校准点。@环设定的ơ数后,采集到的触摸屏坐标值和校准点屏q坐标送到TouchPanelSetCalibration函数中进行处理。该函数生校准基准参数?/p>

TouchPanelSetCalibration函数执行的动作是一套数学算法,具体内容?

在触摸屏数据与其位置偏移关系且屏q像素与其位|偏Udpd为线性关pd设情况下Q触摸屏q回的位|信息与像素位置信息之间?D坐标变换关系。则对于触摸屏按下点的触摸屏坐标(Tx,Ty)与其在显C备位|关pM匚w的点的屏q坐?Sx,Sy)之间的{换关p,可以通过下述坐标变换表示Q?/p>

Sx =  A1*Tx + B1*Ty + C1

Sy =  A2*Tx + B2*Ty + C2

TouchPanelSetCalibration的具体工作就是通过校准的动作获取的屏幕坐标和触摸屏坐标TouchCoordinate来确定A1QB1QC1和A2, B2, C2?/p>

6. l束?br>本文作者的创新点:从分析嵌入式Windows CE操作pȝ中触摸屏驱动E序的模型及实现Ҏ的角度深入剖析了Windows CE中触摸屏数据采集和校准的执行程Q对于类似系l的驱动开发具有一定的借鉴性?/p>

参考文献:

[1] Paul Kovitz. 电阻式触摸屏l构和实现原理,夏普公司Q?003


本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/zhongnanjun_3/archive/2008/11/11/3274020.aspx



心羽 2011-03-01 11:51 发表评论
]]>
wince下的触摸屏驱动分?Z2410) http://m.shnenglu.com/tdweng/articles/140893.html心羽心羽Tue, 01 Mar 2011 03:50:00 GMThttp://m.shnenglu.com/tdweng/articles/140893.htmlhttp://m.shnenglu.com/tdweng/comments/140893.htmlhttp://m.shnenglu.com/tdweng/articles/140893.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140893.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140893.html

转蝲h明出?/font>

作?马


 

前段旉UL 6.0 BSPQ目前已UL到触摸屏部分? ULq程中学C不少东西. 由其是关于触摸屏q部? 掌握了很多以前不会的东西. 觉得有必要把q些知识Ҏ理一? 


一 g部分


g上的原理不是本文的重点,只讲一下大概的原理(主要是我也只知道大概的原? 毕竟׃是搞g? d!)


我移植用的这个屏?20*240 的TFT? 四线电阻式触? q种触屏的原理是׃个电dl成, 一个实现X位置的测量,一个用于Y位置上的量. 单来_是当用触笔按下屏幕Ӟ两个电阻层接? 电阻发生变化Q然后在X Y方向上生信? q个信号是电压信P 再经qCPU内部分AD转换为坐标? q个原理有点像高中物理课用的滑动电阻Q有一个最大上限,滑动C同的地方Q阻g? 2410本n集成了touch的控制器Q通过单的配置和读取相关的寄存器,可以实现触摸屏的操? 


?驱动部分

Wince下的touch驱动跟很多其它的驱动一? 是分层的, 有MDD 和PDD两层. MDD层被pȝ隐藏h, 一般不用我们来修改. 而我们真正关心的是PDD ? 也就是要由开发者来修改的这一? 


分析touch驱动Ӟ以我最q刚刚移植到一个基?410的板子上?.0的BSP包的触屏驱动Z.?span style="COLOR: red">C:\WINCE600\PLATFORM\DEVICEEMULATOR\SRC\DRIVERS\TOUCH? 扑ֈs3c2410x_touch.cpp文g. q里面正是PDD层的实现代码. Ҏ发现q里面的函数分ؓ两类Q一cL以TSP开头的函数Q一cL以DDSI开头的函数. TSP开头的函数为内部私有的函数Q是被DDSI调用? 而DDSI开头的函数则是对外的接? 也就是被MDD层的函数调用的接? 


DdsiTouchPanelEnable是首先被调用的一个外部接? 它的实现可参见源E序,  它主

要做了下面几个事?

1 通过调用TSP_VirtualAlloc函数为驱动所用的IO,中断{硬件中断分配内存空? 


2 通过调用KernelIoControl向系l申请两个中断,如果甌成功Q赋予相应的逻辑中断? KernelIoControl向底层是调用OEMIoControl函数, OEMIoControlҎKernelIoControl传进来的IOCTL代码Q做相应的操?比如q里, IOCTL是IOCTL_HAL_REQUEST_SYSINTRQ?它是向内核申请一个物理中断和逻辑中断的映? 


3 通过调用TSP_PowerOn来初始化中断控制器,ADC寄存器,定时器等, 在TSP_PowerOn的实CQ有几点要说明一?

ADCDLY q个值在不同的模式下意义不同, 因ؓ前面通过ADCTSC已经配置为wait for interrupt mode, 所以这个值的意义和你的触W按下时,  从生中断信号到开始自动{换X,Y时的旉间隔是相关的Q它的单位是ms


v_pPWMregs->TCNTB3  = g_timer3_sampleticks

TCNTB3是timer3的count buffer, 当定时器启动? 0Q这个g一个设|好的频率递减Q直到减?Q?q时会生一个定时器中断. q个有什么用? 要理解它Q得知道触摸屏在中断模式下是如何工作? 


当我们按下的触摸屏时Q会产生一个ADC的中? 同时我们的驱动还会启动一个定时器, q个定时器触发一个事件做数据采集, 在我们的手或触笔抬v来前Q这个定时器不断的触发采集事Ӟ直到它被关闭, 而它什么时候会被关闭呢Q就是在触笔的抬h? 下面截取的代码很好的说明的这个原?

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

            ……

}

上面的代码,if判断的正是是否抬? 

而g_timer3_sampleticks的值是q样计算出来? 

g_timer3_freq        = (g_s3c2410_pclk / TIMER3_DIVIDER);

g_timer3_sampleticks = (g_timer3_freq / TSP_SAMPLE_RATE_LOW); 

TIMER3_DIVIDER 的值是2, TSP_SAMPLE_RATE_LOW的值是100, ?/p>

v_pPWMregs->TCFG1  &= ~(0xf << 12);  

v_pPWMregs->TCFG1  |=  (0   << 12); 

可知定时?/2分频, 所以,很容易计出Q所讄的定时器是每10ms产生一ơ定时器中断

而触摸屏中断是在你按下和抬v时生的. 


DdsiTouchPanelGetPoint是采L主要实现函数Q当MDD到中断事g发生Ӟ该函C被调? 触摸屏的中断是SYSINTR_TOUCH, 而定时器的中断是SYSINTR_TOUCH_CHANGED 

该函数用if else分别处理两种中断, 如下:

if (v_pINTregs->SUBSRCPND & (1<<IRQ_SUB_TC))      /* 触摸屏中?/

{

    ……

}


else        /*定时器中?span style="WHITE-SPACE: pre"> */

{

}

DdsiTouchPanelGetPoint函数的实C码中Q调用了两个很重要的函数TSP_TransXY和TSP_GetXY

需要说明的是,q两个函数的实现跟LCD本n的分辨率是没有关pȝ.

TSP_GetXY用来获到AD采样|TSP_TransXY把它转化为屏上的坐标. 我移植touch驱动Ӟ遇到q点屏幕上面Q下面有反应Q或者点左上角,右上角有反应{类似的问题, 都是因ؓq两个函数没实现?


先来看TSP_GetXY函数.它的实现如下:

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[n])*/

(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*/


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

x = (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[n])*/

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

}


关于q个函数有几点要说明. 

Ҏ2410的手? ADCDAT0 保存是X方向上采Ll果,  ADCDAT1 保存是Y方向上采Ll果,  所? 我们看到下面的两行代?/p>

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

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

与上0x3ff, 是因? ADCDAT寄存器只用了前面 10位来保存AD采样的结? 而这?410内部的AD模块只有10位精度是怸致的.所以,AD转换后的最大g会超q?024-1. 

当然上在那种计算Ҏq不是绝对的 Q?Ҏg构造的不同, 比如有可能你x方向的坐标值和采样值成反比Q就要按下面的方式计?

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


再看TSP_TransXY函数. 我移植的版本的实现如?

PRIVATE void

TSP_TransXY(INT *px, INT *py)

{

*px = (*px >= TSP_MAXX) ? (TSP_MAXX) : *px;

*py = (*py >= TSP_MAXY) ? (TSP_MAXY) : *py;


*px = (*px - TSP_MINX);

*py = (*py - TSP_MINY);


*px = (*px >= 0) ? *px : 0;

*py = (*py >= 0) ? *py : 0;


*px = *px * TSP_LCDY / (TSP_MAXX - TSP_MINX);

*py = *py * TSP_LCDX / (TSP_MAXY - TSP_MINY);


*px = (*px >= TSP_LCDY)? (TSP_LCDY - 1) : *px;

*py = (*py >= TSP_LCDX)? (TSP_LCDX - 1) : *py;


*px = TSP_LCDY - *px - 1;

*py = TSP_LCDX - *py - 1;


}

q个实现是我在模拟器的实C码基上修改的. q个函数计算X,Y的坐标用的是一个公式,至于q个公式是怎么来的Q我׃太清楚了. 只说明一?

#define TSP_MINX 88

#define TSP_MINY 84


#define TSP_MAXX 952

#define TSP_MAXY 996

上面四个值是定义X+, X-, Y+, Y-四个有效的采样? 理论上应该是0?023(10 bit ADC), 但实际肯定有偏差Q准来? 换了不同的硬件^収ͼq四个值应该是要重新测q的. 我就直接沿用原BSP中的g. 

    



心羽 2011-03-01 11:50 发表评论
]]>
WinCE 6.0中断驱动E序分析Q电源例子)http://m.shnenglu.com/tdweng/articles/140884.html心羽心羽Tue, 01 Mar 2011 02:55:00 GMThttp://m.shnenglu.com/tdweng/articles/140884.htmlhttp://m.shnenglu.com/tdweng/comments/140884.htmlhttp://m.shnenglu.com/tdweng/articles/140884.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140884.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140884.html阅读全文

心羽 2011-03-01 10:55 发表评论
]]>
常用?/title><link>http://m.shnenglu.com/tdweng/articles/140818.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 28 Feb 2011 08:26:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/140818.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/140818.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/140818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/140818.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/140818.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 14pt"><span style="COLOR: red"><strong>UNREFERENCED_PARAMETER的作?/strong></span><br>我们?UNREFERENCED_PARAMETER 开始吧。这个宏?winnt.h 中定义如下: <br>#define UNREFERENCED_PARAMETER(P) (P)<br>  换句话说 UNREFERENCED_PARAMETER 展开传递的参数或表辑ּ。其目的是避免编译器关于未引用参数的警告。许多程序员Q包括我在内Q喜Ƣ用最高别的警告 Level 4Q?W4Q进行编译。Level 4 属于“能被安全忽略的事?#8221;的范畴。虽然它们可能你难堪,但很破坏你的代码。例如,在你的程序中可能会有q样一些代码行Q?/p> <p style="FONT-SIZE: 14pt">int x=1;<br>  但你从没用到q?x。也许这一行是你以前?x 时留下来的,只删除了使用它的代码Q而忘了删除这个变量。Warning Level 4 能找到这些小ȝ。所以,Z么不让编译器帮助你完成可能是最高别的专业化呢Q用Level 4 ~译是展CZ工作态度的一U方式。如果你为公众用者编写库QLevel 4 则是C交CD上需要的。你不想你的开发h员用低U选项清洁地编译他们的代码?br>  问题是,Level 4 实在是太q于注意l节Q在 Level 4 上,~译器连未引用参数这h伤大雅的事情也要抱怨(当然Q除非你真的有意使用q个参数Q这时便相安无事Q。假设你有一个函数带来两个参敎ͼ但你只用其中一个:</p> <p style="FONT-SIZE: 14pt">int SomeFunction(int arg1, int arg2){     return arg1+5;}<br>使用 /W4Q编译器抱怨:</p> <p style="FONT-SIZE: 14pt">“warning C4100: ''arg2'' : unreferenced formal parameter.”<br>Z骗过~译器,你可以加?UNREFERENCED_PARAMETER(arg2)。现在编译器在编译你的引?arg2 的函数时便会住口。ƈ且由于语句:</p> <p style="FONT-SIZE: 14pt">arg2;<br>实际上不做Q何事情,~译器不会ؓ之生Q何代码,所以在I间和性能上不会有M损失?/p> <p style="FONT-SIZE: 14pt">  l心的h可能会问Q既然你不?arg2Q那当初Z要声明它呢?通常是因Z实现某个函数以满x些API固有的v名需要,例如QMFC?OnSize 处理例程的v名必要像下面这P</p> <p style="FONT-SIZE: 14pt">void OnSize(UINT nType, int cx, int cy);<br>  q里 cx/cy 是窗口新的宽/高,nType 是一个类?SIZE_MAXIMIZED ?SIZE_RESTORED q样的编码,表示H口是否最大化或是常规大小。一般你不会在意 nTypeQ只会关?cx ?xy。所以如果你想用 /W4Q则必须使用 UNREFERENCED_PARAMETER(nType)。OnSize 只是上千?MFC ?Windows 函数之一。编写一个基?Windows 的程序,几乎不可能不到未引用参数?br>  说了q么多关?UNREFERENCED_PARAMETER 内容。Judy 在她的问题中q提C另一?C++ E序员常用的q且其作用与 UNREFERENCED_PARAMETER 相同的诀H,那就是注释函数v名中的参数名Q?/p> <p style="FONT-SIZE: 14pt">void CMyWnd::OnSize(UINT /* nType */, int cx, int cy){}<br>  现在 nType 是未命名参数Q其效果像你敲?OnSize(UINT, int cx, int cy)一栗那么现在的关键问题是:你应该用哪U方法——未命名参数Q还?UNREFERENCED_PARAMETERQ?br>  大多数情况下Q两者没什么区别,使用哪一个纯_Ҏ风格问题。(你喜Ƣ你?java 咖啡是黑色还是奶油的颜色Q)但我认ؓ臛_有一U情况必M?UNREFERENCED_PARAMETER。假设你军_H口不允许最大化。那么你便禁?Maximize 按钮Q从pȝ菜单中删除,同时L每一个用戯够最大化H口的操作。因Z是偏执狂Q大多数好的E序员都是偏执狂Q,你添加一?ASSERT Q断aQ以保代码按照你的意图q行Q?/p> <p style="FONT-SIZE: 14pt">void CMyWnd::OnSize(UINT nType, int cx, int cy){     ASSERT(nType != SIZE_MAXIMIZE);     ... // use cx, cy}<br>  质检团队竭尽所能以各种方式q行你的E序QASSERT 从没有弹Q于是你认ؓ~译生成 Release 版本是安全的。但是此?_DEBUG 定义没有了,ASSERT(nType != SIZE_MAXIMIZE)展开?((void)0)Qƈ?nType 一下子成了一个未引用参数Q这栯入你q净的编译。你无法注释掉参数表中的 nTypeQ因Z要在 ASSERT 中用它。于是在q种情况下——你唯一使用参数的地Ҏ?ASSERT 中或其它 _DEBUG 条g代码中——只?UNREFERENCED_PARAMETER 会保持编译器?Debug ?Release 生成模式下都没有问题。知道了吗?<br>  l束讨论之前Q我惌有一个问题我没有提及Q就是你可以象下面这L pragma 指o抑制单一的编译器警告Q?/p> <p style="FONT-SIZE: 14pt">#pragma warning( disable : 4100 )<br>4100 是未引用参数的出错代码。pragma 抑制其余文g/模块的该警告。用下面Ҏ可以重新启用q个警告Q?/p> <p style="FONT-SIZE: 14pt">#pragma warning( default : 4100 )<br>  不管怎样Q较好的Ҏ是在用特定的警告之前保存所有的警告状态,然后Q等你做完之后再回到以前的配|。那P你便回到的以前的状态,q个状态不一定是~译器的默认状态?br>  所以你能象下面q样在代码的前后?pragma 指o抑制单个函数的未引用参数警告Q?/p> <p style="FONT-SIZE: 14pt">#pragma warning( push ) #pragma warning( disable : 4100 )void SomeFunction(...){}#pragma warning( pop )<br>  当然Q对于未引用参数而言Q这U方法未免冗长,但对于其它类型的警告来说可能׃是这样了。库生成者都是用 #pragma warning 来阻塞警告,q样他们的代码可以用 /W4 q行清洁~译。MFC 中充满了q样?pragmas 指o。还有好多的 #pragma warning 选项我没有在本文讨论。有兛_们的信息请参考相x档?/p> <p style="FONT-SIZE: 14pt"> </p> <p style="FONT-SIZE: 14pt">本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/apunix/archive/2008/01/14/2043945.aspx</a></p> <img src ="http://m.shnenglu.com/tdweng/aggbug/140818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2011-02-28 16:26 <a href="http://m.shnenglu.com/tdweng/articles/140818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WinCE中的Debug Zone调试http://m.shnenglu.com/tdweng/articles/140815.html心羽心羽Mon, 28 Feb 2011 08:18:00 GMThttp://m.shnenglu.com/tdweng/articles/140815.htmlhttp://m.shnenglu.com/tdweng/comments/140815.htmlhttp://m.shnenglu.com/tdweng/articles/140815.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140815.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140815.html?/span>WinCE的开发环境中支持Debug Zones功能Q通常也被UCؓ调试域,通过它可以控制打C息。当某个调试域被打开以后Q在q个域中的打C息就会被打印出来Q如果某个调试域被关闭了Q那么这个域中的打印信息׃被关闭。调试域是基于模块的Q也是说一个模块,可能是在一个驱动或者一个应用中都可以定义一个调试域Q用来调试该模块。一个调试域最多可以包?/span>16个域Q一般在每一个模块中都会有一个全局变量dpCurSettingsQ该变量用于描述调试域的相关信息Q它׃个模块名字,16个域的名字和一个掩码组成。下面具个例子:

DBGPARAM dpCurSettings =

{
    TEXT("PCIBUS"), {
    TEXT("Errors"),TEXT("Warnings"),TEXT("Functions"),TEXT("Initialization"),
    TEXT("Enumeration"),TEXT("Load Order"),TEXT("Resource"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined") },
    0x20

};

先来解释一?/span>DBGPARAMl构Q该l构?/span>Dbgapi.h中定义,所以在定义dpCurSettings的时候还需要包含这个头文gQ该l构定义如下Q?/span>

typedef struct _DBGPARAM {

    WCHAR  lpszName[32];                    //模块的名?/span>

    WCHAR  rglpszZones[16][32];            //调试域的名字

    ULONG  ulZoneMask;                        //调试域的掩码

}DBGPARAM, *LPDBGPARAM;

 

在上面的例子中可以看刎ͼW一个是模块的名字,?/span>PCIBUS。而后定义?/span>16个域的名字,其中只用C7个域Q剩下的都定义ؓUndefined了。最后一个数字ؓ域的掩码Q表C当前哪个域是被ȀzȝQ?/span>0x20表示只有W?/span>6个域是被Ȁzȝ。从上面的例子还可以看出Q前7个域是有意义的,而且按照序分别对应1?/span>7。下面针对这些域需要定义相?/span>Debug调试的宏定义Q?/span>

#define DBGZONE_ERROR                           1

#define DBGZONE_WARNING                     2

#define DBGZONE_FUNCTION                    3

#define DBGZONE_INIT                                4

#define DBGZONE_ENUM                            5

#define DBGZONE_LOADORDER                6

#define DBGZONE_RESOURCE                    7

 

上述宏定义对应在dpCurSettings中的7个域Q然后就可以在打C息的时候,通过q些宏定义来对应相应的调试域了。例如:

  1. while(1)
  2. {
  3.     if (dwFlag)
  4.     {
  5.          DEBUGMSG(DBGZONE_ERROR, (L"Error found: %d\r\n", NumDevKeys));
  6.          break;
  7.      }
  8.      else
  9.      {
  10.          DEBUGMSG(DBGZONE_WARNING, (L"Warning found\r\n"));
  11.      }
  12.      DEBUGMSG(DBGZONE_LOADORDER, (L"load in a while loop\r\n"));
  13.      Sleep(100);
  14. }
  15.  

从这D代码可以看出,如果dpCurSettings中的掩码定义?/span>0x20Q那么在DEBUGMSG的打CQ只有条件ؓDBGZONE_LOADORDER才会被打华ͼ循环中的前两个打C息是不会被打印的。如果想让上面的代码中的所?/span>DEBUGMSG都能打印必须讄掩码如下Q?/span>

dpCurSettings.ulZoneMask = DBGZONE_ERROR | DBGZONE_WARNING | DBGZONE_LOADORDER;

 

在一个模块中定义了调试域Q如果想在系l中M用还必须注册该调试域Q需要用到的函数?/span>DEBUGREGISTER(..)Q其中要把该调试模块的句柄作为参Cl它。例如:

DllMain(..)

{

    switch(op)

    {

        case DLL_PROCESS_ATTACH:

            DEBUGREGISTER(hPCIBUS);

            break;

        ….

    }

}

 

完成了上q工作以后,可以重新编译调试的模块Q然后运行系l来调试了。调试域的一个好处就是在Debug的过E中Q不需要终止系l可以动态的改变调试域,方便我们分析问题。首先,我们可以ZPlatform. Builder中的CE Debug Zones来调试,?/span>VS2005的菜单中选择TargetQ然后选择CE Debug ZonesQ如图:

 

然后会出C?/span>Debug Zones的窗口,在窗口弹Z后,它可能会׃Ҏ间来攉当前支持Debug Zone的模块,如下图:

 

该图只是一个例子,左边昄了可调试的模块,选择serial_SMDK2410.dllq个模块Q就?/span>S3C2410的串口驱动模块。在右侧可以看到各个调试域及名字Q用户可以根据需要来选择打开和关闭相应的调试域,最后点?/span>Apply?/span>OK可以了?/span>

 

当然Q还有其他的Ҏ来修改调试域Q一U方法是使用Target Control中的zo命o来修改,Target Control在以后介绍。还有一U方法就是通过SetDbgZone(..)函数来修攏V定义如下:

BOOL SetDbgZone(DWORDdwProcid, LPVOIDlpvMod, LPVOIDbaseptr, DWORDzone, LPDBGPARAMlpdbgTgt)

    dwProcidQ?/span>    q程的句?/span>

    lpvModQ?/span>        调试模块的句?/span>

    baseptrQ?/span>        讄?/span>NULL

    zoneQ?/span>            新的调试域掩?/span>

    lpdbgTgtQ?/span>      q回新的DBGPARAMl构

 

上面?/span>Debug Zone的定义,使用以及调试作了大致的介l,按照上面的步骤可以给一个模块添加调试域Q注册调试域q在pȝq行以后随时更改调试域,其根本目的无非是帮助我们来调试模块和分析问题。一般情况下Q调试域只在Debug模式下用,但是也可以在Release模式下用。但是有些地斚w要修改,首先前面已经介绍q?/span>Debug模式下的打印?/span>DEBUGMSGQ?/span>Release模式下的打印应该使用RETAILMSG函数。所以在Release模式下,打印函数应该改ؓRETAILMSG函数。还有在注册调试域的时候,不能再?/span>DEBUGREGISTER(..)函数Q而是应该改用RETAILREGISTERZONES(..)函数?/span>




心羽 2011-02-28 16:18 发表评论
]]>
þù| 97þþƷˬ| Ʒ˾Ʒþþ| ˾þô߽ӰԺ95| þþ99Ʒһ| þþƷAV㽶| þþþAVۿ | þþþþþ޾Ʒ| ƷۺϾþ| þݺҹҹ2O2O | þˬˬƬAV| þ¾ƷĻ| ھƷþ| þþ޾Ʒ| þùƷ99Ʒ| ޹Ʒľþþ| þۺϹ׾Ʒ| ƷþþĻ| þþƷAvӰƬ | 777ҹƷþav| 㽶þþþ| re99þ6Ʒ| ŷҹƷþþþþ˳| þþƷAAƬһ| պʮ˽һþ| ˾þۺߴý| ƷþþĻѿ| þҹӰ| þˬˬƬAV鶹| Ʒþþ| þþƷĻ̾ | ձvaĻþ| ʵҶ԰׾ʾþ| þ99ھƷ| ҹƷþþþþþþ| ŷսպ91ۺһþþ| ˾þô߽Ʒ| ɫۺϾþ88ɫۺ| ŷƷþþ | 99þþùƷţ| þùƷӰԺ|