Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1024402
  • 博文数量: 238
  • 博客积分: 2842
  • 博客等级: 少校
  • 技术积分: 2765
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-16 00:20
个人简介

stdlf

文章分类

全部博文(238)

文章存档

2013年(6)

2012年(13)

2011年(82)

2010年(89)

2009年(48)

我的朋友

分类:

2010-01-28 17:37:03

s3C44B0X中关于frameBuffer的问题
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.
.
#if (LCD_TYPE==MLCD_240_320)
#define SCR_XSIZE     (480) 
#define SCR_YSIZE     (640)
.
.
#define ARRAY_SIZE_G16        (SCR_XSIZE/2*SCR_YSIZE)
.
.
unsigned int (*frameBuffer16)[SCR_XSIZE/8];
.
.
void Lcd_Init(int depth)
{       
    switch(depth)
    {case 16:
       if((U32)frameBuffer16==0)
       {
           //The total frame memory should be inside 4MB.
           //For example, if total memory is 8MB, the frame memory
           //should be in 0xc000000~0xc3fffff or c400000~c7fffff.
           //But, the following code doesn't meet this condition(4MB)
           //if the code size & location is changed..
           frameBuffer16=(unsigned int (*)[SCR_XSIZE/8])malloc(ARRAY_SIZE_G16);
.
.
.
       }
我的S3C44B0X开发板外接的是240X320的STN  16级灰度LCD,在初步学习了相关的LCD显示的程序后,通过改动开发板配套的程序也实现了在LCD上显示自己照片的功能,对LCD的驱动显示过程有了一个大体的了解,但是在学习程序的细节上有很多的疑惑,主要是某些涉及指针的变量,函数,以及某些运算过程。以上的一段程序(将必要的语句集合到一起以便研究)就让我迷惑了很久,在网上搜索了相关的资料,发现一些论坛上对于这个问题的讨论也不少,但都没有太详细的解答,参考了各种资料和大家的讨论后,我自己琢磨了一下,问题终于有点眉目了,我想把我的一点心得写出来和大家分享,有什么不对的地方,欢迎大家一起讨论!
 
    **首先要弄清楚LCD是如何显示的,16灰度的LCD是每4位(也就是半个字节)代表一个象素,那么对于256色的LCD来说就是8位(恰好是一个字节的数据宽度)对应一个象素,而S3C44B0X是通过写显示缓冲区来实现在LCD屏上显示图象的,也就是显示缓冲区映射的是LCD屏幕上的每一点!明白这一点很关键,接下来看一下程序中相关的参量的意义:

#if (LCD_TYPE==MLCD_240_320) 
  //这里是LCD的类型,我板上的是24X320的16级灰度屏
#define SCR_XSIZE     (480)
#define SCR_YSIZE     (640)
//这实际是定义的虚拟屏幕的宽度(X)和高度(Y),就是说用                               
240X320的屏可以局部显示480X640的图象,当然也可以定义的更大  一些来显示更大的图象

#define ARRAY_SIZE_G16         (SCR_XSIZE/2*SCR_YSIZE)
//这里将ARRAY_SIZE_G16显示缓冲区大小为SCR_XSIZE/2*SCR_YSIZE,也就是480*640/2=480*640*4/8个字节的空间作为显存(16 gray levels:4bits/pixel)。

unsigned int (*frameBuffer16)[SCR_XSIZE/8];
//在这里定义了显示缓冲区,它的大小是SCR_XSIZE/8,也就是480/8,在这里frameBuffer16是一个指针,它指向的是包含SCR_XSIZE/8个unsigned int类型的(在DEF.H中该类型为32位,即U32)元素的数组; 这时,SCR_XSIZE/8的意义就显而易见了,因为数组的元素是32位的unsigned int类型的,只需要有SCR_XSIZE/8个元素即可以实现输出480个象素的目的!当然480个象素只是分辨率为480X640的图象的1/640,也就是屏幕上的一行,——是一行的显示缓冲区;要对应480X640大小的图象,至少需要480X640大小显示缓冲区,所以我们接着往下看,

void Lcd_Init(int depth)
//来到真正LCD初始化的地方,在这里要着重理解的是其中分配内存的一句,其他的很容易理解,就略去了。

if((U32)frameBuffer16==0)
//这一句是在检查是否已经为显示缓冲分配过内存了?(我的猜测,不知道省掉这一句会有什么区别?)

frameBuffer16=(unsigned int (*)[SCR_XSIZE/8])malloc(ARRAY_SIZE_G16);
//由于刚才已经定义了一个指针frameBuffer16,而且知道要显示480X640的图象至少需有480X640/2字节大小的显示缓冲,理解这一句已经不象开始那样一头雾水了,通过malloc(ARRAY_SIZE_G16)在内存中分出一块大小为ARRAY_SIZE_G16字节,也就是刚好可以满足480X640显示需要的内存区做为显示缓存,也许有人要问了,刚才不是定义过frameBuffer16了吗?为什么现在又定义一次?第1次定义了frameBuffer16这个指针,是指向数组类型的指针,而第2次是将frameBuffer16指向一个实际的内存区域,也就是通过malloc(ARRAY_SIZE_G16)分配的,注意ARRAY_SIZE_G16的大小是480X640/2个字节,(unsigned int (*)[SCR_XSIZE/8])是强制类转换;我理解这里在(*)后加一个[SCR_XSIZE/8]的用意,其实只是把malloc(ARRAY_SIZE_G16)分配的内存分成大小为SCR_XSIZE/8的块(并没有实际的意义,为了便于理解可以这么考虑),也就是说frameBuffer16每进行一次‘+1’的操作,实际上是地址增加[SCR_XSIZE/8]个字,指针frameBuffer16仍然是32位的,这样的话就共有(ARRAY_SIZE_G16/8(换算成U32类型的))/(SCR_XSIZE/8)=(480X640/8)/(480/8)=640块,这说明什么呢?要是换个理解方式,用2维数组的概念来理解的话,也就是说frameBuffer16指向的是一块[640][480/8]的2维空间。
 
有了以上的理解,可以看一个最基本的象素输出函数:
void _PutPixelG16(U32 x,U32 y,U8 c)

{
 
    if(x 
        frameBuffer16[(y)][(x)/8]=( frameBuffer16[(y)][x/8] & ~(0xc0000000>>((x)%8)*4) )
 
            | ( (c)<<((8-1-((x)%8))*4) );
 
}
为了更方便形象地对应屏幕上指定位置(X,Y)的点,可以看到_PutPixelG16这个函数即是通过frameBuffer16[(y)][(x)/8],以2维数组的形式来写显示缓冲区的。
有了这些理解,对于其它图形函数的理解应该会更轻松了!
 
不知道以上我说的有没有什么不对的地方,我也是刚刚学S3C44B0X,没有什么经验可谈,就把我自己的理解和大家分享吧!
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
补充:
 
在lcdlib.c可以找到关于MALLOC()的定义,可以看出MALLOC分配的内存的大小以字节来计算,
 
char Image$$RW$$Limit[];
 
void *mallocPt=Image$$RW$$Limit;
.
.
.
void * malloc(unsigned nbyte)
/*Very simple; Use malloc() & free() like Stack*/
 
{
    void *returnPt=mallocPt;
    mallocPt= (int *)mallocPt+nbyte/4+((nbyte%4)>0); //to align 4byte
    if( (int)mallocPt > HEAPEND )
    {
       mallocPt=returnPt;
       return NULL;
    }
    return returnPt;
}
当程序中第1次使用MALLOC   时,RETURNPT指向的初始位置就是Image$$RW$$Limit[]的起始位置,由mallocPt= (int *)mallocPt+nbyte/4+((nbyte%4)>0)来计算出分配NBYTE后的指针的位置,接下来判断所分配的内存大小是否超过了堆(HEAP)的界限,如果没有超过界限,将可以使用从Image$$RW$$Limit到mallocPt之间的内存块,由于mallocPt是一个全局变量,所以在第1次分配内存后,它的值将是(int *)mallocPt+nbyte/4+((nbyte%4)>0),在下一次使用MALLOC的时候将从这个位置开始分配。但这样来分配内存似乎存在一个很严重的问题,特别是在多次使用MALLOC的时候,由于没有有效的边界检测,误操作很可能导致指针从第1次MALLOC分配的内存区进入第2次分配的内存区,从而引起数据的错乱而使程序崩溃

阅读(643) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~