2009年3月30日星期一

MTK平台程序开发-1

作者:Sam(甄峰) sam_code@hotmail.com


Sam以MediaTek MT62xx为平台开发。首先介绍MediaTek开发平台。

MediaTek提供标准软件包,它包含完整的一体化软件,由GSM/GPRS L1和协议栈,device driver,应用程序和MMI组成。通常情况下,采用MTK解决方案的用户,只需要修改一小部分代码来配合他们的硬件修改和定制。目录位于:.../mcu/custom.

程序安装:
1.ADS安装。
2.copy ADS_1.2 Others\ADS_1.2\ADS Patch\armAdsBuild842\bin中内容到 C:\Program Files\ARM\ADSv1_2\Bin
3.copy ADS_1.2 Others\ADS_1.2\ADS Patch\armlib_build_837\Adsv1_2\Lib\armlib内容到 C:\Program Files\ARM\ADSv1_2\Lib\armlib
就是修改编译器和lib.
4. ActivePerl安装:
ActivePerl-5.8.4.810-MSWin32-x86

驱动安装:

程序编译:
打开cmd,进入字符界面。进入source code 目录。
1>. make ivy grps r
然后开始编译。编译完成后,会生成目录 ~\build\IVY\IVY_PCB01_gprs_MT6235B_S01_IVY_SW_0.9.bin, image文件就放在其中。

编译命令的解释:
make xxx gprs new
make xxx gprs update
make xxx gprs remake
make xxx gprs clean
编译成功后,在build目录下生成所有的.obj,编译信息log文件、下载.bin文件等;编译失败时,到build目录下查看相应的log文件,可看到出错信息。

几个关键字解释如下:
1). xxx,Project名,对应make目录下的xxx_GPRS.mak文件;
2) 最后一个关键字:
a. new:不管资源、代码是否有改变,全部重编;
b. update:扫描资源、代码的改变,有改变的重编,无改变的不编;
c. remake:不扫描资源,只扫描代码的改变,有改变的重编,资源和无改变的代码不编;
d. clean:清除build目录下的所有内容,保留目录结构。



程序烧入:
将手机和PC用烧入线连接起来。
运行FlashTool_v3.0836.00\Flash_tool.exe
选择Scatter-loading, 选择~build\IVY\IVY_PCB01_gprs_MT6235B_S01_IVY_SW_0.9.bin\scatIVY.txt文件
Option-〉选择对应的serial port.
关机
按下download
开机,之后开始download



Sam的工作从MMI开始。
MMI:Man Machine Interface。即人机界面。
首先加入一个UI,上面写上:Hello World!


建议加入的代码放到新目录内:
一:目录结构的创建:
首先在plutommi\mmi目录中创建BluetoothUI目录,并在其中创建BluetoothUIInc目录和BluetoothUISrc。顾名思义,里面分别放头文件和源文件。

Sam在plutommi\mmi\BluetoothUI\BluetoothUISrc中创建了一个源文件:BluetoothUISrc.c
又在plutommi\mmi\BluetoothUI\BluetoothUIInc中创建了:
BluetoothUIProt.h :本程序所有函数声明,但只被本程序include
BluetoothUIDefs.h: 本程序的资源ID.
BluetoothUITypes.h:放置本程序使用的所有类型,结构,常量。
BluetoothUIGprot.h:需要被别的程序使用的函数声明,被别的程序include。

二:程序的编写:
void mmi_BluetoothUI_entry(void)
{
//从前一个Screen中退出,进入当前Screen,如果不这样,那前一个Screen还在响应一些消息。
EntryNewScreen(SCR_3DIJOY_SCREEN, NULL, mmi_BluetoothUI_entry, NULL);
//清屏
clear_screen();
//指针位置
gui_move_text_cursor(2, 100);
//字符颜色
gui_set_text_color(UI_COLOR_GREEN);
//写字符入屏幕
gui_print_text(L"Bluetooth Game Controller");

gui_move_text_cursor(60, 200);
gui_set_text_color(UI_COLOR_BLACK);
gui_print_text(L"3DiJoy Inc.");

//刷新,否则字符没有显示
gui_BLT_double_buffer(0, 0, UI_device_width - 1, UI_device_height - 1);
return;
}

并且:SCR_3DIJOY_SCREEN需要被加入到ConnectivityResDef.h中。Screen ID

三:程序加入主程序:
MTK程序与PC或其它Linux嵌入式程序不同,它的程序与整个系统是固定在一起的。Nuclues类似于UC/OS-II。所以Sam只提供了一个 mmi_BluetoothUI_entry()供别人调用。为了测试这个函数,Sam将它加入到:
plutommi\mtkapp\AudioPlayer\AudioPlayerSrc\AudioPlayerSrc.c中的mmi_audply_app_pre_entry()中。也就是“多媒体-〉音乐播放器”的入口程序中。

如同Makefile中需要指定某个obj需要被编译出一样。我们也需要指出BluetoothUISrc.c需要被编译。
Sam先查看AudioPlayerSrc.c在make目录中是被加入到哪里的。发现是:
make\plutommi\media_app\media_app.lis中。于是需要将BluetoothUISrc.c也加入到这个文件中以指出这个.c需要被编译。
并在make\plutommi\media_app\media_app.pth中加入源码路径:
plutommi\mmi\BluetoothUI\BluetoothUISrc,
编译时会报一些东西未定义,只需要加入相应头文件即可。
注[1]
编译成功,烧入手机,进入多媒体-〉音乐播放器,则显示自己的UI。









注1:之前Sam严格按照目录创建了头文件,然后在AudioPlayerSrc.c中include。但在make\plutommi\media_app\media_app.inc指定头文件目录后,还是无法找到头文件,估计是需要 make ivy gprs n
但我们并没有所有的源码,所以无法成功编译。

2009年3月25日星期三

SDL学习

作者:Sam(甄峰) sam_code@hotmail.com

Sam在移植SDL时遇到一些问题,虽然解决了。但还是有点知其然,不知其所以然的感觉。主要原因是对SDL不熟悉造成的。所以抽空利用SDL的test程序学习一下SDL编程。


先看几个常用的structure:
1. SDL_Surface: Graphical Surface Structure
这个结构体实际上是给出了一个可以显示的Surface。其中包含了surface大小,bit_per_pixel,以及pixel data.
它通常是由SDL_SetVideoMode()创建。


以testsprite为例:
1.初始化Video
SDL_Init(SDL_INIT_VIDEO);

2.使用SDL_SetVideoMode()创建一个定制长宽,以及bit-per-pixel的surface。
screen = SDL_SetVideoMode(width, height, video_bpp, videoflags);
创建了一个Surface_A(背景 surface).

3. 使用SDL_LoadBMP()load 图像,并把数据存到一个SDL_Surface ---Surface_B(笑脸surface)中。

4. 使用SDL_DisplayFormat copy Surface_B到一个可以被快速显示的Surface_C(将要显示的笑脸surface)中。

5. 使用SDL_MapRGB()将Surface_A(背景 surface)的 format设置。

6. 使用SDL_BlitSurface()将Surface_C(将要显示的笑脸surface) 快速copy到Surface_A(背景 surface)的0,0位置,大小与Surface_C大小一致。

7. 使用SDL_FillRect()将Surface_A(背景 surface)刚才被copy的位置给盖起来了。Sam:等于没copy.

8. 在loop中:
8.1 首先使用SDL_FillRect()将Surface_A(背景 surface)重新用背景色填充。Sam:Erase

8.2 使用SDL_BlitSurface()将Surface_C(将要显示的笑脸surface) 快速copy到Surface_A(背景 surface)的某个位置(Rand)。

8.3 调用SDL_Flip()或者SDL_UpdateRects()重新画。

GCC,glibc, uclibc,stdc的一些基本概念

作者:Sam(甄峰) sam_code@hotmail.com

Sam有一个C++程序,其中用到:
std::wstring mbstowcs(std::string str);
使用X5平台的编译器编译时,遇到如下问题:
error: expected constructor, destructor, or type conversion before "mbstowcs"
error: expected `,' or `;' before "mbstowcs"

Sam就开始寻找原因。顺便把gcc,glibc,uclibc,stdc++等东西的概念性东西放在这里。

GCC:gcc(gnu collect compiler)是一组编译工具的总称。它主要完成的工作任务是“预处理”和“编译”,以及提供了与编译器紧密相关的运行库的支持,如libgcc_s.so、libstdc++.so等。

glibc:glibc是gnu发布的libc库,也即c运行库。glibc是linux系统中最底层的api,几乎其它任何的运行库都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现.

uclibc:uclibc是另一c运行库,与glibc对应。它比glibc小。虽然uClibc和Glibc在已有的接口上是兼容的,但有些接口并没有实现。

libstdc++:libstdc++ 是GNU C++ standard Library .


Sam觉得既然编译就通不过,那说明X5的编译器本身就不认识,有可能是X5平台的交叉编译器在创建时没有添加stdc支持?后来觉得不是这样,因为STL完全是以头文件形式提供的。
1.所以只需要指定头文件路径,就应该可以编译。于是Sam添加了:
-I/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include/c++/3.4.3/
(Sam觉得海思的交叉编译器做得不是特别规范,为什么呢。因为它放头文件,库文件的地点多变)
添加这个之后,理论上应该是可以编译了。
可发现还是不认识wstring.
2.于是查看/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include/c++/3.4.3/bits/stringfwd.h。
发现要定义_GLIBCXX_USE_WCHAR_T才会有wstring.
3.于是在编译程序时添加了 -D_GLIBCXX_USE_WCHAR_T
还是通不过,说没有wint_t。
4.于是又查STL. 添加了 -D__WINT_TYPE__
又通不过, 说没有 btowc,Sam查遍了toolchain. 也没找到这个类型的定义。感觉很奇怪,就去查/usr/include. 发现这个类型有定义。但toolchain中没有对应的头文件。

所以,Sam觉得很多做嵌入式程序的工程师都不愿使用STL,喜欢用标准C,是有原因的,因为toolchain限制太大。很多提供toolchain的公司对类似STL的提供都不是很全。

2009年3月19日星期四

scons 学习

作者:Sam(甄峰) sam_code@hotmail.com

http://www.scons.org/

Sam有个好朋友是做游戏的,整天嘲笑做嵌入式的用的工具多土多原始。gdb不是图形化,DDD又没VC调试好用,只会写Makefile等等。
刚好最近有需要使用scons。所以Sam准备学习之以回击这种挑衅。呵呵。

scons简介:
scons是一个Python写的自动化构建工具,从构建这个角度说,它跟GNU make是同一类的工具。

scons与其它工具最显著的差别就是:scons配置文件是Python script.

它的思想是跟GNU make完全不同的。GNU make的核心是“依赖关系”,我要做的事情,就是告诉系统,一个目标依赖什么东西,并且,当被依赖的东西发生变化时,我要做什么。
例如:
all: main.c
$(CC) $(CFLAGS) $(LFLAGS) main.c -o BT_remote -lbluetooth -lBluetooth_remote -lm -lpthread
意思是:all依赖于main.c。 如果main.c有了变化,作下面这些事。


这样做可以解决相当多的问题,但是也带来了一个最大的问题:我如何判别这个目标依赖什么?

对于一个两个,甚至十几个文件,我当然还比较容易搞清楚,谁依赖谁。但是当文件有成百上千个时,要分清楚谁依赖谁可就没这么容易了。尤其是C/C++头文件的依赖,如果手工分析的话,工程量可是不小。为了解决这个问题,GNU又提供了另外一套工具:Automake,使用程序来分析依赖性,然后辅助你产生makefile。

于是乎,就有人想了,既然如此,我干吗费那劲,用程序分析依赖性,然后生成一个文件,再交给另外一个程序去处理呢?既然依赖性需要用程序来分析,那么就直接交给构建工具本身去做不就好了吗?对的,这是一个非常自然的思路,于是,Java世界有了Ant,而Python世界有了scons。

scons就是这样一个构建工具:你告诉它要做的任务,以及完成这个任务需要的输入,以及这个任务产生的输出,怎么做这个任务(当然其中就包括依赖性分析),就交给工具本身完成。


例1:
只有一个 test.c文件,需要编译成可执行文件。
创建SConstruct,内容为:
Program('test.c')
这句话透露2层意思:
1.编译方法:想要编译成什么类型。(Program:可执行文件)
2.哪个东西想编译(test.c)
#scons
% scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o test.o -c test.c
cc -o test test.o
scons: done building targets.

clean:
#scons -c
则把编译出的东西又删除了,类似make clean


例2:
只有一个文件,想编译成object文件。
Object('test.c')
1.编译方法:想要编译成什么类型。(Object: .o文件)
2.哪个东西想编译(test.c)

#scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
scons: done building targets.

清空:
#scons -c
则把编译出的东西又删除了,类似make clean

例3:
有多个.c文件,并想指定生成的程序名:
Program('program', ['prog.c', 'file1.c', 'file2.c'])
生成可执行文件 program, 由prog.c file1.c file2.c 生成。
#scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o prog.o -c prog.c
cc -o program prog.o file1.o file2.o

甚至可以这样写:
common_sources = ['file1.c', 'file2.c']
Program('program2', common_sources + ['program2.c'])



例4:
有很多个.c文件,不想一个一个指定,类似Makefile中 *.o: *.c
Program('test', Glob('*.c'))


不管使用common_sources = ['file1.c', 'file2.c'] 还是Program('test1.c'....'testn.c')
每个文件名都需要被单或者双引号包起来。这太不方便了。
SCons 提供了Split函数
Program('program', Split('main.c file1.c file2.c'))
或:
src_files = Split('main.c file1.c file2.c')
Program('program', src_files)



例5:
SCons还对output file和source file有关键字,可以用来指定

src_files = Split('main.c file1.c file2.c')
Program(target = 'program', source = src_files)
因为有关键字指定,多以可以换前后:
Program(source = src_files, target = 'program')


例6:
创建库:
Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o'])
#scons -Q
cc -o f1.o -c f1.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o f4.o
ranlib libfoo.a

例7:建立静态和动态库:
静态库:其实使用Library也是建立静态库。
StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
动态库:
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])

% scons -Q
cc -o f1.os -c f1.c
cc -o f2.os -c f2.c
cc -o f3.os -c f3.c
cc -o libfoo.so -shared f1.os f2.os f3.os

例8:使用静态和动态库:
使用$LIBS 来指定库,使用$LIBPATH 指定库位置。
Library('foo', ['f1.c', 'f2.c', 'f3.c'])
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
% scons -Q
cc -o f1.o -c f1.c
cc -o f2.o -c f2.c
cc -o f3.o -c f3.c
ar rc libfoo.a f1.o f2.o f3.o
ranlib libfoo.a
cc -o prog.o -c prog.c
cc -o prog prog.o -L. -lfoo -lbar


Program('prog.c', LIBS = ['m'], LIBPATH = ['/usr/lib', '/usr/local/lib'])
% scons -Q
cc -o prog.o -c prog.c
cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm




以BTX为例使用scons:
Sam创建了一个SConstruct,(类似于GNU make的Makefile文件,是scons的默认文件名).

Sam首先想生成BTX library.
然后想将library 和 main.c和成一个可执行文件:BTX_Test
内容如下:
#指定生成文件名为:libBTX.a. 由BTX.c生成的。-I'/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include -I../include
StaticLibrary('BTX', ['BTX.c'], CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include', '../include'])
Program('BTX_Test', ['main.c'], CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include', '../include'], LIBS=['BTX','blu\etooth','pthread'], LIBPATH=['.', '/usr/lib'])

#scons
提示之不到bluetooth库,Sam在/usr/lib中将 libbluetooth.so 软连接到libbluetooth.so.2。
于是编译成功,所以,Sam觉得Scons和Makefile很类似,只需要编译时指定-I ,-L, -l就好了。对应关系如下:
-I:CPPPATH=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/include', '../include']
-L:LIBPATH=['.', '/usr/lib']
-l: LIBS=['BTX','bluetooth','pthread']
CPPPATH,LIBPATH,LIBS,CC等从:
http://www.scons.org/doc/1.2.0/HTML/scons-user/a4774.html#cv-CPPPATH 中找到
同时请注意,最好在每个关键字赋值后面都跟 [],里面有多个时用逗号分开。


X5 Version:
StaticLibrary('BTX', ['BTX.c'], CC=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/bin/arm-uclibc-linux-gcc'], CPPPATH=['/opt/his\ilicon/toolchains/arm-uclibc-linux-soft/include', '../include'])
Program('BTX_Test', ['main.c'], CC=['/opt/hisilicon/toolchains/arm-uclibc-linux-soft/bin/arm-uclibc-linux-gcc'], CPPPATH=['/opt/his\ilicon/toolchains/arm-uclibc-linux-soft/include', '../include'], LIBS=['BTX','bluetooth','pthread'], LIBPATH=['./', '../resource/']\)



scons只需要描述任务,并不需要指定依赖关系,甚至我们都没有指出头文件,但是你修改BTX.h的时候仍然会触发构建。这是因为scons内部有个scanner,可以帮助扫描包含文件的关系。
我们还发现,这里我们根本没有指定编译器,也没有指定编译选项,但scons仍然很聪明的选择了gcc. 这是因为scons内置提供了很多编译器及其对应选项的选择,然后对于不同的平台,会有一个默认项。



Environments:
Scons有3种环境变量:
1. External Environment
2. Construction Environment
3. Execution Environment

当想要使用External Environment,必须通过os.environ。这意味着首先要加入:
import os
之后就可以在SConscript文件中使用os.environ来初始化construction environments 为用户环境变量了。

1.创建Construction Environment
env = Environment()

例如:
import os
env = Environment(CC = 'gcc', CCFLAGS = '-O2')
env.Program('foo.c')



最重要的环境变量是:Construction Environment
它在复杂的工程中非常重要,例如,不同的源文件需要不同的编译选项。或者不同的可执行程序需要链接不同的库。scons提供Construction Environment。让我们可以创建不同的Construction Environment来创建不同的编译选项。

1. 创建Construction Environment ,使用Environment function。
env = Environment() 所有的Construction Environment 项目值全用scons自己找到的。
env = Environment(CC = 'gcc', CCFLAGS = '-O2') ,其他的与上一个相同,但只有CC和CCFLAGS 自定义。

2. 察看Construction Environment 每个项目值:注[1]
需要使用Dictionary() function
env = Environment()
dict = env.Dictionary()
keys = dict.keys()
keys.sort()
for key in keys:
print "construction variable = '%s', value = '%s'" % (key, dict[key])
打印所有Construction Environment项目。








scons中Python模块的导入:
1. import os
os模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。一个例子就是使用os.sep可以取代操作系统特定的路径分割符。


os.name字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。
os.getcwd()函数得到当前工作目录,即当前Python脚本工作的目录路径。
os.getenv()和os.putenv()函数分别用来读取和设置环境变量。
os.listdir()返回指定目录下的所有文件和目录名。
os.remove()函数用来删除一个文件。
os.system()函数用来运行shell命令。
os.linesep字符串给出当前平台使用的行终止符。例如,Windows使用'\r\n',Linux使用'\n'而Mac使用'\r'。
os.path.split()函数返回一个路径的目录名和文件名。
os.environ Shell variables
这里重点说os.environ:
它应该是Linux环境变量。

例1:
想要得到当前Linux环境变量PATH,LD_LIBRARY_PATH,HOME等。(这与前面讲的环境变量对应起来了)

#导入OS模块
import os
#创建一个Construction Environment
env=Environment()
print "HOME: ", os.environ["HOME"]
则打印结果为HOME:/home/sam。这样就得到了Linux环境变量。

例2:
想要用当前Linux环境变量ARMGCC来设置toolchain.

首先:在Linux下:
export ARMGCC=arm-linux-gcc

之后,修改config
#导入OS模块
import os
#创建一个Construction Environment
env=Environment()
if os.environ.has_key('ARMGCC'):
env.Replace(CC = os.environ['ARMGCC'])
则使用arm-linux-gcc取代了Construction Environment中的CC。



2. import sys
sys模块包含系统对应的功能.sys模块包含了与Python解释器和它的环境有关的函数.
import sys
if sys.byteorder == 'little' or env['PLATFORM'] == 'win32':
env.Append(CPPDEFINES = ['LSB_FIRST'])


3. import platform
platform得到编译信息:
platform.processor() ---i686
platform.python_build()---('r251:54863', 'Jun 4 2007 15:03:52')
platform.python_compiler()----'GCC 3.4.4 20050721 (Red Hat 3.4.4-2)'
platform.python_version()----'2.5.1'
platform.release()----'2.6.9-22.ELsmp'
platform.system()----'Linux'
platform.version()----'#1 SMP Mon Sep 19 18:32:14 EDT 2005'
platform.uname()----('Linux', 'nec', '2.6.9-22.ELsmp', '#1 SMP Mon Sep 19 18:32:14 EDT 2005', 'i686' , 'i686')
platform.machine()----'i686'
platform.libc_ver()----('glibc', '2.0')




注[1]:
所有Construction Variables可以在下面找到:
Construction Variables可用在:
1. CPPPATH,LIBS,LIBPATH。(在BTX例子中可见)
2. Construction Environment(env=Environment)中的项目。

Appendix A. Construction Variables

2009年3月11日星期三

Linux下Framebuffer学习


作者:Sam(甄峰) sam_code@hotmail.com


Sam之前写过vfb(虚拟framebuffer) driver. 但现在什么都不记得了。 现在需要在X5平台上使用framebuufer. 只好再学习一次。



零:Framebuffer 简介:

Frame Buffer设备为图形硬件提供抽象。它表示一些视频硬件的Frame Buffer,允许应用软件通过定义好的接口访问图形硬件,所以这些软件不必知道任何关于低层(硬件寄存器)的知识。


使用frame buffer设备的应用程序(例如 X server)默认使用/dev/fb0(老一点的软件使用 /dev/fb0current)。你可以通过设定环境变量$FRAMEBUFFER等于frame buffer设备的路径名来改变frame buffer设备,例如(针对 sh/bash用户):export FRAMEBUFFER=/dev/fb1或者(针对 csh 用户):setenv FRAMEBUFFER /dev/fb1之后,X server将使用第二个frame buffer。


大家都已经知道,frame buffer设备是一个内存设备,就像/dev/mem, 所以他拥有相同的特征。你可以读他,写他,在他里面定位和mmap他(主要用途)。


/dev/fb*也允许在他之上做一些ioctls操作,通过这种方法硬件的许多信息可以获取和设置。颜色映射处理(the color map handling)也通过ioctls工作。


- 你可以取得硬件的不可更改信息,例如名字,屏幕内存组织方式(位面,象素格式,……)和地址和屏幕内存的长度。

- 你可以获取和修改硬件的可变信息,例如可见,虚拟几何,深度,颜色映射格式,定时,等等。如果你试图修改这些信息,驱动可能规整一些值以适应硬件的能力(或者返回EINVAL 如果这个操作不可能) (译注:the driver maybe will round up some values to meet the hardware's capabilities)

- 你可以取得和设置部分颜色映射。通信使用16位每一颜色(红,绿,蓝,透明)来支持所有存在的硬件。驱动处理所有应用于硬件的计算(截取他们到较少的位,可能会舍弃透明)。



视频模式计时:(非常重要)

显示器使用电子束(彩色模式使用3个电子束,单色模式使用1个电子束)绘制屏幕上的图像。屏幕的前面被颜色荧光(象素)覆盖.如果荧光被电子击中,它就会发出光子从而可见.


电子束从左至右绘制水平行,从上到下绘制整个屏幕.通过改变电子束的亮度,便可以显示各种颜色和亮度的像素


每条扫描线完成后电子束必须重新移回到下一行的左端:这称做水平回扫.等到完成整个屏幕(帧)的绘制,电子束会移回到左上方点:这被称做垂直回扫.在水平和垂直回扫期间,电子束被关闭(空).


电子束绘制像素的速度由图形板的时钟决定(译注:dotclock).

例如:时钟是28.37516MHZ(每秒百万周期)。也就是说每秒可以绘制28.37516M像素。

每像素需35242 ps(微秒):1/(28.37516E6 HZ) = 35.242E-9 s


如果屏幕的分辨率是640x480, 将需要640*35.242E-9 s = 22.555E-6 s来绘制一条扫描线上640(xres)个像素.但是水平回扫也需要时间(例如 272 像素), 所以一条完整的水平扫描线需要:(640+272)*35.242E-9 s = 32.141E-6 s

我们称水平刷新率约是31 kHz:1/(32.141E-6 s) = 31.113E3 Hz


整个屏幕有480(yres)条扫描线,但是我们必须还要考虑垂直回扫(例如 49 条扫描线). 所以完整的一屏需要:(480+49)*32.141E-6 s = 17.002E-3 s垂直刷新率约是 59 Hz:1/(17.002E-3 s) = 48.815 Hz这意味着屏幕上的数据每秒钟刷新约59。


从最上面的图可以看出:
水平回扫时间是左边缘(left_margin),右边缘(right_margin)和 hsync 长度(hsync_len)的总和. 而垂直回扫时间是上边缘(upper_margin),下边缘(lower_margin)和 vsync长度(vsync_len)的总和。这些值与fb_var_screeninfo结构体中的项目对应。
frame buffer设备期待所有的水平计时以时钟(以picoseconds, 1E-12 s)为单位,垂直计时则以扫描线数目为单位.
pixclock(以ps为单位的像素时钟)
- pixclock: 以ps为单位的像素时钟(pico seconds)
- left_margin: 从sync到画面的时间
- right_margin: 从画面到sync的时间
- upper_margin: 从sync到画面的时间
-lower_margin: 从画面到sync的时间
- hsync_len: 水平sync的长度
- vsync_len: 垂直sync的长度








一. 基本使用方法:


(之后再补上)





二. 最重要的结构体:


fb_var_screeninfo
简单的项如下:
__u32 xres; /* visible resolution */
__u32 yres; //可见部分的长宽
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual; //虚拟部分的长宽
__u32 xoffset; /* offset from virtual to visible */ //可见和虚拟部分的offset
__u32 yoffset; /* resolution */


__u32 bits_per_pixel; //每个象素占多少位
__u32 grayscale; //不等于0的话,灰度


struct fb_bitfield red; /* bitfield in fb mem if true color, */

struct fb_bitfield green; /* else only length is significant */

struct fb_bitfield blue;

struct fb_bitfield transp; /* transparency */

fb_bitfield:结构很重要:

struct fb_bitfield

{

__u32 offset; /* beginning of bitfield */

__u32 length; /* length of bitfield */

__u32 msb_right; /* != 0 : Most significant bit is */

};

像素详解:

以上的结构其实与像素有关,这个结构是说:这种色值(RGB或者transp=alpha)在一个像素点结构中的offset,length

---------------- 一个像素点

R G B a

这样,上面这个结构就明白了吧。

其它机构的含义,请看上面的视频模式部分。呵呵