2007年11月28日星期三

DRAM precharge power down mode

我们知道 DRAM中的记忆体,或者说电容,打开新行的操作就是precharge(预充电)。预充电可以通过命令控制,也可以通过辅助设定让芯片在每次读写操作之后自动进行预充电。而从预充电到真正发送行有效命令需要一些时间

DRAM中prechar

2007年10月25日星期四

UART hardware flow control

串口,RS232UART这些概念总是让人头晕。如果你也有同感,那么就对了。因为串行通讯这一块从来就没有统一过,连接的方式和协议更是百家争鸣。

不过现在用于嵌入式领域的UART通讯基本是统一的。一般只用rx,tx,cts,rts这几个信号。下图是一个典型的SOC连接蓝牙芯片的连接。其中包含了发送和接受的流控制机制。


2007年7月29日星期日

操作系统内核的中神奇的代码

最近free download一个Linux kernel 2.6.22。由于工作的原因,大概有2年没有碰触Linux了,这些天又有生活无目标的感觉。花了2年时间才大概弄清楚WinCE整体的结构,基本能够理解微软的设计思想,也尝试看WinCE5的内核代码,但是有时候会很不爽,一个函数跟着跟着就丢失了。尤其是GWES,我最想知道的部分,完全没有代码。内核代码很多类似的部分,其中几乎都是C语言构成,C语言的组织基本架构就是函数,我们平时写应用程序时,也经常用函数,可是内核中的函数有时充满了玄机,有的是不归路,有的切换,有的是交错运行,对了,此时让我突然想起硬件文境切换代码,有空大家一定要看看绝对长见识。不过今天不看那些东西,我随便读,代码到哪里就说到哪里。看内核启动时,初始化终端的函数

void __init console_init(void)

{

initcall_t *call;

/* Setup the default TTY line discipline. */

(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

/*

* set up the console device so that later boot sequences can

* inform about problems etc..

*/

call = __con_initcall_start;

while (call <>

(*call)();

call++;

}

}

__con_initcall_start这个变量你就是找遍所有C和汇编代码你也找不到它的原型。它是出现在内核编译的链接阶段,是一个编程语言中的标记,或者说是一个地址,在这里也确实表现为地址,__con_initcall_start__con_initcall_end一起前后界定了了代码段中.con_initcall.init

#define console_initcall(fn) \

static initcall_t __initcall_##fn \

__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

搞这个macro声明了很多已赋值的函数指针,如32CPU那么就占用4个字节,console_init就是循环运行这些函数指针多对应的函数。这个架构真是太好了,很多驱动程序只要用这个macro就可以声明自己,而内核初始化部分就无须直接关心有多少console驱动程序做这样的声明,靠着强大的编译器就可以帮助你了解到。还是GCCLD厉害,微软的编译器功能太少,灵活度不高(至少微软对外放出的编译器是这样,说不定他们内部有很高级的)。不过毕竟微软不希望你利用他们的操作系统再去开发别的系统。呵呵。

所以分析内核代码是一定要想象这段代码的运行环境,否则你很难理解作者到底要干什么。文境切换代码更是如此,经过schedule函数直接就到另外一个进程去了,很神奇。还有在SMP环境下,一个函数直接会分叉,编程同时在多个CPU运行。今天就看了这点东西,以后再遇到什么好玩的东西,再和大家分享。

2007年7月28日星期六

程序员你有资格骄傲么?

我遇到过太多太多自以为是的例子,有时候包括自己。

超级解霸之父梁肇新在他书中提到程序员进阶的几个阶段,我非常同意这位大师的观点。

其中有个阶段就是学习驱动程序和理解操作系统的内核,从1990年一直有以研究linux内核所引发的研究操作系统内核的一股风潮。Ring0Ring3,虚拟内存,系统调用,进程同步,缺页等等,有一些听起来很炫的专业词汇,更有甚者,以为自己能说出这些词,自己就是高手了。

Ring0/3,如果你不懂Intel IA-32体系架构,那么请你谦虚一点。

虚拟内存,page poolpage fileswap partition,如果你没有仔细研究过当代CPU中的MMU的一些共性,当虚拟页面不在时,CPU如何响应,CPU特权级如何切换。这些都是硬件知识。虚拟内存的管理涉及ring0内核的管理,和ring3普通进程管理,他们是关系?这些你都不懂,那么请你谦虚一点。

系统调用,Intel CPUtrap 0x80是实现linux系统调用的入口,然后ring0内核再进行一次派发,最后到达实现体。windows也是类似,他们运行在同一个CPU上,不可能有太大区别。当然这里有安全机制,不可能让你这么容易就进入ring0胡作非为。如果这些你都不懂,那么你就很难想象windows如此多的DLL是干什么的,他们之间的堆叠关系,Windows丰富的API都做了些什么,在哪个ring运行,更很难想象,很多API会引发一场轰轰烈烈的ring3ring0的切换。ntDll.dll这个连接ring0ring3的使者在干什么。Glibclinuxz这个系统中的地位。如果你不懂,那么请你谦虚一点。

进程同步,进程调度算法,这个是现在的大学最喜欢教学生的部分,还会出很多颠过来倒过去的题让学生作答。这些东西没他们宣扬的那么重要。Tanenbaum教授在<>中就是这样说,“而实际系统中很重要的部分,如IO系统和文件系统又以为缺乏理论性而被忽略”。在1969年贝尔实验室第一个PDP-11系统,后来被认为是unix操作系统第一版中,当时已经可以多进程同时运行,但是multiprogramming就不可以,就是因为还没有设计出完善的文件系统,这样的问题直到1972UNIX系统被C重写时,问题才被真正解决。

缺页,现代物理内存有限,只好用虚拟内存,没进程2GB,或者4GB空间,说起来很容易,我只想问你理解么?为什么WINCE5.0进程是32MB6.02GB?微软会做什么调整?你能想象一下么?如果你是微软,那么你怎么做这个调整?createprocess底层实现中,进程空间内存分配原则就要改掉。.exe有两个模型,一个是在文件系统中的模型,一个是在进程空间的模型,他们往往会有差异,微软建立在COFF文件结构基础上的的PE文件结构是如何来说明她们的不同。Process loader在操作系统中的地位。有次引发的page on demand策略的产生。多任务不一定要实现缺页,只要进程足够小。但是多任务,而且每进程空间都是CPU所能承受的最大空间,这就必须有缺页机制。如果你都不懂,那么请你谦虚一点。

一个操作系统是在另一个操作系统里面编译完成的,你信么?还有很多很多的知识,你懂么?如果你说你都懂,好,那么我告诉你,你也没什么了不起。哦你说你可以用C+汇编实现上面东西,那么我告诉你,你同样没什么值得骄傲的,这个世界上很多人都能写自己的内核,注意我说的是“内核”,仅仅指“内核”。你能写只能说明你的编程功底很深,你能预见这些技术难题。补充一下,这些“技术难题”在现代根本不是难题,但确实是几十年前的技术难题。说明你把“古人”的解决这些问题的方法掌握了,计算机对你已经很通透。但是程序员的最高境界你仍未达到。内核只是整个操作系统中的一部分,是核心部分,注意不要被“核心”二字迷惑,它只是指地理位置的核心,并不是指重要性的核心。你可知道微软的office套件比他的XP professional贵很多。相信不用我说你也可以理解。说明微软在OFFICE上所花的心血绝对不亚于一个操作系统。从这些“高手”认为,内核最牛,可是你看office这样应用程序会比你的内核复杂,你信么?有幸您写一个能和微软这么强大的OFFICE出来,在下一定跪拜师学艺。就不说office,就说XP操作系统,内核是什么,ntoskrnl.exe一个2MB的文件,好了不用我多说,你也能很清楚掂量内核的地位。内核以外,操作系统要提供友好的界面,丰富的API,安全机制,大量可用的应用程序等等这些才是大头。一个不懂电脑的人,你和他说操作系统,他不会懂。你说对他重要么?不重要。“能用,好用”这才是重要的,你那些后台努力的骄傲就收起来吧。享受一下用户说这个东西好的感觉。

程序员最高境界不会再关心这些,什么语言?什么系统?什么内核?什么驱动?什么应用?那是一种对大局的把握。对一个庞大软件的设计能力。不过没有前一阶段的积累,你也决不可能到达这个阶段。因为假如让你来设计这个庞大系统,你会有很多自己的技术问题还没有解决,你根本不敢乱想。很多人或者公司也做大系统,为企业定制。那也许不是我说的庞大系统。你注意到,你的系统里只涉及若干东西,数据库操作,浏览器等等。我想大概oracle算是这样庞大软件了。当然office3DmaxmayaProEapache等等应该都算。他们的设计者是真正的高手。

工作经历告诉我,对硬件的控制并不是什么难事,一个驱动程序你能做,往往只是指你能做硬件控制部分,和操作系统的部分也往往是别人都写好的代码,并不是你设计的,如果这部分你也可以设计,那你也是高手,可以小骄傲一下。所以收起骄傲,停止说这个驱动简单,那个驱动简单,我看哪怕是一个完整串口驱动的设计者,也绝对是行业中的高高手。奉劝那些为windowsLinux或者WINCE写驱动程序的程序员,谦虚点,不要一搞就瞧不起做应用程序的。去看看apache之父的言谈,就知道什么才是真正的高手。

2007年7月26日星期四

Windows Mobile bus driver

Windows Mobile的驱动程序程序实际是一个树状结构。Device.exe
负责加载几乎所有的驱动程序,而驱动程序的各种信息是存在于注册表里面。在系统启动?
锥危琩evice.exe是不知道有多少驱动是要加载的。他只是找到bus driver
,然后由它继续加载所有的驱动,所以bus driver是很重要的驱动程序,是桥梁驱动。
注册表中,HKEY_LOCAL_MACHINE\Drivers的键值RootKey指示了bus driver
的位置,一般你会看到Drivers\BuiltIn。那么HKEY_LOCAL_MACHINE\Drivers\BuiltIn下
Dll说明的是bus driver的名称。
微软的Ak中是默认有个驱动的BusEnum.dll(在public下有源代码)。这个驱动会枚举
BuiltIn下的所有键值,将这些驱动都加载进device.exe。
bus driver OEM是可以替换的。你此时可能回想既然已经有现成的,为什么还要自己写?
在很多时候,SOC的许多module的clock
开关都会放在一个统一的寄存器组里,那么驱动程序在想开/关这些寄存器时,都要操作?
桓黾拇嫫髯椋庵止蚕碜试吹姆梦适强赡芤鸪逋坏摹?

每个驱动要访问这个寄存器组,他们也就需要映射这个物理空间。如果每个驱动都映射,?
驮斐尚槟饪占涞募罄朔选?
那么如何完成自定义的bus driver
?微软为我们提供了很完善的类库,使我们很容易做到。Class DefaultBusDriver 和
Class DeviceFolder就是这样基础类。详细的代码细节自己看吧。Bus driver
是也是标准的流驱动。它需要在xxx_Init中引发一系列枚举动作,将驱动加载进来。

2007年6月21日星期四

Stay in Unattended mode(written by Mike)

I believe the fastest way to get the screen to turn off is this. As soon as your app detects the phone ring, first call:

PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);

Then call

PowerPolicyNotify(PPN_POWERBUTTONPRESSED, 0);

Now handle the call. You need to be calling SystemIdleTimerReset(); every 30 seconds to keep the system from falling asleep while you're processing the call.

When the call is over, do:

PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE);

The first PPN puts the system into a state where, if the power button is pressed, it will turn the screen off but not suspend.

The second PPN simulates the press of the power button. Assuming the screen was on at the time, this will tell the system to suspend, but will instead go to the Unattended (screen off) state because of the first call. (If the screen was off when you did the PowerButtonPressed, it would turn the screen on.)

When you're done with the call, the last PPN tells the system to suspend immediately (as long as there isn't another app in Unattended).

SD卡关于WINCE睡眠的思考

blogs.msdn.com的Mike这样说:
On most devices, the SD hardware is powered down when the system suspends. So it needs to be re-initialized on wakeup. Then, after it is initialized, it needs to find the SD card and mount it. Depending on the SD bus hardware and the particular SD card, this process can take a few seconds.
在大多数的设备上,当系统进入睡眠时,SD设备是断电的。因此当系统醒来时,它需要重新的初始化。很自然地,初始化后,要查找SD卡和挂装文件系统。由于SD设备和SD卡的不同,这个过程需要一些时间。

由此想到以下的测试要求是不合理的:
1.SD卡复制文件时,susend和wakeup系统,不能要求他还能续传
2.Media player在播放SD卡上的音乐文件时,susend和wakeup系统,不能要求还能继续播放

2007年6月19日星期二

Windows Mobile 5 虚拟内存空间危机

虚拟内存空间这个概念我们常常听见,也有很多人能说出个一二。但是其实真正能理解这个概念的人并不多。今天就以Windows Mobile 5这个嵌入式操作系统理解一下什么叫Virtual Memory Space

Windows Mobile 5的虚拟内存模型如下图:

我们会看见这样的概念:kernel space user space。看似简单,你真的理解么?分析这样的memory space概念的时候一定分清视角,通俗说就是你是以user进程的角度,还是以微软操作系统内核的角度看这个空间。这点非常重要。不信你试试看。

0x8000,00000xFFFF,FFFF这个叫内核空间,也就是只有内核代码可以用这样的地址,他们是高特权级的区域。你的应用程序是访问不到的。如果你要“硬”来,操作系统一定会把你destroy掉,并给你一个类似非法访问的警告提示。除非你是“黑客”,用类似“缓冲溢出”等攻击方法来访问。

那么对于0x8000,0000以下的空间,叫做用户空间。什么?你做就知道了?!哈哈!那我问你,用户空间是不是只有用户程序可以访问的空间?你要是回答是,那就错了。用户空间是用户程序可以访问的空间,但不是“只有”。内核是老大,他当然也可以访问。所以你看,我们定义user space的概念一般只是针对user来说,而定义kernel space只是针对kernel来说,如果你只是单单把user spacekernel space放在一起,实际上没什么可比性。

小总结一下,kernel可以访问整个4GB空间,而user“最多”只能直接访问下2GB空间。我这里又多强调了一个“最多”。下面将详细讲解。

“最多”也就是说用户程序不能整个空间都是他的,一个多任务分时操作系统上同时有很多的用户的程序在“奔跑”,而且彼此独立,互不打扰。内存空间这样宝贵的资源,内核不可能让某个进程独占,因此,Windows Mobile5将下2GB空间均匀划分成64块,每一块32MB,并且slot0~slot32用于用户程序,slot32-slot63用于shared memory,所以WM5最多能有32个进程同时在运行。我们可以看见,每个单独的process是有可怜的32MB的大小。这个数值才是我们真正该关心的东西。每个进程的内存是不允许其他空间随便访问的。可怜可怜,你只有有32MB可以“使用”。“使用”这个概念再落实一下,就是如你调用VirtualAlloc()这样的内存分配函数。

我这篇文章叫“危机”,不是光介绍一下这些概念。想想,像device.exe这样的“进程大户”,身上挂装了n多的DLL,而且每个驱动程序都要类似调用VirtualAlloc的函数来映射寄存器空间,也就是CPU的整个寄存器空间几乎都要映射到这个狭小的32MB空间里,自己本身还有很多的代码与数据要占用空间,这个进程真是很吃力呀。随着SOCsystem on chip)的茁壮成长,一个chip里集成的module数量越来越多,随之而来的寄存器的增多,也就是寄存器组空间的增大,Windows Mobile5将不再可以使用。

幸好2007年我们迎来了Windows CE 6,虚拟空间的问题得以解决。可是微软相继发布的CrossBow主要是UI的变化,内核依然采用windows CE 5。不知什么时候微软会发布使用CE6内核的Windows Mobile

我们现在还要继续使用Windows CE5 kernel,那就要想办法解决这个问题。

前面提到slot32-slot63用于shared memory,如果能使用这块空间,那么虚拟内存不足的问题就可以解决。微软告诉我们mapped file是使用这块空间的,所以解决方案自然是
h_map=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, Size, NULL);
VirBase=MapViewOfFile(h_map, FILE_MAP_WRITE, 0, 0, 0);

这样分配下来的虚拟地址会在0x4200,0000-0x7E00,0000区域内。此时只有虚拟空间被分配,实际的物理内存还并没有映射。因此这个时候你不能类似这样:

*(volatile DWORD *)VirBase=123;

写内存,这个动作会分配实际的物理内存,从而直接导致下面的VirtualCopy的失败。

这样虚拟空间有了,实际的物理内存可以这样映射


VirtualCopy((void*)VirBase, (void *)(PhyBase >> 8), fbSize, PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL)

这个三个函数的结合使用,使我们可以充分利用user memory 的空间。

2007年6月13日星期三

Windows Mobile文件系统相关注册表设置

在工作过程中,很多同事都会问起文件系统注册表的设定。今天我就总结一下贴在这里。下面是一个典型的注册表的设置:

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SMFLASH]

"Prefix"="DSK"

"Dll"="ONDisk.dll"

"Index"=dword:1

"Order"=dword:10

"Profile"="SMFLASH"

"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"

"BmlVolumeId"=dword:0

"BmlPartitionId"=dword:3

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SMFLASH]

"DefaultFileSystem"="IMGFS"

"PartitionDriver"="mspart.dll"

"AutoMount"=dword:1

"AutoPart"=dword:1

"AutoFormat"=dword:1

"Name"="Microsoft Flash Disk"

"Folder"="Storage"

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SMFLASH\IMGFS]

"MountHidden"=dword:1

"MountAsROM"=dword:1

"XIP"=dword:0

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SMFLASH\FATFS]

"Flags"=dword:10

"FormatTfat"=dword:1

"CheckForFormat"=dword:1

"EnableWriteBack"=dword:1

"MountAsBootable"=dword:1

"MountAsRoot"=dword:1

红色的是经常被质疑的部分,他们虽然在微软的document上可以找到相关解释,可是还是有很多歧义,让我们一起仔细看看。下面我会用到很多PC的概念来帮助大家理解。

第一段代码是说明“硬盘”驱动是那个DLLProfile键值说明profile的名字,也就是【HKEY_LOCAL_MACHINE\System\StorageManager\Profiles】之后跟着的名字,这个名字你随便取,只要不超过7个字符都可以。其实profile可以理解为在“硬盘”驱动之上的软件层,属于文件系统这个领域的概念。而第一段是驱动程序领域的概念。

第二段是这个profile的总体的信息,他一定会有分区的概念,所以我们需要mspart.dll来识别分区信息。

"AutoMount"=dword:1

"AutoPart"=dword:1

"AutoFormat"=dword:1

这几个你就一起用,没关系的。我知道你担心什么。那就是担心分区的内容会不会每次重启都会重建,分区内容会丢失。实际上不会的。Autoformat是当发现分区的文件系统没有格式化时,才回去format,反之,如果已经formated,那么就不会有任何动作。Autopart是在你的profile没有分区时,系统自动帮你分区,不过他没有那么智能,只能将整个profile分成一个区,从头到尾。当然同上,如果你已经有分区信息,系统不会做任何动作。Automount是如果分区没有安装,就会自动安装。这3个键值,你就一起把他们加上,肯定没问题。

第三段定义了profile之上的特定分区imgfs分区,这是一定要有的分区。MountHidden是将这个分区安装为不可见。这样你在资源管理器里就不会看见这个目录。MountAsROM是以只读方式安装,这样分区的文件是不可写的。

第四段代码是真正的用户空间,是fat文件系统。FORMATTFAT是强制以tfat文件系统格式化,tfatfat更加的强壮。CheckForFormat键值是可选的,加上之后,这个分区在每次重启是系统都会用

IOCTL_HAL_QUERY_FORMAT_PARTITION ioctl来检查是否需要格式话。如果没有这个键值,文件系统就不会调用这个ioctl

"MountAsBootable"=dword:1

"MountAsRoot"=dword:1

这两个键值一般都一起用,就是指明是该分区是root file system

好了,到此就基本说完了。如果有什么问题可以mail我。

2007年5月30日星期三

dio nb0 bin的关系


在wm533中,生成的image的扩展名很多,dio,nb0,bin等等,他们都是什么关系。看一个例子。
Memory.cfg.xml的内容如下

我们可以看见image由4个分区组成,分别为ULDR,NK,OS,Storage(最多只能有4个分区)。这4个分区都放在一个NAND flash上面,叫做FLASH,所以build完整个image会生成一个flash.dio。
Flash.dio完全是一个flash的镜像,如果用于工厂的量产,可以直接映射在NAND flash上面用。
同时会生成flash.dio.nb0,看似只多了一个扩展名,可是内容就完全不同了,这是为第三方的flash用的,会在每个512字节后面,也是是一个扇区后面,添加8个字节的sectorinfo。所以它会比flash.dio大。要强调的是,这个文件用flash.dio处理而来。
最后会生成flash.bin,它由flash.dio.nb0处理而来,这个文件是有格式的,也就是说有文件头,文件信息之类。
总结一下,flash.dio -> flash.dio.nb0 -> flash.bin,如此的生成过程。

2007年5月28日星期一

天蝎和水瓶

男天蝎和女水瓶
你俩是“刹那触电型”搭配,速配指数7.0。你严谨且实际而她崇尚自由,也很理想化。彼此会有着不可捉摸的吸引力,有时也会有一瞬间的触电感。但你俩在各 方面的差异都很大,你会觉得她的博爱是不专一,还认为她只会有不切实际的空想;而她也会觉得你善妒、占有欲也极强,束缚着她喘不过气来。若真心想在一块, 还是很有希望的。其实,你俩都有着坚定的信心,尤其对自己意志贯彻执守的程度,及超越自我的企图心强,最好还能创造一些共同的目标和兴趣。抓住这些,你俩 还是很有机会成双成对的咧!

男水瓶和女天蝎
你俩是“刹那触电型”搭配,速配指数7.0。她严谨且实际而你崇尚自由,也很理想化。彼此会有着不可捉摸的吸引力,有时也会有一瞬间的触电感。但你俩在各 方面的差异都很大,她会觉得你的博爱是花心,还认为你只会有不切实际的空想;而你也会觉得她妒忌心强、占有欲也极强,束缚着你喘不过气来。若真心想在一 块,还是很有希望的。其实,你俩都有着坚定的信心,尤其对自己意志贯彻执守的程度,及超越自我的企图心强,最好还能创造一些共同的目标和兴趣。抓住这些, 你俩还是很有机会成双成对的咧!




天蝎座—水瓶座 3 Back 3


水——固定型——消极的 气——固定型——积极的
由冥王星制约 由天王星制约
象征:蝎子和鹰 象征:水瓶
夜晚力量——阴性 白天力量——阳性

这两种人很难接近,都太野性。在这一章里,我们尽量保持不偏不倚,坚持中立。不过要保持中立也不容易,因为从文学角度讲,就没办法让人保持冷静,超然局外,尤其看到两人缠到一起,一会儿爱得死去活来,一会儿暴跳如雷地争吵,谁能不动心?

有人会想:这样两个人怎么会相识的呢?还有的人会想:这样两个人相处是明智的做法吗?他们之间的4—10日宫型决定他们总会处于紧张的关系中。问题是:这两人要在这些紧张关系中干些什么呢?他们是需要把这些紧张化作争执冲突,还是化为一种能量去完成共同的心愿呢?

在天蝎座人看来,水瓶座人穿着标新立异,与众不同,挺有意思,而在水瓶座人看来,天蝎座温文有礼,安静沉着,不知整天想些什么,也够让人好奇。

于是两人走近了,但都抱着很强的防范意识。由于他们一人属气,一人属水,结果反而不易相互伤害,甚至令双方受益匪浅。这两人最热衷的业余消遣便是刺探彼此 的秘密。这两人都是天生的侦探,谁也不能忍受对对方的隐秘有所不知。他们喜欢研究对方,把对方像一个钟一样在想象中一一分解。不过,天蝎座人干起来老道, 不太显山露水,而水瓶座人干起来则不太知掩饰。当然水瓶座人读到这里时一定会抗议,说他们压根不爱和人说三道四,但他们喜欢凡事都找个究竟。因此,建议由 天蝎座人和水瓶座人组成的伴侣,最好各自锁好自己的记事本、日记和抽屉,以免产生不快。

他们另一个必须逾越的障碍是由于天蝎座和水瓶座都是固定型,所以他们都很固执。不过,固定型也意味着稳定长久,所以未尝不好。

他们中的差异之一是天蝎座人记忆力太好,而水瓶座人总心不在焉,所以对什么都悄会久存在心底。天蝎座人可以极好控制自己;而水瓶座人自制力极差,这点可真该好好向对方学习。

天蝎座人花钱谨慎,而水瓶座人大手大脚,甚至连钱是被偷还是花了也弄不清。明白这点后,天蝎座人最好去管家,但也不要让水瓶座人手头太紧。

天蝎 vs 水瓶

很麻烦的一对,基本大家都不是雷同的东西,你们一齐只有一个原因:贪新鲜的水瓶座偶然被深情的天蝎魅力所吸引,一见就闪出电光来,但结果只有两个:就是水 瓶座顶不顺天蝎座这一种情绪高低起伏及独霸性,一声不向就走了,其二就是天蝎座支持不了水瓶座那种不是一般人可以接受到的奇异行为,根本无办法控制他而黯 然引退。

水瓶座觉得自己不属于任何人,只是属于自己,但天蝎座就要他只是属于天蝎座一个人,你说这样怎么办。

对于家庭的概念亦有不同,水瓶座没有天蝎座那么实际,只要想拥有,不惜任何代价,对天蝎座来说总是费解,在屋企、衣食住行问题方面就会出乱子了。

勾 引:天蝎座要找紧水瓶座贪新鲜,求新的心理,要捉住他,不妨用多些自己天然的性感魅力,多做勾引性的举动,日日给一些新惊喜,这样或者可以吸引住他的心, 还有行事之时,要多一些神秘感,太多的保留,配合你收收埋埋的个性,你知道吗,你愈神秘,他愈想起你底子,吊起来买是最好的方法。

发烂:这一套是两个人都要避忌的行为,因为你们都会有的倾向,水瓶座好急燥,见到不满的事,就会即刻发烂,而天蝎座可以忍住忍住,但一有机会就乘机发烂,结果伤的就系两个人的感情,说到侵略性,你不是天蝎座的班底。

2007年5月8日星期二

微软引起的while不归路

如果你是windows mobile的驱动程序开发人员,又恰好写了类似的这样一句话。
while(dev->devState!=5);
说明一下,dev是个结构体指针。你希望等待它的成员变量变成5,继续执行。同时

有可能你在中断服务程序中改变这个成员变量的值。
哈哈!我幸运的告诉你你已经进入了“死循环”,永远跳不出去啦。

这是个编译器优化产生的问题,看看编译器产生的汇编片段。
|$L39064|
cmp r3, #5
bne |$L39064|
它将dev->devState优化为了一个寄存器r3,这样的比较是跳不出循环的。

那么要解决这个问题就是将dev这个指针声明为volatile,之后,看编译器产生的汇编片段,变成了
|$L39064|
ldr r3, [r6, #4]
cmp r3, #5
bne |$L39064|
这才是我们想要的结果。汗!!

我在WM533做的实验,确实有这个问题。我觉得这个优化,微软做的太离谱了。不知道算不算编译器bug

2007年4月3日星期二

优化耗电过程

我们可以不允许系统进入backlight off和suspend,然后看系统能够运行多久。如果这个时间能够增长,再对suspend进行实现,这样就有更长的使用时间了。

2007年3月31日星期六

PowerButton高频率点击

变态的测试人员,居然会把高频率点击powerbutton也变为他们的测试项目。可是更有“高水平”开发人员为了迎合这种测试,“自以为是”对wince的电源状态转换进行改动。比如为了切换速度快,按power button让系统先进入unattended mode,再按power button系统又切到on。的确是切换速度快了很多,但是他们欺骗了用户,让用户以为unattended就是suspend。哈哈,可是问题接踵而来,suspend该有的系统行为,unattend模式怎么可能有,结果更多的bug由然而生。

还有人会说PowerPolicyNotify(PPN_POWERBUTTONPRESSED, 0)不怎么好用,认为SetSystemPowerState好用,可以直接使系统变到自己想要的状态。不要以为看了public下面的code就以为自己了解了PM,光说这“看”与“看”还有区别呢,你到底消化了多少??!

我们是谁?开发人员,我们可以改变用户的习惯,不要惯了他们的“毛病”。我们可以定义如:
1. power button 最高速度一秒按一下
2. 连续按住power button达一秒,才产生一次power button消息

请你们平时多提升一下个人的专业水平,理解软件架构的意义。

2007年3月16日星期五

Windows Mobile Activity timer

Activity Timers也不是什么新鲜东西。这个东东真的很难懂,连续看了MSDN的解释不下20遍,也还是没弄懂怎么回事,说得太抽象了。希望这里我能帮大家有个形象的理解。

我们都知道在PocketPC上,我们点击touch panel,如果机器没有睡觉,那么屏幕就会亮起来。这其实是系统backlight offon的一次电源状态转换,这个动作是由pm.dll来完成的。

那么pm.dll是如何“感知”到这种“user activity”的呢?其实就是这个activity timer

touch panel为例,当有点击事件时,会SetEvent()来通知Pm.dll,这个event的名字由注册表HKEY_LOCAL_MACHINE\System\GWE\ActivityEvent的键值指明,其值一般为PowerManager/ActivityTimer/UserActivity ,这个event是被pm.dll随时“监视”的。也就是说如果你setEventpm.dll就会认为是“user activity”,然后再做相应得电源状态转换。

2007年3月12日星期一

[新手上路]在你的WinCE应用程序中映射硬件物理地址

在你的WinCE应用程序中映射硬件物理地址,下面是个例子

void * MapPhys(UINT32 addr,int size)
{
BYTE * Buffer=NULL;

//分配size大小虚拟地址空间
Buffer = (BYTE *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
if(!Buffer)
{
MessageBox(NULL, _T("mem map error"), _T("Error"), MB_OK|MB_TOPMOST);
goto cleanup;
}
//映射物理地址(传给内核的地址总是要右移8位)
if (!VirtualCopy(Buffer, (void *)(addr>>8),size,PAGE_READWRITE | PAGE_PHYSICAL | PAGE_NOCACHE))
{
MessageBox(NULL, _T("mem copy error"), _T("Error"), MB_OK|MB_TOPMOST);
goto cleanup;
}
cleanup:
return (void*)Buffer;
}


这个函数返回的地址你就可以用了。Good luck!

2007年3月9日星期五

Wince shell 电池指示器反应慢?

Windows Mobile桌面上的电池图标有时会更新的太慢,我们知道可以用
hevent = CreateEvent(NULL, FALSE, FALSE, TEXT("SSUpdatePower"));
SetEvent(hevent);
CloseHandle(hevent);
来强制shell去更新电池状态。可是你会发现即时这样做,有时还是达不到目的。
为什么?
shell必然是调用GetSystemPowerStatusEx或GetSystemPowerStatusEx2来询问电池状态,这两个函数都用一个共同的参数BOOL fUpdate,据我了解到,shell正是传了FALSE进这个函数,结果导致,读到的是battery驱动中cache的信息,因此会表现出反应慢。
那么我们可以在battery驱动中强制调用GetSystemPowerStatusEx(TRUE),来达到目的

unattended mode不是驱动玩的东西

我们在写wince驱动的时候,千万不要自己去调用PowerPolicyNotify( PPN_UNATTENDEDMODE),永远要记住,整个操作系统中除了驱动程序,更重要的还有应用程序,他们才是上帝,是需求的提交者。
总感觉自己的废话很多,但是无论我重复多少遍,还有很多程序员犯这样的错误。

2007年3月2日星期五

wince电源管理框图


流接口驱动程序总是通过IOCTL接收系统对自己的设置。IOCTL_POWER_SET就是系统把设备的状态设置成D0D1D2D3D4其中之一。可以想象,设备驱动自己如果想主动的改变自己的状态,那么很容易可以在自己的代码中调用自己的IOCTL。可是,如果这样做,设备的状态是不被系统知道的,我们必须通知系统。DevicePowerNotify()就是用于通知系统,再由系统决定当前是否需要改变设备的电源状态。注意,千万不要假设,当你call DevicePowerNotify(),你一定会收到IOCTL_POWER_SET。因为系统会根据应用程序的需求决定当前是否改变设备状态。

2007年2月28日星期三

power消息


Battery驱动程序总是和power management有关。battery当前的状态是由battery驱动主动通过powerpolicynotify()报告给pm.dll的,然后当Pm.dll收到这个消息,它会GetSystemPowerStatusEx2()读取一次电池的状态,如果确实发生改变,pm.dll会发送消息给提出消息通知RequestPowerNotifications()的应用程序

电源管理之 关于电源状态的思考

系统状态的onsuspend是最基本的状态,对于CPU一般就是onsleep两个状态,因此很容易理解。

Backlight off就是关掉背光灯,其他设备都正常运转,此时用户的所有活动(按键,点击触摸屏等)都会通知到pm.dll,使系统状态变回on,同时也由pm.dll调用ioctlIOCTL_POWER_SET把每个设备的状态设置一次。我们可以在控制面板中设置什么时候关掉背光。

Backlight off超时,就会suspend,此时所有的设备进入D3CPU进入等待中断的节能状态。我们可以SystemIdleTimerReset()间隔一段时间重置一下timeout时间,使系统永远都不能suspend,这就是为什么media player可以连续播放音乐,而不至于sleep。你可以注意到这种对电源的需求是由应用程序提出的,而不是驱动程序。

系统一但进入suspend,只有靠hardware中断才能唤醒CPU core,驱动程序可以调用KernelIoControl(IOCTL_HAL_ENABLE_WAKE)来宣告自己是唤醒系统的中断源。我要强调一下,这里的“唤醒”不是使系统变为on,而是系统由suspend变为resumingresuming对应D2,作为用户或者开发者的你,在外面是看不见任何现象的(不会有背光被打开)。如果你想要如SD卡插入系统被唤醒(即系统进入on的状态),需应用程序或驱动程序监视系统进入resuming状态,此时查看唤醒源是什么中断,如果是SD,可以模拟一次application button press,发送PowerPolicyNotify(PPN_APPBUTTONPRESSED0),即可以完全唤醒系统。

Resuming被定义为“最不稳定”的状态。因为当处于其他的任何状态,都可以通过间隔性的调用SystemIdleTimerReset()来保持住当前状态,唯独resuming不可以被保持,15秒之后系统会睡眠。

那么来假想一种需求,如果某个应用程序每隔5分钟需要做一些例如同步的事情。5分钟很长,这个程序还想为系统考虑,节约用电,那么5分钟之内系统可以suspend来节电,5分钟之后通过RTC中断将系统唤醒,做一些“后台”同步的事情,因此这个事不需要用户参与(也就是背光和屏幕可以关闭,同时声音关闭)。这个需求导致了unattended电源状态的产生。在进入resuming状态15秒以后,如果系统发现有程序提出unattended的需求,
PowerPolicyNotify( PPN_UNATTENDEDMODE
TRUE)
PowerPolicyNotify( PPN_UNATTENDEDMODE
FALSE)
那么系统进入unattended电源状态,使机器在不打扰用户的情况下运行。

2007年2月27日星期二

winCE电源管理之 系统状态 与 设备状态

最近一直在看window mobile 5.0的电源管理,试图抓住他们的思想。终于发现光看文档是不会有什么感觉的,非要看代码,然后回来结合文档才知道是怎么回事。

所谓的电源管理(power management),就是让电池驱动的winCE嵌入式系统,能够有尽可能长的使用时间。这里主要想谈谈pocket PC

系统中device.exe是加载大部分驱动程序的进程,wince5.0的电源管理核心代码在pm.dll中,而pm.dll也是device.exe加载的对象。所以这是集中管理的模式,pm.dll承载了绝大多数管理代码。

从软件层面看,电源管理中涉及两种状态:system power statesdevice power states

System power states包括:OnSuspendBacklight offResumingUnattendedUser idle。这是“系统”的状态,也可以理解为CPU的状态或者操作系统得状态。

Device power states包括几个等级:D0D1D2D3D4。这些是winCE管理的“设备”状态,如果你是某个设备的驱动程序员,每个设备都有自己的电源管理模式,最基本的是开和关两个状态,对应D0D4。因此D1D2D3自然就是开与关之间的状态。就是这么简单,不要想复杂了。

“系统”状态和“设备”状态他们之间有系统默认的对应关系,就是说对于一个“系统状态”,系统中所有设备都默认被设置成某个“设备状态”(除非有特殊说明,某些设备可以对应不同的“设备状态”)。on对应D0,即系统在on状态时,所有的设备都是打开的。suspend对应D3,即系统在睡眠的时候,所有设备都被设置为D3Backlight off对应D0,同理所有的设备打开,不过这个状态有特殊说明(要不它如何区别onbacklight off),bkl1:对应D4,即,背光灯关闭,因此backlight off就是其他所有设备打开,bkl1:关闭。同理可以理解其他的系统状态。Suspend对应D3resuming对应D2等等。

整个wince系统就是一个状态机,每个状态现在都可以理解,但是有状态,就有状态转换,在特定条件下的转换。几个系统状态中只有一个状态suspend是比较稳定的,因为其他的几个状态都会经过timeout最后变成suspend。引用wince开发人员Mike Calligaro的话,装有wince的设备就像一个疲劳的看守坟场的保安在值夜班,正托着下垂的眼皮在看电视,偶尔拍他一下,他才醒过来。

驱动程序和应用程序的区别

懂软件结构的人都知道这两个概念,那我要是问你他们有什么区别,真的很难回答。你可能会说驱动是对硬件操作,应用程序是调用驱动程序。那么如果你写过WINCE的嵌入式应用程序,同时又写过wince的驱动程序,你会发现这个区别更加难回答。wince user mode驱动可以使用的函数,wince应用程序一样可以使用,都可以操作硬件。昏倒!

从代码这个层面说区别不容易,我今天在写其他文章的时候,突然对这两个概念有一个新的想法。驱动程序和应用程序在代码上是一样的,驱动程序一般是很被动的,不是被硬件触发一个中断,就是被上层调用。而应用程序是主动的,它可以向系统提出请求,甚至调用驱动。

通过自己的这个定义,引出我们驱动程序员在开发驱动时,不要以为自己处于核心地位,想干什么就干什么。其实应该“老实”一点,不要在驱动中做出“主动”的事情来,记住我们的程序是被动的,跟多的精彩然应用程序去发挥吧!

展望2007

今天是过年后上班的第二天。新年总是希望有新的开始,今年希望自己能做到技术总监类似的位置,能对系统总体架构把握,并进行很好的设计。培养team members很好的编程习惯.

WinCE 5.0 power state machine