一只鱼 さんのプロフィールEE小站フォトブログリストその他 ![]() | ヘルプ |
|
9月25日 在ARM Linux上使用OpenGL这两天在ARM上跑了一个OpenGL,应该说是OpenGL|ES的软件包,虽然我觉得可能最后我不会使用这个软件包,但是还是记录下来以备忘记。
先全局介绍下,首先,什么是OpenGL和OpenGL|ES。OpenGL是一套绘图函数的标准,OpenGL|ES是OpenGL中针对嵌入式系统的一套函数子集。OpenGL|ES的官方是http://www.khronos.org/opengles/,上面有更多的信息。需要注意的是,OpenGL仅仅是标准,而如果你要使用OpenGL,则需要找到可以实现这些OpenGL标准函数的程序库或源代码。目前,在ARM这种一般没有图形加速器的平台上,OpenGL|ES的实现都是靠软件的。主要的OpenGL|ES程序库有:Klimt,Vincent (ogles),TinyGL等。Google一下,可以看到它们的主页。这些实现基本上都是基于X11、Qt/E这样的窗口平台的。我用的软件包叫做PicoGL,它是TinyGL的一个分支,不同之处就在于PicoGL支持直接在Framebuffer上输出图像。PicoGL是一位台湾同胞写的,他的主页http://jserv.sayya.org/。但是这个软件包的源码极其难找,我用的是一位很牛的同事搜到的,地址是http://people.openmoko.org/jserv/graphics/picogl-20051108.tar.bz2。
要使用这个软件包还必须有支持软件浮点的交叉编译器,我们一般用的arm-linux-gcc 2.95.3/3.3.2/3.4.1等都不支持软件浮点,这需要我们重新编译一个。编译一个交叉编译器,引用Crosstool作者Dan Kegel的话,used to be a scary prospect,requiring iron will,days if not weeks of effort……幸好有Crosstool这个工具,如果你的机器好网速快,输入个指令,差不多1个多小时就可以编译出来。crosstool的主页http://kegel.com/crosstool/,下载地址http://kegel.com/crosstool/crosstool-0.43.tar.gz。
首先制作交叉编译器,先以root用户登陆,建立交叉编译器安装目录,而且把目录所有者改为你的普通用户
# mkdir /opt/crosstool
# chown /opt/crosstool lxz
# chgrp /opt/crosstool users
然后以普通用户登陆,解压缩和安装
# tar xvzf crosstool-0.43.tar.gz
# cd crosstool-0.43
# ./demo-arm-softfloat.sh
crosstool会从网上下载需要的源码包,然后编译,最后安装。crosstool相关的资料可以看http://kegel.com/crosstool/current/doc/crosstool-howto.html。然后在/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu里面就会有支持软件浮点的交叉编译器了。
然后解压缩picogl,修改picogl的代码。
首先是picogl的一处bug,在backends/vesafb/tk.c的第一行增加宏
#define _FB_TK_
然后把backends/vesafb/glx_impl.h里面的
struct fb_fix_screeninfo FixedInfo;
struct fb_var_screeninfo VarInfo, OrigVarInfo;
修改为
#ifdef _FB_TK_
struct fb_fix_screeninfo FixedInfo;
struct fb_var_screeninfo VarInfo, OrigVarInfo;
#else
extern struct fb_fix_screeninfo FixedInfo;
extern struct fb_var_screeninfo VarInfo, OrigVarInfo;
#endif
这是因为有好几个文件调用了backends/vesafb/glx_impl.h,如果不这么改,会出现多重定义错误。
然后,为了让你的程序使用picogl更方便些,最好再改个地方include/GL/glx.h
#include GLX_IMPL_HEADER
改为你喜欢的方式,指向backends/vesafb/glx_impl.h
修改backends/vesafb/tk.c中,initialize_fbdev函数有关VarInfo的设置,改为适合你的LCD的。
然后配置
# cd PicoGL
# CC=/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin/arm-softfloat-linux-gnu-gcc ./configure --with-backend=vesafb --host=arm-softfloat-linux-gnu --prefix=/home/lxz/builtPicoGL
说明下,CC=设置交叉编译器的位置,--with-backend=vesafb指定使用FB作为显示设备,host=arm-softfloat-linux-gnu设定交叉编译,--prefix=/home/lxz/builtPicoGL设定编译后库和示例程序安装位置。
然后
# make
# make install
在/home/lxz/builtPicoGL/lib里就有PicoGL的库了,把动态库文件拷贝到arm-linux根文件系统的/lib里面,把/home/lxz/builtPicoGL/bin里的程序拷贝到arm-linux文件系统的任何地方,然后制作和烧写文件系统映像(或者使用NFS),执行,就可以看到结果了。
当你编译一个使用PicoGL库的程序(假设叫做hello.c)时,需要输入
# arm-softfloat-linux-gnu-gcc -c -I /home/lxz/PicoGL/include -I /usr/include hello.c
# arm-softfloat-linux-gnu-gcc -o hello -L /home/lxz/builtPicoGL/lib/libPicoGL.so -L /home/lxz/builtPicoGL/lib/libPicoGLU.so -lm hello.o /home/lxz/builtPicoGL/lib/libPicoGL.a /home/lxz/builtPicoGL/lib/libPicoGLU.a
今天写得比较粗糙,呵呵。 9月18日 使用DDD+GDB开发ARM Linux程序今天又取得了一些进展,赶快写下来以免自己忘记。
自从Linux在我的板子上跑起来之后,我一直在想一个问题,怎么调试将来写的程序。其实我在Linux开发方面真得很外行,到了今天才知道GDB到底是干什么用的,呵呵。我相信很多人从Bootloader调试开始一直都使用LED啊,printf这样的方法来调试。我做毕设时,就是在MTDBLOCK里面划出一个USER分区,然后把编译好的程序放入文件系统映像,通过Bootloader用串口下到NAND里,然后mount上调试,实在很花时间。今天,白痴的我终于找到了一条捷径,已经不咳嗽了!
先介绍下DDD和GDB,GDB是一种用于调试Linux下程序的工具,它不仅能调试C/C++,还可以调试Pascal等很多其他语言。我们看个例子:假设有一个程序叫做test.c,要用GDB调试它,首先,编译的时候需要加上产生debug信息选项“-g”,如#arm-linux-gcc test.c -o test -g;然后,由于我们并不是开发本机程序,在目标机(arm)上需要用一个server启动这个含有调试信息的程序,当然,本机和目标机之间得有一定的数据共享方式(如nfs)和一定的通信方式(如以太网或串口);最后,在本机上启动一个GDB客户端,就可以登陆到目标机的server上调试程序了。GDB的原理网上也有很多文章说,可以搜索下,但是我是初学者,就不去看那些内容了。为了让大家更加明确GDB和DDD的区别,我们先看一个GDB的调试过程:
我通过以太网调试,本机IP地址192.168.2.31,目标机(arm开发板IP地址192.168.2.223),本机通过nfs共享开发目录lgraphics。
首先本机上编译:
lxz@lxzlinux:~/lgraphics> arm-linux-gcc lgraphics.c -o lg -g
切换到目标机:
[root@(none) lgraphics]# gdbserver 192.168.2.31:2345 lg
Process lg created; pid = 402 Listening on port 2345 切换到本机:
lxz@lxzlinux:~/lgraphics> arm-linux-gdb lg GNU gdb 6.6 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-linux"... (gdb) target remote 192.168.2.223:2345 lg Remote debugging using 192.168.2.223:2345 lg 0x40001290 in _start () from /lib/ld-linux.so.2 此时,目标机上也会出现:
Remote debugging from host 192.168.2.31
在本机上输入:
(gdb) b main (设置断点到main函数)
Breakpoint 1 at 0x9c00: file lgraphics.c, line 442. (gdb) cont (开始执行) Continuing. Breakpoint 1, main () at lgraphics.c:442 (遇到断点,并显示断点程序行)
442 int i, j, b = 0; (gdb) step (单步执行) 445 linitgraph("/dev/fb0"); (显示目前程序行) 好了,看到这里,差不多就明白GDB是干什么的、怎么用了吧。我相信你会和我一样对GDB界面的不友好表示愤慨,想想Windows下的开发工具,哪一种调试的时候还是文本界面的。幸运的是,有一些勤快的人,帮我们写了很多GDB的图形化前端,我们更本不用像上面这样使用GDB。
开始说DDD。DDD是一种GDB的图形化前端,就是一种用图形界面帮你输入繁琐的GDB调试指令工具。当然,也有很多文章说DDD多么不足,用Insight来取代它之类的。我的Suse里恰好就有DDD,我也不管那么多了,先用了。看看用DDD的时候怎么调试:
一样本机上编译:
lxz@lxzlinux:~/lgraphics> arm-linux-gcc lgraphics.c -o lg -g
切换到目标机:
[root@(none) lgraphics]# gdbserver 192.168.2.31:2345 lg
Process lg created; pid = 402 Listening on port 2345 切换到本机:
lxz@lxzlinux:~/lgraphics> ddd -debugger arm-linux-gdb lg 然后就会启动DDD的图形界面,在窗口下方有一个文本输入框,这里就是ddd的基础gdb的所在,在这里输入target remote 192.168.2.223:2345 lg,提示信息和我们用GDB时候是一样的。不同的是,除了这句连接目标机的指令,其他指令都不用输入了,可以在图形化界面里找到,这我就不说了。另外,连接目标机的指令也可以用在DDD中设置,不用输入,可以查找其他介绍DDD使用的文章。下面是DDD的图形界面,工具栏下面的是watch,代码可以设置断点(红色点),可以看到单步位置(绿色箭头),右边是执行控制工具条,最下面是GDB的输入和输出显示。
看到这里,想我一样的菜鸟们一定发现了,原来Linux程序可以这么好调啊,简直和CE没有什么差别了,呵呵。下面介绍为了使用GDB+DDD所要做的东西。我不是从零开始建立的,具体的包依存关系我也不明白,只好假设你在安装Linux的时候已经安装了像GCC,DDD之类的工具。GDB的源代码包gdb-6.6.tar.bz2可以从ftp://gcc.gnu.org上下载到,还有一个要求是你已经安装了交叉编译器arm-linux-gcc。
下载下来后:
# tar xvjf gdb-6.6.tar.bz2
# mkdir gdbbuild
# cd gdbbuild
# ../gdb-6.6/configure --target=arm-linux --prefix=/home/lxz/lxzgdb
这里,--prefix参数是需要安装的目录,然后
# make
# make install
这样,arm-linux-gdb这个工具就在/home/lxz/lxzgdb/bin里头了,你可以把这个路径添加到PATH里面去
接下来建立gdbserver,在gdbbuild的上一级目录下
# mkdir gdbserverbuild
# cd gdbserverbuild
# CC=arm-linux-gcc ../gdb-6.6/gdb/gdbserver/configure --host=arm-linux --prefix=/home/lxz/lxzgdbserver
一样,--prefix参数是需要安装的目录,然后
# make
# make install
有的文章里说,要去除arm-linux-strip的调试信息
# cd /home/lxz/lxzgdbserver/bin
# arm-linux-strip gdbserver
把这个gdbserver复制到你的开发板上,就OK了。
今天就写到这里。 9月13日 由一些小问题引起的东西又是好久没有更新了,同样记录下这段时间干的事情。
来到公司报道之后我就去了工厂,呆了一个多月,熟悉公司各种产品的生产过程。当然,就是和生产线上的小MM们聊聊天,哈哈,开玩笑了。这期间我的导师给我了个任务——一个UI的低成本实现。这个UI必须具有LCD显示、USB主机、网络等功能,要求就是低成本低成本再低成本;很自然选型选完之后就又变成搞ARM了。买了开发板,硬件就没有什么好说的了。任务的重点落在了软件上,刚开始我和导师达成的意见是代码裸奔(省去授权费用),或者穿个自己写的小OS。于是我花了2个星期的时间写了0.8(写了任务切换,其他没有最后写完)个类似uCOS功能的小OS,发现这种东西跑在ARM920T上实在发挥不出920T的功能,于是我又花了2个星期写了存储管理,打算加入MMU;但是写完发现就算系统能工作,我怎么调试应用程序是个大问题,因为用了MMU,用户进程就不能和内核一起玩了。经过和导师的商量,我再次回到了Linux;目前的打算是使用免费的内核,自己写个类似TC的图形库,或者使用Microwindows + FLTK之类的不要钱的东西。很浪费时间啊,花了4个星期才发现原来自己写系统真的是非常困难的。但是这4个星期也没有白花,有些附属产品,例如自己写的不需要stdlib库的malloc。其实我是第二次写这个东西了,第一次的不太成熟,用了几次就发现局限性了。现在写的这个是我啃了几天操作系统原理写的,应该相对好用,以后有空我会贴出代码来。
然后就是我做过的Linux开发过程了,其实说起来,这次开发我发现自己Linux真的什么都不懂。过去偷懒没有花时间好好看看Linux内核,现在造成很多麻烦,今天这些问题,熟悉内核的人只需要1分钟就能搞定了,我花了1天多。写下这个笔记,以便以后查阅使用。
第一个问题:启动Linux的时候LCD会全屏花屏大约0.5秒,然后左上角出现一块不明花斑。
这个问题相对简单。因为我在Bootloader里面打开了液晶显示,缓冲区映射在某个地址上,当内核初始化MMU的时候,LCD控制寄存器里缓冲区的位置信息就不对了,或者是Bootloader使用的缓冲区被内核的数据或代码覆盖,导致在内核初始化LCD之前,LCD花屏。
那个不明花斑其实是Linux的可爱小企鹅图片,但是可能因为缓冲区像素位宽和格式、LCD调色板设置等问题显示不出来。
花屏解决方法:在Bootloader加载系统之前关掉LCD控制器或者关掉LCD的背光,这样做比较简单。复杂的,就得改MMU映射部分代码,在修改了MMU映射之后,立即修改LCD缓冲的位置。反正我就关掉LCD控制器了,因为内核很快就会初始化LCD,Windows启动都黑屏呢,我们黑那么2秒钟也没有什么大不了的。
花斑解决方法:相信如果做产品的话,不需要显示什么企鹅给用户看,所以可以在内核选项里将这个企鹅logo关掉。具体位置在Device Drivers>Graphics support>Logo configuration,对应的宏相信在.config里面很容易找到。如果非要显示这个企鹅,那么可以在/drivers/video/console/fbcon.c里面找找,我也不知道怎么弄。
第二个问题:Linux启动之后,只要一段时间不动键盘(开发板上用IO扩展出来的键盘),LCD就会自动关闭(黑屏、显示慢慢消失之类),只要按下键盘就能恢复。
这个问题让我花了一天多的时间。其实如果是手持设备,这样也没有什么。但是我们公司的产品是要一直显示东西的,必须解决这个问题。我看了很多论坛,有不少人也遇到了这个问题,但是我刚才是搜索的时候,关键词不对,总找不到正确的答案。如果你遇到了同样的问题,而且不想看我的三脚猫分析,那么就在百度上搜索“blankinterval”、“setterm -blank 0”之类的,马上你就能找到简单的解决方案。
这个问题很容易让人想到屏幕保护和电源管理。的确,这是一种电源管理。但是,你却无法从Linux内核选项的电源管理中解决这个问题。我们一步步来。
首先,我测量到LCD的PCLK时钟消失了,这意味着内核把LCD控制器关掉了。于是,从LCD驱动程序着手。我用的是S3C2440,这是2410的升级版,但是LCD控制器是一样的,在我拿到的开发板厂商给我做好驱动的内核里,驱动的位置在/drivers/video/s3c2410fb.c。为什么后面有个fb呢?这是Framebuffer的缩写,百度下你能找到很多关于它的解释。Framebuffer是所有Linux下GUI程序对硬件操作的设备接口,位于/dev中,一般为fb0。在s3c2410fb.c中可以找到一个类似s3c2410_disable_controller()这样名称的函数,我的驱动里叫pxafb_disable_controller(),可以看出这个驱动是从pxa处理器改的,当然厂家不一样名字也叫得不一样。里面有一句类似这样写的__raw_writel(fbi->reg.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);,把这句话删掉LCD就不会关掉了。这是第一个层次,我也看到有人是这样做的。但是,这有问题,按键盘恢复后,原本显示在屏幕上的东西如果你不重画会消失,就算你重画了,也会看到屏幕的某些部分先黑了下,然后恢复了。当然如果你可以接受,那么就这样吧。
然后,可以很自然的想到是谁调用了这个函数,从源头把这个问题消除掉。但是情况却不是这样的。我搜索这个函数名,找到了一个set_ctrlr_state()的函数调用了pxafb_disable_controller(),搜索set_ctrlr_state(),发现有个pxafb_task()调用了set_ctrlr_state(),但是到了pxafb_task()就没有办法再往上找了,因为这是提供给内核的一个任务,以指针传递函数入口。我对内核了解太不够了,花了很多时间看了很多论坛上的文章,机缘巧合之下,我找到了/drivers/char/vt.c这个文件。vt.c我感觉应该是2.4内核的console.c和vt.c的结合体,应为它集成了console基本上所有功能函数,就ioctl在vt_ioctl.c这个文件里。这个文件的主要作用是负责管理控制台,如控制台的模式(图形、字符)、向控制台输出等等。其中能找到一些如do_blank_screen(),blank_screen_t()这样的函数,就是这些函数关闭了LCD控制器,修改任意一个都可以起作用。网上的一个解决方案是把blank_screen_t()变成空函数,但是我没有这样试过,我觉得已经来到了问题的根源附近,应该能从根本上解决。
我们先看下屏幕关闭问题的真正起因,看这个控制台初始化函数
static int __init con_init(void)
{ const char *display_desc = NULL; struct vc_data *vc; unsigned int currcons = 0; acquire_console_sem();
if (conswitchp)
display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; release_console_sem(); return 0; } init_timer(&console_timer);
console_timer.function = blank_screen_t; if (blankinterval) { blank_state = blank_normal_wait; mod_timer(&console_timer, jiffies + blankinterval); } // 这是对控制台定时器的初始化,定时器事件函数被连接到了blank_screen_t()
/*
* kmalloc is not running yet - we use the bootmem allocator. */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data)); visual_init(vc, currcons, 1); vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size); vc->vc_kmalloced = 0; vc_init(vc, vc->vc_rows, vc->vc_cols, currcons || !vc->vc_sw->con_save_screen); } currcons = fg_console = 0; master_display_fg = vc = vc_cons[currcons].d; set_origin(vc); save_screen(vc); gotoxy(vc, vc->vc_x, vc->vc_y); csi_J(vc, 0); update_screen(vc); printk("Console: %s %s %dx%d", vc->vc_can_do_color ? "colour" : "mono", display_desc, vc->vc_cols, vc->vc_rows); printable = 1; printk("\n"); release_console_sem();
#ifdef CONFIG_VT_CONSOLE
register_console(&vt_console_driver); #endif return 0; } 其中引用了一个叫blankinterval的全局变量和一个console_time,我不知道内核的定时器是具体是怎么工作,但是这样的代码已经很明显了。这个定时器和电源管理宏PM_CONFIG没有任何关系,它是控制台的一部分。再看下blank_screen_t(): static void blank_screen_t(unsigned long dummy)
{ blank_timer_expired = 1; schedule_work(&console_work); } 可以发现vt.c开头的宏,static DECLARE_WORK(console_work, console_callback, NULL);,找到了console_callback()这个函数:
static void console_callback(void *ignored)
{ acquire_console_sem(); if (want_console >= 0) {
if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(vc_cons[fg_console].d); change_console(vc_cons[want_console].d); /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ } want_console = -1; } if (do_poke_blanked_console) { /* do not unblank for a LED change */ do_poke_blanked_console = 0; poke_blanked_console(); } if (scrollback_delta) { struct vc_data *vc = vc_cons[fg_console].d; clear_selection(); if (vc->vc_mode == KD_TEXT) vc->vc_sw->con_scrolldelta(vc, scrollback_delta); scrollback_delta = 0; } if (blank_timer_expired) { do_blank_screen(0); blank_timer_expired = 0; } release_console_sem();
} 再看do_blank_screen(),随着struct vc_data中的与fops类似指针跟踪下去,就可以找到驱动里面的相应代码了。写出来太麻烦,让我偷懒把。
小总结下,其实在控制台内部就有一个定时器,它负责在一定时间之后将显示关闭,而无视是否打开了电源管理功能。那这和Framebuffer有什么关系呢?我从一个很弱智的角度解释,内核刚启动的时候有这样一句输出:
Console: colour dummy device 80x30
在初始化LCD控制器(Framebuffer)之后,有这样一句输出:
Console: switching to colour frame buffer device 80x30
我就理解:这时候,内核把控制台(也不知道是console还是tty)切换到了Framebuffer上,大虾们赶快跳出来批判我吧,呵呵。
回到正题,从代码可以发现,根本的解决之道是让blankinterval = 0,blank_state就不会是blank_off之外的值,也就不会关闭屏幕了。
但是问题到这里还是没有完全解决,如果用户程序希望改变blankinterval来实现屏保(当然在我的系统上用不着);另外,一些程序改变了blankinterval,程序退出之后,屏幕在一段时间之后还是会关闭的。怎么才能在用户程序那头解决这个问题呢,这又耗费了我很多时间。
我在追查代码的过程中走了个弯路,认为修改控制台的模式可以不让黑屏现象出现,但是后来发现,这样可能会使控制台没有办法画图,不知道对不对。
忽略弯路,直接正解。vt.c中不是有很多操作控制台的函数么?看看是谁修改了blankinterval。于是搜索blankinterval,发现setterm_command()修改了它,然后搜索setterm_command,找到了do_con_trol()函数,搜索do_con_trol,找到了do_con_write()函数,搜索do_con_write,终于最终BOSS现身了:con_write()函数。为什么说它是最终BOSS呢?看看这段:
static struct tty_operations con_ops = {
.open = con_open, .close = con_close, .write = con_write, .write_room = con_write_room, .put_char = con_put_char, .flush_chars = con_flush_chars, .chars_in_buffer = con_chars_in_buffer, .ioctl = vt_ioctl, .stop = con_stop, .start = con_start, .throttle = con_throttle, .unthrottle = con_unthrottle, }; 熟悉fops的话你就能看出来了,这是对tty设备的文件操作函数的表。也就是说,在用户程序里,通过open函数打开/dev/tty,然后再用write函数就可以修改blankinterval了。原理是找到了,实践上有很大困难,那么多重函数调用,再看看do_con_trol()里面的switch语句,正常人都要发晕。好在伟大的百度为我们提供了很多信息:在命令行下,可以使用setterm -blank 0指令来设置blankinterval。哈哈,救星来了,赶快看看setterm的源代码。setterm属于util-linux包,搜索一下很容易找到。其中的perform_sequence()函数里有这样一段:
/* -blank [0-60]. */
if (opt_blank && vcterm) printf("\033[9;%d]", opt_bl_min); 真得很神奇啊,用个printf就可以在用户程序里解决这个问题,本来我是打算只说用printf解决的,看到原理我想会更舒服一些;况且,在我的系统上用printf是不行的。
但是!问题还没有完,往往在我们的系统中,LCD的虚拟控制台和控制台TTY不是同一个设备,也就是说,如果在程序里单纯的printf是不行的!这样只能修改你正在使用的TTY的blankinterval,而你用的却是文本方式的设备,不存在黑屏问题。
于是,就需要仔细比较/dev/console、/dev/tty、/dev/ttyn的设备号,在我的系统里,用户程序里/dev/console和/dev/tty都是5,说明他们是一个东西,/dev/ttyn是4,这才是FB上的虚拟控制台。但是/dev/ttyn不是正在使用的TTY,那么怎么printf呢?只好用write函数来解决了。
写这样一段代码:
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
void some_function()
{
int f;
f = open("/dev/tty0", O_RDWR);
write(f, "\033[9;0]", 8);
close(f);
}
问题终于解决了。
总结下,第二个问题有很多种解决方法:
1.修改LCD驱动,把关闭LCD控制器的函数变为空(不推荐)
2.修改vt.c中的blank_screen_t()函数,让其为空(在系统不需要使用关闭显示功能时推荐)
3.修改vt.c中的blankinterval,让其为0(系统可能需要使用关闭显示功能,而且希望系统上电后正常状态下不会关闭显示时推荐)
4.修改用户程序,加入设置blankinterval的代码(推荐)
今天就写到这里,继续干活了。 |
|
|