﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-jie-uestc</title><link>http://www.cppblog.com/jie-uestc/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 23:09:01 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 23:09:01 GMT</pubDate><ttl>60</ttl><item><title>winCE的驱动</title><link>http://www.cppblog.com/jie-uestc/archive/2009/05/04/81896.html</link><dc:creator>茶叶蛋</dc:creator><author>茶叶蛋</author><pubDate>Mon, 04 May 2009 15:07:00 GMT</pubDate><guid>http://www.cppblog.com/jie-uestc/archive/2009/05/04/81896.html</guid><wfw:comment>http://www.cppblog.com/jie-uestc/comments/81896.html</wfw:comment><comments>http://www.cppblog.com/jie-uestc/archive/2009/05/04/81896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jie-uestc/comments/commentRss/81896.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jie-uestc/services/trackbacks/81896.html</trackback:ping><description><![CDATA[<p>一般开发驱动采用分层的结构，这样可以方便移植，而且开发起来肯定会容易一些。<br>单体驱动虽然可能会提供较高的性能，但是可能会造成系统的崩溃，还有较差的移植性。<br></p>
<img src ="http://www.cppblog.com/jie-uestc/aggbug/81896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jie-uestc/" target="_blank">茶叶蛋</a> 2009-05-04 23:07 <a href="http://www.cppblog.com/jie-uestc/archive/2009/05/04/81896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>郁闷，用evc写驱动是什么样的阿！</title><link>http://www.cppblog.com/jie-uestc/archive/2009/05/01/81655.html</link><dc:creator>茶叶蛋</dc:creator><author>茶叶蛋</author><pubDate>Fri, 01 May 2009 15:47:00 GMT</pubDate><guid>http://www.cppblog.com/jie-uestc/archive/2009/05/01/81655.html</guid><wfw:comment>http://www.cppblog.com/jie-uestc/comments/81655.html</wfw:comment><comments>http://www.cppblog.com/jie-uestc/archive/2009/05/01/81655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jie-uestc/comments/commentRss/81655.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jie-uestc/services/trackbacks/81655.html</trackback:ping><description><![CDATA[<p>需要写驱动，原来以为会很简单，可是没人教自己看资料真的又累又难，到底应该怎么开始学习呢！郁闷！狂郁闷！！！网上说用gpio最简单，可是我连这个最简单的都搞不懂！！郁闷阿！！！！！！！</p>
<img src ="http://www.cppblog.com/jie-uestc/aggbug/81655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jie-uestc/" target="_blank">茶叶蛋</a> 2009-05-01 23:47 <a href="http://www.cppblog.com/jie-uestc/archive/2009/05/01/81655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>winCE下I/O操作基础（转载，个人觉得很好）</title><link>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81380.html</link><dc:creator>茶叶蛋</dc:creator><author>茶叶蛋</author><pubDate>Tue, 28 Apr 2009 15:12:00 GMT</pubDate><guid>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81380.html</guid><wfw:comment>http://www.cppblog.com/jie-uestc/comments/81380.html</wfw:comment><comments>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jie-uestc/comments/commentRss/81380.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jie-uestc/services/trackbacks/81380.html</trackback:ping><description><![CDATA[<table cellSpacing=1 cellPadding=4 width="100%" bgColor=#f0f7fb border=0>
    <tbody>
        <tr>
            <td align=middle><font size=4><strong>WINCE下I/O操作基础</strong></font></td>
        </tr>
        <tr>
            <td height=10></td>
        </tr>
        <tr>
            <td class=red style="FONT-SIZE: 14px" align=middle>发布日期：2007-5-10&nbsp;12:16:06&nbsp;&nbsp;&nbsp;作者：&nbsp;&nbsp;&nbsp;出处：</td>
        </tr>
        <tr>
            <td height=10></td>
        </tr>
    </tbody>
</table>
<table class=tbl width="100%" border=0>
    <tbody>
        <tr>
            <td height=10></td>
        </tr>
        <tr>
            <td class=tb><font id=remark_view style="FONT-SIZE: 14px">对外设进行&nbsp;I/O&nbsp;操作实际上也就是读写外设的寄存器,而我们通常使用的X86或者ARM处理器在硬件上决定了wince系统启动后,无法直接访问物理地址,因此需要做一些工作来实现I/O操作.&nbsp; <br><br>首先要理解&nbsp;windows&nbsp;CE&nbsp;下的地址映射机制。&nbsp;wince有两种地址：物理地址和虚拟地址．不同架构的&nbsp;CPU&nbsp;硬件上的区别导致地址映射也不同。ＭＩＰＳ和ＳＨ&nbsp;x&nbsp;处理器，不采用ＭＭＵ，直接在ＣＰＵ和内核里定义&nbsp;1G&nbsp;的物理地址；而Ｘ８６和ＡＲＭ带有&nbsp;MMU&nbsp;单元，在&nbsp;OEMAddressTable&nbsp;中定义物理地址到虚拟地址间的映射关系或者是ＯＳ启动后调用&nbsp;CreateStaticMapping&nbsp;和&nbsp;NKCreateStaticMapping&nbsp;来实现从虚拟地址到物理地址的静态映射．经过静态映射的地址，可以由操作系统内核用于&nbsp;ISR&nbsp;访问设备。如果我们要在应用程序中访问外设，必须在物理地址和虚拟地址间建立动态映射关系，我们可以使用&nbsp;VirtualAlloc&nbsp;和&nbsp;VirtualCopy&nbsp;（或者直接调用&nbsp;MmmapIoSpace&nbsp;函数）来实现。&nbsp; <br><br>其次，如果是操作通过总线挂接的&nbsp;I/O&nbsp;或者存储器，必须先把总线地址转化成&nbsp;CPU&nbsp;上的系统地址，再做物理地址到虚拟地址的映射。这里需要查&nbsp;CPU&nbsp;的&nbsp;Datasheet&nbsp;，找出所要操作的I/O地址.先调用&nbsp;HALTranslateBusAddress(&nbsp;)把总线地址转化成CPU上的系统地址,&nbsp;再调用&nbsp;MmmapIoSpace&nbsp;函数实现虚实映射；也可以使用&nbsp;TransBusAddrToVirtual&nbsp;（）直接把总线上的地址转化成系统的虚拟地址。&nbsp; <br><br>第三，在一般的应用程序中访问&nbsp;I/O&nbsp;是访问它的缓存段虚拟地址，而驱动中必须访问无缓存段虚拟地址。简单来说无缓存段虚拟地址&nbsp;=&nbsp;缓存段虚拟地址&nbsp;+0x20000000&nbsp;。&nbsp; <br><br>&nbsp;&nbsp;&nbsp;&nbsp;总结起来，如果是&nbsp;wince&nbsp;内核(如HAL)访问外部&nbsp;I/O&nbsp;，只需要在&nbsp;OEMAddressTable&nbsp;中定义物理地址到虚拟地址间的映射关系就可以了；如果是应用程序或者驱动要访问&nbsp;I/O&nbsp;，要做的工作包括：&nbsp;1&nbsp;。在&nbsp;CPU&nbsp;物理地址和虚拟地址间做一个动态映射，&nbsp;2&nbsp;。对虚拟地址进行操作。 <br><br><br>在X86和ARM架构的CPU中,wince访问系统内存的方法随程序所属模式层次的不同而有所区别. <br>&nbsp;&nbsp;1.在系统内核模式下(kernel&nbsp;mode),在OAL层访问,只需要在OEMAddressTable&nbsp;中做静态的虚实地址映射就可以了.例如X86架构的映射表格式如下: <br>&nbsp;&nbsp;&nbsp;;&nbsp;OEMAddressTable&nbsp;defines&nbsp;the&nbsp;mapping&nbsp;between&nbsp;Physical&nbsp;and&nbsp;Virtual&nbsp;Address&nbsp;&nbsp;//&nbsp;定义4GB的虚拟地址和512MB存储的映射关系 <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;MUST&nbsp;be&nbsp;in&nbsp;a&nbsp;READONLY&nbsp;Section <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;First&nbsp;Entry&nbsp;MUST&nbsp;be&nbsp;RAM,&nbsp;mapping&nbsp;from&nbsp;0x80000000&nbsp;-&gt;&nbsp;0x00000000 <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;each&nbsp;entry&nbsp;is&nbsp;of&nbsp;the&nbsp;format&nbsp;(&nbsp;VA,&nbsp;PA,&nbsp;cbSize&nbsp;) <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;cbSize&nbsp;must&nbsp;be&nbsp;multiple&nbsp;of&nbsp;4M <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;last&nbsp;entry&nbsp;must&nbsp;be&nbsp;(0,&nbsp;0,&nbsp;0) <br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;o&nbsp;must&nbsp;have&nbsp;at&nbsp;least&nbsp;one&nbsp;non-zero&nbsp;entry <br>&nbsp;&nbsp;&nbsp;;&nbsp;RAM&nbsp;0x80000000&nbsp;-&gt;&nbsp;0x00000000,&nbsp;size&nbsp;64M&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//把物理地址为0x00000000映射到虚拟地址为&nbsp;0x80000000&nbsp;处 <br>&nbsp;&nbsp;&nbsp;dd&nbsp;&nbsp;80000000h,&nbsp;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;04000000h <br>&nbsp;&nbsp;&nbsp;;&nbsp;FLASH&nbsp;and&nbsp;other&nbsp;memory,&nbsp;if&nbsp;any <br>&nbsp;&nbsp;&nbsp;;&nbsp;dd&nbsp;&nbsp;FlashVA,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashPA,&nbsp;&nbsp;&nbsp;&nbsp;FlashSize <br>&nbsp;&nbsp;&nbsp;;&nbsp;Last&nbsp;entry,&nbsp;all&nbsp;zeros <br>&nbsp;&nbsp;&nbsp;dd&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;0 <br>2.在驱动或应用程序(user&nbsp;mode)中访问RAM,既可以通过OEMAddressTable+VirtualCopy方式,也可以直接用MmMapIoSpace函数建立物理地址到当前进程虚拟地址的映射关系. <br>经过OEMAddressTable,实现的只是CPU物理地址到OS内核层虚拟地址的一次映射,如果需要在普通的应用程序中访问内存,还要再用VirtuaAlloc+VirtualCopy做一个内核到当前进程的二次映射(有一种情况例外，就是你的OS被配置成Full&nbsp;Kernel&nbsp;Mode，这时任何应用程序都可以访问OS内核地址). <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;简单说明几个关键函数: <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualAlloc用于在当前进程的虚拟地址空间中保留或者提交空间，在保留时以64KB为单位，提交时以4KB为单位。其函数原型为&nbsp; <br><br>&nbsp;LPVOID&nbsp;VirtualAlloc(&nbsp; <br><br>&nbsp;&nbsp;LPVOID&nbsp;lpAddress,&nbsp;&nbsp;//&nbsp;分配虚拟地址的起始指针&nbsp; <br><br>&nbsp;&nbsp;DWORD&nbsp;dwSize,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;大小，以字节为单位&nbsp; <br><br>&nbsp;&nbsp;DWORD&nbsp;flAllocationType,&nbsp;//&nbsp;类型，设为MEM_RESERVE&nbsp; <br><br>&nbsp;&nbsp;DWORD&nbsp;flProtect&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;存取保护，设为PAGE_NOACCESS&nbsp; <br><br>);&nbsp; <br><br>&nbsp;&nbsp;VirtualCopy&nbsp;用来绑定物理地址到静态映射虚拟地址：&nbsp; <br><br>&nbsp;&nbsp;BOOL&nbsp;VirtualCopy(&nbsp; <br><br>&nbsp;&nbsp;LPVOID&nbsp;lpvDest,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;虚拟目的地址指针，接受VirtualAlloc的返回值&nbsp; <br><br>&nbsp;&nbsp;LPVOID&nbsp;lpvSrc,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;源物理地址指针&nbsp; <br><br>&nbsp;&nbsp;DWORD&nbsp;cbSize,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;大小必须与虚拟地址相同&nbsp; <br><br>&nbsp;&nbsp;DWORD&nbsp;fdwProtect&nbsp;&nbsp;//&nbsp;存取保护类型&nbsp; <br><br>);&nbsp; <br><br>这里需要注意的是&nbsp;fdwProtect&nbsp;参数。如果是驱动程序访问，需要设置为&nbsp;PAGE_NOCACHE&nbsp;，以访问无缓存段虚拟地址。如果映射的物理地址范围在&nbsp;0x1FFFFFFF&nbsp;之上，必须使用&nbsp;PAGE_PHYSICAL&nbsp;，此时必须把&nbsp;lpvSrc&nbsp;右移八位，实现地址对齐。（这是由内核中&nbsp;VirtualCopy&nbsp;的实现决定的，在那个函数中会判断如果是&nbsp;PAGE_PHYSICAL&nbsp;就将&nbsp;PHYSADDR&nbsp;左移&nbsp;8&nbsp;位移回来，源代码位于&nbsp;private/winceos/coreos/nk/kernel&nbsp;目录下的&nbsp;virtmem.c中的DoVirtualCopy&nbsp;）&nbsp; <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MmMapIoSpace&nbsp;用来把物理地址直接映射到与进程无关的虚拟地址上。函数原型为&nbsp; <br><br>&nbsp;PVOID&nbsp;MmMapIoSpace(&nbsp; <br><br>&nbsp;&nbsp;PHYSICAL_ADDRESS&nbsp;PhysicalAddress,&nbsp; <br><br>&nbsp;&nbsp;ULONG&nbsp;NumberOfBytes,&nbsp; <br><br>&nbsp;&nbsp;BOOLEAN&nbsp;CacheEnable&nbsp; <br><br>); <br><br><br>&nbsp;&nbsp;一个使用&nbsp;VirtualAlloc+Copy&nbsp;的例子：把物理地址为&nbsp;0x10000000&nbsp;的单元映射到虚拟地址空间中。&nbsp; <br><br>#include&nbsp;&lt;windows.h&gt;&nbsp; <br><br>&nbsp;&nbsp; <br><br>#define&nbsp;PHYSADDR&nbsp;&nbsp;((PVOID)0x10000000)&nbsp; <br><br>//&nbsp;PHYSADDR&nbsp;is&nbsp;the&nbsp;physical&nbsp;address&nbsp;of&nbsp;the&nbsp;peripheral&nbsp; <br><br>//&nbsp;registers&nbsp; <br><br>&nbsp;&nbsp; <br><br>#define&nbsp;SIZE&nbsp;&nbsp;(4800*4)&nbsp; <br><br>&nbsp;&nbsp; <br><br>LPVOID&nbsp;lpv;&nbsp; <br><br>BOOL&nbsp;bRet;&nbsp; <br><br>&nbsp;&nbsp; <br><br>lpv&nbsp;=&nbsp;VirtualAlloc(0,&nbsp;SIZE,&nbsp;MEM_RESERVE,&nbsp;PAGE_NOACCESS);&nbsp; <br><br>//&nbsp;For&nbsp;a&nbsp;user&nbsp;mode&nbsp;driver,&nbsp;always&nbsp;leave&nbsp;the&nbsp;first&nbsp; <br><br>//&nbsp;parameter&nbsp;0&nbsp;and&nbsp;use&nbsp;only&nbsp;the&nbsp;flags&nbsp;MEM_RESERVE&nbsp; <br><br>//&nbsp;and&nbsp;PAGE_NOACCESS&nbsp;Check&nbsp;the&nbsp;return&nbsp;value:&nbsp;lpv&nbsp;==&nbsp;0&nbsp; <br><br>//&nbsp;is&nbsp;an&nbsp;error&nbsp; <br><br>&nbsp;&nbsp; <br><br>printf(TEXT("VirtualAlloc&nbsp;reservation&nbsp;@%8.8lx\r\n"),&nbsp;lpv);&nbsp; <br><br>bRet&nbsp;=&nbsp;VirtualCopy(lpv,&nbsp;PHYSADDR&gt;&gt;8,&nbsp;SIZE,&nbsp;PAGE_READWRITE&nbsp;|&nbsp;PAGE_NOCACHE&nbsp;|&nbsp;PAGE_PHYSICAL);&nbsp; <br><br>//&nbsp;The&nbsp;lpv&nbsp;parameter&nbsp;is&nbsp;the&nbsp;virtual&nbsp;address&nbsp;returned&nbsp; <br><br>//&nbsp;by&nbsp;VirtualAlloc().&nbsp; <br><br>//&nbsp;Always&nbsp;use&nbsp;PAGE_NOCACHE&nbsp;*/&nbsp; <br><br>&nbsp;&nbsp; <br><br>//&nbsp;Check&nbsp;the&nbsp;return&nbsp;value:&nbsp;bRet&nbsp;==0&nbsp;is&nbsp;an&nbsp;error&nbsp;*/&nbsp; <br><br>printf(TEXT("VirtualCopy&nbsp;returned:&nbsp;%d\r\n"),&nbsp;bRet);&nbsp; <br><br>&nbsp;&nbsp; <br><br>//&nbsp;At&nbsp;this&nbsp;point&nbsp;lpv&nbsp;is&nbsp;a&nbsp;virtual&nbsp;address&nbsp;which&nbsp;maps&nbsp; <br><br>//&nbsp;the&nbsp;I/O&nbsp;registers&nbsp; <br><br>//&nbsp;at&nbsp;PHYSADDR&nbsp;for&nbsp;SIZE&nbsp;bytes&nbsp;*/&nbsp; <br></font></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/jie-uestc/aggbug/81380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jie-uestc/" target="_blank">茶叶蛋</a> 2009-04-28 23:12 <a href="http://www.cppblog.com/jie-uestc/archive/2009/04/28/81380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gpio</title><link>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81379.html</link><dc:creator>茶叶蛋</dc:creator><author>茶叶蛋</author><pubDate>Tue, 28 Apr 2009 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81379.html</guid><wfw:comment>http://www.cppblog.com/jie-uestc/comments/81379.html</wfw:comment><comments>http://www.cppblog.com/jie-uestc/archive/2009/04/28/81379.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jie-uestc/comments/commentRss/81379.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jie-uestc/services/trackbacks/81379.html</trackback:ping><description><![CDATA[<font face=宋体>GPIO 是ARM芯片最基本的输入输出通道,在ARM9平台上，Windows CE系统将GPIO的实地址(例如2410的GPIO的基地址为0x56000000)映射到虚拟地址空间（GPIO对应为0xB1600000），这样，通过对这段虚拟地址空间的操作，就能够完成对GPIO或者其他片内资源的控制、输入输出工作。<br><br>要操作一个平台的GPIO，在其对应BSP中按照基地址，找到虚拟地址，并且找到方便操作这个地址的数据结构就可以了，关键函数就是VirtualAlloc和VirtualCopy。并且CE的方便之处就是用户态的应用程序仍然可以使用这两个函数来访问所有这些虚拟空间，对于不太复杂的程序，甚至可以省略写驱动直接在应用程序中操作，其实在CE6之前，这些驱动也是工作在用户态的。[但是，这样做是有危险的，如果没有驱动而让用户程序直接和硬件打交道，可能会出现很严重的错误]<br><br></font>
<img src ="http://www.cppblog.com/jie-uestc/aggbug/81379.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jie-uestc/" target="_blank">茶叶蛋</a> 2009-04-28 23:09 <a href="http://www.cppblog.com/jie-uestc/archive/2009/04/28/81379.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>