framebuffer学习

Android surfaceflinger学习笔记之framebuffer管理 最近由于工作的Android surfaceflinger 阅读详情


一.应用程序
在fb_fix_screeninfo中有
__u32 smem_len 是这个/dev/fb0的大小,也就是内存大小。
__u32 line_length 是屏幕上一行的点在内存中占有的空间,不是一行上的点数。
在fb_var_screeninfo 中有
__u32 xres ,__u32 yres 是x和y方向的分辨率,就是两个方向上的点数。
__u32 bits_per_pixel 是每一点占有的内存空间。
显存中存有两页屏幕数据,这是方便快速的改变屏幕内容实现动画之类比较高的要求。
一切东西都是文件。我们对屏幕的读写就可以转换成对/dev/fb0的读写。那么就把/dev/fb0
用open打开,再用lseek定位要读写的位置,最后调用read或者write来操作。通过这么一大
段的操作我们才完成了对一个点的读或者写。这种方法开销太大了。还有一种方法,我们把
/dev/fb0映射到程序进程的内存空间中来,然后得到一个指向这段存储空间的指针,这样就
可以方便的读写了。但是我们要知道能映射多少和该映射多少,这能很方便的从上面一个程
序得出的参数来决定。
例子程序:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

int main () {
 int fp=0;
 struct fb_var_screeninfo vinfo;
 struct fb_fix_screeninfo finfo;
 long screensize=0;
 char *fbp = 0;
 int x = 0, y = 0;
 long location = 0;
 fp = open ("/dev/fb0",O_RDWR);
 ioctl(fp,FBIOGET_FSCREENINFO,&finfo);
 ioctl(fp,FBIOGET_VSCREENINFO,&vinfo);
  screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
 /*这就是把fp所指的文件中从开始到screensize大小的内容给映射出来,得到一个指向这块空间的指针*/
 fbp =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);
/*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/
  x = 100;
  y = 100;
  location = x * (vinfo.bits_per_pixel / 8) + y  *  finfo.line_length;
  *(fbp + location) = 100;  /* 蓝色的色深 */  /*直接赋值来改变屏幕上某点的颜色*/
  *(fbp + location + 1) = 15; /* 绿色的色深*/  
  *(fbp + location + 2) = 200; /* 红色的色深*/  
  *(fbp + location + 3) = 0;  /* 是否透明*/ 
  munmap (fbp, screensize); /*解除映射*/
  close (fp);    /*关闭文件*/
  return 0;
}
二.硬件原理
1.我们根据数据手册来描述一下这个集成在S3C2440内部的LCD控制器:
a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组成;
b:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的;
c:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,
视频数据在不需要CPU的干预的情况下显示在LCD屏上;
d:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,
然后通过数据端口VD[23:0]传送视频数据到LCD驱动器;
e:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,
而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能
产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)
2.作为帧同步信号的vsync,每发出一个脉冲,都意味着新的一副图像数据开始传送。而作为行同步信号的hsync,
每发出一个脉冲,都表明新的一行图像资料开始发送。在帧同步和行同步的头尾都必须有回扫时间,这个原因
始于CRT的电子枪是需要回扫时间的,后来延续下来成工业标准,LCD的显示参数描述如下:
(1)定时参数,诸如行场起始,有效值,行场同步宽度等,均可参考LCD规格书获得。
(2)像素时钟,最简单的算法是:行像素之和 X 列像素之和 X 场频。反之,如果我们知道某LCD的时钟,如
28.37516MHZ,那么取其倒数,即得画一个像素点需要多少秒。
(3)颜色位域,这个是由显示缓冲区跟显示像素点的对应关系决定的。比如RGB565模式,RED占5位,偏移11位;
GREEN占6位,偏移5位;BLUE占5位,偏移0位。那么就把这些值赋给结构体fb_info->var->red.offset,
fb_info->var->red.length等。
(4)固定参数,比如根据LCD的显示参数计算帧缓冲设备分配的缓冲区大小,为:行最大显示解析度*列最大解析度*
每像素最大字节数。
三.裸机驱动
端口初始化----------
static void Lcd_Port_Init( void )
{
    rGPCUP=0xffffffff; // Disable Pull-up register
    rGPCCON=0xaaaa02a8; //1010 1010 1010 1010 0000 0010 1010 1000Initialize VD[7:0],VM,VFRAME,VLINE,VCLK
    rGPDUP=0xffffffff; // Disable Pull-up register
    rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}
显示模式初始化----------------------------------------------

CLKVAL---
确定VCLK频率的参数,单位为HZ。
MMODE--
确定VM的改变速度。在此选择MMODE=0,为每帧变化模式
VM----通过VM信号改变控制像素点得显示或熄灭。
PNRMODE---
确定扫描方式。选择PNRMODE=0x3,为TFT LCD面板扫描模式。
BPPMODE--
确定BPP(每像素位数)模式。在此选择BPPMODE=0xc,为TFT16位模式。
ENVID----
数据输出和逻辑信号使能控制位。选择ENVID=1,为允许数据输出和逻辑控制
LCD_PIXCLOCK=4;
/*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
    rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 <<  5) | (12 << 1);
0100 0000 0000
0000 0110 0000
0000 0001 1000
0100 0111  1000     
static void Lcd_EnvidOnOff(int onoff)
{
    if(onoff==1)
    rLCDCON1|=1; // ENVID=ON
    else
    rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_HEIGHT 320
#define LCD_HSYNC_LEN 5

/*bit[31:24](1:VBPD);bit[23:14](320-1:行数);bit[13:6](5:VFPD);bit[5:0](1:VSPW)*/
       rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);
VBPD----表示一帧图像开始时,帧同步信号以后的无效的行数,对应驱动中的upper_margin
VFBD-----表示在一帧图像结束后,帧同步信号以前的无效的行数,对应驱动中的lower_margin
VSPW-----表示垂直同步脉冲的宽带,用行数计算,对应驱动中的vsync_len
LINEVAL----确定显示的垂直方向的尺寸
LINEVAL=YSIZE-1=479
若是480行,LINEVAL=479;

HBPD------表示从水平同步信号开始到一行有效数据开始之间的VCLK的个数,对应驱动中的left_margin
HFPD------表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK个数,对应
HOZVAL----确定显示的水平方向尺寸
公式HOZVAL=XSIZE-1
就是决定显示器有多少列。
/*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
       rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);

HSPW-----表示水平同步信号的宽带,用VCLK计算,对应驱动中的hsync_len
/*bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)*/
       rLCDCON4 = (13 <<  8) | (LCD_HSYNC_LEN << 0);
/*bit[11](5:6:5 Format);bit[9](VLINE/HSYNC polarity inverted);bit[8](VFRAME/VSYNC inverted)
      bit[3](Enalbe PWERN signal),bit[1](half-word swap control bit)*/
    rLCDCON5   =  (1<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);
FRM565---------三基色模式选择
帧缓冲初始化----告诉lcd控制器,帧缓冲--显示缓存的位置。
记录了帧缓冲的起始地址。
/*帧缓冲地址初始化*/
    /*
    LCDBANK: 视频帧缓冲区内存地址30-22位
    LCDBASEU: 视频帧缓冲区的开始地址21-1位
    LCDBASEL: 视频帧缓冲区的结束地址21-1位
    */
    /*bit[29:21]:LCDBANK,bit[20:0]:LCDBASEU*/
        rLCDSADDR1 = ((LCD_ADDR >> 22) << 21) | ((M5D(LCD_ADDR >> 1)) <<  0);   
        /*bit[20:0]:LCDBASEL*/
        rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);
        /*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
      OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
    */
    /*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
        rLCDSADDR3 = LCD_WIDTH;       
#define LCD_N35 //NEC 256K色240*320/3.5英寸TFT真彩液晶屏,每一条水平线上包含240个像素点,共有320条这样的线
#if defined(LCD_N35)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 4
#define LCD_RIGHT_MARGIN 39
#define LCD_LEFT_MARGIN 16
#define LCD_HSYNC_LEN 5
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
#endif
void TFT_LCD_Test(void);
#define LCD_XSIZE  LCD_WIDTH
#define LCD_YSIZE  LCD_HEIGHT
#define SCR_XSIZE  LCD_WIDTH
#define SCR_YSIZE  LCD_HEIGHT
volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE];  //定义320行,240列的数组,用于存放显示数据
extern unsigned char sunflower_240x320[];
#define    M5D(n)    ((n)&0x1fffff)
#define LCD_ADDR ((U32)LCD_BUFFER)
#define ADC_FREQ 2500000
volatile U32 preScaler;
static void cal_cpu_bus_clk(void);
void Set_Clk(void);
/*演示函数*/
void delay(int times)
{
    int i,j;
    for(i=0;i<times;i++)
       for(j=0;j<400;j++);
}

/*在屏幕上画图*/
static void Pait_Bmp(int x0,int y0,int h,int l,const unsigned char *bmp)
{
    int x,y;
    U32 c;
    int p = 0; 
    for( y = 0 ; y < l ; y++ )
    {
        for( x = 0 ; x < h ; x++ )
        {
            c = bmp[p+1] | (bmp[p]<<8) ;

        if ( ( (x0+x) < SCR_XSIZE) && ( (y0+y) < SCR_YSIZE) )
            LCD_BUFFER[y0+y][x0+x] = c ;

            p = p + 2 ;
        }
    }
}
/*填充全屏为某一颜色*/
static void Lcd_ClearScr( U16 c)
{
    unsigned int x,y ;       
    for( y = 0 ; y < SCR_YSIZE ; y++ )
    {
        for( x = 0 ; x < SCR_XSIZE ; x++ )
        {
        LCD_BUFFER[y][x] = c ;
        }
    }
}
/*LCD开关*/
static void Lcd_EnvidOnOff(int onoff)
{
    if(onoff==1)
    rLCDCON1|=1; // ENVID=ON
    else
    rLCDCON1 =rLCDCON1 & 0x3fffe; // ENVID Off
}
/*端口初始化*/
static void Lcd_Port_Init( void )
{
    rGPCUP=0xffffffff; // Disable Pull-up register
    rGPCCON=0xaaaa02a8; //Initialize VD[7:0],VM,VFRAME,VLINE,VCLK
    rGPDUP=0xffffffff; // Disable Pull-up register
    rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]
}
/*LCD初始化*/
static void LCD_Init(void)
{
    Lcd_Port_Init();
    /*显示模式初始化*/
    /*bit[17:8](4:CLKVAL);bit[6:5](11:TFT LCD panel);bit[4:1](1100:16 bpp for TFT)*/
    rLCDCON1 = (LCD_PIXCLOCK << 8) | (3 <<  5) | (12 << 1);   
    /*bit[31:24](1:VBPD);bit[23:14](320-1:行数);bit[13:6](5:VFPD);bit[5:0](1:VSPW)*/
       rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);     
       /*bit[25:19](36:HBPD);bit[18:8](240-1:列数);bit[7:0](19:HFPD)*/
       rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH  - 1) <<  8) | (LCD_LEFT_MARGIN << 0);   
       /*bit[15:8](13:MVAL,只有当LCDCON1 bit[7]MMODE=1才有效);bit[7:0](5:HSPW)*/
       rLCDCON4 = (13 <<  8) | (LCD_HSYNC_LEN << 0);     
       /*bit[11](5:6:5 Format);bit[9](VLINE/HSYNC polarity inverted);bit[8](VFRAME/VSYNC inverted)
      bit[3](Enalbe PWERN signal),bit[1](half-word swap control bit)*/
    rLCDCON5   =  (1<<11) | (1 << 9) | (1 << 8) | (1 << 3) | (1 << 0);  
        /*帧缓冲地址初始化*/
    /*
    LCDBANK: 视频帧缓冲区内存地址30-22位
    LCDBASEU: 视频帧缓冲区的开始地址21-1位
    LCDBASEL: 视频帧缓冲区的结束地址21-1位
    */
    /*bit[29:21]:LCDBANK,bit[20:0]:LCDBASEU*/
        rLCDSADDR1 = ((LCD_ADDR >> 22) << 21) | ((M5D(LCD_ADDR >> 1)) <<  0);
   
        /*bit[20:0]:LCDBASEL*/
        rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2) >> 1);
      
        /*PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数
      OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
    */
    /*bit[21:11]:OFFSIZE; bit[10:0]:PAGEWIDTH*/
        rLCDSADDR3 = LCD_WIDTH;       

    /*屏蔽中断*/
        rLCDINTMSK |= 3;
      rTCONSEL   &= (~7);
    /*disable调色板*/
       rTPAL = 0x0;     
       /*禁止LPC3600/LCC3600模式*/
       rTCONSEL &= ~((1<<4) | 1);    
       /*打开LCD*/
       Lcd_EnvidOnOff(1);    
}
void TFT_LCD_Show(void)
{   
    /*红(255:0:0);绿(0:255:0);蓝(0:0:255);黑(0:0:0);白(255,255,255)*/  
    /*在屏幕上显示三基色*/ 
    Lcd_ClearScr( (0x00<<11) | (0x00<<5) | (0x00)  )  ;        //clear screen black
    delay(10000);     
    Lcd_ClearScr((0x1f<<11) | (0x00<<5) | (0x00));            //red
    delay(10000);     
    Lcd_ClearScr((0x00<<11) | (0x3f<<5) | (0x00));            //green
    delay(10000);
    Lcd_ClearScr((0x00<<11) | (0x00<<5) | (0x1f));            //blue
    delay(10000);
    Lcd_ClearScr( (0x1f<<11) | (0x3f<<5) | (0x1f)  )  ;        //clear screen white
    delay(10000);
    /*显示一副图片在屏幕上*/
    Pait_Bmp(0, 0, 240, 320, sunflower_240x320);
}
  

/* 设置CPU的时钟频率*/
void Set_Clk(void)
{
    int i;
    U8 key;
    U32 mpll_val = 0 ;
    i = 2 ;                 //don't use 100M!
                         //boot_params.cpu_clk.val = 3;
    switch ( i ) {
    case 0:    //200
        key = 12;
        mpll_val = (92<<12)|(4<<4)|(1);
        break;
    case 1:    //300
        key = 13;
        mpll_val = (67<<12)|(1<<4)|(1);
        break;
    case 2:    //400
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    case 3:    //440!!!
        key = 14;
        mpll_val = (102<<12)|(1<<4)|(1);
        break;
    default:
        key = 14;
        mpll_val = (92<<12)|(1<<4)|(1);
        break;
    }
   
    //init FCLK=400M, so change MPLL first
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON
    ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit
    cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M
}
/*设置PCLK\HCLK\FCLK的频率*/
static void cal_cpu_bus_clk(void)
{
    static U32 cpu_freq;
    static U32 UPLL;
    U32 val;
    U8 m, p, s;   
    val = rMPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;
    //(m+8)*FIN*2 不要超出32位数!
    FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000   
    val = rCLKDIVN;
    m = (val>>1)&3;
    p = val&1;   
    val = rCAMDIVN;
    s = val>>8;   
    switch (m) {
    case 0:
        HCLK = FCLK;
        break;
    case 1:
        HCLK = FCLK>>1;
        break;
    case 2:
        if(s&2)
            HCLK = FCLK>>3;
        else
            HCLK = FCLK>>2;
        break;
    case 3:
        if(s&1)
            HCLK = FCLK/6;
        else
            HCLK = FCLK/3;
        break;
    }  
    if(p)
        PCLK = HCLK>>1;
    else
        PCLK = HCLK;   
    if(s&0x10)
        cpu_freq = HCLK;
    else
        cpu_freq = FCLK;      
    val = rUPLLCON;
    m = (val>>12)&0xff;
    p = (val>>4)&0x3f;
    s = val&3;
    UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
    UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
    Uart_Printf("\nFCLK:%dMHz,HCLK:%dMHz,PCLK=%dMHZ\n",FCLK/1000/1000,HCLK/1000/1000,PCLK/1000/1000);
}
/*主函数*/
int Main(void)
{   
    Set_Clk();  
    LCD_Init(); 
    TFT_LCD_Show(); 
    return 0;
}
四.linux驱动
驱动主要跟fb_info结构体有关,该结构体记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及对底层
硬件操作的函数指针。
struct fb_info{
    int node;
    int flags;
    struct fb_var_screeninfo var;/*LCD可变参数结构体*/
    struct fb_fix_screeninfo fix;/*LCD固定参数结构体*/
    struct fb_ops *fbops; /*对底层硬件操作的函数指针*/  
    ......
};
fb_var_screeninfo结构体主要记录用户可以修改的控制器的参数,比如屏幕的分辨率和每个像素的比特数等
struct fb_var_screeninfo{
    __u32 xres;                /*可见屏幕一行有多少个像素点*/
    __u32 yres;                /*可见屏幕一列有多少个像素点*/
    __u32 xres_virtual;        /*虚拟屏幕一行有多少个像素点*/       
    __u32 yres_virtual;        /*虚拟屏幕一列有多少个像素点*/
    __u32 xoffset;             /*虚拟到可见屏幕之间的行偏移*/
    __u32 yoffset;             /*虚拟到可见屏幕之间的列偏移*/
    __u32 bits_per_pixel;      /*每个像素的位数即BPP*/
    struct fb_bitfield red;    /*fb缓存的R位域*/
    struct fb_bitfield green;  /*fb缓存的G位域*/
    struct fb_bitfield blue;   /*fb缓存的B位域*/
    struct fb_bitfield transp; /*透明度*/
    /*定时:除了pixclock本身外,其他的都以像素时钟为单位*/
    __u32 pixclock;            /*像素时钟(皮秒)*/
    __u32 left_margin;         /*行切换,从同步到绘图之间的延迟*/
    __u32 right_margin;        /*行切换,从绘图到同步之间的延迟*/
    __u32 upper_margin;        /*帧切换,从同步到绘图之间的延迟*/
    __u32 lower_margin;        /*帧切换,从绘图到同步之间的延迟*/
};
fb_fix_screeninfo结构体又主要记录用户不可以修改的控制器的参数,比如屏幕缓冲区的物理地址和长度等
struct fb_fix_screeninfo{
    char id[16];                /*字符串形式的标示符 */
    unsigned long smem_start;   /*fb缓存的开始位置 */
    __u32 smem_len;             /*fb缓存的长度 */
    __u32 type;                 /*看FB_TYPE_* */
    __u32 type_aux;             /*分界*/
    __u32 visual;               /*看FB_VISUAL_* */
    __u16 xpanstep;             /*如果没有硬件panning就赋值为0 */
    __u16 ypanstep;             /*如果没有硬件panning就赋值为0 */
    __u16 ywrapstep;            /*如果没有硬件ywrap就赋值为0 */
    __u32 line_length;          /*一行的字节数 */
    unsigned long mmio_start;   /*内存映射IO的开始位置*/
    __u32 mmio_len;             /*内存映射IO的长度*/
};
fb_ops结构体是对底层硬件操作的函数指针,该结构体中定义了对硬件的操作有:
struct fb_ops{
    struct module *owner;
    //检查可变参数并进行设置
    int (*fb_check_var)(struct fb_var_screeninfo*var,struct fb_info *info);
    //根据设置的值进行更新,使之有效
    int (*fb_set_par)(struct fb_info*info);
    //设置颜色寄存器
    int (*fb_setcolreg)(unsigned regno,unsigned red,unsigned green,
             unsigned blue,unsigned transp,struct fb_info*info);
    //显示空白
    int (*fb_blank)(int blank,struct fb_info *info);
    //矩形填充
    void (*fb_fillrect)(struct fb_info*info,const struct fb_fillrect*rect);
    //复制数据
    void (*fb_copyarea)(struct fb_info*info,const struct fb_copyarea*region);
    //图形填充
    void (*fb_imageblit)(struct fb_info*info,const struct fb_image*image);
};
2.platform
(1)平台参数
Linux把它看做是一个平台设备,故在内核代码/arch/arm/plat-s3c24xx/devs.c中定义有LCD相关的平台设备及资源:
/* LCD Controller */
//LCD控制器的资源信息
static struct resource s3c_lcd_resource[]={
    [0] = {
        .start = S3C24XX_PA_LCD,//控制器IO端口开始地址
        .end= S3C24XX_PA_LCD+ S3C24XX_SZ_LCD- 1,//控制器IO端口结束地址
        .flags= IORESOURCE_MEM,//标识为LCD控制器IO端口,在驱动中引用这个就表示引用IO端口
    },
    [1] = {
        .start = IRQ_LCD,//LCD中断
        .end= IRQ_LCD,
        .flags = IORESOURCE_IRQ,//标识为LCD中断
    }
};
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = {
    .name         = "s3c2410-lcd",//作为平台设备的LCD设备名
    .id        =-1,
    .num_resources = ARRAY_SIZE(s3c_lcd_resource),//资源数量
    .resource    = s3c_lcd_resource,//引用上面定义的资源
    .dev = {
        .dma_mask =&s3c_device_lcd_dmamask,
        .coherent_dma_mask = 0xffffffffUL
    }
};
EXPORT_SYMBOL(s3c_device_lcd);//导出定义的LCD平台设备,好在mach-smdk2440.c的smdk2440_devices[]中添加到平台设备列表中
Linux还在/arch/arm/mach-s3c2410/include/mach/fb.h中为LCD平台设备定义了一个s3c2410fb_mach_info结构体,该结构体主要是
记录LCD的硬件参数信息(比如该结构体的s3c2410fb_display成员结构中就用于记录LCD的屏幕尺寸、屏幕信息、可变的屏幕参数、
LCD配置寄存器等),这样在写驱动的时候就直接使用这个结构体。下面,我们来看一下内核是如果使用这个结构体的。在/arch/arm
/mach-s3c2440/mach-smdk2440.c中定义有:
Linux在arch/$(ARCH)/kernel/vmlinux.lds中定义了.init段。__init和__initdata属性的数据都在这个段中,当内核启动完毕后,
这个段中的内存会被释放掉供其他使用.
/* LCD driver info */
//LCD硬件的配置信息,注意这里我使用的LCD是NEC 3.5寸TFT屏,这些参数要根据具体的LCD屏进行设置
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata={
   //这个地方的设置是配置LCD寄存器5,这些宏定义在regs-lcd.h中,计算后二进制为:111111111111,然后对照数据手册上LCDCON5的各位来看,注意是从右边开始
    .lcdcon5 = S3C2410_LCDCON5_FRM565|
               S3C2410_LCDCON5_INVVLINE |
               S3C2410_LCDCON5_INVVFRAME |
               S3C2410_LCDCON5_PWREN |
               S3C2410_LCDCON5_HWSWP,
    .type    = S3C2410_LCDCON1_TFT,//TFT类型
    /* NEC 3.5'' */
    .width        = 240,//屏幕宽度
    .height      = 320,//屏幕高度
   //以下一些参数在上面的时序图分析中讲到过,各参数的值请跟据具体的LCD屏数据手册结合上面时序分析来设定
    .pixclock    = 100000,//像素时钟
    .xres        = 240,//水平可见的有效像素
    .yres        = 320,//垂直可见的有效像素
    .bpp         = 16,//色位模式
    .left_margin  = 19,//行切换,从同步到绘图之间的延迟
    .right_margin = 36,//行切换,从绘图到同步之间的延迟
    .hsync_len    = 5,//水平同步的长度
    .upper_margin = 1,//帧切换,从同步到绘图之间的延迟
    .lower_margin = 5,//帧切换,从绘图到同步之间的延迟
    .vsync_len    = 1,//垂直同步的长度
};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata={
    .displays        = &smdk2440_lcd_cfg,//应用上面定义的配置信息
    .num_displays    = 1,
    .default_display = 0,
    .gpccon          = 0xaaaa555a,//将GPC0、GPC1配置成LEND和VCLK,将GPC8-15配置成VD0-7,其他配置成普通输出IO口
    .gpccon_mask    = 0xffffffff,
    .gpcup           = 0x0000ffff,//禁止GPIOC的上拉功能
    .gpcup_mask      = 0xffffffff,
    .gpdcon          = 0xaaaaaaaa,//将GPD0-15配置成VD8-23
    .gpdcon_mask    = 0xffffffff,
    .gpdup           = 0x0000ffff,//禁止GPIOD的上拉功能
    .gpdup_mask      = 0xffffffff,
    .lpcsel         = 0x0,//这个是三星TFT屏的参数,这里不用
};
(2)平台初始化
//S3C2440初始化函数
static void __init smdk2440_machine_init(void)
{
   //调用该函数将上面定义的LCD硬件信息保存到平台数据中
    s3c24xx_fb_set_platdata(&smdk2440_fb_info);
   
    s3c_i2c0_set_platdata(NULL);

    platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
    smdk_machine_init();
}
void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info*pd)
{
    struct s3c2410fb_mach_info *npd;

    npd = kmalloc(sizeof(*npd), GFP_KERNEL);
    if (npd){
        memcpy(npd, pd,sizeof(*npd));
       //这里就是将内核中定义的s3c2410fb_mach_info结构体数据保存到LCD平台数据中,所以在写驱动的时候就可以直接在平台数据中获取s3c2410fb_mach_info结构体的数据(即LCD各种参数信息)进行操作
        s3c_device_lcd.dev.platform_data= npd;
    } else {
        printk(KERN_ERR "no memory for LCD platform data\n");
    }
}

泰森多面体Voronoi 3D-V5.0 功能介绍 Abaqus Voronoi3D 阅读详情

相关推荐

手把手教你用STM32CubeMX和HAL库驱动DW3000:从SPI配置到第一个测距Demo

本文详细介绍了如何使用STM32CubeMX和HAL库驱动DW3000 UWB定位通信模块,从SPI配置到实现厘米级测距Demo的全过程。涵盖硬件连接、SPI通信调试、驱动移植及双向测距(TWR)算法实现,帮助开发者快速掌握UWB高精度定位技术,适用于仓储物流、智能家居等场景。

weixin_27038245的博客 485

linux下实现对framebuffer(/dev/fb0)的截屏操作

在linux系统中,使用framebuffer来提供用户态进程直接操作显示屏的功能. 在嵌入式系统开发中,需要对显示屏的内容进行截取,实现一个lcd截屏工具实现对显示屏内容的截取,存储为bmp格式. 一个bmp文件有四部分组成: 其中位图文件头内容如下: WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; bfType 说

weixin_45312249的博客 3680

阿里奇门接口联调全流程详解:从沙箱自测到正式上线的保姆级攻略

本文详细解析阿里奇门接口联调的全流程,从沙箱自测到正式上线的关键步骤与避坑指南。涵盖环境配置、业务场景测试、跨团队协作、灰度发布及生产运维监控,帮助开发者高效完成API对接,确保供应链协同系统的稳定运行。特别适合首次接触奇门对接的技术负责人参考。

weixin_42535461的博客 413

framebuffer缓冲帧/dev/fb0学习

framebuffer(帧缓冲): 定义:是用一个视频输出设备从包含完整的帧数据的一个内存缓冲区中来驱动一个视频显示设备 帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0到/dev/fb31,而/dev/fb则为当前缺省的帧缓冲设备,通常指向/dev/fb0,在嵌入式系统中支持一个显示设备就够了。帧...

优快云_liu_sir的博客 1628

从打印攻击到视频重放:手把手用OULU-NPU训练你的第一个活体检测模型

本文详细介绍了如何使用OULU-NPU数据集训练活体检测模型,以应对打印攻击和视频重放等安全威胁。通过PyTorch框架,从环境准备、数据加载、预处理到模型架构设计,手把手教你构建一个高效的双流网络,结合CNN和LSTM技术,提升模型在多种攻击场景下的检测准确率。

weixin_29092031的博客 383

DBeaver 实战:手动配置 PostgreSQL JDBC 驱动的高级技巧

本文详细介绍了在DBeaver中手动配置PostgreSQL JDBC驱动的高级技巧。针对企业内网、多版本数据库兼容等场景,从获取官方驱动文件、创建自定义驱动配置,到使用Maven坐标管理、连接参数调优及解决常见连接问题,提供了完整的实战指南,帮助开发者实现对数据库连接环境的精准掌控。

apple5的专栏 835

framebuffer / 像素深度 / 颜色深度 / RGB565

framebuffer / 像素深度 / 颜色深度 / RGB565 1, framebuffer相关的.     framebuffer的可变的信息就是指Framebuffer的长度、宽度以及颜色深度等信息。这两个命令字相关的结构体有两个:struct fb_fix_screeninfo和struct fb_var_screeninfo,这两个结构体都比较大,前者用于保存Fram

后端系统和架构 8579

LCD驱动芯片——BL55072A驱动程序

初始化子程序: START 0x7C; I2C子地址 0xEA;ICSET,软件复位芯片 0xC0;MODSET,关显示 0xF0;BLKCTL,关闪烁 0xA3;DISCTL,80Hz Line inversion,High Power mode 0xE8;ICSET,清复位bit1 STOP 显示刷新子程序: START 0x7C;I2C子地址 0xF0;BLKCTL,关闪烁 0xA3;DISCTL,80Hz Line inversion,High Power mode 0xE8或0xEC;ICSE

love421的博客 3174

framebuffer设备的参数

<br />如果应用程序需要知道Framebuffer设备的相关参数,必须通过ioctl()系统调用来完成。<br />在头文件<linux/fb.h>中定义了所有的ioctl命令字,不过,最常用的ioctl命令字是下面这两个:FBIOGET_FSCREENINFO和FBIOGET_VSCREENINFO。<br />前者返回与Framebuffer有关的固定的信息,比如图形硬件上实际的帧缓存空间的大小、能否硬件加速等信息。<br />而后者返回的是与Framebuffer有关的可变信息。<br />之所以

hdusunny44的专栏 7955

CH376S模块实战:如何通过串口轻松实现单片机与U盘的数据交互

本文详细介绍了如何利用CH376S模块,通过串口通信实现单片机与U盘的数据交互。文章从模块原理、硬件连接到核心指令集进行了全面解析,并提供了基于STM32的实战代码示例。CH376S模块极大地简化了USB协议和文件系统的复杂性,使开发者能快速为嵌入式设备添加便捷的数据存储与导出功能,适用于数据记录、配置导入等多种应用场景。

weixin_29165725的博客 457

YOLOv8改进 | 主干篇 | 利用MobileNetV1替换Backbone(轻量化网络结构)

本文给大家带来的改进机制是MobileNetV1,其是专为移动和嵌入式视觉应用设计的轻量化网络结构。这些模型基于简化的架构,并利用深度可分离卷积构建轻量级深度神经网络,其引入了两个简单的全局超参数,用于在延迟和准确性之间进行有效的权衡。实验表明,MobileNets在资源和准确性的权衡方面表现出色,并在多种应用(如对象检测、细粒度分类、面部属性识别和大规模地理定位)中展现了其有效性,这个模型非常适合轻量化的读者来使用。适用检测目标:轻量化网络结构适合轻量化的读者。

Snu77的博客 3965

嵌入式学习第三十六!(FrameBuffer的使用)

可以译作“帧缓冲”,有时简称为fbdrv。这是一种独立于硬件的抽象图形设备,是Linux为显示设备提供一个接口,把显示抽象后的一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作,即向应用层提供一个统一标准接口的显示设备。用户无法通过用户内存空间向显存内存空间写入RGB颜色值,但可以通过内存映射单元,将用户空间的部分内存,映射到显存空间,实现RGB颜色值数据的写入,再通过显卡的转换在显示屏中显示。即通过内存映射技术,向显存中写入RGB颜色值,从而实现像素点的绘制。

weixin_52799506的博客 1653

作物生长模型Oryza V3实战2:下载、安装与使用

摘要:ORYZA 现在的应用范围已从单一水稻作物模拟扩展到多个水稻作物模拟。我在csdn站内也上传了“作物生长模型oryza v3大全(含所有参数模板和4个校准程序1个分析工具)”,可以说是全网最全的吧。网上搜索一般下载的v3只有一个a3主程序,不适合作全面与深入的研究,本版本从国外下载回来,一开始少了一个“SoilHydrau.exe”文件,说是有病毒被隔离了,后经历各种技术手段,并向国际水道研究所发送邮件,才得以补全所有的参数化及校准程序、分析工具,来之不易,有缘人得之。

502

与afreez一起学习DirectFB之:framebuffer相关基础

在学习DirectFB的过程中,其中很重要的一部分就是framebuffer的学习,下面把我收集到的一些自己认为比较有价值的文字列出,希望也对大家有帮助!---------------------------------------------------------------------------------------------------------------------声明:   

afreez's home 3677

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Framebuffer学习

Frame是帧的意思,buffer是缓冲的意思,这意味着Framebuffer就是一块内存,里面保存着一帧图像。Framebuffer中保存着一帧图像的每一个像素颜色值,假设LCD的分辨率是1024x768,每一个像素的颜色用32位来表示,那么Framebuffer的大小就是:1024x768x32/8=3145728字节。假设需要设置LCD中坐标(x,y)处像素的颜色,首要要找到这个像素对应的内存,然后根据它的BPP值设置颜色。文件中,Framebuffer主要定义了2类参数:可变的参数。

studyingdda的博客 1268

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

framebuffer 的学习

FrameBuffer设备文件一般为/dev/fb*,如果系统有多个FrameBuffer设备文件,则表示该系统可能有多个显卡,一个子设备号对应一个显卡。FrameBuffer 也称帧缓存,是 Linux 内核将显存进行抽象后的一块缓存(内存),目的是为了给用户态进程提供一套直接写屏的接口,而不用关心物理显存的位置、换页机制等具体细节。这是一种独立于硬件的抽象图形设备,是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作;

smile202066的博客 826

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

framebuffer学习及fb绘图程序

一、了解framebuffer 在Linux系统下,如果我们想对lcd屏或者其他显示器件进行画点、画线、画图案等操作,那么我们就必须要了解framebuffer(帧缓存)。 对于用户来说,帧缓冲是Linux为显示设备提供的一个接口,它把一些显示设备描述成一个缓冲区,允许应用程序通过 FrameBuffer定义好的接口访问这些图形设备,从而不用去关心具体的硬件细节。 对于驱动工程师来说,帧缓存是内核驱动申请的一片内存空间,然后lcd内有一片sram,cpu内部有个lcd控制器,它有个单独的dma用来将fram

q1449660223的博客 3436

嵌入式Linux学习——Framebuffer应用

mmap 是一个系统调用,用于将文件或设备的内容映射到进程的虚拟地址空间中,从而允许程序直接访问这些内容。命令定义:request 参数通常是通过宏定义的命令,例如 IOCTL_CMD,这些宏定义可能在设备驱动的头文件中找到。设备依赖:ioctl 操作依赖于具体的设备驱动程序,因此不同设备支持的命令和操作可能有所不同。ioctl 提供了与设备进行细粒度控制的能力,但它的具体实现和使用方式取决于设备的驱动程序。: 可选参数,通常是指向数据的指针,用于传递命令相关的信息。

沙福林大人博客 1306

linux下FrameBuffer学习

2011-08-16 09:49:23|  分类: Linux 编程 |字号 订阅 linux下FrameBuffer学习   2009-11-18 10:20:18|  分类: linux学习 |  标签: |字号大中小 订阅 http://miaomeng06.blog.163.com/blog/static/12368617020091018102018

manshq163com的专栏 918

Ubuntu Framebuffer学习笔记

  Ubuntu Framebuffer学习笔记   一、环境搭建 1. 直接在Ubuntu上运行Framebuffer 默认Ubuntu是直接进入X视窗,如果要使用Framebuffer, 需要修改内核引导参数: $ sudo gedit /etc/default/grub 查找 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 把它改为 ...

weimingtom的待宵草 698

linux framebuffer 学习

linux framebuff 其实是本身linux写缓存的一种机制,对于应用级别的程序,比如需要获取屏幕的尺寸等等,只需要拥有足够的权限,打开相应的设备,然后再使用ioctl 接口获取相应的信息,然后再通过mmap获取相应的地址,然后进行相应的操作即可,咳,我的第一篇写的博客,没有保存,结果给弄丢了,现在一下子没有心情写了,随便写点吧郁闷基本上开发步骤如下:1、判断出你使用...

weixin_34413065的博客 189

FrameBuffer驱动学习

FrameBuffer驱动学习 Daniel Wood 20110301 转载时请注明出处和作者 文章出处:http://danielwood.cublog.cn 作者:Daniel Wood ------------------------------------------------------------ 写在前面的话: 这篇文章是自己学习Framebuffer所

virus026的专栏 529

Framebuffer 驱动学习总结(二)---- Framebuffer模块初始化

---恢复内容开始--- Framebuffer模块初始化过程:--driver\video\fbmem.c 1、 初始化Framebuffer: FrameBuffer驱动是以模块的形式注册到系统中,在模块初始化时,创建FrameBuffer对应的设备文件及proc文件,并注册FrameBuffer设备操作接口函数fb_fops。 static int __init f...

Xiaohui6666的博客 741

Linux驱动开发之FrameBuffer子系统学习

一、引言 之前在调显示驱动的时候,主要是根据平台设计好的套路来——也就是调屏参,但从来没有想过更底层的原理。 随着工作的深入,也开始慢慢接触所谓的显示驱动——FrameBuffer子系统,简称fb驱动。 接下来,就跟着我来了解一下Linux的显示驱动到底是怎样一个原理。 二、FrameBuffer子系统 1、FrameBuffer的字面意思 FrameBuffer。从字面意思我们知道,也就是帧缓存。缓存我们清楚,那就是一段内存,用以存储某些东西。 那么,什么是帧呢?我们将铺满一个lcd屏幕的数

陈子陌的博客 895

linux fb0测试,与afreez一起学习DirectFB之:一个linux下的framebuffer例子的学问

与afreez一起学习DirectFB之:一个linux下的framebuffer例子的学问摘要:通过一个一个framebuffer例子,复习了内存分配的应用。其中的framebuffer例子为网上流行的(确实有bug的),在编译运行的过程中又重新温习了好多差不多已经被遗忘的知识点,写出来和大家分享!-------------------------------------------------...

weixin_34268462的博客 306
上一篇: SPI总线驱动分析
下一篇: proc及读写内存
快乐的小鸟
博客等级 码龄14年 25粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值