ARM开发过程中最最需要注意的问题
平时大家接触最多的可能是X86平台,在这种系统上写程序几乎不需要考虑太多问题,但ARM上就不一样了,最常见也最容易被忽略的问题可能就是字节的对齐,即使像我这样有六七年程序开发经验的才手也时常难于提防,最近就有一个BUG,花了一天时间最终发现是对齐引发的,在此与大家分享,但愿大家能够注意到。
我在EBOOT中读取存在HARD DISK上的nk.bin文件,从而从HARD DISK上LOAD WINCE系统,在这个过程中总是有check sum错误,但从ethernet下载时不会有错,所以问题应该还是在我加的这部分代码上,而且同样的代码在PC上能正常运行。经过检查代码的逻辑关系是正确的。接着我在出错时将那些数据全部用调试信息打出来,发现从文件开始算起第4096个字节被丢掉了,而其它的字节都是对的。初步判断是对齐引发的问题,所以去查每一个BUFFER,最终发现是在读取硬盘数据时BUFFERR并没有按双字节对齐,而硬盘以16BIT读取数据,而引发了错误。
实际上,这类问题在ARM系统上很常见,让人防不胜防,以下是我的一些例子。
1,解析数据流时应该时刻注意。如果需要把一个数据流(BUFFER)转化成结构进行取值,就应该把这个结构定义为按字节存取.考虑如下结构:
struct a{
char a;
short b;
long c;
};
如果某个数据流中包含这样的结构,而且我们要直接将数据流的指针转化成该结构的指针,然后直接取结构成员的值,我们就应该将这个结构定义成按字节访问,即将其夹在语句
#pragma pack(push,1)
...
#pragma pack(pop)
之中。如果我们不这样做,编译器会将成员b的地址对齐到short指针的地址,即在a之后加上一个char即8位的成员,将C对齐到LONG,即在B之后再加一个char成员。如此一来,成员B和成员C就得不到正确的值了。
如果我们定义一个普通的结构用来存放一些数据,则不用定义成按字节存取,编译器会加上一些占位成员,但并不会影响程序的运行。从这个意义上讲,在ARM中,将结构成员定义成CHAR和SHORT来节约内存是没有意义的。
一个典型的例子就文件系统的驱动程序,文件是以一些已经定义好的结构存放在存储介质上的,它们被读取到一个BUFFER中,而具体取某个文件、目录结构时,我们会将地址转化成结构而读取其中的值。
2,访问外设时。
例如,磁盘驱动通常以16BIT的方式存取数据,即每次存取两个字节,这样就要求传给它的BUFFER是双字节对齐的,驱动程序应该至上层传来的指针做出正确的处理以保证数据的正确性。
3.有时,我们没有将数据流指针转化为结构指针取值,但如果我们读取的是双字节或者是四字节的数据,同样需要注意对齐的问题,例如,如果从一个BUFFER的偏移10处读取一个四字节值,则实际得到的值是偏移8处的
地址上的DWORD值。
如何改wince装驱动
打开之前做wince内核定制烧写的工程,把驱动文件,假设叫A.dll, 拷贝到工程目录下,D:/WINCE420/PUBLIC/wince工程/RelDir/SAMSUNG_SMDK2410_ARMV4Release 这个下边.然后在pb工作环境中,找到ParameterView区,展开树型列表,找到project.bib和project.reg两个文件,要对他们进行修改.
修改 project.bib 添加 A.dll $(_FLATRELEASEDIR)/A.dll NK SH 这样一行 .
将产家提供的reg文件里的内容copy到project.reg里.
以上做好后,因为我是pb4.2的环境,这时候点bulide菜单下的make image.等完成后,再重新烧写一遍镜像文件(nk) 到开发板上就可以了。注意我这里选make image而不是build platform。如果选build platform会抱错的,说找不到dll等等几个错误。我买的周立功的一本书上是在pb5.0环境下,到这一步时说 在菜单buuild os中,不选clean before building。然后再选择sysgen重新编译生成新的wince映像
物理地址映射方法分为两种,一种静态映射另一种为动态映射。在OEMAddressTable中定义了物理地址与虚拟地址的映射关系属于静态映射,用VirtualCopy映射属于动态映射,采用哪种办法都可以。问题中提到的属于静态映射,2440的BSP在map.a文件中定义了IIC控制寄存器的物理起始地址和对应的虚拟地址如下:
DCD 0x91400000, 0x54000000, 1 ;
在OEMAddressTable中定义的虚拟地址范围在0x8000 0000—0x9FFF FFFF,这部分可缓存,适合内核程序和应用程序使用,同时WINCE内核在0xA000 0000—0xBFFF FFFF中映射了另一份,指向了同样的物理地址,这部分不可缓存,适合驱动程序使用。三星ARM处理器带有L1级高速缓存,可缓存会提高执行效率。对于特殊的设备寄存器适合映射到不可缓存的虚拟地址。
当驱动程序调用VirtualCopy对0xB1400000地址读写时,WINCE自动将这个地址减去0x2000 0000,也就是0x91400000,对应的物理地址就是0x54000000,也就是IIC控制寄存器的物理起始地址。