最新日志

发表于:2008-5-12 15:18:03
标签:无标签

0

s3c2410 Timer(转)

s3c2410 Timer
2007-10-22 15:51
作者:蔡于清
www.another-prj.com


s3c2410提供了5个16位的Timer(Timer0~Timer4),其中Timer0~Timer3支持Pulse Width Modulation—— PWM(脉宽调制 )。Timer4是一个内部定时器(internal timer),他没有输出引脚(output pins)。
下面是Timer的工作原理图。
点击在新窗口查看全图
[attach]60[/attach]
如上图所示,PCLK是Timer的信号源,我们通过设置每个Timer相应的PrescalerClock Divider把PCLK转换成输入时钟信号传送给各个Timer的逻辑控制单元(Control Logic),事实上每个Timer都有一个称为输入时钟频率(Timer input clock Frequency)的参数,这个频率就是通过PCLK,Prescaler和Clock Divider确定下来的,每个Timer 的逻辑控制单元就是以这个频率在工作。下面给出输入时钟频率的公式:

Timer input clock Frequency = PCLK / {prescaler value+1} / {clock divider }
{prescaler value} = 0~255
{ clock divider } = 2, 4, 8, 16


然而并不是每一个Timer都有对应的Prescaler和Clock Divider,从上面的原理图我们可以看到Timer0,Timer1共用一对Prescaler和Clock Divider,Timer2,Timer3,Timer4共用另一对Prescaler和Clock Divider,s3c2410的整个时钟系统模块只存在两对Prescaler和Clock Divider。

我曾经在讨论watchdog的文章中提到,watchdog也是一种定时器,他的工作就是在一个单位时间内对一个给定的数值进行递减和比较的操作,而我们这篇文章讨论的定时器他的工作内容和watchdog在本质上是一样的。定时器在一个工作周期(Timer input clock cycle)内的具体工作内容主要有3个。分别是:

1.        对一个数值进行递减操作
2.        把递减后的数值和另一个数值进行比较操作
3.        产生中断或执行DMA操作


在启用Timer之前我们会对Timer进行一系列初始化操作,这些操作包括上面提到的设置Prescaler和Clock Divider,其中还有一个非常重要的就是要给Timer两个数值,我们分别称之为Counter(变量,用于递减)和Comparer(定值,用于比较),Counter会被Timer 加载到COUNT BUFFER REGISTER(TCNTB),而Comparer会被Timer 加载到和COMPARE BUFFER REGISTER(TCMPB),每个Timer都有这样两个寄存器。当我们设置完毕启动Timer之后,Timer在一个工作周期内所做的就是先把TCNTB中的数值(Counter)减1,之后把TCNTB中的数值和TCMPB中的数值(Comparer)进行对比,若Counter已经被递减到等于Comparer,发生计数超出,则Timer产生中断信号(或是执行DMA操作)并自动把Counter重新装入TCNTB(刷新TCNTB以重新进行递减)。以上就是Timer的工作原理。

下面我们结合代码具体说明如何对Timer0进行初始化并开启它。
首先我假设我的PCLK是50700000Hz

// define Timer register
#define rTCFG0 (*(volatile unsigned int *)0x51000000)
#define rTCFG1 (*(volatile unsigned int *)0x51000004)
#define rTCON (*(volatile unsigned int *)0x51000008)
#define rTCNTB0 (*(volatile unsigned int *)0x5100000C)
#define rTCMPB0 (*(volatile unsigned int *)0x51000010)
#define rTCNTO0 (*(volatile unsigned int *)0x51000014)
#define rTCNTB1 (*(volatile unsigned int *)0x51000018)
#define rTCMPB1 (*(volatile unsigned int *)0x5100001C)
#define rTCNTO1 (*(volatile unsigned int *)0x51000020)
#define rTCNTB2 (*(volatile unsigned int *)0x51000024)
#define rTCMPB2 (*(volatile unsigned int *)0x51000028)
#define rTCNTO2 (*(volatile unsigned int *)0x5100002C)
#define rTCNTB3 (*(volatile unsigned int *)0x51000030)
#define rTCMPB3 (*(volatile unsigned int *)0x51000034)
#define rTCNTO3 (*(volatile unsigned int *)0x51000038)
#define rTCNTB4 (*(volatile unsigned int *)0x5100003C)
#define rTCNTO4 (*(volatile unsigned int *)0x51000040)


void timer0_config()
{

/*
            Timer0的prescaler由rTCFG0 的 0~7 bit决定
            Prescaler="119"
*/

            rTCFG0=119       
/*
            Timer0的divider value由TCFG1的 0~3 bit决定,设置为3表示divider value = 1/16
            rTCFG1的第20~23bit用于决定Timer计数超出后所采取的响应,我们使用了中断模式(20~23bit全部为0),
            即计数超出后产生中断
*/

            rTCFG1=3;
      
            rTCNTB0=26406;
            rTCMPB0=0;
}

由于我们的PCLK是50700000Hz, 根据Timer input clock Frequency的计算公式我们如下计算Timer0的时钟输入频率:

prescaler value = 119
divider value = 1/16
PCLK= 50700000
Timer input clock Frequency =50700000/ (119+1)/(1/16)=26406

也就是说通过设置prescaler和divider value之后,Timer0的工作频率为26406,也就是说一秒内Timer0会进行26406次递减和比较操作,假设我们现在是要让Timer0每1秒产生一次中断的话,我们应该设置Counter=26406和Camparer=0,既:
rTCNTB0=26406;
rTCMPB0=0;

如果我们要让Timer0每0.5秒产生一次中断,则我们应该设置Counter=26406/2和Camparer=0,既:
rTCNTB0=13203;
rTCMPB0=0;

如果我们要让Timer0每0.25秒产生一次中断,则我们应该设置Counter=26406/4和Camparer=0,既:
rTCNTB0=6601;
rTCMPB0=0;

初始化完Timer后我们要开启它。

void timer0_start()
{

/*
            Update TCNTB0 & TCMPB0
            rTCON寄存器的第1位是刷新Timer0的COUNT BUFFER REGISTER(TCNTB)和
            COMPARE BUFFER REGISTER(TCMPB),由于是第一次加载Counter和Comparer,
            所以我们需要手动刷新它们
*/

             rTCON|=1<<1;
/*
            置rTCON第0位为1,开启Timer0
            把rTCON第1位置为0,停止刷新TCNTB0 和 TCMPB0
            置rTCON第3位为1,设置Counter的加载模式为自动加载(auto reload),这样每当
            Timer计数超出之后(此时TCNTB的值等于TCMPB的值),Timer会自动把原来我们给
            定的Counter重新加载到TCNTB中
*/

      rTCON=0x09;       
}


要使你的Timer能够正常的工作,除了调用timer0_config()和timer0_start()之外,我们还必须设置Timer的中断服务例程并取消对Timer的中断的屏蔽.这些操作可以参考<<s3c2410 中断异常处理>>一文.
另外OS实验区提供的源代码中有更为详细的代码,需要的朋友可以参考,关于Timer的代码存在于timer.c timer.h文件中

点击此处查看原文 >>

系统分类: ARM   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(49)
发表于:2008-5-10 13:35:16
标签:无标签

0

平台号的设置

平台的设置在D:\WINCE420\PLATFORM\SMDK2440\KERNEL\HAL\oemioctl.c

能过下列函数可以进行读取

SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(platformstring), &platformstring,0);

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类: 无分类    |    来源: 原创

评论(0) | 阅读(163)
发表于:2008-5-10 13:24:25
标签:无标签

0

NETCF运行平台检测

该文章参考了https://blogs.msdn.com/netcfteam/archive/2006/09/15/756755.aspx,上面详细介绍了如何在程序中检测NETCF的各种运行平台,此处对于其中的代码片段进行了整理。
 
测试过程中发现文章中提供的代码存在兼容性问题,这源于一次偶然性的测试,当时用的是HP和SIEMENS的PDA进行测试,发现SIEMENS中当获取OEM信息时抛出异常,尝试性的进行了修改,居然解决了问题。具体的注释在代码中有详细的说明。
 
鉴于有些PDA程序被要求在PC上面兼容运行,这也是客户的一个需求。在此对文章中的代码进行了改进。文章中的代码原本被设计为在NETCF中运行,且使用了PINVOKE调用PDA中的相关底层函数,此代码如果在PC中运行,将产生不可预料的结果。由于当在PC上运行时,实际上是由.NET Framework的完整版本在执行代码,已经失去了对目标平台检测的意义。所以为了防止不可预料的结果出现,对相关代码做了修改。这一功能的实现是通过一个新添加的方法IsWinCE来实现的。该方法也可以向调用方提供必要的信息,作为检测实际执行代码的Framework的方法,具体参见源代码。
 
最终版本提供的检测功能:
  • IsWinCE ()
  • IsEmulator ()
  • IsSmartPhone ()
  • IsPockPC ()
  • IsTouchScreen ()
源码如下:
using System;
using System.IO;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Text;

namespace PlatformDetection
{
    
internal class PInvoke
    
{
        [DllImport(
"Coredll.dll", EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode)]
        
static extern int SystemParametersInfo4Strings(uint uiAction, uint uiParam, StringBuilder pvParam, uint fWinIni);

        
const int MAX_PATH = 260;
        [DllImport(
"Coredll.dll")]
        
static extern int SHGetSpecialFolderPath(IntPtr hwndOwner, StringBuilder lpszPath, int nFolder, int fCreate);

        
public enum SystemParametersInfoActions : uint
        
{
            SPI_GETPLATFORMTYPE 
= 257// this is used elsewhere for Smartphone/PocketPC detection
            SPI_GETOEMINFO = 258,
        }


        
public static string GetOemInfo()
        
{
            
//10/26/2006 wangyun Change from 50 to 100, as it doesn't work on "FUJITSU SIEMENS COMPUTERS Pocket LOOX"
            StringBuilder oemInfo = new StringBuilder(100);
            
if (SystemParametersInfo4Strings((uint)SystemParametersInfoActions.SPI_GETOEMINFO,
                    (
uint)oemInfo.Capacity, oemInfo, 0== 0)
                
throw new Exception("Error getting OEM info.");
            
return oemInfo.ToString();
        }


        
public static string GetPlatformType()
        
{
            
//10/26/2006 wangyun Change from 50 to 100 to avoid the possible bug as above
            StringBuilder platformType = new StringBuilder(100);
            
if (SystemParametersInfo4Strings((uint)SystemParametersInfoActions.SPI_GETPLATFORMTYPE,
                (
uint)platformType.Capacity, platformType, 0== 0)
                
throw new Exception("Error getting platform type.");
            
return platformType.ToString();
        }


        
public enum SpecialFolders : int
        
{
            CSIDL_WINDOWS 
= 0x0024,
        }


        
public static string GetSpecialFolder(SpecialFolders specialFolder)
        
{
            StringBuilder path 
= new StringBuilder(MAX_PATH);
            
if (SHGetSpecialFolderPath(IntPtr.Zero, path, (int)specialFolder, 0== 0)
                
throw new Exception("Error getting Windows path.");
            
return path.ToString();
        }

    }


    
public class PlatformDetection
    
{
        
private const string MicrosoftEmulatorOemValue = "Microsoft DeviceEmulator";

        
//10/26/2006 wangyun To effect compatibility between PC and PDA devices
        public static bool IsWinCE()
        
{
            
return System.Environment.OSVersion.Platform == PlatformID.WinCE;
        }


        
public static bool IsEmulator()
        
{
            
if (IsWinCE())
                
return PInvoke.GetOemInfo() == MicrosoftEmulatorOemValue;
            
else
                
return false;
        }


        
public static bool IsSmartphone()
        
{
            
if (IsWinCE())
                
return PInvoke.GetPlatformType() == "SmartPhone";
            
else
                
return false;
        }


        
public static bool IsPocketPC()
        
{
            
if (IsWinCE())
                
return PInvoke.GetPlatformType() == "PocketPC";
            
else
                
return false;
        }


        
public static bool IsTouchScreen()
        
{
            
if (IsWinCE())
            
{
                
string driverFileName = Registry.GetValue(@"HKEY_LOCAL_MACHINE\Hardware\DeviceMap\Touch",
                    
"DriverName""touch.dll").ToString();
                
string windowsFolder = PInvoke.GetSpecialFolder(PInvoke.SpecialFolders.CSIDL_WINDOWS);
                
string driverPath = Path.Combine(windowsFolder, driverFileName);
                
bool driverExists = File.Exists(driverPath);

                
return
                    driverExists 
&&
                    
// Windows Mobile 5.0 Smartphone emulator and earlier has a driver, but no touch screen.
                    !(IsSmartphone() && IsEmulator() && Environment.OSVersion.Version.Major < 6);
            }

            
else
                
return false;
        }

    }

}

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(48)
发表于:2008-5-10 11:30:15
标签:无标签

0

嵌入式设备的ID确定(转)

关于ID   的问题   我以前也遇到国,   在我看来主要是由于没有经过系统分析师分析过的系统才会出现过这个问题,一般的大公司出来的产品一般都是比较正规的,这些问题都考虑的很全面了。   一般情况下    
  1、存贮介质:  
  硬件ID肯定都是保存在某个EPPROM     或者NOR   FLASH   或者NANDFLASH   之类的存贮介质上。这些介质有某些特殊的区域保存这些资料。  
   
  2、读写控制:  
  一般驱动层提供读写控制接口,那些扇区可读   ,那些可写,怎么样读,怎么样写都是经过严格的定义和约束的。否则,别人可以通过其他途径获取。   好的情况下也是需要进行加密字符串或者可识别信息的。  
  3、上层应用程序访问接口:  
  通过驱动程序或者系统标准接口,提供给应用程序一套标准的调用接口,在WINCE4.2   下    
  一般提供了  
  BOOL   KernelIoControl(    
      DWORD   dwIoControlCode,    
      LPVOID   lpInBuf,    
      DWORD   nInBufSize,    
      LPVOID   lpOutBuf,    
      DWORD   nOutBufSize,    
      LPDWORD   lpBytesReturned    
  );    
  或者  
  SystemParametersInfo()『SPI_GETOEMINFO、SPI_GETPLATFORMTYPE』   或者:  
   
  IOCTL_HAL_GET_DEVICE_INFO    
  IOCTL_HAL_GET_UUID    
  IOCTL_HAL_QUERY_DEVICE_SETTINGS    
  IOCTL_HAL_GET_DEVICE_INFO.    
   
   
  4、   提供成熟的写入工具提交给生产部门,专门写入guid  
   
   
  希望对你有帮助

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(53)
发表于:2008-4-30 13:44:16
标签:无标签

0

中断代码结构比较之WinCE4.2 VS WinCE5.0 (转)

现在项目要从wince4.2下port到wince5.0下,今天将sd卡的驱动加到wince5下。用的是现有的也就是wince4.2下的驱动程序,几个dll文件:SDBusDriver.dll;SDCSDCard.dll;SDMemory.dll。这个工作主要就是将相应的中断加上就好了。

      下面进入正题。4.2下的中断:InterruptInitialize(具体的驱动中注册中断与事件)->SC_InterruptInitialize(系统的函数,可以根据private\winceos\coreos\nk\kernel\kwin32.c中的const PFNVOID Win32Methods[]数组得知这是一个系统函数。这一步为猜测,该函数在private\winceos\coreos\nk\kernel\intrapi.c中实现。enable中断-通过调用下面的函数,之后将相应的事件放入中断事件队列)->DoInterruptEnable(在private\winceos\coreos\nk\kernel\intrapi.c中实现,先调用pfnOEMTranslateSysIntr映射一下,不过我没有找到这个函数指针的原型。之后才是OEMInterruptEnable)->OEMInterruptEnable(在platform\xxx\kernel\hal\cfw.c中,地球人都知道。在这个文件中有个static void OEMInitInterrupts(void),是在oeminit中被调用的,差点被忽悠了。)这只是enable(也包含初始化),相应的disable和done也在相应的文件中实现。可能用4.2用多了,感觉这些中断的处理一气呵成,很容易理解,就是修改或者增加比较麻烦。要分别处理OEMInterruptXXX中相应的各个中断。
      5.0下的中断:感觉上就一个字“乱”,主要是这些代码分别放在不同的地方,或许这样更合理化吧,谁知道MS怎么想的。主要分布在以下几个地方:(A1)platform\common\src\common\intr;(A2)platform\common\src\xxx(type of cpu)\yyy(intel or samsung or ...)\zzz\intr;(A3)platform\zzz\src\kernel\oal\intr.c。
      5.0下中断初始化流程:从时间上来看先是OEMInit(oal\init.c)->OALIntrInit(A2中实现)->BSPIntrInit(A3中实现,这个地方比较关键了,因为要添加或修改中断就要在这里来做,主要实现SYSINTR_XXX与IRQ_XXX的映射)。OK中断初始化完毕。
     5.0下中断的enable流程:在5.0下面没有找到SC_InterruptInitialize,或者类似的实现,不过我想5.0下面的应该和4.2下面的一样。由驱动的InterruptInitialize最终调用到OEMInterruptEnable(在A1\common\oem.c中实现)->OALIntrEnableIrqs(在A3中实现)->BSPIntrEnableIrq(在A3中实现)。至此enable完成。对应的disbale和done也是在相应的文件中实现。
      从名字上也可以看出来A1提供了一个对内核开放的中断层,由它再去调用对应的oal层的代码A2,A2再在其中调用A3中的代码;则A3中最主要的就是提供一个给程序员注册的一个接口BSPIntrInit。

本文出自 “bluefish” 博客,请务必保留此出处http://bluefish.blog.51cto.com/214870/58125

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(58)
发表于:2008-4-30 13:26:14
标签:无标签

0

WINCE系统开发中的一些小窍门(转)


1.处理设备的热挺拔事件:

调用 RequestDeviceNotifications,然后处理 WM_DEVICECHANGE消息。

2将WINCE4.2 BSP移植到5.0,只需要在OEMInit中调用 OALCacheGlobalsInit()函数,它是 5.0BSP比4.2唯一多出来的一个函数。

3. CETK测试时,不能同时连多个设备,是因为HAL_IOCTL_GET_UUID没有实现,或者不对

4.soft keyboard 不能隐藏,解决方法,ShowWindow( GetParent( g_hwndMain ), SW_HIDE ); 将其父窗口hide

5.CE下同名设备不能大于10

CE5.0中已经没有这个问题了,
以前的版本可以这样做:
只给上层输出一个设备,
然后用一个IOCTL去打开一个个的物理设备
这样就可以做到不受任何限制了

6. XXX_Init函数的返回句柄

通常,这个句柄是驱动程序自己保存数据的一个指针,
我们在Init返回时告诉上层程序,以后上层调用其它函数(例如Open)时,
会将这个值传入,这样,我们就可以访问自己的一些私有数据。

当然,也可以返回一个任意的非0值


对于一个设备驱动程序,系统不用的层会有不同的句柄。
我们在XXX_Init中返回的句柄保存在设备管理器中,别的程序中应该是看不到的,
而用CreateFile也会得到一个文件句柄,这个保存在哪我不知道,
但和前者是不一样的。

也就是说不同层的软件所关心的句柄也会不一样
转自(http://devnote.bloghome.cn/posts/22003.html

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(53)
发表于:2008-4-22 15:19:22
标签:无标签

0

在启动过程中黑一下屏的问题

一直困扰的一个问题今天终于得以解决,记录下来。

现象,在boot过程中log显示中黑屏一次。

首先以为是把那个VCLK进行了设置,经过仔细排查,无任何地方对其进行了改变。后来在NK中设置断点来查询问题点,结果都没找到。

后来使用仿真器进行逐步调试,发现在此出现的问题(位于fw.s)

; ldr r0, = MPLLCON  ; Configure MPLL ; Fin="12MHz", Fout="50MHz"
; ldr r1, = PLLVAL
; str r1, [r0]

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类: 无分类    |    来源: 原创

评论(0) | 阅读(74)
发表于:2008-4-18 9:01:40
标签:无标签

0

移植PPC的XIP探讨[转]

转贴:
提供网上搜到的xip移植方法共享(地址等不适用2046,但是方法应该是共通的)
移植PPC的XIP探讨
有了Kitchen和G'Reloc.exe之后移植WM的高版本的系统已经是简单的事了,但Kitchen没有办法对XIP部份的系统内核进行操作,因此对这一部份的移植得另外用其他办法:
一、准备工具:XIPPort.exe、G’reloc.exe、Winhex.exe、RomMaster.exee等工具,工具的用法在这篇文章中会涉及到一些,但如大部份的工具你都不会用,那这篇文章不适合你,你应该在其他的帖子或是其他的论坛上去潜水进修一下。
二、ROM操作、提XIP、查找XIP在ROM中的地址ROM制作,不管原来的ROM文件是NBF或是HNB文件文件,都要先解出不带加密或是标志插值的干净的WM系统ROM,假设文件名为nk.nb
用RomMaster.exe从ROM中提取出XIP.bin:
    RomMaster.exe -x -w 5 nk.nb -o xip.bin
查找XIP在ROM中的地址,备用
方法:
第一个first xip部分,从FE 03 00 EA 00 00 00 00 00 00 00 00 00 00 00 00
可能在第二个或是第三FE 03 00 EA 00 00 00 00 00 00 00 00 00 00 00 00,到F8 AC 2C 9D .......... ,这一部分应该就是移植内核XIP需要改动的部分最好对比一下提出来的XIP.bin的内容,第4部分:imgfs部分,通常做ROM时修改dump文件夹就是对这里,呵呵!这个也可以作为查找XIP的一个参考,记下XIP区域的FE 03 00 EA 00 00 00 00 00 00 00 00 00 00 00 00所在的地址。
三、借想要的XIP:
准备好想借XIP的xip.bin文件和你自己要升级的xip.bin文件,放在两个不同的目录,分别将XIPPort.exe放到他们在的目录,并运行
1 、用XIPPort的dump xip.bin解开两个xip.bin文件,会多出来out目录
2 、分别执行write maps,可以在out目录得到MAP.physical.txt和MAP.txt,复制到别的地方备用
3 、分别执行make pkgs,out目录被重新非配,将要借的XIP下的\OUT\MODULES\MSXIPKernel目录下的文件复制到自己的XIP的\OUT\MODULES\MSXIPKernel目录,替换相同的文件。(此处注意,仅仅替换module形式的exe和dll,还有同名的txt文件,nk.exe, cecompr, ceddk, fsdspy等文件不要替换,如果有的话,OEMXIPKernel的目录更不能替换!!!!。)
4 、在自己的XIP的目录下操作:执行Undo操作,
四、重新分配地址,在自己的XIP目录下操作
1、执行Relocate P'操作(如果能执行不出错是你福气!祝贺你!!! 。
2、 执行write maps,得到新的MAP.physical.txt和MAP.txtROM制作,t智能手机改进,Diypda,PPC乐园.
3、然后你需要修正 nk.exe 模组中的 S000 文件,在那里放上你的新 ROMHDR offset。
首先查找旧的 ROMHDR offset,在你自己的旧的 MAP.txt 文件有类似的一行:
8019bb68 - 8019bbbc L00000054 rom_00 header: dlls="01fa01fe-02000000" phys="80000000-80276358", 25 modules, 8 files, 3 copyentries ext="8000291c"  ram=80277000-83a00000 cputype="000001c2",告诉你这个XIP中含有25 个modules, 8个 files, 3 个copyentries ,你见到 - 8019bb68- 它是你的旧offset - 在 nk.exe 的 S000 部份查找这 hex 数值,在 hex 中这一个数值 68 BB 19 80, 修正它为你的新 romhdr offset,新的romhdr offset你可以在上面2中产生的 MAP.txt 文件中找到,如果相同就不用找了
五、生成新的xip.bin文件
1、 打开新产生的的MAP.txt文件,如果没有哪一行出现“!!!!!!!!!!!!!!!!!”那么证明地址没有冲突基本成功了!那你的运气真是太好了
2、执行build xip_out.bin,会在你的目录来新产生一个xip_out.bin的文件
3、将nk.nb文件也复制到你的XIP的目录下,在XIPPort的界面中的下面两个输入框中的第一个填入第二中找到的地址,如00320000,在第二框中填入nk.nb
4、执行build xip_out.bin to:将会把xip_out.bin加入到nk.nbROM文件中的00320000的地址中,至此你的nk.nb文件的XIP已经和那个借来的XIP的版本一样了。
六、问题解决:
在第五的中1,发现在“!!!!!!!!!!!!!!!!!”
       1、在MAP.TXT中发现有类似的这些内容(篇幅问题,裁减了些实际内容):
00000000 - 01fa01fe L01fa01fe NULDIYPDA.COM7
01fa01fe - 01fa01fe L00000000 Start: first DLL address
01fa01fe - 01fea000 L00049e02 NUL
01fea000 - 01feb000 L00001000 initialized data of region_1 relfsd.dll
01feb000 - 01fec000 L00001000 initialized data of region_1 FLASHDRV.DLL
01fec000 - 01fed000 L00001000 initialized data of region_3 FLASHDRV.DLL
01fff000 - 02000000 L00001000 initialized data of region_1 busenum.dll
02000000 - 02000000 L00000000 End: last DLL

02000000 - 03e42000 L01e42000 NUL
03e49000 L00007000 Virtual base address of relfsd.dll
03e49000 - 03e54000 L0000b000 Virtual base address of FLASHDRV.
03ffa000 - 04000000 L00006000 Virtual base address of busenum.dll
04000000 - 80000000 L7c000000 NULwww.diypda.com* s
如果在其中的某些行有“!!!!!!!!!!!!!!!!!”则要参考自己的旧的MAP.TXT文件,用mreloc.exe对相应的模块的地址按自己旧的MAP.TXT文件的地址进行修改
2、如果是在类似这样的地址80000000 - 80000000 L00000000 Start: first physical address的这一行到80276358 - 80276358 L00000000 End: highest physical address之间的地址出现“!!!!!!!!!!!!!!!!!”
说明新装进来的文件在调入RAM时他们的地址和其他的东西有冲突了,你必须要调他们的地址,地址重复的地址长度在这一行的LXXXXXXXX中,,查看前后行的LXXXXXXXX值,看看他们的地址长度是多少,再查找有NUL的行,它的LXXXXXXXX代表那里有相应的空的地址,如果空出的长度能装下出现“!!!!!!!!!!!!!!!!!”的上行或下行的地址长度+“!!!!!!!!!!!!!!!!!”行的地址长度,你要做的是将那一行的数据移到空的地方!!
移动完一个数据段的数据,再做一下write maps,再重新查看MAP.TXT文件,如此重复,直到不再有“!!!!!!!!!!!!!!!!!”出现为止!
这样再做上面的第五步就可以了

3、数据段的移动方法:查看当前要移动的那一行的第一个数据,它是个地址值,如:80243fd8 - ,在OUT\MODULES对应的文件目录中imageinfo.txt中查找它,它可能是P+某个值或是D+某个值,P或D的值可以在OUT里面的ROMHDR.txt中看到,修改imageinfo.txt的这个数据使其+P或+D的值等于你移动数据的目标NUL那一行的地址值,因为imageinfo.bin和imageinfo.TXT的值是一一对应的,用WINHEX修改对应的数据,保存! 呵呵!这个是个细心量大的手工活,没有耐心的就不要做了

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(119)
发表于:2008-4-17 19:18:41
标签:无标签

0

WINCE恢复默认HIVE注册表的方法

WINCE恢复默认HIVE注册表的方法     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

当Wince使用了HIVE注册表后,每次用户的注册表改动将得到保存,但是在某些应用场合需要将注册表还原成为出厂的默认设置,通常要求能够在AP中通过点击一个按钮来实现这种clean boot。使用我前面的文章的方法配置的HIVE系统注册表和HIVE用户注册表分别保存在/HDD/Document and Setting/system.hv 中和 /HDD/Document and Setting/default/user.hv中,每次系统在启动到加载HIVE系统注册表之前都会先检查保存在/HDD中的文件的存在和合法性,如果不满足要求系统将会用binfs中的缺省文件创建新的system.hv和user.hv文件于/HDD中,根据这个特性我先试图在WinCE运行起来后删除这两个hv文件,但是由于WinCE已经事先加载了它们,删除被禁止,只有采用其他的方法。
重新研究了基于HIVE注册表的WinCE的启动过程发现,系统在完成了第一阶段也就是加载完了boot.hv+binfs之后和加载系统HIVE注册表之前,filesys.exe都会调用OEMIoControl来查询是否需要清除保存在block设备上的hv文件,其CODE代码为IOCTL_HAL_GET_HIVE_CLEAN_FLAG,它的输入参数lpInBuf固定为HIVECLEANFLAG_SYSTEM或HIVECLEANFLAG_USERS,filesys.exe会分别用这两种参数调用两次IOCTL_HAL_GET_HIVE_CLEAN_FLAG,第一次用HIVECLEANFLAG_SYSTEM来问OEM是否需要清除system.hv,第二次用HIVECLEANFLAG_USERS做参数来查询是否要清除user.hv,如果返回的lpOutBuf中的值为TRUE则做清除操作,如果为False则保留block设备上的注册表文件。
所以我们要做的就是实现和IOCTL_HAL_GET_HIVE_CLEAN_FLAG相对应的OEMIoControl源码(假设由OALIoCtlBGetHiveCleanFlag()这个function来实现),加入对是否需要清除注册表的判定条件并告知filesys.exe即可。现在棘手的问题是如何让AP通知OALIoCtlBGetHiveCleanFlag()该不该清除注册表,因为OALIoCtlBGetHiveCleanFlag()只能在指定的时候由filesys.exe去调用,AP的运行只能在OALIoCtlBGetHiveCleanFlag()运行完之后。
后来终于想到可以使用共享内存空间来实现,我们可以在物理内存中保留出一块不会被其他模块占用的空间,在这个空间放置两个BOOL变量分别来保存system和user的hv清除的标志符,缺省它们都为False,OALIoCtlBGetHiveCleanFlag()读到Flase则认为不清注册表,AP在需要的时候将这两个标志符置为True,接下来就是要重新启动到OALIoCtlBGetHiveCleanFlag()函数被调用的地方,由于标志符号是保存在RAM中的,断电会丢失,还好有个方法可以让系统复位而又能保存RAM中的内容,那就是Reset,所以让AP在设置完标志符后马上调用Reset指令就可以完美实现Clean boot了。
提供相关代码作为参考:
BOOL OALIoCtlBGetHiveCleanFlag(   // 一般在IOCTL.C中实现
       UINT32 code, VOID *lpInBuf , UINT32 nInBufSize, VOID *lpOutBuf,
       UINT32 nOutBufSize , UINT32 *pOutSize)
{
BSP_ARGS *pArgs = (BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START; //保留的共享RAM空间的虚拟地址
if (!lpInBuf || (nInBufSize != sizeof(DWORD)) || !lpOutBuf || (nOutBufSize != sizeof(BOOL)))
 {
     SetLastError(ERROR_INVALID_PARAMETER);
     return FALSE;
 }
else
{
     DWORD *pdwFlags = (DWORD*)lpInBuf;
     BOOL *pfClean = (BOOL*)lpOutBuf;
    if (*pdwFlags == HIVECLEANFLAG_SYSTEM) {
          if(*pfClean = pArgs->bcleansystemhive) //判断是否清除system.hv
                   RETAILMSG(1, (TEXT("OEM: cleaning system hive\r\n")));
               else
                   RETAILMSG(1, (TEXT("OEM: Not cleaning system hive\r\n")));
          *pfClean = pArgs->bcleansystemhive;
               pArgs->bcleansystemhive=FALSE; //一定在执行完后设置为默认的false否则常规reset都会清空注册表
     } else if (*pdwFlags == HIVECLEANFLAG_USERS) {
     if(*pfClean = pArgs->bcleanuserhive) //判断是否清除user.hv
                   RETAILMSG(1, (TEXT("OEM: cleaning user hive\r\n")));
               else
                   RETAILMSG(1, (TEXT("OEM: Not cleaning user hive\r\n")));
                 *pfClean = pArgs->bcleanuserhive;
                   pArgs->bcleanuserhive=FALSE; //restore to default
     }
 }
return TRUE;
}
 
AP中的实现代码如下:
Void On_CleanBoot()
{
BSP_ARGS* pArgs = (BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START; //保留的共享RAM空间的虚拟地址
pArgs->bcleansystemhive=TRUE;         //设置system.hv清空标志符
pArgs->bcleanuserhive=TRUE;            //设置user.hv清空标志符
ReSet();
}
 
引用本文请注明出处:http://blog.csdn.net/fredzeng

点击此处查看原文 >>

系统分类: 软件开发   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(76)
发表于:2008-4-17 19:14:32
标签:无标签

0

WinCE中的Flash分区和CheckSum点滴

 WinCE中的Flash分区和CheckSum点滴     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

 
CheckSum是一种用于检查数据文件有没有发生变化的方法,对于一些重要的数据文件为了检查传输过程过程中有没有数据的损坏或丢失,常常会用到CheckSum算法。
WinCE中经常用到CheckSum的地方就是对即将烧写进Flash中的image文件进行校验,和烧写完对写入的数据进行完整性检查,一般这里的imageOSimageUTbin文件两种。
CheckSum的原理是把一个文件以二进制的方式打开,将里面所有的字节的值一个一个的累加起来,一直到最后一个字节,最后得到一个累加值,它就是我们要的CheckSum的结果。从CheckSum的这个特性可知数据值为0的字节是不会影响到最终的结果,这种特性我认为也是CheckSum的一个弱点,不能像MD5SHA1等摘要算法一样基本上能反映出哪怕一个bit的改动,但是这个特性也给WinCE运行期间计算保存在FLASH上的image数据文件的完整性带来了方便。
为了从Flash中得到正确的CheckSum值必须先了解imageFlash中的烧写方式,这包括了解image文件内部是怎么组织的,Flash的分区和块的分配是如何进行的。
先以SumsungFLASH为例来分析一下Flash的分区大体原则:
WinCEFlash分区大体分为Nand BootLoader(NBL)区,Binfs区和文件区,NBL区存放BootLoader和烧写Image的工具程序,Binfs分区存放MBRimageXIPKERNEL.binChain.binNK.binOS的数据。文件区一般格式化为FAT分区让WinCE上层的磁盘和分区管理程序管理。Flash的分区是由UT在烧入image的时候决定的,包括每个分区的起止块地址,分区的大小和类型等,Detail如下:
1NBL区一般占10个块(128K/块)的大小,分区虽小但是却是最重要的部分,保存着UT的三大模块:NBL1bootloader),NBL2IPLInit Program Loader)和NBL3Upgrade Tools),其中NBL1NBL2共同保存在FlASH的第一个block中,FLASH芯片在生产的时候厂商都会特别保障这些block的可靠性,特别是保存了最开始bootloader代码和IPL的第一块。按经验来讲,NBL的三个模块加起来一共大约400K,其占用的10块的block128K×10 byte的空间大部分是空余的,为了下面叙述方便,这里假设NBL3_END_BLCOKNBL的最后的block编号。
2Binfs分区紧接着BL分区,即CE_START_BLOCK=NBL3_END_BLCOK+1,然后一般会将Binfs分区的第一个块存放MBRMBR在这里仅仅是个标志,不像PC的硬盘中的MBR主要用来保存分区表的信息和引导代码。所以Binfs分区中保存OS数据的起止block范围为CE_START_BLOCK+1CE_START_BLOCK+CE_MAX_BLOCK为止,我接触的项目中其大小一般为250个块左右,大约等于30MbytesWinCEimage一般不会超过这个大小,如果需要可以在分区时加大它的大小。
3Flash的文件分区就是将剩下的block模拟成为和硬盘,CF卡类似的块设备让WinCE加载成盘符使用。
现在回到正题:如何计算CheckSum
1UTCheckSum计算
UTbin文件是由bootloader.binNBL1),IPL.binNBL2)和UpgradeTools.binNBL3)这三文件打成的一个封包,然后用PC上的checksum工具计算出checksum值,我们的目的就是在WinCE起来后用AP能通过读FlashNBL的三个分区并实时计算到这个值。
UTbin文件最后会被完整的烧写到NAND Flash的编号为0NBL3_END_BLCOKblock中(虽然会被分为三块烧,但是数据是完整的),具体占用多少blockbin文件的大小决定,剩余的空间会以0填满。虽然不知道bin文件具体的结尾的位置,但是知道剩余空间填0的这个特性后,我们就可以直接调用NAND Flash的驱动程序,而且可以使用轻量级的不带坏块管理的驱动代码直接去读0NBL3_END_BLCOK的所有数据,然后把每个