Hi,欢迎来到中国优发娱乐手机版高端品牌 - 华清远见嵌入式学院<北京总部官网>,专注嵌入式工程师培养13年!
  • 全国咨询热线:400-611-6270
  • 新浪微博
  • 微信
  • 北京
    校区
  • 上海
    校区
  • 深圳
    校区
  • 成都
    校区
  • 南京
    校区
  • 武汉
    校区
  • 西安
    校区
  • 广州
    校区
  • 沈阳
    校区
  • 济南
    校区
  • 重庆
    校区
  • 长沙
    校区
  • 研发
    中心
  • 当前位置: > 嵌入式学院 > 嵌入式学习 > 讲师博文 > 4412 lcd驱动及简单字符显示
    4412 lcd驱动及简单字符显示
    时间:2017-09-18作者:李老师
    1.驱动: 基于framebuffer,整体代码参考内核s3c-fb.c 代码初始化步骤: 1、申请fb_info 2、初始化fb_info 3、管脚设置 4、时钟设置 5、控制芯片设置 6、注册fb 代码: 1/*head file*/ 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include "mylcd.h" 12 13/*module info*/ 14 MODULE_LICENSE("Dual BSD/GPL"); 15 16staticstructfb_info *my_fbInfo = NULL; 17staticintmyLcdBpp = 32; /*位深*/ 18staticshortmyPaletteSize = 256; /*调色板大小*/ 19static unsigned intmyXvSize = 1024; /*缓冲列大小*/ 20static unsigned intmyYvSize = 600; /*缓冲行大小*/ 21static unsigned intpseudo_palette[16]; 22 23/*io管脚寄存器*/ 24static unsigned int * __iomem gpf0con; 25static unsigned int * __iomem gpf1con; 26static unsigned int * __iomem gpf2con; 27static unsigned int * __iomem gpf3con; 28static unsigned int * __iomem gpd0con; 29/*pwm寄存器*/ 30static unsigned int * __iomem tcfg0; 31static unsigned int * __iomem tcfg1; 32static unsigned int * __iomemtcon; 33static unsigned int * __iomem tcntb1; 34static unsigned int * __iomem tcmpb1; 35/*时钟相关寄存器*/ 36static unsigned int * __iomemclk_div_lcd; 37static unsigned int * __iomem clk_src_lcd0; 38static unsigned int * __iomemlcdblk_cfg; 39static unsigned int * __iomem lcdblk_cfg2; 40/*lcd寄存器*/ 41static unsigned int * __iomem vidcon0; 42static unsigned int * __iomem vidcon1; 43static unsigned int * __iomem vidcon2; 44static unsigned int * __iomem vidtcon0; 45static unsigned int * __iomem vidtcon1; 46static unsigned int * __iomem vidtcon2; 47static unsigned int * __iomem wincon0; 48static unsigned int * __iomem vidoso0a; 49static unsigned int * __iomem vidoso0b; 50static unsigned int * __iomem vidoso0c; 51static unsigned int * __iomemshaadowcon; 52static unsigned int * __iomem winchmap2; 53static unsigned int * __iomem vidw00add0b0; 54static unsigned int * __iomem vidw00add1b0; 55static unsigned int * __iomem win0map; 56static unsigned int * __iomem vidw00add2; 57 58//static T_LCD_REG * __iomemlcdBase; 59 60static inline unsigned intchan_to_field(unsigned intchan, 61structfb_bitfield *bf) 62 { 63chan&= 0xffff; 64chan>>= 16 - bf->length; 65returnchan<< bf->offset; 66 } 67 68staticintmy_fb_setcolreg(unsigned regno, 69 unsigned red, unsigned green, unsigned blue, 70 unsigned transp, structfb_info *info) 71 { 72 unsigned intval = 0; 73switch (info->fix.visual) { 74case FB_VISUAL_TRUECOLOR: 75/* true-colour, use pseudo-palette */ 76if (regno<16) { 77 u32 *pal = info->pseudo_palette; 78 79val =chan_to_field(red, &info->var.red); 80val |= chan_to_field(green, &info->var.green); 81val |= chan_to_field(blue, &info->var.blue); 82 83pal[regno] = val; 84 } 85break; 86default: 87return1; /* unknown type */ 88 } 89 90return0; 91 } 92 93staticstructfb_opsmy_fb_ops = { 94 .owner = THIS_MODULE, 95 .fb_setcolreg = my_fb_setcolreg, 96 .fb_fillrect = cfb_fillrect, 97 .fb_copyarea = cfb_copyarea, 98 .fb_imageblit = cfb_imageblit, 99 }; 100 101staticintfb_fill_var(structfb_info *myfb) 102 { 103myfb->var.activate = FB_ACTIVATE_NOW; 104myfb->var.vmode = FB_VMODE_NONINTERLACED; 105myfb->var.bits_per_pixel = myLcdBpp; 106myfb->var.xres_virtual = myXvSize; 107myfb->var.yres_virtual = myYvSize; 108myfb->var.xres = myXvSize; 109myfb->var.yres = myYvSize; 110myfb->var.xoffset = 0; 111myfb->var.yoffset = 0; 112/* always ensure these are zero, for drop through cases below */ 113myfb->var.transp.offset = 0; 114myfb->var.transp.length = 0; 115 116switch (myfb->var.bits_per_pixel) { 117case1: 118case2: 119case4: 120case8: 121/* non palletised, A:1,R:2,G:3,B:2 mode */ 122myfb->var.red.offset = 5; 123myfb->var.green.offset = 2; 124myfb->var.blue.offset = 0; 125myfb->var.red.length = 2; 126myfb->var.green.length = 3; 127myfb->var.blue.length = 2; 128myfb->var.transp.offset = 7; 129myfb->var.transp.length = 1; 130break; 131 132case19: 133/* 666 with one bit alpha/transparency */ 134myfb->var.transp.offset = 18; 135myfb->var.transp.length = 1; 136/* drop through */ 137case18: 138myfb->var.bits_per_pixel = 32; 139 140/* 666 format */ 141myfb->var.red.offset = 12; 142myfb->var.green.offset = 6; 143myfb->var.blue.offset = 0; 144myfb->var.red.length = 6; 145myfb->var.green.length = 6; 146myfb->var.blue.length = 6; 147break; 148 149case16: 150/* 16 bpp, 565 format */ 151myfb->var.red.offset = 11; 152myfb->var.green.offset = 5; 153myfb->var.blue.offset = 0; 154myfb->var.red.length = 5; 155myfb->var.green.length = 6; 156myfb->var.blue.length = 5; 157break; 158 159case32: 160case28: 161case25: 162myfb->var.transp.length = myfb->var.bits_per_pixel - 24; 163myfb->var.transp.offset = 24; 164/* drop through */ 165case24: 166/* our 24bpp is unpacked, so 32bpp */ 167myfb->var.bits_per_pixel = 32; 168myfb->var.red.offset = 16; 169myfb->var.red.length = 8; 170myfb->var.green.offset = 8; 171myfb->var.green.length = 8; 172myfb->var.blue.offset = 0; 173myfb->var.blue.length = 8; 174break; 175 176default: 177printk("invalid bpp\n"); 178return -EINVAL; 179 } 180return0; 181 } 182 183staticintfb_fill_fix(structfb_info *myfb) 184 { 185 unsigned intreal_size, virt_size, size; 186dma_addr_tmap_dma; 187 188strcpy(myfb->fix.id ,"mylcd"); 189 190myfb->fix.type = FB_TYPE_PACKED_PIXELS; //在该方式下,像素值与内存直接对应 191myfb->fix.accel = FB_ACCEL_NONE; 192myfb->fix.line_length = (myfb->var.xres_virtual * myfb->var.bits_per_pixel) / 8; //一行的大小(字节数) 193myfb->fix.xpanstep = myfb->var.xres_virtual>myfb->var.xres ?1 :0; 194myfb->fix.ypanstep = myfb->var.yres_virtual>myfb->var.yres ?1 :0; 195 196switch (myfb->var.bits_per_pixel) { 197case32: 198case24: 199case16: 200case12: 201myfb->fix.visual = FB_VISUAL_TRUECOLOR; 202break; 203case8: 204if (myPaletteSize>= 256) 205myfb->fix.visual = FB_VISUAL_PSEUDOCOLOR; 206else 207myfb->fix.visual = FB_VISUAL_TRUECOLOR; 208break; 209case1: 210myfb->fix.visual = FB_VISUAL_MONO01; 211break; 212default: 213myfb->fix.visual = FB_VISUAL_TRUECOLOR; 214break; 215 } 216 217/*计算整体缓冲大小*/ 218real_size = myfb->var.xres * myfb->var.yres; 219virt_size = myfb->var.xres_virtual * myfb->var.yres_virtual; 220 size = (real_size>virt_size) ?real_size :virt_size; 221 size *= (myfb->var.bits_per_pixel>16) ?32 :myLcdBpp; 222 size /= 8; 223myfb->fix.smem_len = size; 224 size = PAGE_ALIGN(size); 225myfb->screen_base = dma_alloc_writecombine(myfb->dev, size, 226&map_dma, GFP_KERNEL); 227if (!myfb->screen_base) 228 { 229return -ENOMEM; 230 } 231memset(myfb->screen_base, 0x0, size); 232myfb->fix.smem_start = map_dma; 233 234return0; 235 } 236 237/*fun*/ 238staticvoidmyfb_Init(structfb_info *myfb) 239 { 240/*varinit*/ 241fb_fill_var(myfb); 242/*fix init*/ 243fb_fill_fix(myfb); 244/*ops init*/ 245myfb->fbops = &my_fb_ops; 246/*other init*/ 247myfb->flags = FBINFO_FLAG_DEFAULT; 248myfb->pseudo_palette =pseudo_palette; 249 } 250 251staticvoidmygpio_Init(void) 252 { 253 gpf0con = ioremap(LCD_F0,4); 254 gpf1con = ioremap(LCD_F1,4); 255 gpf2con = ioremap(LCD_F2,4); 256 gpf3con = ioremap(LCD_F3,4); 257 258writel(LCD_F0_VAL, gpf0con); 259writel(LCD_F1_VAL, gpf1con); 260writel(LCD_F2_VAL, gpf2con); 261writel(LCD_F3_VAL, gpf3con); 262 263//背光 264if(1) //pwm方式 265 { 266 gpd0con = ioremap(LCP_PWMIO_BASE,4); 267writel((readl(gpd0con) & (~(0xf<<4))) | (0x2<<4) , gpd0con); 268 } 269else//直接点亮方式 270 { 271intval; 272 273 unsigned int * __iomem gpd0con; 274 unsigned int * __iomem gpd0dat; 275 276 gpd0con = ioremap(0x114000A0,0x4); 277 gpd0dat = ioremap(0x114000A4,0x4); 278 279val = readl(gpd0con); 280val&= ~(0xf<<4); 281val |= (0x1<<4); 282writel(val, gpd0con); 283 284val = readl(gpd0dat); 285val |= (1<<1); 286writel(val, gpd0dat); 287 } 288 } 289 290staticvoidmyclk_Init(void) 291 { 292clk_div_lcd =ioremap(CLK_DIV_LCD,0x4); 293 clk_src_lcd0 = ioremap(CLK_SRC_LCD,0x4); 294lcdblk_cfg = ioremap(LCDBLK_CFG, 0x4); 295 lcdblk_cfg2= ioremap(LCDBLK_CFG2, 0x4); 296 297/*时钟源选择MPLL,具体参考 298 *SCLK_FIMD0 = MOUTFIMD0/(FIMD0_RATIO + 1) = 800M/1 = 800M 299*/ 300writel(readl(clk_div_lcd)&~0xf,clk_div_lcd); 301writel((readl(clk_src_lcd0)&~0xf)|0x6,clk_src_lcd0); 302 303/*选择FIMD0 具体参考 304 * 305 *Using the display controller data, you can select one of the above data paths by setting LCDBLK_CFG Register 306 *(0x1001_0210). For more information, refer to the "System Others" manual. 307 * 308 *While using RGB interface, the VT_LBLKx bit fields in LCDBLKC_CFG (0x1001_0210) register should be set to 309RGB Interface out (2'b00), even though you use DSI Video Mode.*/ 310writel((readl(lcdblk_cfg)&(~(0x3<<10)))|(1<<1),lcdblk_cfg); 311//writel(readl(lcdblk_cfg2)|(1<<0),lcdblk_cfg2); 312 } 313 314staticvoidmypwm_Init(void) 315 { 316 tcfg0 = ioremap(LCP_PWM_TCFG0,4); 317 tcfg1 = ioremap(LCP_PWM_TCFG1,4); 318tcon = ioremap(LCP_PWM_TCON,4); 319 tcntb1 = ioremap(LCP_PWM_TCNTB1,4); 320 tcmpb1 = ioremap(LCP_PWM_TCMPB1,4); 321/*占空比控制背光亮度*/ 322writel((readl(tcfg0) &(~0xff))|0xff,tcfg0); 323writel((readl(tcfg1) &(~(0xf<<4)))|0x4<<4,tcfg1); 324writel(300,tcntb1); 325writel(150,tcmpb1); 326writel((readl(tcon)&(~(0xf<<8)))|(0x1<<9),tcon); 327 328//使能 329writel((readl(tcon)&(~(0x1<<9)))|(0x1<<8),tcon); 330 } 331 332staticintlcd_Init(structfb_info *myfb) 333 { 334 unsigned intval; 335//lcd设置,寄存器太多,懒得放头文件了 336vidcon0 =ioremap(0x11c00000,0x4); 337vidcon1 =ioremap(0x11c00004,0x4); 338vidcon2 =ioremap(0x11c00008,0x4); 339 vidtcon0 = ioremap(0x11c00010,0x4); 340 vidtcon1 = ioremap(0x11c00014,0x4); 341 vidtcon2 = ioremap(0x11c00018,0x4); 342 343 win0map = ioremap(0x11C00180, 0x4); 344 wincon0 = ioremap(0x11c00020, 0x4); 345 346 vidoso0a = ioremap(0x11c00040,0x4); 347 vidoso0b = ioremap(0x11c00044,0x4); 348 vidoso0c = ioremap(0x11c00048,0x4); 349shaadowcon = ioremap(0x11c00034,0x4); 350winchmap2 =ioremap(0x11c0003c,0x4); 351 vidw00add0b0 = ioremap(0x11c000a0,0x4); 352 vidw00add1b0 = ioremap(0x11c000d0,0x4); 353 vidw00add2 = ioremap(0x11C00104, 0x4); 354 355/*HV mode fclk :44.9~63 推荐51.2Mhz 参考 356 *vidcon0 [13-6] VCLK = FIMD*SCLK/(CLKVAL+1) 357 *50M = 800M/(CLK_VAL+1) CLK_VAL= 15 这里为了取整,取50M 358*/ 359writel(15<<6, vidcon0); 360 361/* 362 * :VSYNC,HSYNC高电平触发信号,VCLK上升沿开始传输数据 363 *:VSD,HSD低电平触发信号,CLKV下降沿开始传输数据 364 * 365 *VIDCON1: 366 * [5]:IVSYNC ===> 1 : Inverted(反转) 367 * [6]:IHSYNC ===> 1 : Inverted(反转) 368 * [7]:IVCLK ===> 1 : Fetches video data at VCLK rising edge (下降沿触发,反转?) 369 * [10:9]:FIXVCLK ====> 01 : VCLK running 370 * */ 371writel((1<<9)|(1<<7)|(1<<5)|(1<<6),vidcon1); 372 373//Reserved: This bit should be set to 1. 374writel(1<<14, vidcon2); 375 376/*参考 HV mode 377 * thbp: 160 (DCLK) 378 * thfp: 160 (DCLK) 379 * thpw: 1-140 (DCLK) 380 * tvpw: 1-20 (Th) 381 * tvbp: 23 (Th) 382 * tvfp: 12 (Th) 383*/ 384 385#define HSPW 10 //行同步 386#define HBPD 160 387#define HFPD 160 388#define VSPW 1 //帧同步 389#define VBPD 23 390#define VFPD 12 391writel(((VBPD <<16)|(VFPD <<8)|(VSPW <<0)),vidtcon0); 392writel(((HBPD <<16)|(HFPD <<8)|(HSPW <<0)),vidtcon1); 393 394/*设置大小,参考 Display Format Graphic 1024RGB*600 Dot-matrix 395 * HOZVAL = (Horizontal display size) – 1 and LINEVAL = (Vertical display size) – 1. 396*/ 397writel(((1023<<0) | (599<<11)), vidtcon2); 398 399/*绑定win,这里直接使用了win0 400 * TODO:0xd=32位,这里强行写的,具体需要参考实际情况写16或32 401*/ 402writel((1<<6)|(0xD<<2)|1,wincon0); 403 404/* LCD左上角坐标*/ 405writel(0<<11|0, vidoso0a); 406/* LCD右下角坐标 参考 407 * 24 BPP mode should have X position by 1 pixel. (For example, X = 0, 1, 2, 3….) 408 * 16 BPP mode should have X position by 2 pixel. (For example, X = 0, 2, 4, 6….) 409 * 8 BPP mode should have X position by 4 pixel. (For example, X = 0, 4, 8, 12….) 410*/ 411if(myLcdBpp == 16) 412 { 413val = (((1023*2) <<11) | ((599*2) <<0)); 414 } 415elseif((myLcdBpp == 24) || (myLcdBpp == 32)) 416 { 417val = (((1023) <<11) | ((599) <<0)); 418 } 419writel(val, vidoso0b); 420 421/*总大小*/ 422writel(1024*600, vidoso0c); 423 424/*帧缓冲起始地址*/ 425writel(myfb->fix.smem_start, vidw00add0b0); 426/*帧缓冲结束地址*/ 427writel(myfb->fix.smem_start+myfb->fix.smem_len, vidw00add1b0); 428/*设置偏移和宽度*/ 429writel((0<<13) | ((1024 * myLcdBpp / 8)<<0), vidw00add2); 430 431/*绑定通道和窗口*/ 432writel(1, shaadowcon); 433writel((readl(winchmap2)&(~(0x7<<16))&(~0x7))|(1<<16)|(1<<0), winchmap2); 434 435/*Enables the video output and video control signal*/ 436writel(readl(vidcon0)|0x3, vidcon0); 437return0; 438 } 439 440staticint fs4412_lcd_init(void) 441 { 442int ret =0 ; 443/************************kernel相关*******************************/ 444/**这部分参考s3c-fb.c**/ 445/*申请fb_info*/ 446my_fbInfo = framebuffer_alloc(0,NULL); //这里没有私有数据,所以是0;dev没有,平台驱动需要添加。 447/*初始化fb_info*/ 448myfb_Init(my_fbInfo); 449/************************硬件相关*******************************/ 450/*管脚设置*/ 451mygpio_Init(); 452/*时钟设置*/ 453myclk_Init(); 454/*控制芯片设置*/ 455mypwm_Init(); 456lcd_Init(my_fbInfo); 457 458/*注册*/ 459 ret = register_framebuffer(my_fbInfo); 460if(0> ret){ 461printk(KERN_ERR "failed to register framebuffer \n"); 462//dma_free_coherent(fs_info->dev, fs_info->fix.smem_len,fs_info->screen_base, fs_info->fix.smem_start); 463return ret; 464 } 465 466printk("Lcdinit ok\n"); 467return0; 468 } 469 470/*没考虑退出,这里暂时没写*/ 471staticvoid fs4412_lcd_exit(void) 472 { 473printk("Lcd exit\n"); 474 } 475 476/**/ 477module_init(fs4412_lcd_init); 478module_exit(fs4412_lcd_exit); 2.应用: 下载一个字符转换工具,转换字符,我用的是字模提取V2.2。 先取一个字符转换码: 1、先在右下角的文字输入区输入需要转码的字,按Ctrl+Enter输入结束 2、在左边列里面选择取模方式,C51 格式,点击后在右下的点阵生成区显示转换的字节数组。
    3、把字节数组放到测试程序中,我为了方便,直接在c里面用了一个数组来装载。 应用编码 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 12#define MY_W 320 //图像宽 13#define MY_H 240 //图像高 14#define MAX_SIZE 1024*600*4 //lcd屏幕大小,具体要看对应的lcd手册。我的是1024*600 15 16/*字符矩阵 16*14*/ 17#define C_W 40 18#define C_H 35 19 20staticchar *fbp = 0; //映射内存起始地址 21staticintfbfd = 0; //帧缓冲fd 22 23/*存放转换后的汉字字节*/ 24const unsigned charcbuf[1024]= 25 { 26/*-- 文字: 我 --*/ 27/*-- 宋体26; 此字体下对应的点阵为:宽x高=35x35 --*/ 28/*-- 宽度不是8的倍数,现调整为:宽度x高度=40x35 --*/ 290x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x38,0x00,0x00,0x00, 300x0F,0xBE,0x00,0x00,0x00,0x7F,0xFD,0xE0,0x00,0x07,0xF8,0x3C,0x78,0x00,0x3E,0x78, 310x3C,0x7C,0x00,0x00,0x78,0x3C,0x3E,0x00,0x00,0x78,0x3C,0x1C,0x00,0x00,0x78,0x3C, 320x0C,0x00,0x00,0x78,0x3C,0x06,0x00,0x00,0x78,0x3C,0x0F,0x00,0x7F,0xFF,0xFF,0xFF, 330x80,0x00,0x78,0x3C,0x00,0x80,0x00,0x78,0x1C,0x10,0x00,0x00,0x78,0x1C,0x38,0x00, 340x00,0x78,0x1C,0x3C,0x00,0x00,0x78,0x5C,0x7E,0x00,0x00,0x7F,0xDC,0x70,0x00,0x00, 350x7E,0x1C,0xF0,0x00,0x01,0xF8,0x1F,0xE0,0x00,0x1F,0xF8,0x1F,0xC0,0x00,0x7F,0x78, 360x0F,0x80,0x00,0x3C,0x78,0x0F,0x00,0x00,0x30,0x78,0x0F,0x01,0x80,0x00,0x78,0x3F, 370x81,0x80,0x00,0x78,0x7B,0xC1,0x80,0x00,0x78,0xF1,0xE1,0x80,0x00,0x7B,0xC0,0xF3, 380x80,0x00,0x7F,0x00,0x7F,0x80,0x0F,0xFC,0x00,0x3F,0x80,0x01,0xF0,0x00,0x0F,0xC0, 390x00,0xE0,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 40 }; 41 42/*转换,并显示*/ 43voidpch(int *add,const unsigned char* buf) 44 { 45int row = 0; 46int col = 0; 47inti = 0; 48int color = 0x0; 49for(row=0;row>j))>0?1:0 ; 61 index++; 62 } 63i++; 64 j = 0; 65 } 66 67/*一行数据,按位显示*/ 68for(col=0;col显示效果:

    发表评论
    全国咨询电话:400-611-6270,双休日及节假日请致电值班手机:15010390966 在线咨询: 曹老师QQ(3337544669), 徐老师QQ(1462495461), 刘老师 QQ(3108687497) 企业培训洽谈专线:010-82600901,院校合作洽谈专线:010-82600350,在线咨询:QQ(248856300) Copyright 2004-2017 华清远见教育集团 版权所有 ,沪ICP备10038863号,京公海网安备110108001117号

    优发娱乐手机版

    百度360搜索搜狗搜索

    优发娱乐手机版

    百度360搜索搜狗搜索