当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 >
4412 lcd驱动及简单字符显示
时间:2018-09-29作者:华清远见

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-2018 华清远见教育集团 版权所有 ,京ICP备16055225号,京公海网安备11010802025203号

博聚网