<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-4426105232971900916</id><updated>2009-09-24T01:38:35.827-07:00</updated><title type='text'>ARM WinCE BSP Development</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-6498195226372247155</id><published>2008-08-18T18:45:00.000-07:00</published><updated>2008-08-18T18:48:11.970-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FAL'/><category scheme='http://www.blogger.com/atom/ns#' term='WinCE'/><category scheme='http://www.blogger.com/atom/ns#' term='NandFlash'/><category scheme='http://www.blogger.com/atom/ns#' term='FMD'/><title type='text'>WinCE中nandflash驱动开发介绍</title><content type='html'>&lt;p&gt;作者：ARM-WINCE&lt;br /&gt;&lt;br /&gt;先来谈一下flash，flash是一种非易失存储器，一般flash存储设备分为Nandflash和Norflash。这两种flash各有优缺点。在读写速度上，norflash的读速度快一些，nandflash的写速度会快一些。Nandflash的容量一般都比Norflash大很多，而且相比价格比较便宜。但是Norflash支持XIP，而nandflash不支持，而且Nandflash可能有坏块。相关的比较，网上很多文章都有介绍，这里就说这么多了。&lt;br /&gt;&lt;br /&gt;这里介绍nandflash驱动，在WinCE中，有专门针对flash存储设备驱动的支持，一般传统采用FAL+FMD的架构。在WinCE最新的版本中，也就是Windows CE6.0 R2中，还支持MDD+PDD的架构。在FAL+FMD架构中，FAL层由微软来实现，我们需要实现FMD层的相关接口函数。在MDD+PDD的架构中，MDD替换了原来架构中的FAL，而PDD相当于原来的FMD，只要实现PDD层就可以了。如果你的系统已经升级到WinCE6.0 R2，那么你应该可以在\WINCE600\Public\COMMON\OAK\DRIVERS目录下面找到这两种架构驱动的源代码。 由于MDD+PDD的架构在WinCE6.0 R2中才有支持，本人也没有实现过。所以这里只介绍基于FAL+FMD架构下，nandflash驱动的开发，这也是目前大家都采用的开发flash驱动的架构。&lt;br /&gt;&lt;br /&gt;如上面所说，我们需要实现FMD层的相关接口，下面来介绍一下各个接口函数：&lt;br /&gt;1. PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)： 这个是Flash设备的初始化函数。在WinCE启动的时候，要加载Flash驱动时，首先调用这个函数对flash设备进行初始化。如果你的系统中有nandflash的controller，那么你需要在这里对你的nandflash controller进行初始化。如果没有的话，你需要针对你的硬件设计进行相关的片选，时序等进行配置。返回一个handle表示成功，这个handle将被FMD_Deinit(..)函数用到，如果返回NULL表示失败。 &lt;/p&gt;&lt;p&gt;&lt;br /&gt;2. BOOL FMD_Deinit(PVOID hFMD)： 这个函数在nandflash驱动卸载的时候被调用，参数就是FMD_Init函数返回的Handle.一般在这个函数里面，你可以释放一些用到的资源，然后关闭nandflash controller。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;3. BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)： 这个函数用于读nandflash的一个扇区。对于nandflash来说，分大page和小page，大page是2048个bytes一页，小page是512个bytes一页。所以大page每个扇区有2048 bytes，小page每个扇区有512 bytes。&lt;br /&gt;    startSectorAddr： nandflash物理扇区的起始地址，对于nandflash来说，就是nandflash中从哪个page开始。&lt;br /&gt;    pSectorBuff：扇区数据buffer，从nandflash中读出的每一个扇区的数据都存放在这个buffer中。&lt;br /&gt;    pSectorInfoBuff：扇区信息buffer，一般每个扇区的信息会被保存在nandflash的带外数据中，针对小page，带外数据有16 bytes，大page有64 bytes。从nandflash的带外数据将该扇区的相关信息读出来，存放在这个buffer中。&lt;br /&gt;    dwNumSectors：读取多少个扇区，对于nandflash来说相当于读取多少个page。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;4. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)： 该函数用于写nandflash的一个扇区。参数和上面的FMD_ReadSector的参数意思一样，就不多说了。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;5. BOOL FMD_EraseBlock(BLOCK_ID blockID)： 该函数用于擦出nandflash的一个block，参数为要擦除nandflash的block地址，也就是第几个block。 &lt;/p&gt;&lt;p&gt;&lt;br /&gt;6. DWORD FMD_GetBlockStatus(BLOCK_ID blockID)： 该函数获得nandflash中某一个block的状态。参数为nandflash的block地址。由于nandflash中可能有坏块，所以针对nandflash，这个函数首先会检查当前块是否是坏块，这个一般通过读取当前block的第0个page和第1个page的带外数据。对于小page nandflash一般是读取第5个byte，对于大page nandflash一般读取第0个byte，如果不为0xff表示该块是坏块。当然，至于具体该读哪个byte，最好还是看一下所用nandflash的datasheet，确认一下，不同的厂家可能有所不同。如果发现该块是坏块，应该返回BLOCK_STATUS_BAD。如果不是坏块，需要读取这个块的起始扇区的扇区信息。如果读该扇区信息出错，应该返回BLOCK_STATUS_UNKNOWN，否则，判断独到的信息，返回相应结果。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;7. BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)： 该函数设置nandflash某个block的状态，第一个参数是nandflash的block地址，第二个是要设置的状态。在这个函数中，首先检查dwStatus是不是BLOCK_STATUS_BAD，如果是就对nandflash作坏块标记，然后返回FALSE。如果不是，就将dwStatus写到该block的第0个page的扇区info中。这个函数和上面的函数正好是相反的。 &lt;/p&gt;&lt;p&gt;&lt;br /&gt;8. BOOL FMD_GetInfo(PFlashInfo pFlashInfo)： 该函数用于返回flash的信息。其中pFlashInfo是一个包含flash信息的结构。&lt;br /&gt;    pFlashInfo-&gt;flashType：flash的类型，对于nandflash来说，应该是NAND。&lt;br /&gt;    pFlashInfo-&gt;wDataBytesPerSector：一个扇区多少个bytes，对于大page是2048，对于小page是512。&lt;br /&gt;    pFlashInfo-&gt;dwNumBlocks：flash中总共有多少个block，查一下所用的nandflash的datasheet就知道了。&lt;br /&gt;     pFlashInfo-&gt;wSectorsPerBlock：每个block中包含多少个扇区。&lt;br /&gt;    pFlashInfo-&gt;dwBytesPerBlock：每个block中包含多少个bytes。 &lt;/p&gt;&lt;p&gt;&lt;br /&gt;9. VOID FMD_PowerDown()和VOID FMD_PowerUp()： 这两个函数用于电源管理。FMD_PowerDown()用于关闭flash设备电源，FMD_PowerUp()用于恢复flash设备电源。根据你所用处理器和相关硬件环境，去实现这两个函数。不实现也不会影响nandflash的使用。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;10. BOOL FMD_OEMIoControl(..)： 就像很多的IOControl函数一样，根据不同的case，实现相应的功能。针对nandflash来说，这里面的case不一定都需要实现。事实上，如果什么都没有实现，也不影响nandflash的使用。在WinCE的文档中，定义了一些需要实现的case，你可以实现，也可以不去实现。&lt;br /&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;对于nandflash来说，实现上述函数就可以了。在nandflash出厂的时候，厂家已经对nandflash中的坏块进行了标记。所以第一次对nandflash操作的时候，不要随便擦除nandflash，因为这样可能会把坏块标记擦掉，这样你就判断不出哪个块是坏块了。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;关于ECC校验，目前很多处理带有nandflash controller，而且nandflash controller带有硬件ECC功能。如果没有硬件ECC，也可以使用软件ECC，软ECC的代码可以在\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\BLOCK\MSFLASHFMD\ECC下找到。一般来说，ECC校验会对512个BYTE产生3个字节的校验码，也就是说对小PAGE来说，每个PAGE有3个字节的ecc校验码；对于大PAGE来说，有12个字节。这些校验码应该在写扇区数据的时候，被写在扇区的带外数据里面。当读扇区数据时，会先把数据读出来，然后根据这些数据计算ecc，再和读出来的ecc进行比较，如果一致，则表示正确。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-6498195226372247155?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/6498195226372247155/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=6498195226372247155' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/6498195226372247155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/6498195226372247155'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/08/wincenandflash.html' title='WinCE中nandflash驱动开发介绍'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-5758829351679656894</id><published>2008-02-13T23:25:00.000-08:00</published><updated>2008-02-13T23:40:09.986-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RTC'/><title type='text'>WinCE中RTC驱动开发介绍</title><content type='html'>快到春节了，稍微轻松点了。刚刚在WinCE6.0下开发了RTC的驱动，在这里介绍一下。&lt;br /&gt;&lt;br /&gt;RTC就是实时时钟(real time clock)。目前大部分32bit处理器都自带RTC模块，也有外接RTC模块的。一般外接的RTC都是通过I2C总线来访问。如果CPU本身自带RTC，那通过读取内部寄存器就能访问RTC模块。如果是外接的，就要麻烦一点，还要写个I2C的驱动来访问外部RTC模块。&lt;br /&gt;在WinCE6.0里面，RTC的驱动是在OAL里面实现的，文件名一般都叫rtc.c。在这个文件里面有3个重要的函数，只要实现了他们，RTC的驱动就完成了，函数如下：&lt;br /&gt;BOOL OEMGetRealTime(LPSYSTEMTIME lpst) ： 获得当前的时间&lt;br /&gt;BOOL OEMSetRealTime(LPSYSTEMTIME lpst)：   设置当前的时间&lt;br /&gt;BOOL OEMSetAlarmTime(LPSYSTEMTIME lpst)： 设置报警的时间&lt;br /&gt;&lt;br /&gt;上面三个函数的参数都是lpst，这里介绍一下：&lt;br /&gt;LPSYSTEMTIME实际上是一个指向SYSTEMTIME结构的指针，关于SYSTEMTIME，定义如下：&lt;br /&gt;typedef struct _SYSTEMTIME {  WORD wYear;  WORD wMonth;  WORD wDayOfWeek;  WORD wDay;  WORD wHour;  WORD wMinute;  WORD wSecond;  WORD wMilliseconds;} SYSTEMTIME;&lt;br /&gt;明白了吧，呵呵。&lt;br /&gt;&lt;br /&gt;OEMGetRealTime(..)用来获得当前的时间。WinCE启动以后，默认情况下，WinCE会每隔一段时间调用OEMGetRealTime(..)函数来获得系统的时间，这种方式被称为hardware mode。WinCE还有另一种获得系统时间的方法，被称为software mode，就是通过调用GetTickCount(..)函数跟踪系统的timetick的变化来累加时间。如果要用software mode，那么需要在注册表中做如下的设置：&lt;br /&gt;HKEY_LOCAL_MACHINE\Platform\"SoftRTC" = 1&lt;br /&gt;我来谈谈我的看法，一般都要使用hardware mode，这样获得的系统时间比较准。software mode获得系统时间不会很准的。&lt;br /&gt;&lt;br /&gt;OEMSetRealTime(..)用来设置当前的时间。当WinCE启动以后，我们会在界面的右下角看到时间显示，我们可以直接在WinCE的界面里面设置时间，这个时候，系统就会调用OEMSetRealTime(..)把你设置的时间写到RTC模块里面。这里要提一下，我们都知道在OEMIoControl函数里面有一个case叫IOCTL_HAL_INIT_RTC，这个case用来在初始化的时候设置实时时钟的初始值，一般在这个case里面会调用OEMSetRealTime(..)函数。参考代码如下：&lt;br /&gt;&lt;br /&gt;case IOCTL_HAL_INIT_RTC:   &lt;br /&gt;// The kernel has detected a cold boot.    &lt;br /&gt;// The real-time clock probably needs to be reset.   &lt;br /&gt;if( nInBufSize &gt;= sizeof(SYSTEMTIME) )     &lt;br /&gt;     return OEMSetRealTime( (LPSYSTEMTIME)lpInBuf );   &lt;br /&gt;else     &lt;br /&gt;     return FALSE;     break;&lt;br /&gt;&lt;br /&gt;OEMSetAlarmTime(..)用来设置报警时间。实现这个函数，要看你的RTC模块是否具有报警功能。具备报警功能的RTC会允许你设置报警时间，当你设置了报警时间以后，RTC会比较你的报警时间和当前时间，一旦这两个时间相等了，就会产生中断。大致原理就是这样了。所以这个函数里面实际上就是实现设置一个报警时间，还有就是打开相应的RTC中断。当然在中断程序ISR中，要返回SYSINTR_RTC_ALARM。在应用程序中，我们可以通过调用CeRunAppAtTime(..)来在一个指定的时间运行一个应用程序。这个函数好像会调用OEMSetAlarmTime(..)来设置报警时间。具体没有试过。 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;大致就是这些内容，一般在WinCE5.0和WinCE6.0中，RTC没有太大变化。唯一的不同就是在WinCE6.0中，这三个函数都需要添加临界区的保护，以前在WinCE5.0中没有看到过。 说了这么多，来举个例子，下面的代码基于实时时钟芯片ISL1208做的，仅供参考：&lt;br /&gt;#define  AL_ENABLE   0x80 &lt;br /&gt;CRITICAL_SECTION RTC_critsect;&lt;br /&gt;static unsigned char critical_flag = 1; &lt;br /&gt;&lt;br /&gt;void  I2C_Init(void);&lt;br /&gt;void  ISL1208_Init(void);&lt;br /&gt;DWORD I2C_Write(unsigned char slaveaddr, unsigned char regaddr, unsigned char* buf, DWORD num);&lt;br /&gt;DOWRD I2C_Read(unsigned char slaveaddr, unsigned char regaddr, unsigned char* buf, DWORD num); &lt;br /&gt;BOOL OEMGetRealTime(LPSYSTEMTIME lpst)&lt;br /&gt;{&lt;br /&gt;     unsigned char buf[12];&lt;br /&gt;     DWORD flg;&lt;br /&gt;&lt;br /&gt;    //RETAILMSG(1, (_T(":::::OEMGetRealTime:::::\r\n")));&lt;br /&gt;     if (critical_flag)         // 第一次上电&lt;br /&gt;     {&lt;br /&gt;          InitializeCriticalSection(&amp;amp;RTC_critsect);            //初始化临界区&lt;br /&gt;          I2C_Init();                                          //初始化&lt;br /&gt;          I2C  ISL1208_Init();                                 //初始化ISL1208实时时钟芯片。&lt;br /&gt;          critical_flag = 0;&lt;br /&gt;     }&lt;br /&gt;    EnterCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;    memset(buf, 0, sizeof(buf));&lt;br /&gt;    flg = I2C_Read(ISL1208, 0x0, buf, 6);       //读取ISL1208的时间&lt;br /&gt;    if (!flg)                                                //I2C失败，返回错误&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: OEMGetRealTime Error...\r\n")));&lt;br /&gt;          return FALSE;&lt;br /&gt;     }&lt;br /&gt;    LeaveCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;    buf[2] &amp;amp;= 0x7f;                                          //清除MIL位&lt;br /&gt;    lpst-&gt;wSecond = (WORD)((buf[0] &amp;amp; 0x0f) + (buf[0] &gt;&gt; 4) * 10);     // 获得当前时间，并将时间从BCD码转换为十进制&lt;br /&gt;    lpst-&gt;wMinute = (WORD)((buf[1] &amp;amp; 0x0f) + (buf[1] &gt;&gt; 4) * 10);&lt;br /&gt;    lpst-&gt;wHour = (WORD)((buf[2] &amp;amp; 0x0f) + (buf[2] &gt;&gt; 4) * 10);&lt;br /&gt;    lpst-&gt;wDay = (WORD)((buf[3] &amp;amp; 0x0f) + (buf[3] &gt;&gt; 4) * 10);&lt;br /&gt;    lpst-&gt;wMonth = (WORD)((buf[4] &amp;amp; 0x0f) + (buf[4] &gt;&gt; 4) * 10);&lt;br /&gt;    lpst-&gt;wYear = (WORD)buf[5] + 2000; &lt;br /&gt;    return TRUE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;BOOL OEMSetRealTime(LPSYSTEMTIME lpst)&lt;br /&gt;{&lt;br /&gt;     unsigned char buf[12];&lt;br /&gt;     WORD year;&lt;br /&gt;     DWORD flg;&lt;br /&gt;&lt;br /&gt;    //RETAILMSG(1, (_T(":::::OEMSetRealTime:::::\r\n")));&lt;br /&gt;    EnterCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;    if (lpst-&gt;wYear &gt; 2000)&lt;br /&gt;    {&lt;br /&gt;          year = lpst-&gt;wYear - 2000;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;          year = 0;&lt;br /&gt;    }&lt;br /&gt;    buf[0] = (((lpst-&gt;wSecond) / 10) &lt;&lt;&gt;wSecond) % 10); //设置时间，十进制转换成BCD码&lt;br /&gt;    buf[1] = (((lpst-&gt;wMinute) / 10) &lt;&lt;&gt;wMinute) % 10);&lt;br /&gt;    buf[2] = (((lpst-&gt;wHour) / 10) &lt;&lt;&gt;wHour) % 10); &lt;br /&gt;    buf[3] = (((lpst-&gt;wDay) / 10) &lt;&lt;&gt;wDay) % 10); &lt;br /&gt;    buf[4] = (((lpst-&gt;wMonth) / 10) &lt;&lt;&gt;wMonth) % 10);&lt;br /&gt;    buf[5] = ((year / 10) &lt;&lt; 4)  (year % 10); &lt;br /&gt;    buf[6] = (unsigned char)lpst-&gt;wDayOfWeek; &lt;br /&gt;    buf[2] = 0x80;              // Set MIL bit equal 1&lt;br /&gt;    flg = I2C_Write(ISL1208, 0x0, buf, 7);&lt;br /&gt;    if (!flg)&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: OEMSetRealTime Error...\r\n")));&lt;br /&gt;          return FALSE;&lt;br /&gt;    }&lt;br /&gt;    LeaveCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;    return TRUE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;BOOL OEMSetAlarmTime(LPSYSTEMTIME lpst)&lt;br /&gt;{&lt;br /&gt;     unsigned char buf[12];&lt;br /&gt;     DWORD flg;&lt;br /&gt;&lt;br /&gt;    //RETAILMSG(1, (_T(":::::OEMSetAlarmTime:::::\r\n")));&lt;br /&gt;    EnterCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;    memset(buf, 0, sizeof(buf));&lt;br /&gt;    buf[1] = (((lpst-&gt;wSecond) / 10) &lt;&lt;&gt;wSecond) % 10)  AL_ENABLE; //设置报警寄存器&lt;br /&gt;    buf[2] = (((lpst-&gt;wMinute) / 10) &lt;&lt;&gt;wMinute) % 10)  AL_ENABLE;&lt;br /&gt;    buf[3] = (((lpst-&gt;wHour) / 10) &lt;&lt;&gt;wHour) % 10)  AL_ENABLE; &lt;br /&gt;    buf[4] = (((lpst-&gt;wDay) / 10) &lt;&lt;&gt;wDay) % 10)  AL_ENABLE; &lt;br /&gt;    buf[5] = (((lpst-&gt;wMonth) / 10) &lt;&lt;&gt;wMonth) % 10)  AL_ENABLE;&lt;br /&gt;    flg = I2C_Write(ISL1208, 0xC, buf, 6);&lt;br /&gt;    if (!flg)&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: OEMSetRealTime Error...\r\n")));&lt;br /&gt;          return FALSE;&lt;br /&gt;    }&lt;br /&gt;    flg = *VIC2_INTENABLE;                   //使能外部中断1，因为RTC的中断输出接在了处理器的外部中断1上面&lt;br /&gt;     flg = INT2_EXT1;&lt;br /&gt;     *VIC2_INTENABLE = flg;&lt;br /&gt;    LeaveCriticalSection(&amp;amp;RTC_critsect);&lt;br /&gt;&lt;br /&gt;    // return TRUE if alarm set, FALSE otherwise   &lt;br /&gt;   return TRUE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DWORD ISL1208_Init(void)&lt;br /&gt;{&lt;br /&gt;     DWORD flg;&lt;br /&gt;     unsigned char buf[12];&lt;br /&gt;&lt;br /&gt;    memset(buf, 0, sizeof(buf));&lt;br /&gt;    flg = I2C_Read(ISL1208, 0x0, buf, 6);&lt;br /&gt;    if (!flg)    &lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: ISL1208_Init Error...\r\n")));&lt;br /&gt;          return FALSE;&lt;br /&gt;    }&lt;br /&gt;    if ((buf[0] != 0)  (buf[1] != 0)  (buf[2] != 0)  (buf[3] != 0)  (buf[4] != 0)  (buf[5] !=0))&lt;br /&gt;    {//时间被设置过，证明ISL1208被初始化过，直接返回&lt;br /&gt;          return TRUE;&lt;br /&gt;    }&lt;br /&gt;    buf[0] = STATUS_WRTC STATUS_ARST;&lt;br /&gt;    flg = I2C_Write(ISL1208, 0x7, buf, 1, 0);    // 设置ISL1208状态控制寄存器&lt;br /&gt;    DelayInMsec(1);&lt;br /&gt;    buf[0] = INT_ALME  0x80;         // 使能ISL1208报警功能，中断输出，单次触发&lt;br /&gt;    flg = I2C_Write(ISL1208, 0x8, buf, 1, 0);&lt;br /&gt;    if (!flg)&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: OEMSetRealTime Error...\r\n")));&lt;br /&gt;          return FALSE;&lt;br /&gt;    }&lt;br /&gt;    buf[0] = DEFAULT_SECOND  AL_ENABLE;     // 设置报警寄存器，设置报警时间，这里设置了个默认值&lt;br /&gt;    buf[1] = DEFAULT_MINUTE  AL_ENABLE;     //&lt;br /&gt;    buf[2] = DEFAULT_HOUR  AL_ENABLE; &lt;br /&gt;    buf[3] = DEFAULT_DATE  AL_ENABLE;&lt;br /&gt;    buf[4] = (DEFAULT_MONTH + 1)  AL_ENABLE;&lt;br /&gt;    flg = I2C_Write(ISL1208, 0xC, buf, 5, 0);&lt;br /&gt;    if (!flg)&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: I2C Write Error...\r\n")));&lt;br /&gt;          return 0;&lt;br /&gt;     } &lt;br /&gt;    buf[0] = DEFAULT_SECOND;       //设置系统时间，这里设置了个默认时间&lt;br /&gt;    buf[1] = DEFAULT_MINUTE;   &lt;br /&gt;    buf[2] = DEFAULT_HOUR;     &lt;br /&gt;    buf[3] = DEFAULT_DATE;  &lt;br /&gt;    buf[4] = DEFAULT_MONTH; &lt;br /&gt;    buf[5] = DEFAULT_YEAR;&lt;br /&gt;    buf[6] = DEFAULT_WEEK; &lt;br /&gt;    flg = I2C_Write(ISL1208, 0x0, buf, 7, 0);&lt;br /&gt;    if (!flg)&lt;br /&gt;    {&lt;br /&gt;          RETAILMSG(1, (_T("::::::: I2C Write Error...\r\n")));&lt;br /&gt;          return 0;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-5758829351679656894?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/5758829351679656894/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=5758829351679656894' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/5758829351679656894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/5758829351679656894'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/02/wincertc.html' title='WinCE中RTC驱动开发介绍'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-4880915442037728201</id><published>2008-02-13T23:23:00.000-08:00</published><updated>2008-02-13T23:24:13.104-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='telnet'/><category scheme='http://www.blogger.com/atom/ns#' term='ftp'/><title type='text'>WinCE中telnet,FTP及网络共享的使用方法</title><content type='html'>WinCE为我们提供了强大的网络功能，只要在编译WinCE的时候，选择适当的组件，我们就可以在WinCE运行以后通过telnet或者FTP访问WinCE的文件系统，而且还可以相互共享文件夹，现在进入主题：&lt;br /&gt;1. 在WinCE6.0中，打开“Catalog Items View”，然后依次选择“Core OS”-&gt;"CEBASE"-&gt;"Communication Services and Networking"-&gt;"Servers"，然后我们会看到“FTP Server”和“Telnet Server”，选中这两项就可以了，接下来就是重新编译工程了。&lt;br /&gt;2. 这里补充一句，我们的BSP里面要支持网络驱动，你的网络可以是基于以太网的网卡，或者基于USB的设备(比如RNDIS)，或者其它能支持网络的设备。你可以在注册表里为这个设备设定一个固定的IP地址，也可以使用DHCP(如果你的网络里有DHCP服务器的话)。&lt;br /&gt;3. 脑子有点乱，这里还要补充一下，我们使用telnet和ftp每次登录都输入用户名和密码比较麻烦，把下面的注册表配置信息加入到platform.reg里面就可以匿名登录了：&lt;br /&gt;[HKEY_LOCAL_MACHINE\COMM\TELNETD] "UseAuthentication"=dword:0&lt;br /&gt;[HKEY_LOCAL_MACHINE\COMM\FTPD] "AllowAnonymous"=dword:1 "AllowAnonymousUpload"=dword:1 "AllowAnonymousVroots"=dword:1 "DefaultDir"="\\" "IsEnabled"=dword:1 "UseAuthentication"=dword:0&lt;br /&gt;4. WinCE启动以后，假如WinCE的IP地址是192.168.0.86，当然PC要和WinCE的板子在同一个网段，这个属于网络基础知识，呵呵。通过telnet登录就输入：telnet 192.168.0.86，就应该能够登录到板子上了。如果通过FTP登录，就在PC上面打开Explorer，然后在地址栏输入：&lt;a href="ftp://192.168.0.86/"&gt;ftp://192.168.0.86&lt;/a&gt;  就可以了。&lt;br /&gt;上面介绍的应该比较简单。总之，只要你的BSP里面有网卡驱动，在WinCE中选择telnet和FTP就可以了。&lt;br /&gt;下面介绍一下如何在WinCE这边访问PC的共享文件夹：&lt;br /&gt;实现这个功能，我们要在“Catalog Items View”中添加一个组件，依次“Core OS”-&gt;"CEBASE"-&gt;"Communication Services and Networking"-&gt;"Networking-General"-&gt;"Windows Networking API/Redirector"，然后重新编译就可以了。&lt;br /&gt;在WinCE启动以后，在PC端打开命令行窗口，然后通过telnet登录到WinCE系统上(比如：telnet 192.168.0.86)，然后输入dir命令，就能看到WinCE里面的文件目录了，你会看到一个文件夹叫“network”。这时，使用net use命令将PC端的共享文件夹映射到"network"文件夹下面。举例如下：&lt;br /&gt;net use a &lt;a title="file://\\dell-01\\share"&gt;\\dell-01\\share&lt;/a&gt; /user:guest&lt;br /&gt;net use是命令；a是映射到本地的“network”文件夹下面的文件夹的名字；dell-01是计算机名；share是计算机上面的共享文件夹的名字；；/user:guest表示登录用户&lt;br /&gt;这样，我们就能在“\network\a”下面看到PC端所共享的"Share"文件夹下面的所有文件了。&lt;br /&gt;&lt;br /&gt;总结一下，上面介绍了telnet和ftp的使用，这个对于那些没有键盘鼠标和显示的WinCE系统是非常有用的，通过在WinCE上面使用net use命令可以将PC的共享文件夹映射到本地并进行操作。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-4880915442037728201?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/4880915442037728201/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=4880915442037728201' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/4880915442037728201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/4880915442037728201'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/02/wincetelnetftp.html' title='WinCE中telnet,FTP及网络共享的使用方法'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-7239343001876455997</id><published>2008-01-15T01:13:00.000-08:00</published><updated>2008-01-15T01:14:38.669-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='console'/><title type='text'>WinCE中的console重定向</title><content type='html'>在WinCE中开发BSP的初期，可能我们还没有显示驱动，也没有键盘，鼠标，USB的驱动。这个时候，如果有一个基于Serial串口的console 会感到很幸福，呵呵。&lt;br /&gt;将console重定向到串口比较简单，首先串口驱动必须是好的。然后需要在platform.reg中添加下面的配置：&lt;br /&gt;[HKEY_LOCAL_MACHINE\Drivers\Console] "OutputTo"=dword:1"COMSpeed"=dword:9600 ; 38400&lt;br /&gt;"OutputTo"的意思是重定向到哪个串口，比如要重定向到COM1，就设置为1。如果定义为0xffffffff表示输出到Debug端口，据说在WinCE6.0中有问题，具体没有试过。&lt;br /&gt;"COMSpeed"是设置串口的波特率，这里要注意，9600的意思是0x9600，也就是38400，别搞错了。&lt;br /&gt;下面的问题是，我们需要在WinCE启动以后自动运行cmd.exe，这样我们才能在串口看到提示符，如何实现呢？&lt;br /&gt;这里采用的方法是使用Autolaunch.exe，Autolaunch是一个用于自动加载程序的程序，Autolaunch工程可以在网上搜索到，这里提供一个参考网址：&lt;br /&gt;&lt;a href="http://www.learningce.com/Downloads/796.aspx"&gt;http://www.learningce.com/Downloads/796.aspx&lt;/a&gt;&lt;br /&gt;它可以作为一个sub project被添加到WinCE6.0的工程当中，然后打开Autolaunch子工程里面的Autolaunch.reg，把cmd.exe添加进去就可以了，参考如下：&lt;br /&gt;[HKEY_LOCAL_MACHINE\Init]"Depend99"=hex:0a,00,14,00,1e,00,32,00[HKEY_LOCAL_MACHINE\Init]"Launch99"="AutoLaunch.exe"&lt;br /&gt;[HKEY_LOCAL_MACHINE\Startup]"Process1"="cmd""Process1Delay"=dword:000003E8&lt;br /&gt;这样，当WinCE启动以后会自动运行Autolaunch.exe，然后Autolaunch会根据Autolaunch.reg中的配置启动cmd.exe，这样就可以在超级终端中看到命令行提示符了。&lt;br /&gt;这个功能我是在WinCE6.0下面用的，感觉重定向到串口以后有一些问题：&lt;br /&gt;1。输入字符没有回现，我必须在超级终端里面使用超级终端的回现功能，而不是WinCE中Console本身的回现。&lt;br /&gt;2。命令太少，也就执行个cd, dir等命令，要是运行ipconfig这样的命令，就不行了，没有任何打印信息出来，感觉没有被执行。当然也运行不了其它的程序。&lt;br /&gt;个人感觉，这个cmd.exe被重定向到串口以后，功能很有限，只能运行一些基本的命令。查找过他的源代码，在\WINCE600\private\winceos\utils\cmd2\下面。&lt;br /&gt;我个人的看法是，最开始开发BSP的时候，这种方法或许会有一些用，当我们有了ethernet的驱动以后，我们就可以用telnet了，这个方法就可以放弃了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-7239343001876455997?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/7239343001876455997/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=7239343001876455997' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/7239343001876455997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/7239343001876455997'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/01/winceconsole.html' title='WinCE中的console重定向'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-8987989844132347994</id><published>2008-01-15T01:09:00.000-08:00</published><updated>2008-01-15T01:10:33.905-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OEMIoControl'/><title type='text'>WinCE BSP中OAL层中的OEMIoControl介绍</title><content type='html'>在WinCE的BSP中的OAL部分，会有一个ioctl.c或者oemioctl.c文件，里面主要定义了一个叫OEMIoControl(..)的函数。可以说OEMIoControl是一个很有用的WinCE内核输入/输出函数。&lt;br /&gt;在WinCE5.0中，应用程序和驱动程序可以通过调用KernelIoControl(..)函数来访问WinCE内核，导致调用OEMIoControl函数，这样应用程序和驱动程序就可以访问到OAL中的资源了。但在WinCE6.0中，提供了更好的安全性，应用程序能够访问OEMIoControl中的case受到了限制，只有下面的这些case是可以让应用程序访问的：&lt;br /&gt;IOCTL_HAL_GET_CACHE_INFOIOCTL_HAL_GET_DEVICE_INFOIOCTL_HAL_GET_DEVICEIDIOCTL_HAL_GET_UUIDIOCTL_PROCESSOR_INFORMATION&lt;br /&gt;如果用户在应用程序中试图访问其他的case，肯定会返回失败的。在WinCE6.0中，驱动程序还像以前一样，可以访问OEMIoControl中的任何case。也许有人会问，那么我们如何让应用程序也访问到一些case呢？？&lt;br /&gt;办法还是有的，可以看一下\WINCE600\public\common\oak\oalioctl\oalioctl.c，这个文件中定义了应用程序可以访问的case，把你的应用程序要访问的case加到这个文件中的IOControl(..)函数中就可以了。当然，你需要重新编译\public目录。&lt;br /&gt;在WinCE5.0中，OEMIoControl函数被定义在BSP中的OAL部分，上面已经提到，应该是ioctl.c或者oemioctl.c，但是在WinCE6.0中，这个函数的定义被移到了\WINCE600\platform\common\src\common\ioctl\ioctl.c中了，这里面的OEMIoControl函数和以前也有了变化，该函数会查一个表：g_oalIoCtlTable[]。该表实际上是一个结构数组，定义了OEMIoControl中所有的case，已经针对这个case的处理函数，还包括一个针对每个case的flag，该flag表示是否使用临界区保护。具体定义如下：typedef struct { UINT32 code; UINT32 flags; BOOL (*pfnHandler) (UINT32, VOID*, UINT32, VOID*, UINT32, UINT32*);} OAL_IOCTL_HANDLER, *POAL_IOCTL_HANDLER;&lt;br /&gt;所以，在WinCE6.0的BSP中，我们只需要实现g_oalIoCtlTable[]就可以了。例如：&lt;br /&gt;const OAL_IOCTL_HANDLER g_oalIoCtlTable[]={{ IOCTL_HAL_POSTINIT,                                               0, OALIoCtlHalPostInit         },{ IOCTL_HAL_GET_HIVE_CLEAN_FLAG,                  0, OALIoCtlHalGetHiveCleanFlag },{ IOCTL_HAL_GET_HWENTROPY,                             0, OALIoCtlHalGetHWEntropy     },{ IOCTL_HAL_GET_IMAGE_SIGNED_STATE,          0, OALIoCtlHalGetImageSignedState },{ IOCTL_HAL_QUERY_FORMAT_PARTITION,         0, OALIoCtlHalQueryFormatPartition },{ 0,                                                                                      0, NULL}};&lt;br /&gt;在OEMIoControl函数中，我们不光要实现OEMIoControl中的case，有一些全局的OAL变量我们也需要定义：&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl01" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl01',this);" href="http://207.46.199.254/en-us/library/aa917733.aspx"&gt;g_oalIoCtlClockSpeed&lt;/a&gt;&lt;br /&gt;This global variable contains information about the processor clock speed.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl02" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl02',this);" href="http://207.46.199.254/en-us/library/aa917751.aspx"&gt;g_oalIoCtlInstructionSet&lt;/a&gt;&lt;br /&gt;This global variable contains the processor instruction set identifier.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl03" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl03',this);" href="http://207.46.199.254/en-us/library/aa913499.aspx"&gt;g_oalIoCtlPlatformOEM&lt;/a&gt;&lt;br /&gt;This global variable contains information about the hardware platform OEM.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl04" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl04',this);" href="http://207.46.199.254/en-us/library/aa910447.aspx"&gt;g_oalIoCtlPlatformType&lt;/a&gt;&lt;br /&gt;This global variable contains information about the hardware platform type.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl05" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl05',this);" href="http://207.46.199.254/en-us/library/aa915755.aspx"&gt;g_oalIoCtlProcessorCore&lt;/a&gt;&lt;br /&gt;This global variable contains information about the processor core.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl06" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl06',this);" href="http://207.46.199.254/en-us/library/aa915991.aspx"&gt;g_oalIoCtlProcessorName&lt;/a&gt;&lt;br /&gt;This global variable contains information about the processor name.&lt;br /&gt;&lt;a id="ctl00_rs1_mainContentContainer_ctl07" onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00ctl00_rs1_mainContentContainer_ctl07',this);" href="http://207.46.199.254/en-us/library/aa912515.aspx"&gt;g_oalIoCtlProcessorVendor&lt;/a&gt;&lt;br /&gt;This global variable contains information about the processor vendor.&lt;br /&gt;其实都是一些硬件及平台的相关信息，定义一下就可以了。&lt;br /&gt;有时根据具体需要，我们还希望在OEMIoControl函数中添加自己定义的case，这个比较简单，只要定义个case，然后在这个case下写你的实现代码就可以了，驱动程序通过KernelIoControl调用同样的case就可以调用到你在OEMIoControl中定义的case了。关于case值得定义，一般都在2048到4096之间会比较安全，我记得在WinCE6.0下，看微软的代码好像256以上就可以了，具体没有试过，要是保险的话，还是用2048以上的值吧。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-8987989844132347994?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/8987989844132347994/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=8987989844132347994' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/8987989844132347994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/8987989844132347994'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/01/wince-bspoaloemiocontrol.html' title='WinCE BSP中OAL层中的OEMIoControl介绍'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-8266378406202601053</id><published>2008-01-15T01:02:00.000-08:00</published><updated>2008-01-15T01:09:23.824-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OEMAddressTable'/><title type='text'>OEMAddressTable介绍</title><content type='html'>一般在ARM架构的CPU上，物理地址都是统一编址的，寻址空间为4GB(32Bit CPU)。也就是说，针对一个ARM的处理器，它可以访问的物理空间是4GB。在WinCE中，ARM中的4GB物理地址空间将被映射为512MB的虚拟内存空间。 OEMAddressTable就是一个4GB物理地址空间到WinCE Kernel中的512MB虚拟地址空间的映射表。&lt;br /&gt;在BSP中，会定义OEMAddressTable来描述系统中可访问的物理空间及对应的虚拟地址空间，还有大小。这个表会在WinCE系统开始启动的时候传给MMU，具体到BSP中应该是在OAL中的startup.s中，OEMAddressTable的起始地址会被放到r0寄存器中，然后就跳转到KernelStart里面，KernelStart会用OEMAddressTable完成MMU得初始化。当WinCE启动以后，就只能访问虚拟地址空间了。&lt;br /&gt;举个例子，比如我们要开发一个Flash的驱动程序，那么首先我们知道这个flash所接的片选对应的物理起始地址是多少(假如是0x60000000)，大小是多少(假如是0x2000000)。如果我们要在WinCE中访问它，就必须为它定义一个虚拟地址(假如是0x80000000)，并添加到OEMAddressTable中，这样，我们才能在我们的驱动里面通过这个虚拟地址访问到flash。&lt;br /&gt;虚拟地址不是随便定义的，WinCE中有规定，必须在0x80000000---0x9FFFFFFF。实际上WinCE创建了两套虚拟地址空间，一个是0x80000000---0x9FFFFFFF，是Cache Enabled。另一个是0xA0000000---0xBFFFFFFF，是Cache Disabled。有啥区别呢：&lt;br /&gt;如果我们访问的这个空间只是一段内存空间(比如SDRAM)，那么就可以用Cache Enabled的空间来访问，这样存取数据的速度会比较快，因为数据被保存在Cache中。&lt;br /&gt;如果我们访问的这个空间是一个外设的地址，那么我们就要使用Cached Disabled的空间来访问，这样才能使CPU与外设同步。&lt;br /&gt;可能说得有点绕，我的经验就是：只要是SDRAM，可以用Cache Enabled空间访问。如果是寄存器，就用Cache Disabled空间访问。&lt;br /&gt;如何定义OEMAddressTable呢，如果安装了WinCE5.0或者6.0，那么提供的参考BSP中都已经有定义了，在BSP目录下搜索“OEMAddressTable”，一看代码就明白了，这里重复一下，格式如下：&lt;br /&gt;                    虚拟地址                物理地址               大小&lt;br /&gt;比如：&lt;br /&gt;OEMAddressTable:&lt;br /&gt;dd             0x80000000          0x60000000        0x2000000&lt;br /&gt;dd             0                              0                            0&lt;br /&gt;上面这个表定义了一个flash的物理地址到虚拟地址的映射，物理地址是0x60000000，虚拟地址是0x80000000，大小是32MB。OEMAddressTable最后必须以0结尾，表示OEMAddressTable结束。&lt;br /&gt;&lt;br /&gt;总之，说白了就是一张物理地址/虚拟地址映射表，当我们要在WinCE中要访问相关硬件的时候，查查这张表，然后通过虚拟地址就可以访问了。如果没有定义，自己添加一个物理地址到虚拟地址的映射就好了。　&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-8266378406202601053?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/8266378406202601053/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=8266378406202601053' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/8266378406202601053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/8266378406202601053'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/01/oemaddresstable.html' title='OEMAddressTable介绍'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-1204011869599763063</id><published>2008-01-03T02:09:00.000-08:00</published><updated>2008-01-03T02:10:51.231-08:00</updated><title type='text'>在WinCE5.0和WinCE6.0下，编译选项介绍</title><content type='html'>在WinCE5.0中，在"Build OS”菜单中，我们会看到不同的编译选项：&lt;br /&gt;"Sysgen"，"Build and Sysgen"和"Build and Sysgen current BSP"&lt;br /&gt;Sysgen：不用多说，当你在"Catalog"中添加或删除了新的item的时候，就用这个吧。&lt;br /&gt;Build and Sysgen：当你更新了\public目录下的源代码的时候，你就需要用这个了。一般比如在打patch以后，可能就需要进行Build and Sysgen了。&lt;br /&gt;Build and Sysgen current BSP： 当你只改变了你的BSP部分的代码，就可以用这个选项。据说，当你改变了\platform目录下的代码，也可以用这个，具体没有试过。&lt;br /&gt;&lt;br /&gt;在WinCE6.0中，在VS2005的"Build"菜单中，有一个“Advanced Build Commands”，其中有很多编译选项：&lt;br /&gt;"Sysgen"：相当于执行命令"blddemo -q”，一般第一次编译或者是改变了"Catalog"中的item的时候，就用这个了。&lt;br /&gt;"Clean Sysgen"：相当于执行命令"blddemo clean -q"，按照文档上的说明，当修改了 %_WINCEROOT%\Public\CEBASE\OAK\Misc\Cesysgen.bat的时候，或者改变了以SYSGEN，BSP为前缀的环境变量的时候，需要使用这个来编译。&lt;br /&gt;在此我说一下我个人的经验，一般只有第一次创建完工程的时候，我会用"Sysgen"命令，以后只要是改变了SYSGEN为前缀的环境变量的设置或者是"Catalog"中的item，我就会使用"Clean Sysgen"，而改变了以BSP为前缀的环境变量要看具体情况，也不一定就要用"Clean Sysgen"。继续...&lt;br /&gt;"Build and Sysgen"：相当于执行命令"blddemo"，当改变了\public目录下的代码，比如你打了WinCE的patch，你就需要用这个了。&lt;br /&gt;"Rebuild and Sysgen Clean"：相当于执行命令"blddemo clean cleanplat -c"，相当于清除上一次编译生成的文件，然后重新编译\public目录和你的工程。&lt;br /&gt;"Build and Sysgen Current BSP"：相当于执行命令"blddemo -qbsp"，仅编译\platform目录下的代码。所以当改变了\platform目录下的代码的时候或者说改变了BSP的代码的时候，可以用这个来编译。&lt;br /&gt; "Rebuild and Clean Sysgen Current BSP"：相当于执行命令"blddemo -qbsp -c"，相当于完全重新编译\platform目录下要编译的代码。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-1204011869599763063?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/1204011869599763063/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=1204011869599763063' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/1204011869599763063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/1204011869599763063'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2008/01/wince50wince60.html' title='在WinCE5.0和WinCE6.0下，编译选项介绍'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-4366234644675320697</id><published>2007-12-26T23:53:00.000-08:00</published><updated>2007-12-27T00:00:56.805-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cvrtbin'/><title type='text'>WinCE中命令行工具Cvrtbin简介</title><content type='html'>关于cvrtbin的用途，最常用的就是将NK.bin转换出NK.nb0。用法如下：&lt;br /&gt;&lt;br /&gt;cvrtbin [options] [filename]&lt;br /&gt;&lt;br /&gt;-s       从bin文件中产生sre文件&lt;br /&gt;-r       从bin文件中产生rom文件&lt;br /&gt;&lt;br /&gt;-a      rom文件的起始地址&lt;br /&gt;-w     总线的宽度&lt;br /&gt;-l       rom文件的大小&lt;br /&gt;&lt;br /&gt;这个工具可以和viewbin工具一起使用，将NK.bin文件转换成NK.nb0。&lt;br /&gt;首先通过：viewbin -nk.bin命令获得NK.bin的起始地址和大小，然后通过下面的命令：&lt;br /&gt;&lt;br /&gt;cvrtbin -a C02C0000 -l 00D5E380 -w 32 -r NK.bin&lt;br /&gt;&lt;br /&gt;将NK.bin转换成NK.nb0。起始地址为0xC02C0000，大小是0x00D5E380，总线宽度为32bit，最后输出NK.nb0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-4366234644675320697?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/4366234644675320697/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=4366234644675320697' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/4366234644675320697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/4366234644675320697'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2007/12/wincecvrtbin.html' title='WinCE中命令行工具Cvrtbin简介'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-6094508396808667007</id><published>2007-12-25T02:13:00.000-08:00</published><updated>2007-12-25T02:32:52.620-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='viewbin'/><title type='text'>WinCE中命令行工具Viewbin简介</title><content type='html'>Viewbin是微软提供的一个命令行工具，在WinCE6.0中，可以在"\WINCE600\PUBLIC\COMMON\OAK\BIN\I386"找到他。Viewbin工具可以用来查看NK.bin文件。它可以从NK.bin中获得这个NK image的大小，运行的起始地址等。还能查看到里面所包含的模块，应用程序及相关的信息。&lt;br /&gt;&lt;br /&gt;Viewbin的使用格式如下：&lt;br /&gt;          viewbin  [parameter]  [filename]&lt;br /&gt;&lt;br /&gt;举几个例子吧：&lt;br /&gt;1.  viewbin -nk.bin&lt;br /&gt;&lt;br /&gt;ViewBin... nk.bin&lt;br /&gt;Image Start = 0xC02C0000, length = 0x00D5E380 &lt;br /&gt;Start address =   0xC02C1006&lt;br /&gt;Checking record #126 for potential TOC (ROMOFFSET = 0x40000000)&lt;br /&gt;Found pTOC  = 0x8101c8d0&lt;br /&gt;ROMOFFSET = 0x40000000&lt;br /&gt;Done.&lt;br /&gt;这条命令可以查看NK image的起始地址，长度等信息，这些信息应该和config.bib文件中定义的一致。&lt;br /&gt;&lt;br /&gt;2.   viewbin -t nk.bin &gt; output.txt&lt;br /&gt;这条命令可以将NK image里面包含的模块及相关信息列成一个表并输出到output.txt里面，这样打开output.txt就可以看到里面包含了哪些模块，其中包括驱动，应用程序等。&lt;br /&gt;&lt;br /&gt;3.   viewbin -r nk.bin &gt; output.txt&lt;br /&gt;打印记录信息到output.txt中。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-6094508396808667007?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/6094508396808667007/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=6094508396808667007' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/6094508396808667007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/6094508396808667007'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2007/12/winceviewbin.html' title='WinCE中命令行工具Viewbin简介'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-390012355831230615</id><published>2007-12-23T23:55:00.000-08:00</published><updated>2007-12-23T23:59:26.467-08:00</updated><title type='text'>WinCE下，快速编译驱动及BSP</title><content type='html'>在WinCE下面，创建工程，然后编译是需要花很长时间的。当我们第一编译完工程以后，如果需要改我们的驱动或者BSP，我们是不需要重新编译整个工程的：&lt;br /&gt;&lt;br /&gt;1. 如果更改了driver，以WinCE6.0为例，我们可以在菜单里面选择“build”-&gt;“Open Release Directory in Build Window” ，然后在弹出的命令行窗口中，通过dos命令切换到你要编译的driver的目录下面，然后运行“build”就可以了。也可以运行“build -c”会强制把所有的文件都编译一遍。被编译后的driver的dll会被自动拷贝到release目录下面，然后再切换的工程的release目录下面，运行一下“make image”就可以了。&lt;br /&gt;&lt;br /&gt;2. 如果改变了OAL部分的代码，同样用上面介绍的方法，需要注意的是，OAL部分可能包含多个文件夹，如果改变了OAL里面的代码，不要进入OAL里面的文件夹去编译，一定要在OAL这层进行编译，这样OAL部分的lib，dll才会被重新编译并拷贝到release目录下面。&lt;br /&gt;&lt;br /&gt;3. 如果改变了配置文件，比如config.bib，platform.reg文件，那么直接将这些文件拷贝到你的工程的release目录下面，然后运行一下“make image”就可以了。&lt;br /&gt;&lt;br /&gt;4. 如果改变了bootloader部分的代码，那按照步骤1的方法就可以了，可能你都不需要运行“make image”命令，因为可能你只需要eboot.bin或者eboot.nb0。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-390012355831230615?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/390012355831230615/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=390012355831230615' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/390012355831230615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/390012355831230615'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2007/12/wincebsp.html' title='WinCE下，快速编译驱动及BSP'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4426105232971900916.post-1238898593064804686</id><published>2007-12-23T23:52:00.000-08:00</published><updated>2007-12-23T23:55:22.046-08:00</updated><title type='text'>WinCE中，环境变量的添加，删除和查询</title><content type='html'>在WinCE中有很多的环境变量，那么如何设置/删除/查询这些环境变量呢：&lt;br /&gt;&lt;br /&gt;1. 查询环境变量：无论是在WinCE5.0还是WinCE6.0，当我们在PB里打开或者创建一个工程以后，我们可以在菜单中点“build”-&gt;“Open Release Directory in Build Window”，然后会弹出命令行对话框。在对话框中输入“set”命令，然后回车，就会看到当前工程下所有的环境变量以及相应的值。&lt;br /&gt;&lt;br /&gt;2. 添加环境变量：有两种方法添加环境变量，一种是点“build”-&gt;“Open Release Directory in Build Window”，再弹出的对话框中添加新的环境变量，例如：set WINCE_TEST=1。这句话的意思是添加一个环境变量叫WINCE_TEST，它的值为1。还有另一种方法添加环境变量，以WinCE6.0为例，在“Solution Explorer”窗口中，右击工程的名字，然后选择“Properties”。在弹出的对话框中选择“Configuration Properties”-&gt;“Enviroment”，然后在右侧的窗口中添加环境变量。&lt;br /&gt;&lt;br /&gt;3. 删除环境变量：同样两种方法，一种是点“build”-&gt;“Open Release Directory in Build Window”，再弹出的对话框中删除已经定义的环境变量，例如：set WINCE_TEST=。这句话的意思是删除环境变量叫WINCE_TEST。另一种删除环境变量的方法是在“Solution Explorer”窗口中，右击工程的名字，然后选择“Properties”。在弹出的对话框中选择“Configuration Properties”-&gt;“Enviroment”，然后在右侧的窗口中删除已经定义的环境变量。&lt;br /&gt;&lt;br /&gt;4. 通过环境变量对代码进行选择性编译：对代码进行选择性编译如下：&lt;br /&gt;#ifdef NANDFLASH_ECC&lt;br /&gt;.....&lt;br /&gt;#endif&lt;br /&gt;对platform.reg进行选择性加载如下：&lt;br /&gt;IF NANDFLASH_ECC&lt;br /&gt;......&lt;br /&gt;ENDIF&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4426105232971900916-1238898593064804686?l=armwince.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://armwince.blogspot.com/feeds/1238898593064804686/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=4426105232971900916&amp;postID=1238898593064804686' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/1238898593064804686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4426105232971900916/posts/default/1238898593064804686'/><link rel='alternate' type='text/html' href='http://armwince.blogspot.com/2007/12/wince.html' title='WinCE中，环境变量的添加，删除和查询'/><author><name>ARM-WinCE</name><uri>http://www.blogger.com/profile/10689189295108081124</uri><email>artistboy2004@hotmail.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='13352560682406718637'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>