Buffer tracked events in RAM 启用RAM缓冲事件跟踪(OSCaptere.exe实现) Enable CE Target Control Support 为 OS 设计启用 CE 目标控制支持会为您的 OS 设计启用目标控制支持,并且启用内核独立传输层 (KITL)。 Enable Eboot Space in Memory 配置Config.bib文件中预留内存空间,允许在启动过程中操作系统可以读取boot loader存储的数据. Enable Event Tracking during Boot 开启事件跟踪子系统 Enable Full Kernel Mode 可使线程运行在内核模式。注意:选择该模式会使系统较脆弱,但是性能会有所提高 Enable Kernel Debugger 通过启用对内核调试器的支持,您可以调试基于您的 OS 设计创建的运行库映像;若选上该选项,调试器值为0,否则为1; Enable KITL 内核独立传输层(Kernel Independent Transport Layer — KITL),为 OS 设计启用完全内核模式可以提高运行库映像中的系统性能,要建立宿主机和目标机间的通讯就必须选择该选项。取消该项也会同时取消被选定的“Enable CE Target Control Support ”选项; Enable Profiling 将Windows CE的有关内核的信息以日志的形式装入平台镜像中 Enable Ship Build 这是一个有条件编译的标志,设置它表示OS会提供详细的调试信息来帮助调试。(这个选项只在release设置才显示的,而Debug下是没有这个选项的) Flush tracked events to Release Directory 将事件也放进release目录,同时开启事件跟踪功能 Run-time Image Can be Larger than 32 MB 通过使运行库映像能够大于 32 MB,您可以具有更大的运行库映像。如果最终的运行库映像需要 32 MB 以上的空间,否则生成过程可能无法成功完成。 Use XCOPY instead of links to populate release directory 用Xcopy将所需的文件复制到Release目录(如:BSP,系统组件等) posted @ 2010-07-30 23:57 jiege 阅读(10) | 评论(0) | 编辑
共同的内核函数: 4.2下的OEMInterruptHandler()函数会跟据转进来的硬件IRQ中断号返回对应的SYSINTR逻辑中断号,也就是说如果需要修改两个中断号对应关系,可以直接在这个函数中修改,这里的这种对应、映射关系称之为静态映射。OEMInterruptEnable()...三个函数传进来的参数是SYSINTR逻辑中断号,可以根据OEMInterruptHandler()函数中的映射关系,对硬件中断IRQ来进行相应的操作。这几个函数分别位于platform\bsp\kernel\hal\cfw.c与bsp\kernel\hal\arm\armint.c文件中。换句话说4.2下的中断可以称之为静态映射,也就是不能在运行时的应用/驱动层将硬件与逻辑IRQ进行映射。 5.0下的OEMIntrruptHandler()函数位于:platform\common\src\arm\samsung\s3c2410x\intr\intr.c中。注意,他不像4.2中的该函直接将参数传递进来的硬件IRQ送出对应的逻辑SYSIRQ,而是调用OALIntrTranslateIrq()函数进行映射。OALIntrTranslateIrq()函数位于platform\common\src\common\intr\base\map.c文件中。这个函数只是简单的将以Irq参数为下标的数组中找出SYSIRQ,然后返回: 5.0下的OEMInterruptEnable()...这三个函数位于platform\common\src\common\INTR\common\oem.c文件小,大致流程是这样的: 总结: platform\smdk410\src\kernel\oal\init.c platform\smdk2410\src\kernel\oal\intr.c platform\common\src\common\intr\base\map.c 贴两个网上找到的资料,都是5.0的: WinCE有两种私有的中断表,一种是物理中断——中断请求(IRQs),另一种是逻辑中断——SYSINTR值。WinCE必须将一个物理中断和一个逻辑中断关联起来。 物理中断号定义在platform\c8090\pubic\csp\arm\intel\pxa27x\inc\Bulverde_intr.h。 逻辑中断号定义在platform\c8090\platform\mainstoneii\src/inc\Bsp_cfg.h。 两个中断表定义在platform\c8090\platform\src\common\intr\base\map.c static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM]; static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM]; OAL_INTR_IRQ_MAXIMUM定义在platform\c8090\common\src\inc\oal_intr.h, #define OAL_INTR_IRQ_MAXIMUM 64 该值表示物理中断——IRQs的最大值,现在最大只支持到64。 SYSINTR_MAXIMUM定义在wm522\public\common\oak\inc\nkintr.h #define SYSINTR_DEVICES 8 #define SYSINTR_MAX_DEVICES 64 #define SYSINTR_MAXIMUM (SYSINTR_DEVICES+SYSINTR_MAX_DEVICES) OEM Adaptation Layer——OAL初始化函数是OEMInit(),它是WinCE的OAL层初始化函数,在基本初始化完成之后,由内核调用,定义在: platform\c8090\platform\mainstoneii\src\kernel\oal\init.c。 在这里调用中断初始化函数:OALIntrInit(),该函数定义在: platform\c8090\platform\common\src\arm\intel\pxa27x\intr\intr.c中,该函数首先调用函数OALIntrMapInit(),初始化前面提到的两个数组表g_oalSysIntr2Irq和goalIrq2SysIntr。该函数定义在platform\c8090\platform\common\src\common\intr\base\map.c,源码如下: for (i = 0; i < SYSINTR_MAXIMUM; i++) { g_oalSysIntr2Irq[i] = OAL_INTR_IRQ_UNDEFINED; } for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) { g_oalIrq2SysIntr[i] = SYSINTR_UNDEFINED; } 然后调用函数BSPIntrInit()将物理中断和逻辑中断关联起来,该函数定义在: platform\c8090\platform\mainstoneii\src\kernel\oal\intr.c中。 关联代码例子如下: OALIntrStaticTranslate(SYSINTR_PMIC, IRQ_GPIO0); OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBOHCI); OALIntrStaticTranslate(SYSINTR_TOUCH, IRQ_GPIOXX_WM9712); OALIntrStaticTranslate(SYSINTR_TOUCH_CHANGED, IRQ_OSMR1); OALIntrStaticTranslate(SYSINTR_KEYPAD, IRQ_KEYPAD); 前面都是逻辑中断,后面是物理中断。OALIntrStaticTranslate函数定义在: platform\c8090\platform\common\src\common\intr\base\map.c,源码如下: if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) { g_oalSysIntr2Irq[sysIntr] = irq; g_oalIrq2SysIntr[irq] = sysIntr; } OAL是位于WindowsCE内核与目标设备硬件之间的一个代码层,用于实现windowCE与目标设备硬件之间的通信。为了实现内核与硬件之间最基本的通信功能,OEM必须实现一些必要的功能,同时为了适合不同的硬件配置与操作系统功能,OEM有必要的选择实现一些其他的功能。 posted @ 2010-07-30 23:54 jiege 阅读(31) | 评论(0) | 编辑
posted @ 2010-07-30 23:36 jiege 阅读(166) | 评论(0) | 编辑
先来谈一下flash,flash是一种非易失存储器,一般flash存储设备分为Nandflash和Norflash。这两种flash各有优缺点。在读写速度上,norflash的读速度快一些,nandflash的写速度会快一些。Nandflash的容量一般都比Norflash大很多,而且相比价格比较便宜。但是Norflash支持XIP,而nandflash不支持,而且Nandflash可能有坏块。相关的比较,网上很多文章都有介绍,这里就说这么多了。 这里介绍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驱动的架构。 如上面所说,我们需要实现FMD层的相关接口,下面来介绍一下各个接口函数: 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表示失败。 2. BOOL FMD_Deinit(PVOID hFMD): 这个函数在nandflash驱动卸载的时候被调用,参数就是FMD_Init函数返回的Handle.一般在这个函数里面,你可以释放一些用到的资源,然后关闭nandflash controller。 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。 startSectorAddr: nandflash物理扇区的起始地址,对于nandflash来说,就是nandflash中从哪个page开始。 pSectorBuff:扇区数据buffer,从nandflash中读出的每一个扇区的数据都存放在这个buffer中。 pSectorInfoBuff:扇区信息buffer,一般每个扇区的信息会被保存在nandflash的带外数据中,针对小page,带外数据有16 bytes,大page有64 bytes。从nandflash的带外数据将该扇区的相关信息读出来,存放在这个buffer中。 dwNumSectors:读取多少个扇区,对于nandflash来说相当于读取多少个page。 4. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors): 该函数用于写nandflash的一个扇区。参数和上面的FMD_ReadSector的参数意思一样,就不多说了。 5. BOOL FMD_EraseBlock(BLOCK_ID blockID): 该函数用于擦出nandflash的一个block,参数为要擦除nandflash的block地址,也就是第几个block。 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,否则,判断独到的信息,返回相应结果。 7. BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus): 该函数设置nandflash某个block的状态,第一个参数是nandflash的block地址,第二个是要设置的状态。在这个函数中,首先检查dwStatus是不是BLOCK_STATUS_BAD,如果是就对nandflash作坏块标记,然后返回FALSE。如果不是,就将dwStatus写到该block的第0个page的扇区info中。这个函数和上面的函数正好是相反的。 8. BOOL FMD_GetInfo(PFlashInfo pFlashInfo): 该函数用于返回flash的信息。其中pFlashInfo是一个包含flash信息的结构。 pFlashInfo->flashType:flash的类型,对于nandflash来说,应该是NAND。 pFlashInfo->wDataBytesPerSector:一个扇区多少个bytes,对于大page是2048,对于小page是512。 pFlashInfo->dwNumBlocks:flash中总共有多少个block,查一下所用的nandflash的datasheet就知道了。 pFlashInfo->wSectorsPerBlock:每个block中包含多少个扇区。 pFlashInfo->dwBytesPerBlock:每个block中包含多少个bytes。 9. VOID FMD_PowerDown()和VOID FMD_PowerUp(): 这两个函数用于电源管理。FMD_PowerDown()用于关闭flash设备电源,FMD_PowerUp()用于恢复flash设备电源。根据你所用处理器和相关硬件环境,去实现这两个函数。不实现也不会影响nandflash的使用。 10. BOOL FMD_OEMIoControl(..): 就像很多的IOControl函数一样,根据不同的case,实现相应的功能。针对nandflash来说,这里面的case不一定都需要实现。事实上,如果什么都没有实现,也不影响nandflash的使用。在WinCE的文档中,定义了一些需要实现的case,你可以实现,也可以不去实现。 对于nandflash来说,实现上述函数就可以了。在nandflash出厂的时候,厂家已经对nandflash中的坏块进行了标记。所以第一次对nandflash操作的时候,不要随便擦除nandflash,因为这样可能会把坏块标记擦掉,这样你就判断不出哪个块是坏块了。 关于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进行比较,如果一致,则表示正确。 posted @ 2010-07-30 23:34 jiege 阅读(18) | 评论(0) | 编辑
设备管理器是Windows CE.Net设备管理的核心机构,它主要负责跟踪、维护系统的设备信息并对设备资源进行调配。(在%WINCEROOT%\PRIVATE\WINCEOS\COREOS \DEVICE\LIB里可以看到Windows CE设备管理器的代码) 设备管理器在Windows CE中主要表现为Device.exe的文件,Device.exe在系统启动的时候通过注册表里面的HKEY_LOCAL_MACHINE\Init\"Launch20"=“Device.exe"加载(Windows CE启动时分别执行[HKEY_LOCAL_MACHINE\init]键下所有子键列出的程序)设备管理器是用户级别的程序,在基于Windows CE的平台上在不停地运行着。设备管理器虽然不是内核的一部分,但是它是与内核、注册表和流接口驱动程序有相互影响的单独部分。设备管理器完成以下任务: 1)在系统启动时或收到用户添加外围设备的信息时初始化驱动程序的加载 2)向内核注册特定的文件名,该文件名把应用程序使用的流I/O函数映射到流接口驱动程序的那些函数的实现。 3)通过从外围设备获得即插即用标示符,或激活一个检查子程序来发现可以处理该设备的驱动程序,为外围设备找到合适的驱动程序。 4)通过读写注册值加载跟踪驱动程序。 5)当不再需要设备时,负责卸载驱动程序。 在系统启动时初始化流驱动程序的加载。加载流驱动程序有三种方法。 第一种加载类型是在系统启动的时候进行的。当Winows CE的平台启动的时候,启动设备管理器。设备管理器从注册表的HKEY_LOCAL_MACHINE\Drivers\RootKey下面加载入口点,通常RootKey的值都被设置为Drivers\BuiltIn。然后设备管理器通过\RootKey提供的入口点开始读取HKEY_LOCAL_MACHINE \Drivers\Builtin健的内容,并加载已列出的流接口驱动程序。 第二种加载的类型是在设备管理程序自动检测外围设备设备与基于Windows CE平台的连接时进行的。PC卡是自动检测设备最常见的类型,因为在用户插入PC卡时PC卡插槽控制程序就通知Windows CE。在用户把PC卡插入插槽时,设备管理程序调用槽驱动程序(这是一个内部设备管理程序)寻找即插即用标示符。然后,设备管理程序检查HKEY_LOCAL_MACHINE\Drivers\PCMCIA健已得到与即插即用标示符所匹配的子键。如果有一个子键存在,该子键就加载键值列表里的这个驱动程序。如果没有匹配的子键,设备管理器就调用HKEY_LOCAL_MACHINE\Drivers\PCMCIA\Detect键中列表的所有侦测函数。如果有一个函数返回一个值,那么设备管理程序就加载并初始化那个流接口驱动程序。 第三种加载类型是当设备管理器程序不能够自动检测或加载某一种驱动程序的时候,一般这种情况大多数出现在串行设备上,因为Windows CE不能自动检测到串行设备。这个时候的可以使用系统提供的函数ActivateDeviceEx函数来加载驱动程序。下面介绍一下ActivateDeviceEx这个函数。 ActivateDeviceEx用于加载驱动程序,事实上Windows CE的实现通过StartOneDriver函数把一个具体的驱动程序挂接到系统中的,不过这个函数是一个纯粹的内部函数。它的实现是通过ActivateDeviceEx来实现的。在PB的%WINCEROOT%\PRIVATE\WINCEOS\ COREOS\DEVICE\LIB\目录下的文件device.c中可以找到ActivateDeviceEx函数的实现。它的代码部分如下: HANDLE FS_ActivateDeviceEx( LPCTSTR lpszDevKey, LPCREGINI lpReg, DWORD cReg, LPVOID lpvParam ) 设备管理器是Windows CE.Net设备管理的核心机构,它主要负责跟踪、维护系统的设备信息并对设备资源进行调配。(在%WINCEROOT%\PRIVATE\WINCEOS\COREOS \DEVICE\LIB里可以看到Windows CE设备管理器的代码) 设备管理器在Windows CE中主要表现为Device.exe的文件,Device.exe在系统启动的时候通过注册表里面的HKEY_LOCAL_MACHINE\Init\"Launch20"=“Device.exe"加载(Windows CE启动时分别执行[HKEY_LOCAL_MACHINE\init]键下所有子键列出的程序)设备管理器是用户级别的程序,在基于Windows CE的平台上在不停地运行着。设备管理器虽然不是内核的一部分,但是它是与内核、注册表和流接口驱动程序有相互影响的单独部分。设备管理器完成以下任务: 1)在系统启动时或收到用户添加外围设备的信息时初始化驱动程序的加载 2)向内核注册特定的文件名,该文件名把应用程序使用的流I/O函数映射到流接口驱动程序的那些函数的实现。 3)通过从外围设备获得即插即用标示符,或激活一个检查子程序来发现可以处理该设备的驱动程序,为外围设备找到合适的驱动程序。 4)通过读写注册值加载跟踪驱动程序。 5)当不再需要设备时,负责卸载驱动程序。 在系统启动时初始化流驱动程序的加载。加载流驱动程序有三种方法。 第一种加载类型是在系统启动的时候进行的。当Winows CE的平台启动的时候,启动设备管理器。设备管理器从注册表的HKEY_LOCAL_MACHINE\Drivers\RootKey下面加载入口点,通常RootKey的值都被设置为Drivers\BuiltIn。然后设备管理器通过\RootKey提供的入口点开始读取HKEY_LOCAL_MACHINE \Drivers\Builtin健的内容,并加载已列出的流接口驱动程序。 第二种加载的类型是在设备管理程序自动检测外围设备设备与基于Windows CE平台的连接时进行的。PC卡是自动检测设备最常见的类型,因为在用户插入PC卡时PC卡插槽控制程序就通知Windows CE。在用户把PC卡插入插槽时,设备管理程序调用槽驱动程序(这是一个内部设备管理程序)寻找即插即用标示符。然后,设备管理程序检查HKEY_LOCAL_MACHINE\Drivers\PCMCIA健已得到与即插即用标示符所匹配的子键。如果有一个子键存在,该子键就加载键值列表里的这个驱动程序。如果没有匹配的子键,设备管理器就调用HKEY_LOCAL_MACHINE\Drivers\PCMCIA\Detect键中列表的所有侦测函数。如果有一个函数返回一个值,那么设备管理程序就加载并初始化那个流接口驱动程序。 第三种加载类型是当设备管理器程序不能够自动检测或加载某一种驱动程序的时候,一般这种情况大多数出现在串行设备上,因为Windows CE不能自动检测到串行设备。这个时候的可以使用系统提供的函数ActivateDeviceEx函数来加载驱动程序。下面介绍一下ActivateDeviceEx这个函数。 ActivateDeviceEx用于加载驱动程序,事实上Windows CE的实现通过StartOneDriver函数把一个具体的驱动程序挂接到系统中的,不过这个函数是一个纯粹的内部函数。它的实现是通过ActivateDeviceEx来实现的。在PB的%WINCEROOT%\PRIVATE\WINCEOS\ COREOS\DEVICE\LIB\目录下的文件device.c中可以找到ActivateDeviceEx函数的实现。它的代码部分如下: HANDLE FS_ActivateDeviceEx( LPCTSTR lpszDevKey, LPCREGINI lpReg, DWORD cReg, LPVOID lpvParam ) { DEBUGMSG(1, (TEXT("DEVICE!ActivateDeviceEx(%s) entered\r\n"), lpszDevKey)); CELOG_ActivateDevice (lpszDevKey); return StartOneDriver( lpszDevKey, MAX_LOAD_ORDER, lpReg, cReg, lpvParam); } ActivateDeviceEx的函数很简单它只是负责调用StartOneDriver这个函数。这个函数将根据注册表设置来初始化不同的设备驱动。在系统刚开始运行的时候Device.exe就是调用这个函数来加载相应的驱动程序的。这个函数将引起一个特定的驱动加载过程。先介绍一下StartOneDriver的运行过程。 { DEBUGMSG(1, (TEXT("DEVICE!ActivateDeviceEx(%s) entered\r\n"), lpszDevKey)); CELOG_ActivateDevice (lpszDevKey); return StartOneDriver( lpszDevKey, MAX_LOAD_ORDER, lpReg, cReg, lpvParam); } ActivateDeviceEx的函数很简单它只是负责调用StartOneDriver这个函数。这个函数将根据注册表设置来初始化不同的设备驱动。在系统刚开始运行的时候Device.exe就是调用这个函数来加载相应的驱动程序的。这个函数将引起一个特定的驱动加载过程。先介绍一下StartOneDriver的运行过程。 posted @ 2010-07-30 23:32 jiege 阅读(34) | 评论(0) | 编辑
本文简单描述一下wince5.0内核的启动流程,以mips cpu为例。msdn有一篇文章叫做Microsoft Windows CE 5.0 Board support Package,Boot Loader,and Kernel Startup Sequence非常不错,可以参考。 1. startup.首先,内核最先执行的代码位于oal当中,叫做startup,这段代码由微软留给开发者定制。当然,各个参考bsp里面都有现成的代码,开发者只需在此基础上改动。在startup()的末尾,会跳转到kernelstart函数。 2. kernelstart. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\mips\startup.s 这里面是汇编代码。是所有的mips开发板都要执行的操作。所以这里面会根据不同cpu类型作判断。虽然是汇编代码,好在里面还是有不少注释,通过这些注释,可以看出它里面主要在干什么。 3. KernelRelocate. kernelstart在完成一些必要的初始化之后,会调用KernelRelocate函数,这是一个比较重要的函数,位于WINCEROOT\Private\winceos\coreos\nk\kernel\loader.c. 它会把kernel用到的数据copy的ram里面。具体的功能msdn里面有解释。 这里的ram就是在config.bib里面指定的具有ram属性的存储区域,不是ramimage. kernelRelocate以pToc为参数,那么pToc的值从何而来呢?即便你搜索完所有的文件也找不到在那里pToc被赋值。因为pToc是在makeimage阶段被romimage.exe赋值的,也就是说pToc并不是在代码中被赋值的,是由外力(romimage.exe)改动nk.bin的内容赋值的。 4.MIPSInit. KernelRelocate处理完成之后,MIPSInit会被调用。位于WINCEROOT\Private\winceos\coreos\nk\kernel\mips\mdsched.c.这里是通用的mips的处理,其中会调用oal当中的OEMInitDebugSerial去初始化调试用的串口。 5.OEMInit.接下来就是大名鼎鼎的OEMInit了。这个函数由开发者定制。是c语言的。由上面的分析我们知道,在进入OEMInit的时候,串口已经初始化完毕,所以现在我们已经可以通过串口打印出一些调试信息了。而在此之前,我们只能通过led的方式作一些简单的显示。 6.KernelFindMemory. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\loader.c OEMInit返回之后调用该函数。这个函数主要是把ram划分为两部分:object store和应用程序可以使用的部分。object store就是用于存贮wince的ram file system的,例如开机以后我们看到的\windows目录就是位于ram file system. 7.KernelInit. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\kwin32.c 这部分跟cpu无关,是kernel要完成自己的初始化。至此,kernel得初始化全部完成,可以开始线程调度。 还有一点需要说明的时,kernel在完成初始化之后,会以IOCTL_HAL_POSTINIT为参数调用OEMIoControl,所以我们可以在这里打印出一句话表明kernel已经初始化完成。 除了kernel本身(nk.exe)之外,第一个被创建的进程是谁呢,对,就是文件系统,filesys.exe. 虽然他不是kernel本身的一部分,但是如果没有文件系统,wince也是玩不转的,注册表的初始化就是由文件系统来完成。 posted @ 2010-07-30 22:26 jiege 阅读(36) | 评论(0) | 编辑
本文简单描述一下wince5.0内核的启动流程,以mips cpu为例。msdn有一篇文章叫做Microsoft Windows CE 5.0 Board support Package,Boot Loader,and Kernel Startup Sequence非常不错,可以参考。 1. startup.首先,内核最先执行的代码位于oal当中,叫做startup,这段代码由微软留给开发者定制。当然,各个参考bsp里面都有现成的代码,开发者只需在此基础上改动。在startup()的末尾,会跳转到kernelstart函数。 2. kernelstart. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\mips\startup.s 这里面是汇编代码。是所有的mips开发板都要执行的操作。所以这里面会根据不同cpu类型作判断。虽然是汇编代码,好在里面还是有不少注释,通过这些注释,可以看出它里面主要在干什么。 3. KernelRelocate. kernelstart在完成一些必要的初始化之后,会调用KernelRelocate函数,这是一个比较重要的函数,位于WINCEROOT\Private\winceos\coreos\nk\kernel\loader.c. 它会把kernel用到的数据copy的ram里面。具体的功能msdn里面有解释。 这里的ram就是在config.bib里面指定的具有ram属性的存储区域,不是ramimage. kernelRelocate以pToc为参数,那么pToc的值从何而来呢?即便你搜索完所有的文件也找不到在那里pToc被赋值。因为pToc是在makeimage阶段被romimage.exe赋值的,也就是说pToc并不是在代码中被赋值的,是由外力(romimage.exe)改动nk.bin的内容赋值的。 4.MIPSInit. KernelRelocate处理完成之后,MIPSInit会被调用。位于WINCEROOT\Private\winceos\coreos\nk\kernel\mips\mdsched.c.这里是通用的mips的处理,其中会调用oal当中的OEMInitDebugSerial去初始化调试用的串口。 5.OEMInit.接下来就是大名鼎鼎的OEMInit了。这个函数由开发者定制。是c语言的。由上面的分析我们知道,在进入OEMInit的时候,串口已经初始化完毕,所以现在我们已经可以通过串口打印出一些调试信息了。而在此之前,我们只能通过led的方式作一些简单的显示。 6.KernelFindMemory. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\loader.c OEMInit返回之后调用该函数。这个函数主要是把ram划分为两部分:object store和应用程序可以使用的部分。object store就是用于存贮wince的ram file system的,例如开机以后我们看到的\windows目录就是位于ram file system. 7.KernelInit. 位于WINCEROOT\Private\winceos\coreos\nk\kernel\kwin32.c 这部分跟cpu无关,是kernel要完成自己的初始化。至此,kernel得初始化全部完成,可以开始线程调度。 还有一点需要说明的时,kernel在完成初始化之后,会以IOCTL_HAL_POSTINIT为参数调用OEMIoControl,所以我们可以在这里打印出一句话表明kernel已经初始化完成。 除了kernel本身(nk.exe)之外,第一个被创建的进程是谁呢,对,就是文件系统,filesys.exe. 虽然他不是kernel本身的一部分,但是如果没有文件系统,wince也是玩不转的,注册表的初始化就是由文件系统来完成。 posted @ 2010-07-30 22:21 jiege 阅读(19) | 评论(0) | 编辑
WINCE5.0的中断深入了解1.总体了解流程 首先描述wince5.0 (2440BSP)的中断流程: 流程1.创建事件aà创建线程ISTà用InterruptInitialize〈系统中断号绑定线程IST〉à线程IST进入等待事件a状态(挂起状态)。 流程2.外部引发中断à OEMInterruptHandler<屏蔽中断à把物理中断转换成系统中断,其他à重新使能中断。(ISR过程)>à操作系统根据系统中断号触发事件a。 流程3.挂起的IST线程等待到事件a进入就绪状态,得到执行时间后开始执行中断服务代码, 最后调用InterruptDone重新使能当前的中断。 你需要为你的设备驱动写好中断处理请求(ISR)和中断服务线程(IST),并牢记这些事件的顺序: 1).当一个中断发生,处理器跳转到核心的中断处理程序(exception handler ); 2).这个中断处理程序禁止所有同级或低优先级的其他中断,然后为当前的IRQ调用对应的ISR; 3).ISR中会按照中断标识的形式,返回一个逻辑中断号给中断处理程序,并会置位板级设备中断; 4).中断处理程序重新使能所有的中断,而目前的中断已经在上一步中置位了,然后就触发对应的IST事件; 5).IST就绪,服务于中断设备,然后完成对中断的处理; 6).IST调用InterruptDone函数,该函数将顺序调用OAL层的OEMInterruptDone函数,它将重新使能当前的中断。 1.1物理中断和逻辑中断的对应关系如何建立 这个函数用将物理中断号来获取逻辑中断号: KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &g_PwrButtonIrq, sizeof(UINT32), &g_PwrButtonSysIntr, sizeof(UINT32), NULL)) 其中:UINT32 g_PwrButtonIrq = IRQ_EINT0; 从help里面查出,KernelIoControl函数最终是调用OEMIoControl函数。 在D:\WINCE500\PLATFORM\COMMON\SRC\COMMON\IOCTL里找到它的定义了,关键代码: // Execute the handler rc = g_oalIoCtlTable.pfnHandler( code, pInBuffer, inSize, pOutBuffer, outSize, pOutSize );在SMDK2440\Src\Kernel\Oal\ioctl.c中可以找到: const OAL_IOCTL_HANDLER g_oalIoCtlTable[] = { #include "ioctl_tab.h" }; 在SMDK2440\Src\Inc\ioctl_tab.h文件中,找到这个表的定义。这个命令对应的函数是OALIoCtlHalRequestSysIntr。 PLATFORM\COMMON\SRC\COMMON\IOCTL\ioctl.c找到这个函数定义: // Find if it is new or old call type if (inpSize > sizeof(UINT32) && pInpData[0] == -1) { // Second UINT32 contains flags, third and subsequents IRQs sysIntr = OALIntrRequestSysIntr(inpSize/sizeof(UINT32) - 2, &pInpData[2], pInpData[1]); } else { // This is legacy call, first UINT32 contains IRQ sysIntr = OALIntrRequestSysIntr(1, pInpData, 0); } 在WINCE500\PLATFORM\COMMON\SRC\COMMON\INTR\BASE\map.c找到OALIntrRequestSysIntr定义: irq = pIrqs[0]; sysIntr = g_oalIrq2SysIntr[irq]; 在同一个文件中定义:static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM]; 对这个表格赋值仅有两个地方:VOID OALIntrStaticTranslate(UINT32 sysIntr, UINT32 irq) { OALMSG(OAL_FUNC&&OAL_INTR, ( L"+OALIntrStaticTranslate(%d, %d)\r\n", sysIntr, irq )); if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) { g_oalSysIntr2Irq[sysIntr] = irq; g_oalIrq2SysIntr[irq] = sysIntr; } OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrStaticTranslate\r\n")); } OALIntrStaticTranslate和OALIntrRequestSysIntr本身两个函数负责建立对应表。后者如果在现有的中断表中找不到已经建立的对应关系,就会分配一个未定义的Sysintr逻辑中断号给这个物理中断号。因此逻辑中断和物理中断的对应,可以说是随机的,只要保证两者是一一对应就好了,不必要硬性建立一个中断号表格(像WINCE4.2那样)。代码中只找到OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);是静态对应。当中断处理程序获得了逻辑中断号,那么就会触发该中断号关联着的事件。 1.2核心部分的中断处理程序如何获得物理中断号 这个问题的目的是:如何添加一个原来系统中没有的物理中断。Physical interrupts (IRQs) are hardware lines over which devices can send interrupt signals to the microprocessor. Logical interrupts (SYSINTRs) are a mapping of the IRQ, which the OAL specifies.一般情况下将ISR与中断处理程序相关联的注册在系统启动的时候进行。在启动过程中,在OAL层kernel调用OEMInit函数。然后,OEMInit调用HookInterrupt 函数来通知中断处理程序,哪些ISR对应到某个物理中断。WINCE500\PUBLIC\COMMON\OAK\INC\nkintr.h,定义了某些逻辑中断号,声明了hookInterrupt等函数。除此之外,再没有hookInterrupt的定义。看看WINCE500\PLATFORM\SMDK2440A\src\kernel\oal\init.c里面的OEMinit函数做了些什么: // Initialize interrupts if (!OALIntrInit()) { OALMSG(OAL_ERROR, ( L"ERROR: OEMInit: failed to initialize interrupts\r\n" )); } OALIntrInit函数在WINCE500\PLATFORM\COMMON\SRC\ARM\SAMSUNG\S3C2440A\Intr\intr.c文件中定义:调用OALIntrMapInit()函数初始化寄存器;最后调用: #ifdef OAL_BSP_CALLBACKS // Give BSP change to initialize subordinate controller rc = BSPIntrInit(); #else rc = TRUE; #endif OALIntrMapInit()函数里面对两个中断表做了初始化: for (i = 0; i < SYSINTR_MAXIMUM; i++) { g_oalSysIntr2Irq = OAL_INTR_IRQ_UNDEFINED; } for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) { g_oalIrq2SysIntr = SYSINTR_UNDEFINED; } WINCE500\PLATFORM\COMMON\SRC\ARM\SAMSUNG\S3C2440A\Intr\sources: TARGETNAME=oal_intr_s3c2440a TARGETTYPE=LIBRARY SYNCHRONIZE_DRAIN=1 NOMIPS16CODE=1 CDEFINES=$(CDEFINES) -DCEDDK_USEDDKMACRO -DOAL_BSP_CALLBACKS ---------------------------------------------------------------------------------- CDEFINES=-DSomeDef : This sets one or more preprocessor definitions. You must include the -D switch on each define you add. You can add new defines by using this syntax: "CDEFINES=$(CDEFINES) -DAnotherDef", or you can ignore existing settings with this syntax: "CDEFINES=-DOnlyDef". ---------------------------------------------------------------------------------- 因此BSPIntrInit会被执行。 在WINCE500\PLATFORM\SMDK2440A\Src\Kernel\Oal\intr.c有这个函数的定义: // Set GPG1 as EINT9 // Add static mapping for Built-In OHCI OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH); 到这里,无法了解如何添加一个物理中断。在CPU接收到中断后,对中断的处理是在 OEMInterruptHandler()中,该函数的首先屏蔽该中断,最后得到实际中断IRQ所对应的sysintr的值”OEMInterruptHandler函数在WINCE500\PLATFORM\COMMON\SRC\ARM\SAMSUNG\S3C2440A\Intr\intr.c文件中,感觉到它实际上就是上面中断序列中谈到的“中断处理程序”和ISR。就是说,中断发生之后,CPU并不知道到底是哪个中断发生了,实际上WINCE中也没有建立中断矢量表,而是直接跳转到OEMInterruptHandler函数,然后在其中查看g_pIntrRegs->INTOFFSET寄存器,来查看到底发生了什么中断。 在s3c2440a_intr.h文件里面有中断号宏定义: #define IRQ_EINT0 0 // Arbiter 0 #define IRQ_EINT1 1 #define IRQ_EINT2 2 #define IRQ_EINT3 3...... INTOFFSET寄存器的值与这个宏定义是完全一一对应。这样,也就搞清楚了物理中断号如何获得,又如何对应到逻辑中断号,最后,触发了IST,整个中断处理就结束了。2440全部的中断源都已经被纳入了,添加一个采用某个中断源的设备驱动,只需要用kernelIOControl函数通过物理中断产生一个逻辑中断号就可以了!这样的话,只要在0x18位置有一个跳转指令就可以了(但还没有找到这条跳转指令)。 1.3 其他中断相关函数了解 关注WINCE500\PLATFORM\COMMON\SRC\ARM\SAMSUNG\S3C2440A\Intr\intr.c中的其他函数: OEMInterruptHandler包含了对以下中断的判断和处理: IRQ_TIMER4,这个是系统节拍; IRQ_TIMER2,作用未知(Profiling timer); IRQ_EINT4_7,EINT8_23,外部中断; 任何一个中断发生后,先mask该中断(禁止中断),然后再清除中断请求: mask = 1 << irq; SETREG32(&g_pIntrRegs->INTMSK, mask); OUTREG32(&g_pIntrRegs->SRCPND, mask); OUTREG32(&g_pIntrRegs->INTPND, mask); 其它中断获取逻辑中断号: // First find if IRQ is claimed by chain sysIntr = NKCallIntChain((UCHAR)irq); if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) { // IRQ wasn't claimed, use static mapping sysIntr = OALIntrTranslateIrq(irq); } 关于NKCallIntChain的说明: 如果没有与ISR关联的IRQ事件,返回SYSINTR_CHAIN ; 除此之外,将返回IRQ对应的SYSINTR值。 posted @ 2010-07-30 16:23 jiege 阅读(57) | 评论(0) | 编辑
转载:http://www./thread-29658-1-1.html2 OAL层中断程序汇总 关于WinCE的中断处理,OAL中主要是实现了ISR部分,一般IST会在设备驱动中实现。架构如图:硬件中断产生以后,会导致内核ISR的运行,然后由OAL中的ISR来处理相应的中断,最后导致相对应的IST运行完成真正的中断处理。所以在WinCE中,中断处理由ISR和IST共同完成。ISR主要完成中断源的确定,屏蔽该中断并返回给内核相对应的系统中断号,ISR应该尽量短小。IST则是完成真正的中断处理,比如数据的传输和解析等。当然不是所有的中断处理都需要ISR和IST,看需要,比如WinCE的系统Timer中断就只需要ISR完成。 2.1 在OAL中支持中断,需要实现以下几个中断处理函数 a. BOOL OEMInterruptEnable(DWORD sysIntr, VOID* pData, DWORD dataSize) sysIntr:要被使能的系统中断号 pData:传入的数据指针,该数据由InterruptInitialize函数传入 dataSize:传入数据的大小 该函数用于使能某一个硬件中断。在设备驱动调用InterruptInitialize来初始化一个中断的时候,内核就会调用该函数来使能相应的硬件中断。 b. VOID OEMInterruptDisable(DWORD sysIntr) sysIntr:要被屏蔽的系统中断号 该函数用于屏蔽一个硬件中断。如果设备驱动调用InterruptDisable函数,则该函数会被调用。 c. VOID OEMInterruptDone(DWORD sysIntr) sysIntr:要被重新使能的系统中断号 该函数标志着一个中断处理过程的完成。当设备驱动调用InterruptDone函数的时候,该函数会被调用,重新使能相应的硬件中断。 d. ULONG OEMInterruptHandler(ULONG ra) ra:指令计数,在实际应用中,没有太大意义 当硬件中断产生的时候,该函数就会被调用完成ISR部分的中断处理。一般会在该函数中读取系统的中断标记位,确定中断源并返回相应的系统中断号。 e. void OEMInterruptHandlerFIQ(void) 针对于ARM处理器,该函数用于处理快速中断。 上面5个函数完成了中断的相关处理。这里要提到两个概念:IRQ和SYSINTR。IRQ是指物理中断或者叫硬件中断,而SYSINTR指的是系统中断,也有的地方称为虚拟中断或者逻辑中断,我个人觉得还是叫系统中断比较好。每一个IRQ会和一个系统中断SYSINTR相对应,当硬件中断产生时,ISR实际上是处理IRQ中断,然后返回相应的系统中断SYSINTR给内核,内核会根据相应的SYSINTR触发相应的IST来完成中断处理。 IRQ和SYSINTR之间的对应关系称为映射,分为静态映射和动态映射。静态映射是指在系统编译时IRQ已经和SYSINTR相对应,一般通过OALIntrStaticTranslate函数来实现。而动态映射是指WinCE系统启动后,动态关联IRQ与SYSINTR,一般通过KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR…)来实现。 SYSINTR的类型在nkintr.h中定义,OEMInterruptHandler函数在处理完中断以后,会返回不同类型的SYSINTR给内核,内核会根据返回值进行下一步操作,分为以下几种类型: SYSINTR_NOP:表示不需要进行任何处理 SYSINTR_RESCHED:表示要进行一次系统调度 SYSINTR_CHAIN:表示不是该中断源产生,在中断链中寻找下一个中断 SYSINTR_RTC_ALARM:表示RTC报警产生 SYSINTR_TIMING:用于ILTiming测试 SYSINTR_PROFILE:用于系统的profile SYSINTR_FIRMWARE:用于用户自定义系统中断号,所有自定义的系统中断号都应该基于该值进行累加加1,这些自定义的系统中断号用于和IRQ一一对应。
2.2 PQOAL架构下中断的实现 posted @ 2010-07-30 16:22 jiege 阅读(46) | 评论(0) | 编辑
申请大容量的物理内存看起来不是难事。这里的大容量是指几十MB甚至更多的物理内存。对于C++程序员来说可能平时习惯了使用“new”操作符来实现。我也是这样。使用“new”非常简单,申请之后只需判断返回的指针是否是空即可。在其它的Windows操作系统上的确不需要在申请大容量物理内存上过多考虑。但是在Windows CE上就不同了。如果只用“new”就能搞定,那就太省事了。 不知道Windows CE下软件开发者是否遇到过这种情况,如果使用“new”申请超过30MB的物理内存,那么返回的一定是空(NULL),甚至程序会死锁无法响应。这其实不奇怪。在《Windows CE下进程、线程和内存管理》的系列文章中我早有所言,Windows CE下每个进程占有32MB的地址空间,虽然Slot 1槽存放所有的非XIP DLL,但是我们不可能占用Slot 1槽。32MB地址空间减去必要的代码段、静态数据段、默认堆和默认栈之后,所剩的地址空间少于32MB。即使程序什么都不做也无法满足超过30MB的地址空间的申请需求。所以返回为空非常正常。好在Windows CE下运行的大多数软件不需要那么多的物理内存。 感觉微软的技术不是支持到很远的将来,而是得过且过,只要满足目前的和不远的将来的需求就行。拿Platform Builder来说,IMGRAM64环境变量用于支持64MB物理内存。可是没有IMGRAM128或者IMGRAM256甚至IMGRAM512。可能是当时绝大多数基于Windows CE的产品都没有过64MB物理内存。现在要支持超过64MB物理内存就必须做一些修改操作。再如现在说的用“new”分配物理内存,也只是限制在32MB以内。如果想new多少就new多少,那多爽! “new”不行是因为地址空间不够,那我们可以采用虚拟内存分配,然后提交物理内存这种办法。理论上是这样,但是实际上还是不行。举例如下:
上面这段代码中第一个语句是申请32MB的虚拟地址空间,函数返回一个地址说明申请是成功的。注意这个地址一定处于0x4200 0000以上(具体参见我的专栏中《Windows CE下进程、线程和内存管理(三)》)。第二个语句是提交物理内存,容量为32MB。这个函数返回NULL,说明申请物理内存不成功。如果申请10MB、20MB的还可以。 希望再一次破灭。最后的办法就是内存映射文件了。在Windows CE的帮助文档中只提到了内存映射文件可以用来申请虚拟地址空间。可以试一试。结果证明用内存映射文件来申请大容量物理内存是可行的。内存映射文件用于多个进程共享数据时,创建内存映射的函数的第一个参数必须设置为INVALID_HANDLE_VALUE,表示在物理内存中创建。利用这个特点我们可以申请超过32MB的物理内存。具体能够申请的大小由剩余的物理内存决定。例子如下:
上述的函数如果都成功了,你就可以使用物理内存了。虚拟内存的首地址是lpAddress。使用完了别忘了调用函数UnmapViewOfFile(lpAddress); 和CloseHandle(hFile); posted @ 2010-07-30 14:36 jiege 阅读(11) | 评论(0) | 编辑
一般在ARM架构的CPU上,物理地址都是统一编址的,寻址空间为4GB(32Bit CPU)。也就是说,针对一个ARM的处理器,它可以访问的物理空间是4GB。在WinCE中,ARM中的4GB物理地址空间将被映射为512MB的虚拟内存空间。 OEMAddressTable就是一个4GB物理地址空间到WinCE Kernel中的512MB虚拟地址空间的映射表。 在BSP中,会定义OEMAddressTable来描述系统中可访问的物理空间及对应的虚拟地址空间,还有大小。这个表会在WinCE系统开始启动的时候传给MMU,具体到BSP中应该是在OAL中的startup.s中,OEMAddressTable的起始地址会被放到r0寄存器中,然后就跳转到KernelStart里面,KernelStart会用OEMAddressTable完成MMU得初始化。当WinCE启动以后,就只能访问虚拟地址空间了。 举个例子,比如我们要开发一个Flash的驱动程序,那么首先我们知道这个flash所接的片选对应的物理起始地址是多少(假如是0x60000000),大小是多少(假如是0x2000000)。如果我们要在WinCE中访问它,就必须为它定义一个虚拟地址(假如是0x80000000),并添加到OEMAddressTable中,这样,我们才能在我们的驱动里面通过这个虚拟地址访问到flash。 虚拟地址不是随便定义的,WinCE中有规定,必须在0x80000000---0x9FFFFFFF。实际上WinCE创建了两套虚拟地址空间,一个是0x80000000---0x9FFFFFFF,是Cache Enabled。另一个是0xA0000000---0xBFFFFFFF,是Cache Disabled。有啥区别呢: 如果我们访问的这个空间只是一段内存空间(比如SDRAM),那么就可以用Cache Enabled的空间来访问,这样存取数据的速度会比较快,因为数据被保存在Cache中。 如果我们访问的这个空间是一个外设的地址,那么我们就要使用Cached Disabled的空间来访问,这样才能使CPU与外设同步。 可能说得有点绕,我的经验就是:只要是SDRAM,可以用Cache Enabled空间访问。如果是寄存器,就用Cache Disabled空间访问。 如何定义OEMAddressTable呢,如果安装了WinCE5.0或者6.0,那么提供的参考BSP中都已经有定义了,在BSP目录下搜索“OEMAddressTable”,一看代码就明白了,这里重复一下,格式如下: 比如: OEMAddressTable: dd dd 上面这个表定义了一个flash的物理地址到虚拟地址的映射,物理地址是0x60000000,虚拟地址是0x80000000,大小是32MB。OEMAddressTable最后必须以0结尾,表示OEMAddressTable结束。 总之,说白了就是一张物理地址/虚拟地址映射表,当我们要在WinCE中要访问相关硬件的时候,查查这张表,然后通过虚拟地址就可以访问了。如果没有定义,自己添加一个物理地址到虚拟地址的映射就好了。 posted @ 2010-07-30 13:38 jiege 阅读(115) | 评论(0) | 编辑
文章来源:http://www.cnblogs.com/lonemaverick/archive/2007/02/16/651481.html GPIO是ARM芯片最基本的输入输出通道,在ADS下操作就是一个单片机工作,直接读写其寄存器。在ARM9平台上,Windows CE系统将GPIO的实地址(例如2410的GPIO的基地址为0x56000000)映射到虚拟地址空间(GPIO对应为0xB1600000),这样,通过对这段虚拟地址空间的操作,就能够完成对GPIO或者其他片内资源的控制、输入输出工作。 #define IOP_BASE 0xB1600000 // 0x56000000 2.在EVC中建立一个应用程序工程,由于VirtualCopy函数没有在头文件中定义,但是在coredll.lib里面提供了符号连接,所以我们这里直接添加一个函数定义就OK了。 BOOL VirtualCopy( LPVOID, LPVOID, DWORD, DWORD ); #ifdef __cplusplus 3.按照驱动程序里面操作的方法在应用程序中写GPIO操作函数 更多的操作,需要查阅ARM的datasheet以及WINCE的BSP源码完成。 对于非ARM的平台,在CE下操作,也可以参考这个思路。
posted @ 2010-07-30 12:36 jiege 阅读(45) | 评论(0) | 编辑
刚学wince那会,对wince下面的文件存储老是理解不了,或者说容易搞混. 最近公司在做一个wince下的终端移植项目,中间也遇到了一些存储方面的问题,我自己学wince也有一段时间了,现在对wince的几个存储的概念也可以谈论一二了. 现在市场上的基于wince的板子,基本上有下面几种存储设备, nand flash, nor flash, SDRAM, SD卡, u 盘. SD卡和U盘不说了,跟PC机没什么驱别. 先说说nand flash(nor flash就不说了,类似), 你可以把它理解为电脑上的硬盘, OK, 我们看一下电脑上的硬盘里放了什么?, 首先是你的操作系统文件占据了C盘的一部分空间, C盘剩下的空间以及其它盘的空间就是你可以随便用的. 再来看看nand flash, 它一般被分为三个部分, 首先是一个叫boot loader的东东,然后是你的wince的映像文件, 最后剩下的部分的就是你可以任意使用的. Boot loader 主要做两件事,一是初始化一些硬件资源(比如cache), 二是加载wince系统运行. 你可能要说,nand flash与电脑硬盘的区别就是它多了一个boot loader. 其实这样说不完全对,电脑其实也有一个bootloader, 它的名字叫BIOS. 只不过BIOS不是放在硬盘里,而是固化在主板上的只读ROM里. Nand flash剩下的这部分这间怎么用呢,wince第一次启动时,打开”我的设备”是看不到这部分空间的,需要你到”存储器管理器”(在控制面板里)去格式化一下,然后新建一个分区. 这之后即使你冷启动系统,它也是可见的. 有个问题我们都很想知道,wince最大可以支持多大的nand flash呢? 一般情况下,bootloader也就是几百K, wince系统映像几十M, 我们当然是希望nand flash越大越好, 这样我们能任意支配的空间就大了. 先来看一下PC上最大可以支持多大的硬盘容量. 目前市场上已出了T数量级的硬盘, 你的电脑能支持的硬盘容量是什么决定呢. 是主板,再具体点,是BIOS,如果你的主板支持48 bit LBA(寻址), 则硬盘最大可以是2的48次方. 是不是wince能支持的最大nandflash也不是wince系统决定的呢. 市场上的nand flash 芯片硬件接口无非是下面几部分,控制引脚,数据引脚夫,电源和地引脚. 然后数据口和地址是复用的. 下面是K9F1208U0B的引脚图,可以很清楚的看到上面几部分(NC表示不用)
是了,只要能和CPU在硬件上接口匹配,然后bootloader里驱动做相应改动,就可以支持市场上最大的nand flash, 目前市场上最大的nand flash容量我不是很清楚,但06年三星就已经推出了32G的nand flash, 所以现在最大的容量起码也得大过这个数. Nand flash. 好了,该说说wince下的内存了. 一般我们买一块基于wince的开发板,如果厂家说这个板子的内存是64M, 一般就是说SDRAM有64M, wince的内存在硬件上就是这个SDRAM(至于什么是SDRAM,网上有很多资料). Wince 下的内存实际上是分为三个部分的. 先说这几部分的名字,对象存储, 系统内存,程序内存. 准确来讲,应该用下面公式说明. Wince内存 = 系统内存 + (对象存储 + 程序内存). 为什么要把后面两个用括号括起来呢. 是为了强调它们的关系密切. 拿64M的这个板子举例. 开发板上电, 进入控制面板—系统,上面显示内存是30M左右, 怪了,明明是64M的DRAM,怎么少了近一半? 要回答这个问题, 先来看看PC机上的情况, 假设你的电脑内存是1G, 开机,你没有运行任何程序, 打开任务管理器, 内存已经用了200多M了(不同的机器可能有点不同), 你应该已经想到是为什么了,操作系统本身运行也是要用内存的. Wince运行也要占用内存, 这就是前面为什么少了30多M的内存. 这部分内存我把它叫系统内存, 或者说是wince映像占用的数据内存. 是不是剩下的30M左右的内存就可以完全给我们自己写的程序用了呢, 当然不是, 看一下前面的公式, 剩下的内存又被分成了两部分,对象存储和程序内存. 程序内存不用解释,就是可供我们的程序用的内存, 对象存储是wince里一个新的概念. 嵌入式wince操作系统一般是用在消费电子上面, 比如pocket pc, 手机, PDA等移动设备上. 这一类的设备一般都是有两个电源的, 一个是主电源(比如你的手机电池), 一个是后备电池(拆开手机,电路板上可以找到那个小电池). 后备电池的作用就是在主电源没电的情况下,维持操作系统的一些需要保存的数据, 比如注册表, 数据库等. 而这些要保存的数据就是放在对象存储里的,可以复制一个文件到wince下(SD卡,U盘除外),会发现对象存储占用空间变大,到这里,你应该理解对象存储了
好了,内存的三部分搞清楚了, 你可能想知道,这三部分的比例是怎么分的呢,是系统固定死了吗, 当然不会, 嵌入式的设备种类有上千种,嵌入式操作系统应该具有充分的灵活性满足不同的需要. 先看看系统内存怎么改.用pb打开一个你的工程, 在config.bib里的Memory域里(bib文件的格式和作用可以去网上查), 会看到类似下面的语句: NK 80001000 01E00000 RAMIMAGE 第一个数是起始地址,第二个就是size了. 对象存储和程序内存的大小修改就比较人性化了, 打开控制面板-存储器管理器,可以看到一个滑块,左右移动它就可以改变它们的比例. 但是有一点要注意,这个设置是不会被保存的, 系统冷启动后还是会恢复默认设置的(一般是各占一半). 那怎么办呢?有办法, 如果你在配置系统时就知道这两部分内存所要占的比例,可以在config.bib里加上下面的语句 FSRAMPERCENT = 0Xxxxxxxxx 这个值可以改变默认设置. 最后一个问题, wince最大支持多大的物理内存, 也就是SDRAM最大可以是多少. 这个是由CPU决定的, 拿三星的2410举个例子. 打开芯片手册,找到Memory controller那个章节,可以看到下面这个图 清楚了,只有最后两个bank支持SDRAM,每个bank最大128m, 所以最大2410最大支持256M的SDRAM. 就说这么多吧,希望对大家有帮助. |
|