EDN首页   博客首页

最新日志

发表于:2008-7-8 11:39:04
标签:无标签

1

wince文件(转)

WinCE 文件

分类:EVC学习
2007.9.21 17:37 作者:大熊 | 评论:0 | 阅读:928

WinCE 文件

以下三种是我都使用过的,归纳如下:
方法一 使用MFC的CFile类
这个最简单了。
打开用Open,关闭用Close(),文件指针移动用Seek,读文件用Read(),写文件用Write,获取文件属性可以使用GetFileStatus方法,这个可以查看MSDN,下面给几行简单代码:
CFile file;
bool isOpenOK = file.Open(L"\\flash disk\\flyfox\\test.txt", CFile::typeBinary|CFile::modeRead); //返回真表示读成功
if (isOpenOK)
{
char buffer[1024];
file.Seek (10L, CFile::begin);
DWORD readCount = file.Read(fileBuffer, 1024); // 返回实际读到的字节数
}
file.Close ();

方法二
基于C的使用FILE结构体
打开文件使用_wfopen,原型如下:
FILE *_wfopen( const wchar_t *filename, const wchar_t *mode );
第二个参数是打开模式,这里有很多,比如r,w,r+等等,意义如下:
"r" 以只读方式打开文件,文件不存在将打开失败
"w" 以只写方式打开文件,如无文件生成新文件,如果文件已存在,将被破坏
"a" 以追加的方式打开文件,如果文件不存在,将自动创建一个新文件,已经存在的文件EOF标志将不动。
"r+" 以读/写方式打开文件,文件不存在将打开失败
"w+" 以读/写方式打开文件,如无文件生成新文件,如果文件已存在,将被破坏
a+ 以追加方式打开文件,如果文件不存在,将自动创建一个新文件,已经存在的文件的EOF标志将会去掉,并在写好新的数据后自动加到文件末尾。
t 以文本模式打开
b 以二进制模式打开。
这些标志可以同时使用,比如rb+(就是br+)以二进制方式,只读打开文件。
读文件使用fread(),原型是size_t fread( void *buffer, size_t size, size_t count, FILE *stream );参数buffer是保存读取的数据,size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。
例:
  char buffer[1024];
  FILE *file = fopen(L"\\flash disk\\flyfox\\test.txt", "r");
  fread(buffer, 2, 150 , file);//按每块2个字节,读取1590块,共读取2*150=300个字节,实际读取块数可由函数返回。
写文件使用fwrite()。与fread对应,原型是size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );参数意义同fread。
fseek()
  此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是iint fseek( FILE *stream, long offset, int origin );如果成功返回0。参数offset是移动的字符数,origin是移动的基准,表示从哪开始移动文件指针,取值如下:
符号常量 值 基准位置
SEEK_SET 0 文件开头
SEEK_CUR 1 当前读写的位置
SEEK_END 2 文件尾部
例:fseek(file, 1000L, SEEK_CUR);//把读写位置从当前位置向后移动1234字节
  fseek(file, 0L, 2);//把读写位置移动到文件尾
关闭则是使用fclose,原型如下:int fclose( FILE *stream );
对这种方法,也给出几行简单代码:
FILE *fp = _wfopen(pFileName, L"ab");
if (!fseek (fp, 100, SEEK_SET))
                        {
                                x = fwrite(buffer, 1, 1024, fp);
                                fflush (fp);
                        }
fclose (fp);

方法三
采用WinCE的API
1.  文件的打开CreateFile
以上参数比较多,这个在EVC下有帮助,可以查到。可以举个例子:
HANDLE hFile = CreateFile (pFileName,
                GENERIC_WRITE,
                FILE_SHARE_WRITE,
                NULL,
                OPEN_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                //打开失败
        }
2.  文件的关闭
文件使用完之后就应该及时关闭,以释放对它的资源
BOOL CloseHandle(HANDLE hObject);
比如CloseHandle(hFile);
3.  文件的读写
文件的读ReadFile
文件的写WriteFile
比如:
bool b = WriteFile (hFile, pBuffer, dToWrite, pWrite, NULL);
dToWrite为准备写入的字节数,pWrite为DWORD*,获取实际写入的字节数 
     if ( !b )
{
//写失败
}
4.  文件指针的移动SetFilePointer
例如:SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
5.  获取和设置文件信息
参数表示文件名或者目录名
DWORD GetFileAtrribute(LPSTSTR lpFileName);
DWORD SetFileAttributes(LPCTSTR lpFileName,DWORD dwFileAttributes);
6.  获取和设置文件时间
BOOL GetFileTime
BOOL SetFileTime
7.  获取文件大小
DWORD GetFileSize(HANDLE hFile, NULL);

你可以通过这个链接引用该篇文章:http://bear5292.bokee.com/viewdiary.19499535.html

点击此处查看原文 >>

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

评论(0) | 阅读(308)
发表于:2008-6-30 9:11:20
标签:无标签

1

如何正确使用ads(axd)

 
     如何正确使用ads(axd)
1、ads是由arm公司提供的编译和调试环境,非常好,不容质疑!搞arm开发的人员,不能不用ads,例如要开发一个驱动,首先是在ads中编译、调试通过,才会加入操作系统中,这是开发过程。 2、Ads中codewarria是编译环境,在这个环境中,应正确设置程序工作或调试的地址,这两个地址不一定同址,每次只能设置一种,除非它们相同。设置是通过菜单项edit->target setting完成的。编译环境中的这个地址是由链结器标记在程序上的(暂且这样说吧,因为这部分实际涉及的是编译原理中的链接定位问题,它主要涉及的是程序中的跳转地址,这是与软件相关的)。这两个地址都必须与硬件地址配合,程序才能正常工作。因为mcu(arm)是硬件寻址的,比如4510在正常初始化后,flash被定位在0x0地址,这时如果mcu有一条指令是跳转到0x0地址,那么mcu一定会将PC指向flash的0x0地址,mcu却是由软件控制的。如果这时remap了,flash被定位在0x1000000地址,但写在flash中的程序仍然控制mcu跳转到0x0地址,那么PC就指向了sdram的0x0地址,那里写着什么是你的事情了。
3、工作地址是指编译好的程序(一般是*.bin文件)写入flash的地址,如软件程序工作地址从0x0开始,flash也应该定位在0x0地址开始,软件与硬件地址要相同,才能正常工作。当然,如果做remap,把程序拷贝到新的0x0地址处,也就是sdram中,程序也可以正常工作的。
4、如果用axd调试,则是另外一种情况:程序必须写在sdram中,而不是flash中。Sdram的地址在那里呢?4510上电后,一般设置在0x1000000,而把flash设置在0x0地址。如果codewarria编译时把程序设置在0x0地址,调试时就会把软件加载在一个“虚”位置,这个位置(地址)是flash的地址,mcu是无法把程序写入flash中,程序就成为空中飘荡的幽灵,这时如果用反汇编,可以看到有些内容已经变质了,不是你的程序了,明白是为什么吗?而执行的话,mcu读取flash中的内容,它们并非你的程序,结果是跑飞了。解决办法是remap(对4510。如是44b0,请在codewarria编译环境中把程序定位在 sdram段,如需中断,请在flash中0x0地址先写入相关中断向量,并跳转到sdram中),把sdram设置在0x0地址,再加载程序。 5、Remap时,请用axd中的命令行方式,程序是实现不了的。即:system view->command line interface。只有先把硬件地址设置的与程序相同了、程序段可以被装入sdram中时,才可加载程序。
6、切记这两点:调试程序一定要放在sdram中、sdram地址与程序地址一定要相同。
7、0x8000这个地址是怎么来的呢?原来:0x0地址是中断向量地址,这要占用几十个字节,有些操作系统利用中断向量之后、0x8000地址之前的部分做点事情,Linux就是其一。所以,编程人员默认的把0x8000这个地址作为一般程序的开始地址。调试程序时,可以把程序起始地址定在0x8000,这个地址一定要是sdram覆盖的地址(我再强调一次吧),mcu执行时,仍然是从0x0开始的,是谁把PC挪到0x8000的,是ads在编译的时候,连接器加进的代码实现的。如果不是调试程序,是工作程序,要写入flash的,程序应该定位在0x0地址,而不是0x8000。
8、有一本书“ARM应用开发系统祥解--S3C4510B”写的非常好,我读过有7、8遍了。但有一点是错的。书中写到:“针对本书所介绍的目标板,就可以使用这个默认地址值(0x8000)。”实际上,只要是4510的板子,不做remap,0x8000地址就是flash,是不能加载程序的。
9、在axd中,注意菜单options->configure processor选项,如果不会用,就把它们都关了。带中断的程序和有跳转到0x0地址的程序执行不了,多是由这项引起的。其实它们非常有用,不提了。
10、所有我以上提到的,均是有程序重定位和跳转情况的,象简单的跑马灯实验,不需要中断、跳转的,把程序直接定位在高位sdram中,remap也不用做,就可以跑的不错了。
11、顺便提一下banyan的接口包非常好,支持ads,不用怀疑它。
 

点击此处查看原文 >>

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

评论(0) | 阅读(248)
发表于:2008-6-27 11:01:06
标签:无标签

1

OAL点点滴滴(一)

OAL点点滴滴(一)

  OAL(OEM Adaptation Layer)既OEM 适配层,从逻辑上讲位于Windows CE内核和硬件之间,从物理上讲OAL各个模块代码被编译后(.lib)和其它内核库链接到一起形成Windows CE的内核可执行文件nk.exe。Windows CE内核在OAL层暴露了大量的函数和全局变量,利用这些函数和全局变量OEM可以编写中断处理、RTC、电源管理、调试端口、通用I/O控制代码等。图1更直观地描述了OAL的结构。CE安装目录的子目录中包含了OAL的部分源码,大多数情况下开发者对OAL只要修改即可,甚至无需修改。通过阅读本篇文章,开发者能够了解OAL的结构、暴露的接口的功能,可以在此基础上实现甚至增强OAL的功能。


图1 OAL结构图

  因为OAL层代码大多数和CE启动时系统初始化工作有关,所以本篇文章以CE的启动顺序为线索。其它OAL知识在下一篇文章中讲解。

一、在Boot Loader解压CE内核镜像文件(nk.bin)后开始跳转到StartUp(),StartUp函数属于OAL层,此时CE操作系统内核还没有运行。StartUp函数的功能主要有两个,一是初始化CPU为已知状态(known state),二是调用内核初始化函数(x86平台为KernelInitialize,其它平台为KernelStart)。初始化CPU工作因CPU的不同而不同,如果是ARM系列,包括设置CPU为管理员模式、禁止IRQ和FIQ、禁止MMU、清空指令和数据缓冲、检测启动原因、配置GPIO和内存控制器、初始化RTC、保存OEMAddressTable地址等。执行完毕后调用KernetStart。如果是x86系列,包括设置CPU为保护模式、初始化内存控制器、保存OEMAddressTable地址等。执行完毕后调用KernetInitialize。

二、内核初始化函数的功能也因CPU的不同而不同,不过有一些功能是相同的,如初始化串口(为了输出调试信息)、调用OEMInit函数等。对于x86系列,初始化工作除了上述的功能外还包括读取OEMAddressTable内容、确定分页大小、内核重定位、初始化中断分配表、初始化分页表、内存初始化和其它初始化。对于其它系列CPU请参考CE帮助文档。

  1. 串口调试:
    串口调试函数包括OEMInitDebugSerial、OEMReadDebugByte、OEMWriteDebugByte等。从OEMInitDebugSerial的源码可以看出,系统从BOOT_ARG_PTR_LOCATION为首地址的结构中判断当前连接的串口是哪个,然后配置这个串口。如果你的设备的串口I/O地址设置和CE默认的一致的话,就能在CE内核得到CPU控制权到启动完毕这段时间里通过串口得到调试信息。
  2. OEMInit
    一般在OEMInit中初始化所有外围的硬件、初始化系统时钟(system tick)和RTC(real time clock)、初始化KITL(Kernel Independent Transport Layer)。例如I486平台的OEMinit函数,它先关联所有的IRQ和中断ID,然后初始化PCI总线、网络适配器、电源管理、PIC(可编程中断控制器)、系统时钟,最后检测是否有扩展内存。另外如果OEM要通过OAL暴露的函数指针或者全局变量来增强功能的话,就要在此函数中实现(在下面详细讲解)。
  3. 检测扩展内存
    我们都知道在config.bib配置文件中设置CE系统使用RAM总量(如果不知道请参考我的文章Platform Builder之旅系列),注意这个RAM总量不是总的物理内存的大小。PB编译的内核包含一个变量ulRAMEnd,将在config.bib中定义的RAM的起始地址 + RAM大小的和赋值给ulRAMEnd。在CE内核的启动过程中,ulRAMEnd的值赋值给全局变量MainMemoryEndAddress,CE内核通过访问MainMemoryEndAddress得到RAM的总量信息。假如基于CE的设备附加了RAM,而MainMemoryEndAddress的值没有包括这段附加的RAM,结果CE内核无法知道已经附加了RAM。为了让CE内核了解附加RAM的信息,OEM应该编写一个函数检测RAM的总量,并把总量值赋给MainMemoryEndAddress。OAL暴露了一个函数指针pNKEnumExtensionDRAM,OEM应该把编写好的函数地址赋给这个函数指针。如果OEM不准备自己编写内存检测函数的话也可以调用OEMGetExtensionDRAM。从帮助文档中看出OEMGetExtensionDRAM这个函数能够检测内存的总量,但是CE的针对X86 平台的源码中没有具体编写这个函数的实现代码(见%_WINCEROOT%\PUBLIC\COMMON\OAK\CSP\I486\OAL\cfwpc.c)。也就是说在X86平台上调用OEMGetExtensionDRAM是检测不到RAM的。如果OEM有兴趣编写检测RAM总量的函数,可以调用现成的函数IsDRAM。这个函数也保存在cfwpc.c中。

三、内核初始化函数执行完毕后开始按如下步骤执行:

  1. 内核创建用于与filesys.exe同步的事件对象SYSTEM/FSReady,之后启动filesys.exe。启动filesys.exe的意义是让filesys.exe读取注册表数据。
  2. 内核等待事件SYSTEM/FSReady被触发,这个事件是由filesys.exe在做完一系列工作后触发。这一系列的工作内容如下:
    2.1 先检测这是一次冷启动还是热启动,如果是冷启动,那么初始化对象存储内存区域。
    2.2 调用OEMIoControl函数,I/O控制代码为IOCTL_HAL_INIT_RTC,也就是初始化RTC。
    2.3 初始化数据库子系统和API、文件系统API、消息队列API。
    2.4 如果操作系统镜像(nk.bin)包括RAM文件系统,那么读取Initobj.dat文件内容后创建一个RAM文件系统。
    2.5 初始化注册表(在内存中形成注册表)。
    2.6 如果此时device.exe没有启动,那么读取HKEY_LOCAL_MACHINE\System\StorageManager下"Dll"的值(这个值为存储管理器所在的.dll的文件名)并加载到内存。加载之后创建一个线程专用于初始化存储管理器,初始化之后此线程结束。
    2.7 初始化NLS(national language support)。关于NLS请参见我的文章《CE下中文输入法编辑器》。
    2.8 为数据库引擎设置本地ID。
    2.9 读取Initdb.ini文件,安装在对象存储中的数据库。
    2.10 触发SYSTEM/FSReady事件,之后filesys.exe处于等待状态,等待内核发通知给它。
  3. 此时注册表已经存在于内存当中,内核开始读取如下位置数据:
            HKEY_LOCAL_MACHINE\Loader\SystemPath
            HKEY_LOCAL_MACHINE\SYSTEM\OOM\cbLow and cpLow
            HKEY_LOCAL_MACHINE\SYSTEM\KERNEL\InjectDLL
            HKEY_LOCAL_MACHINE\MUI\Enable and SysLang
            HKEY_CURRENT_USER\MUI\CurLang
  4. 内核设置低内存处理(out of memory)。低内存处理是指当前可用的内存非常少时,内核所做的解决方案(CE帮助文档中有详细说明)。
  5. 内核在做好了上述工作后通知filesys.exe,由filesys.exe做其余工作。filesys.exe所做的工作内容如下:
    5.1 读取HKEY_LOCAL_MACHINE\System\Events 下包含的所有事件对象名称并一一创建。
    5.2 读取HKEY_LOCAL_MACHINE\Init 下包括的所有应用程序名称并一一启动。如果device.exe在列表中并且此时它已经启动了,那么触发SYSTEM/BOOTPHASE2事件,这会使device.exe重新读取注册表数据来完成最后的驱动程序初始化。
    5.3 初始化时间区域(time zone)。

转自http://fredzeng19791979.spaces.live.com/default.aspx?_c01_BlogPart=blogmgmt&_c=BlogPart&prevPost=true&postPH=cns!8B61E787FA1FE1D!176

 

点击此处查看原文 >>

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

评论(0) | 阅读(150)
发表于:2008-6-25 13:18:14
标签:无标签

1

wince注册表结构(转)

 

 
2007年10月13日 星期六 下午 05:49
与桌面Windows一样,Windows CE也使用注册表(Registry)来保存应用程序、驱动程序和用户的设定以及其他一些配置信息。Windows CE注册表也采用树形结构来管理配置信息,由于Windows CE注册表的结构和功能与桌面Windows几乎一样,在这里就不详细介绍了,读者可以参考其它关于注册表的资料。
Windows CE支持四个根键,描述如下:
键名 描述
HKEY_LOCAL_MACHINE 硬件和驱动配置数据
HKEY_CURRENT_USER 用户配置数据
HKEY_CLASSES_ROOT OLE和文件类型匹配配置数据
HKEY_USERS 适用于所有用户的数据
由于嵌入式系统的特点,一些嵌入式设备是没有外存的。因此Windows CE的注册表提供了两种实现方式:基于RAM的注册表(RAM-Based Registry)和基于Hive的注册表(Hive-Based Registry)。我们可以选择在Windows CE中使用任何一种注册表,注册表类型对于用户和应用程序来说是透明的。
 基于RAM的注册表
正如其名,基于RAM的注册表把整个注册表作为一个对象存储堆存放在系统的内存中。这意味着如果对系统进行冷启动或者系统断电,对注册表的所有改动都会丢失。
如果使用基于RAM的注册表,对注册表的读写访问操作会变得非常高效。因此基于RAM的注册表比较适用于没有外部存储,而且有电池保存内存数据(battery-backed RAM)的设备。如果有外存且经常冷启动的设备采用基于RAM的注册表,则需要在系统断电的时候对注册表进行保存,等系统再次启动时对保存的注册表进行还原。
Windows CE提供了两种方法用来断电保存基于RAM的注册表:
1. Windows CE提供了两个系统API用来保存和还原整个注册表,它们的原形如下:
BOOL RegCopyFile(
    LPCWSTR lpszFile    // 保存注册表信息的文件的名字
);
BOOL RegRestoreFile(
    LPCWSTR lpszFile    // 保存注册表信息的文件的名字
);
如果要保存和恢复注册表,我们只需要在系统断电的时候调用RegCopyFile函数将整个注册表保存为外存上的一个文件。当系统重新启动时,我们再调用RegRestoreFile函数将文件全部读出RAM中,然后再热启动系统,我们保存得注册表就可以生效了。值得注意的是这次热启动是必须的,因为只有在系统启动的时候才会去检测RegRestoreFile放在RAM里的注册表信息。这种方法的优点是完全可以使用应用程序来实现基于RAM的注册表的保存,而且这种方法相对简单。但是此方法的缺点是需要两次启动。因此效率相对比较低。
2. 第二种方法需要OEM的参与,OEM可以在BSP的OAL层中实现WriteRegistryToOEM和ReadRegistryFromOEM两个函数,它们的声明为:
DWORD ReadRegistryFromOEM(
    DWORD dwFlags,    // 参数, REG_READ_BYTES_START表示读新的注册表
    LPBYTE lpData,    // 指向注册表数据的缓冲区,由OS分配
    DWORD cbData    // 缓冲区的大小
);
BOOL WriteRegistryToOEM(
    DWORD dwFlags,    // 参数,REG_WRITE_BYTES_START表示写新的注册表
    LPBYTE lpData,    // 指向注册表数据的缓冲区,由OS分配
    DWORD cbData    // 缓冲区的大小,0表示到达注册表尾部
);
Windows CE会在系统启动和关闭的时候调用这两个函数来保存和恢复注册表。此种方法虽然可以避免两次启动,但是困难的地方是ReadRegistryFromOEM函数的实现比较困难,因为在系统启动的时候,块设备驱动和文件系统的驱动都还没有加载,因此不能使用CreateFile,ReadFile这样的文件系统API来实现ReadRegistryFromOEM函数,只能使用一些更底层的操作来实现。
 基于Hive的注册表
自从Windows CE 4.0之后,Windows CE提供了基于Hive的注册表。基于Hive的注册表把注册表数据存放在文件系统的文件上,这种文件被称作蜂箱Hive。这就意味着不再需要在系统断电和启动时进行保存恢复注册表操作。
Hive是注册表中的一组键,子键和值。Hive是文件系统上表现为单个文件。Windows CE中有三种Hive。
类型 文件 描述
Boot hive ROM中的Boot.hv HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, HKEY_USERS中的所有数据。只在启动时使用。
System hive 由OEM决定
(通常是System.hv) HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, HKEY_USERS中的所有数据。包含设备范围内不随着用户改变而改变的数据。
User hive User.hv HKEY_CURRENT_USER下的所有数据。 包含用户特有的设置,每个用户都有一个单独的User.hv。
基于Hive的注册表适用于对于有永久存储并且需要经常冷启动的设备。我们也可以看到,基于Hive的注册表把系统数据和用户数据分开存放,这就意味着基于Hive的注册表还提供多用户支持。对于每一个用户,可
转自http://blog.163.com/jo2005@126/blog/static/86887952007931111941782/

点击此处查看原文 >>

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

评论(0) | 阅读(170)
发表于:2008-6-19 11:42:31
标签:无标签

1

wince5.0 注册表还原(转)

当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

点击此处查看原文 >>

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

评论(0) | 阅读(219)
发表于:2008-6-19 11:36:04
标签:无标签

1

wince5.0 中HIVE的实现

http://blog.csdn.net/slyzhang/archive/2006/08/10/1046993.aspx(转自)

 

直想实现Wince4.2下的 S3C2440 的 Hive-based的 保存, 几经周折,没有查出来相关资料,也许只有在源码中可以找到思路,以下给出我在网上找到的可以实现的方法,放在这里供大家使用。

2440 在5.0下的注册表保存可以参考这个:http://blog.csdn.net/fredzeng
而在4.2下的保存则参考:http://www.xsgps.com/BBS/forum_posts.asp?TID=7

我也是参考了这个才得以实现,注册表配置为:

; HIVE BOOT SECTION
[HKEY_LOCAL_MACHINE\init\BootVars]
 "SYSTEMHIVE"="system.hv"   
 "Start DevMgr"=dword:1
 "DefaultUser"="default" 
 "Flags"=dword:3   
 "RegistryFlags"=dword:1

[HKEY_LOCAL_MACHINE\System\StorageManager\AutoLoad\FlashDrv]
; "DriverPath"="Drivers\\BlockDevice\\FlashDrv"
; "LoadFlags"=dword:1
; "MountFlags"=dword:11
; "BootPhase"=dword:0
; "Flags"=dword:1000

 "DriverPath"="Drivers\\BlockDevice\\FlashDrv"
 "LoadFlags"=dword:1
 "MountFlags"=dword:11
 "BootPhase"=dword:1
 "Flags"=dword:1000  ;lieal modify
  
[HKEY_LOCAL_MACHINE\Drivers\BlockDevice\FlashDrv]
"Prefix"="DSK"
 "Dll"="FLASHDRV.dll"
 "Order"=dword:0
 "Ioctl"=dword:4
 "Profile"="FlashDrv"
 "FriendlyName"="MS Flash Driver"
 "MountFlags"=dword:11
 "BootPhase"=dword:0
 "Flags"=dword:1000  ;lieal modify
 
; Bind BINFS to the block driver
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\FlashDrv]
DefaultFileSystem"="BINFS"
 "PartitionDriver"="mspart.dll"
 "AutoMount"=dword:1
 "AutoPart"=dword:1
 ;"MountFlags"=dword:2   ;11 to 2 lieal modify
 "Folder"="ResidentFlash"
 "Name"="Microsoft Flash Disk"
 "BootPhase"=dword:0
 "Flags"=dword:1000  ;lieal modify

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\FlashDrv\FATFS]
  "FriendlyName"="FAT FileSystem"
  "Dll"="fatfsd.dll"
  "Flags"=dword:00280014
  "Paging"=dword:1
  "CacheSize"=dword:0
  "EnableCacheWarm"=dword:0
  "EnableCache"=dword:1
  "MountFlags"=dword:2
; END HIVE BOOT SECTION

点击此处查看原文 >>

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

评论(0) | 阅读(174)
发表于:2008-6-19 11:32:19
标签:无标签

1

wince4.2 HIVE的实现(转)

http://www.xsgps.com/BBS/forum_posts.asp?TID=7(转自此)

 

最近比较忙,为了给公司出2DIN机器。昨天下午把机器都送走了,趁机可以去参加IIC CHINA的上海集成电路展。因为是最后一天了,我去的时间也比较晚(2点半才到,展会5点结束),人不是很多,没有来得及慢慢的看完,挑了一些大公司和一些关心的方面看了看。让我吃惊的是WIND RIVER的人竟然没有展位,投靠在INTER门下,帮助INTEL发宣传袋,如果你同意要袋子的话,他们就会问你一些关于VXWORKS的问题,是否用到VXWORKS或者是LINUX。WIND RIVER做两个系统,一个是高端的VXWORKS,另外他们在几年前也开始做LINUX。问清楚了他们的嵌入式LINUX的使用费用(包括一些工具)是2万美金。 

 今天公司停电,在家学习。在WIN CE 4.2下搞了半天的注册表永久保存,总算搞定了(下面把要点记录下,希望EDNCHINA的服务器不要出问题)。
  1、Storage Manager 加入 FAT File System;
  2、Registry Storage 加入Hive-based Registry ,默认的是RAM-based Registry;
  3、修改platform.reg

[HKEY_LOCAL_MACHINE\init\BootVars]
 "SYSTEMHIVE"="system.hv"   ;"SYSTEMHIVE"="Documents and Settings\\system.hv"
 ;"PROFILEDIR"="Documents and Settings"
 "Start DevMgr"=dword:1  ;"Start DevMgr"=dword:0
 "DefaultUser"="default" ;LIEAL
 "Flags"=dword:3   ;LIEAL
 "RegistryFlags"=dword:1 ;LIEAL
; END HIVE BOOT SECTION
; @CESYSGEN ENDIF FILESYS_FSREGHIVE

; HIVE BOOT SECTION
[HKEY_LOCAL_MACHINE\System\StorageManager\AutoLoad\FlashDrv]
 "DriverPath"="Drivers\\BlockDevice\\FlashDrv"
 "LoadFlags"=dword:1
 "MountFlags"=dword:11
 "BootPhase"=dword:1
 "Flags"=dword:1000  ;lieal modify

[HKEY_LOCAL_MACHINE\Drivers\BlockDevice\FlashDrv]
 "Prefix"="DSK"
 "Dll"="FLASHDRV.dll"
 "Order"=dword:0
 "Ioctl"=dword:4
 "Profile"="FlashDrv"
 "FriendlyName"="MS Flash Driver"
 "MountFlags"=dword:11
 "BootPhase"=dword:0
 "Flags"=dword:1000  ;lieal modify

; Bind BINFS to the block driver
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\FlashDrv]
 "DefaultFileSystem"="BINFS"
 "PartitionDriver"="mspart.dll"
 "AutoMount"=dword:1
 "AutoPart"=dword:1
 ;"MountFlags"=dword:2   ;11 to 2 lieal modify
 "Folder"="ResidentFlash"
 "Name"="Microsoft Flash Disk"
 "BootPhase"=dword:0
 "Flags"=dword:1000  ;lieal modify
END HIVE BOOT SECTION

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\FlashDrv\FATFS]
  "FriendlyName"="FAT FileSystem"
  "Dll"="fatfsd.dll"
  "Flags"=dword:00280014
  "Paging"=dword:1
  "CacheSize"=dword:0
  "EnableCacheWarm"=dword:0
  "EnableCache"=dword:1
  "MountFlags"=dword:2

点击此处查看原文 >>

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

评论(0) | 阅读(132)
发表于:2008-6-13 17:26:07
标签:无标签

1

关于volatile关键字的说明以及测试

CSDN - 专家门诊 - C/C++ C语言问题  
  
主  题:  请教:有关volatile (函数前加volatile) 和inline的用法. 
作  者:  chinavistor (china)  
发表时间:  2005-02-25 13:47:41 
   
volatile修饰函数,作用是什么呢?
如 volatile void fun1(int i);

 回复:
--------------------------------------
winstonch 
? volatile 能修饰函数吗?

--------------------------------------
kobefly(科比---不惧挑战!)

volatile的本意是“易变的” 由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如:

static int i=0;

int main(void)
{
...
while (1)
{
if (i) dosomething();
}
}

/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}

程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致dosomething永远也不会被调用。如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。

一般说来,volatile用在如下的几个地方:

1、中断服务程序中修改的供其它程序检测的变量需要加volatile;

2、多任务环境下各任务间共享的标志应该加volatile;

3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义; 
 

-------------------------------------- 
happy__888([顾问团]寻开心)  

volatile表示变量的内容可能在程序未知的情况下被改变
比如,它对应的内存地址的内容被中断函数,或者其他的进程所改变
这种类型的变量,程序执行的时候不会放到cache当中预取,而是每次用到的时候直接取得
比如,你在c中间写这样的程序
for (int i=0; i<100000;i++); 
空循环,什么也不做
这个东西就会被优化调,如果在int前面加入这个标记则不会被优化的,因为i每次的变化不一定++也虚在循环中间被别的程序所改变

--------------------------------------
chinavistor(china)

volatile修饰变量我能理解,但修饰函数我就不清楚

在linux的source code(linux/mm/memory.c)中有这样两句:
volatile void do_exit(long code);

static inline volatile void oom(void)
{
printk("out of memory\n\r");
do_exit(SIGSEGV);

 

-------------------------------------- 
gaoxiaolin_311(随风而去)

 volatile修饰函数是为了线程安全的考虑。 
 
-------------------------------------- 
happy__888([顾问团]寻开心) 
 
volatile 函数 是特指存在于volatile memory当中的函数吧,函数指针也是随时会变化的  
  
 

点击此处查看原文 >>

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

评论(0) | 阅读(120)
发表于:2008-5-30 9:02:38
标签:无标签

0

wince驱动应用程序解决方法收集(转)

wince驱动应用程序解决方法收集


EVC中怎样使弹出的对话框不能移动?
在XXXX::OnInitDialog
里加入ModifyStyleEx(0, WS_EX_NODRAG, 0);即可
如何去掉(加上)某些system tray icon:1.power management(battery.reg去掉,加上) desktop time clock softkeyboard
使用PB建立一个wince image之前先要建立一个workspace来控制除OEM BSP之外的所有的image的属性,包括的内容等等。这些内容主要是通过PB的catalog来管理的,通过PB的viewàcatalog打开的视窗,我们从全部的window ce的可选组件中选择我们需要的加入到workspace中,这样的话我们sysgen出来的image就具备了相应的功能。从catalog的视窗中,我们可以通过查询任意一个组件的属性来获得它唯一对应的一个sysgen_开头的变量。但是这些变量并不能直接用来在runtime的情况下用于判断image具备哪些组件。在实际的运用中,AP可以#include一个名为“ceconfig.h”的头文件,这个头文件里面都是类似”CE_MOULDLE_***  SHELL_MODULES_***  COREDLL_****”之类的宏定义,这些宏定义可以直接被AP用来判定image内是否具备其需要的一些组件,比如MFC,AYGSHELL等等。Ceconfig.h是在sysgen的阶段自动由系统的批处理生成的,由于ceconfig.h的重要性,所以有必要搞清楚通过PB的catalog生成的sysgen_环境变量是如何和ceconfig.h内部的宏对应起来的。



      首先从PB开发环境的OSDesignView中修改的feature将直接反映到以sysgen_开头的环境变量中,为了验证有哪些sysgen_已经被设置,可以执行Build OSàOpen release directory进入命令行模式,然后执行“set sysgen”命令,就可以看到所有的sysgen_XXX的环境变量了。这些环境变量是属于桌面windows的,可以dos下或是bat批处理文件中使用。由于dos下的命令也是支持一些条件判断语法,如IF ELSE等指令,所以利用dos批处理文件就可以根据既有的环境变量做进一步的处理了。



      现在来介绍微软是如何利用bat批处理对sysgen_环境变量做转换,变成cecongfig.h中的宏定义的。

首先来看cesysgen.bat,这个批处理文件每次在Build OsàSysgen的时候会被调用,其位于“D:\WINCE500\PUBLIC\CEBASE\OAK\MISC”(假设wince500安装在D盘)。

在这个目录下你可以看到很多bat文件:

D:\WINCE500\PUBLIC\CEBASE\OAK\MISC 的目录

2004-07-01  12:00              744 cebase.bat

2007-10-31  11:25            7,362 cesysgen.bat

2004-07-01  12:00            3,743 datasync.bat

2004-07-01  12:00            6,081 dcom.bat

2004-07-01  12:00            26,594 directx.bat

2004-07-01  12:00            4,091 gdiex.bat

2004-07-01  12:00            13,610 ie.bat

2004-10-15  07:15            2,841 netcf.bat

2006-05-04  13:48            9,245 netcfv2.bat

2004-07-01  12:00            5,133 rdp.bat

2004-07-01  12:00            2,632 script.bat

2004-07-01  12:00            20,954 servers.bat

2004-07-01  12:00            2,253 shell.bat

2004-07-01  12:00            1,721 shellsdk.bat

2004-07-01  12:00            1,136 speech.bat

2004-07-01  12:00            1,730 sqlce.bat

2005-12-15  02:20            1,762 sqlmobile.bat

2004-07-01  12:00            3,906 viewers.bat

2004-07-01  12:00            5,242 voip.bat

2004-07-01  12:00            3,025 wceappsfe.bat

2004-07-01  12:00            15,167 wceshellfe.bat

2006-08-31  15:26          100,533 winceos.bat

后面我们会知道,其他的bat批处理文件都会被cesysgen.bat调用到的。

调用“D:\WINCE500\PUBLIC\CEBASE\OAK\MISC >cesysgen report”的时候,你可以看到一些类似ceconfig.h中的宏定义的字符串:

Report:

SYSGEN_ASYNCMAC=1

SYSGEN_AS_BASE=1

SYSGEN_AUDIO=1

…….. 省略

CE_MODULES=coredll nk msim commctrl commdlg rsaenh ….. 省略 (和ceconfig.h中的CE_MODULES_XXX一一对应——config.hmctrl commdlg rsaenh ...)

COREDLL_COMPONENTS=coremain lmem showerr thunks correct ….. 省略(和ceconfig.h中的COREDLL _XXX一一对应——config.hmctrl commdlg rsaenh ...)

……



这说明,在这个批处理里面已经有了sysgen->宏定义的转换了。

用ultraedit打开cesysgen.bat,跟踪report参数,可以走到113行,看到下面的命令:

113 :doReport    #标号

114 echo Report:  #语句显示Report

115 set SYSGEN  #显示所有的sysgen_环境变量

116 if "%__IN_BLD_RECURS%"=="1" set SYSGEN >%_WINCEROOT%\__BLD_RECURS_DEP.txt

117 set SYSGEN >%_WINCEROOT%\public\%_TGTPROJ%\__CEBASE_FEATURES.txt

117 for %%f in (%_DEPTREES%) do call :CallProjFile %%f report

主要看117行,这里是一个for循环,f是变量,%_DEPTREES%是f可以取值的范围,这个语句将%_DEPTREES%中的每个字符串作为参数传递给CallProjFile子函数(批处理标号)。为了了解%_DEPTREES%中有那些字符串,可以执行echo %_DEPTREES%,你会看到类似下面的一串字符:

winceos dcom gdiex ie script servers shellsdk shell rdp wceshellfe wceappsfe viewers directx voip datasync netcf SQLCE ostest speech NETCFV2 SQLMOBILE PROJECTNAME

基本上,上面的字符串和D:\WINCE500\PUBLIC\CEBASE\OAK\MISC目录下的每一个bat文件是一一对应的。 而且大致可以看出,它们的名字就是wince所有组件归类之后的组名。

跟踪到:CallProjFile标号,大概在156行,有如下内容:

:CallProjFile       

    if not exist %__CESYSGEN_PATH%\%1.bat goto :CPF_NotCE

        call %__CESYSGEN_PATH%\%1.bat %2 %3 %4 %5 %6 %7 %8 %9

        goto :EOF

    :CPF_NotCE



    if not exist %_PUBLICROOT%\cebase\oak\misc\%1.bat goto :CPF_NotCE2

        call %_PUBLICROOT%\cebase\oak\misc\%1.bat %2 %3 %4 %5 %6 %7 %8 %9

        goto :EOF

    :CPF_NotCE2



    if not exist %_PUBLICROOT%\%1\cebasecesysgen.bat goto :CPF_Unknown

        call %_PUBLICROOT%\%1\cebasecesysgen.bat %2 %3 %4 %5 %6 %7 %8 %9

        goto :EOF

    :CPF_Unknown

    if /i "%___PUBLICPROJECT%"=="common" if "%_ECHOON%"=="1" echo WARNING: Unable to find project file %1, args %2 %3 %4 %5 %6 %7 %8 %9

    goto :EOF



大致的功能就是到三个路径去寻找 “参数1.bat“ 的批处理文件,如果找到并执行之,首先根据%_DEPTREES%可知,第一个参数是winceos,所以我们在D:\WINCE500\PUBLIC\CEBASE\OAK\MISC下面的winceos.bat会被执行。依次类推,dcom.bat gdiex.bat ie.bat script.bat servers.bat ….这些批处理会顺序执行。

接下来就到了揭开谜底的时候了,打开winceos.bat. 你可以发现有很多类似

if "%SYSGEN_XXX%"=="1" set CE_MODULES=%CE_MODULES% YYY的语句,这XXX和YYY的对应关系就是sysgen_和ceconfig的宏定义之间的关系。

所以类似的,打开其他的.bat文件可以分析其他类别的XXXàYYY的对应了。

这样你可以search到所有的,你想知道的对应关系。


引用本文请注明出处:http://blog.csdn.net/fredzeng

点击此处查看原文 >>

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

评论(0) | 阅读(191)
发表于: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) | 阅读(306)
2下一页总共 , 当前 /