Mini2440 linux LCD driver transplantation and some problems encountered

Publisher:紫菜包饭Latest update time:2022-10-18 Source: csdnKeywords:Mini2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

First compile the environment configuration


linux 2.6.32 source code


arm-linux-gcc cross-compiler


There is a root file system of mini2440


The default environment is configured here


Open the linux source code folder, enter it, and find the configuration file corresponding to the development board.

Make a copy of it and rename it to .config


cp config_mini2440_n35 .config

Then execute the kernel configuration and exit if you need to add or remove modules.


make menuconfig

 Remove the default LCD configuration and replace it with our own driver. Exit after completion.


Find Device Drivers ->Graphics support->support for frame buffer devices->


Remove the default s3c2440 lcd frame buffer support


Check the mylcd lcd frame buffer support we added ourselves

 

 

 


Here's how to add your own options


Open the directory linux2.6.32/drivers/video


Modify the Kconfig file and makefile inside


Find the line near config FB_S3C2410 in Kconfig and add


configFB_MYLCD

tristate "MY LCD framebuffer support"

depends on FB && ARCH_S3C2410

select FB_CFB_FILLRECT

select FB_CFB_COPYAREA

select FB_CFB_IMAGEBLIT

---help---

  Frame buffer driver for the built-in LCD controller in the Samsung

  S3C2410 processor.

 

  This driver is also available as a module ( = code which can be

  inserted and removed from the running kernel whenever you want). The

  module will be called s3c2410fb. If you want to compile it as a module,

  say M here and read .

 

  If unsure, say N.


This is what it looks like after adding

Open makefile


Add at the bottom, the mylcd2 here is the driver file I wrote, which is also in this directory.


obj-$(CONFIG_FB_MYLCD)   += mylcd2.o

This is what it looks like after adding (obj-m means module compilation, obj-y means compiling into the kernel)

Next, download the LCD driver and create the mylcd2.c file in the linux2.6.32/drivers/video directory.


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include  

#include

#include

#include  

#include

 

#include

#include

#include


/*LCD: 240*320 */

#define LCD_xres 240 //LCD line resolution

#define LCD_yres 320 //LCD column resolution


/*

Calculate the horizontal frequency (HSF) and field frequency (VSF) based on the pixel clock frequency:

One line refresh rate HSF=VCLK÷[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]

Frame rate VSF=HSF÷[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]

*/

 

//LCDCON1

#define LCD_CLKVAL 8 //[17:8] 5.6MHZ pixel clock frequency=8

#define LCD_PNRMODE 3 //[6:5] =0b11 tft

#define LCD_BPPMODE 12 //[4:1] =0b1100 16bpp

 

//LCDCON2

#define LCD_VBPD (1-1) //[31:24] The larger this value is, the more downward the displayed image will be. Just configure it according to the typical value of the screen.

#define LCD_LINEVAL (LCD_yres-1) //[23:14]

#define LCD_VFPD (5-1) //[13:6]  

#define LCD_VSPW (1-1) //[5:0]

 

//LCDCON3

#define LCD_HBPD (36-1) //[25:19] The larger this value is, the more the displayed image will be shifted to the right.

#define LCD_HOZVAL (LCD_xres-1) //[18:8]

#define LCD_HFPD (19-1)//(2-1) //[7:0] 

 

//LCDCON4

#define LCD_HSPW (5-1) //[7:0]

 

//LCDCON5 

#define LCD_FRM565 1 //[11] =0,5:5:5:1; =1,5:6:5

#define LCD_INVVCLK 1 //[10]

#define LCD_INVLINE    1    //[9]

#define LCD_INVVFRAME   1    //[8]

#define LCD_BSWP       0   //[1]

#define LCD_HWSWP      1   //[0]


/* GPIO prot   */

static unsigned long  *GPBcon;

static unsigned long  *GPCcon;

static unsigned long  *GPDcon;

static unsigned long  *GPGcon;  //GPG4:控制LCD信号 

static unsigned long  *GPBdat;   //GPB0: 控制背光

 

/* LCD control */ 

 struct  lcd_reg{  

      unsigned long    lcdcon1; 

      unsigned long       lcdcon2;  

      unsigned long       lcdcon3; 

      unsigned long       lcdcon4; 

      unsigned long       lcdcon5; 

      unsigned long       lcdsaddr1;     

      unsigned long       lcdsaddr2;     

      unsigned long       lcdsaddr3 ;

      unsigned long       redlut;   

      unsigned long       greenlut;

      unsigned long       bluelut;

      unsigned long       reserved[9];  

      unsigned long       dithmode;     

      unsigned long       tpal ;    

      unsigned long       lcdintpnd;

      unsigned long       lcdsrcpnd;

      unsigned long       lcdintmsk;

      unsigned long       tconsel;  

};

 

static struct lcd_reg  *lcd_reg;

 

static struct fb_info *my_lcd;    //定义一个全局变量

static u32 pseudo_palette[16];   //调色板数组,被fb_info->pseudo_palette调用

 

static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)

{

/*内核中的单色都是16位,默认从左到右排列,比如G颜色[0x1f],那么chan就等于0XF800*/

       chan       &= 0xffff;

       chan       >>= 16 - bf->length;    //右移,将数据靠到位0上

       return chan << bf->offset;    //左移一定偏移值,放入16色数据中对应的位置

}

 

static int my_lcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info)      //设置调色板函数,供内核调用

{

       unsigned int val;      

       if (regno >=16)        //调色板数组不能大于15

      return 1;

 

       /* 用red,green,blue三个颜色值构造出16色数据val */

       val  = chan_to_field(red,      &info->var.red);

       val |= chan_to_field(green, &info->var.green);

       val |= chan_to_field(blue,      &info->var.blue);

      

       ((u32 *)(info->pseudo_palette))[regno] = val;     //放到调色板数组中

       return 0;

}

 

 

static struct fb_ops my_lcdfb_ops = {

      .owner           = THIS_MODULE,

      .fb_setcolreg  = my_lcdfb_setcolreg,//调用my_lcdfb_setcolreg()函数,来设置调色板fb_info-> pseudo_palette

      .fb_fillrect       = cfb_fillrect,     //填充矩形

      .fb_copyarea   = cfb_copyarea,     //复制数据

      .fb_imageblit  = cfb_imageblit,    //绘画图形,

};

 

static int lcd_init(void)

{

  /*1.申请一个fb_info结构体*/

  my_lcd= framebuffer_alloc(0,0); 

 

  /*2.设置fb_info*/

 

  /* 2.1设置固定的参数fb_info-> fix */

  /*my_lcd->fix.smem_start    物理地址后面注册MDA缓存区设置*/ 

  strcpy(my_lcd->fix.id, "mylcd");       //名字

  my_lcd->fix.smem_len =LCD_xres*LCD_yres*2;     //地址长

  my_lcd->fix.type        =FB_TYPE_PACKED_PIXELS;

  my_lcd->fix.visual    =FB_VISUAL_TRUECOLOR;    //真彩色

  my_lcd->fix.line_length      =LCD_xres*2;       //LCD 一行的字节

 

  /* 2.2 设置可变的参数fb_info-> var  */

  my_lcd->var.xres        =LCD_xres;          //可见屏X 分辨率

  my_lcd->var.yres        =LCD_yres;          //可见屏y 分辨率

  my_lcd->var.xres_virtual     =LCD_xres;           //虚拟屏x分辨率

  my_lcd->var.yres_virtual     =LCD_yres;           //虚拟屏y分辨率

  my_lcd->var.xoffset           = 0;     //虚拟到可见屏幕之间的行偏移

  my_lcd->var.yoffset           = 0;      //虚拟到可见屏幕之间的行偏移

 

  my_lcd->var.bits_per_pixel  =   16;        //像素为16BPP

  my_lcd->var.grayscale       =   0;    //灰色比例

 

  my_lcd->var.red.offset      =     11;

  my_lcd->var.red.length      =     5;

  my_lcd->var.green.offset  =       5;

  my_lcd->var.green.length  =       6;

  my_lcd->var.blue.offset     =     0;

  my_lcd->var.blue.length     =     5;

 

/* 2.3 设置操作函数fb_info-> fbops  */

  my_lcd->fbops         = &my_lcdfb_ops;


  /* 2.4 设置fb_info 其它的成员  */ 

 /*my_lcd->screen_base    虚拟地址在后面注册MDA缓存区设置*/

  my_lcd->pseudo_palette   =pseudo_palette;    //保存调色板数组

  my_lcd->screen_size          =LCD_xres * LCD_yres *2;     //虚拟地址长

 

  /*3   设置硬件相关的操作*/

  /*3.1 配置LCD引脚*/

  GPBcon = ioremap(0x56000010, 8);

  GPBdat = GPBcon+1;

  GPCcon = ioremap(0x56000020, 4);

  GPDcon = ioremap(0x56000030, 4);

  GPGcon = ioremap(0x56000060, 4);

 

  *GPBcon    &=~(0x03<<(1*2));

  *GPBcon    |= (0x01<<(1*2));     //PGB1背光

  *GPBdat    &=~(0X1<<1);           //关背光

 

  *GPCcon    =0xaaaaaaaa;

  *GPDcon    =0xaaaaaaaa;

  *GPGcon    |=(0x03<<(4*2));    //GPG4:LCD信号

 

  /*3.2 根据LCD手册设置LCD控制器,参考之前的裸机驱动*/

  lcd_reg=ioremap(0X4D000000, sizeof( lcd_reg) );

 

//240*320

/*

      TFT LCD的TTL信号

      VSYNC                        垂直同步信号

      HSYNC                        水平同步信号

      HCLK                           像素时钟信号

      VD[23:0]                       数据信号

      LEND                           行结束信号(非必须)                   

      PWREN                       电源开关信号

HSYNC表示“是跳到最左边的时候了”,VSYNC表示“是跳到最上边的时候了”

VSYNC可以理解为一帧图像有效地信号,在它低电平有效的时候,要连续发出(LINEVAL+1)

个行有效数据HSYNC信号;而在HSYNC有效地时候,要连续发出(HOZVAL+1)个像素有效数据,

这时像素数据的频率是由VCLK控制,VCLK是作为时序图的基准信号。我们开发板上用的屏是

240*320的3.5寸触摸屏,那么LINEVAL+1=240,HOZVAL+1=320。

lcd时钟信号频率,是像素时钟

VCLK=HCLK/[(CLKVAL+1)*2]

TFT:VCLK = 101.25M / [(CLKVAL + 1) × 2] = 6.4M CLKVAL = 7

bit[17:8] CLKVAL = 7

bit[6:5] PNRMODE=0b11 (tft lcd)

bit[4:1] BPPMODE=0b1100 (tft 16bpp)

bit[0] ENDIV=0 lcd使能信号,一开始先关闭使能

*/

lcd_reg->lcdcon1 = (LCD_CLKVAL<<8) | (3<<5) | (12<<1);

/*

水平信号参数

(T0-T2-T1=VBPD+1)

bit[31:24] VBPD=1  (upper_margin)VBPD表示VSYNC信号脉冲之后,还要经过VBPD+1个HSYNC信号周期,有效行才出现。

bit[23:14] LINEVAL=319   y-1

bit[13:6] VFPD=1   (T5-T2=vfpd+1)(lower_margin)VFPD表示在连续发出LINEVAL+1(lineecal=y-1)行有效数据后,还要经过VFPD+1个无效行,之后完整的一帧结束。

bit[5:0] VSPW=0   VSPW表示VSYNC信号的脉冲宽度为(VSPW+1)个,1帧图像周期

 

*/

//lcd_reg->lcdcon2 = (1<<24) | (319<<14) | (1<<6) | (1<<0);

lcd_reg->lcdcon2 = (LCD_VBPD<<24) | (LCD_LINEVAL<<14) | (LCD_VFPD<<6) | (LCD_VSPW<<0);

/*

hoz信号参数

T6-T7-T8

bit[25:19] HBPD=19  HBPD表示在HSYNC信号脉冲之后,还要经过HBPD+1个VCLK信号周期,有效像素才能够出现。

bit[18:8] HOZVAL=239

bit[7:0] HFPD==9    (T8-T11)HFPD表示在连续发出HOZVAL+1个像素的有效数据之后,还要发出(HFPD+1)个无效像素,完整的一行结束。

*/

//lcd_reg->lcdcon3 = (19<<19) | (239<<8) | (9<<0);

lcd_reg->lcdcon3 = (LCD_HBPD<<19) | (LCD_HOZVAL<<8) | (LCD_HFPD<<0);

/*

垂直信号参数

bit[7:0] HSPW=9   HSPW表示HSYNC信号脉冲宽度为(HSPW+1)个VCLK信号周期,即HSPW+1个像素是无效的。

*/

lcd_reg->lcdcon4 = (LCD_HSPW<<0);

/*

引脚的极性设置

bit[11] FRM565=1

bit[10] INVVCLK=1 上升沿取数据

bit[9] INVVLINE=1 水平同步信号反相

[1] [2]
Keywords:Mini2440 Reference address:Mini2440 linux LCD driver transplantation and some problems encountered

Previous article:linux2.6.32.2 mini2440 platform transplantation--Configuring USB peripherals and SD card transplantation
Next article:A simple example of porting ucos-ii to ARM mini2440

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号