一、抽象出重要的结构体【led.h 、lcd_controlloer.h】
先完成:
【lcd_controller.c】<–【s3c244_lcd_controller.c】:
向上接收不同LCD的参数,向下使用这些参数设置对应的LCD控制器
因为要接收不同的LCD参数,所以我们需要把LCD的参数写成一个结构体:
lcd.h:
#ifndef _LCD_H
#define _LCD_H
enum {
NORMAL = 0,
INVERT = 1,
};
/* NORMAL : 正常极性
* INVERT : 反转极性
*/
typedef struct pins_polarity {
int vclk; /* normal: 在下降沿获取数据 */
int rgb; /* normal: 高电平表示1 */
int hsync; /* normal: 高脉冲 */
int vsync; /* normal: 高脉冲 */
}pins_polarity, *p_pins_polarity;
typedef struct time_sequence {
/* 垂直方向 */
int tvp; /* vysnc脉冲宽度 */
int tvb; /* 上边黑框, Vertical Back porch */
int tvf; /* 下边黑框, Vertical Front porch */
/* 水平方向 */
int thp; /* hsync脉冲宽度 */
int thb; /* 左边黑框, Horizontal Back porch */
int thf; /* 右边黑框, Horizontal Front porch */
int vclk;
}time_sequence, *p_time_sequence;
typedef struct lcd_params {
char *name;
/* 引脚极性 */
pins_polarity pins_pol;
/* 时序 */
time_sequence time_seq;
/* 分辨率, bpp */
int xres;
int yres;
int bpp;
/* framebuffer的地址 */
unsigned int fb_base;
}lcd_params, *p_lcd_params;
#endif /* _LCD_H */
lcd_controlloer.h
#ifndef _LCD_CONTROLLER_H
#define _LCD_CONTROLLER_H
#include "lcd.h"
typedef struct lcd_controller {
char *name;
void (*init)(p_lcd_params plcdparams);
void (*enable)(void);
void (*disable)(void);
}lcd_controller, *p_lcd_controller;
#endif /* _LCD_CONTROLLER_H */
二、LCD控制器【s3c2440_lcd_controller.c】
1、初始化
(1) LCDCON1
LCDCON1 | val |
---|---|
CLKVAL [17:8] | VCLK = HCLK / [(CLKVAL+1) x 2] ==>从LCD芯片手册看,将VCLK 取为9。100/(CLKVAL+1)x2则CLKVAL大约为5 |
PNRMODE [6:5] | 11 = TFT LCD panel |
BPPMODE [4:1] | 1011 = 8 bpp for TFT; 1100 = 16 bpp for TFT; 1101 = 24 bpp for TFT |
(2)LCDCON2 、LCDCON3、LCDCON4
将LCD手册上的时序图和s3c2440手册上的时序图,对比我们可以知道:
VSPW+1 = tVp
VBPD+1 = tVb
LINEVAL +1 = tVd
VFPD+1 = tVf
HSPW+1 = thp
HBPD+1 = thb
HOZVAL+1 = thd
HFPD+1= thf
就可以设置LCDCON2 和LCDCON3、LCDCON4。
(3)LCDCON5
LCDCON5 | val |
---|---|
FRM565 [11] | 1 = 5:6:5 Format |
INVVCLK [10] | 0=clk下降沿得到数据 |
INVVLINE [9] | HSYNC pulse polarity |
INVVFRAME [8] | VSYNC pulse polarity |
INVVD [7] | VD (video data) pulse polarity = RGB的脉冲极性 |
INVVDEN [6] | |
INVPWREN [5] | |
INVLEND [4] | |
ENLEND [2] | |
BSWP [1] | 数据存储P412 |
HWSWP [0] | 数据存储P412 |
这些引脚的极性是否要设置取决于原理图上是否有接:
疑惑:PWREN其实不明白这个引脚是怎么接的。
在LCD芯片手册搜索“DE”:34 DE I Data Enable 有这个引脚。
那么这两个引脚的极性如何呢?
我们需要参考s3c2440的时序图,可以看到VDEN在高电平时,VD(RGB)使能数据。
那么PWREN的极性呢?
我们可以在s3c2440芯片手册上再找找看:可以看出PWREN在高电平的时候,LCD引脚工作。
因此完善引脚极性的结构体:
/* NORMAL : 正常极性
* INVERT : 反转极性
*/
typedef struct pins_polarity {
int de; /* normal: 高电平时可以传输数据 */
int pwren; /* normal: 高电平有效 */
int vclk; /* normal: 在下降沿获取数据 */
int rgb; /* normal: 高电平表示1 */
int hsync; /* normal: 高脉冲 */
int vsync; /* normal: 高脉冲 */
}pins_polarity, *p_pins_polarity;
(4)LCDSADDR1
LCDSADDR1 | val |
---|---|
LCDBANK [29:21] | A[30:22] 记得去掉最高位 |
LCDBASEU [20:0] | A[21:1] 记得去掉最低位 |
LCDSADDR2 | val |
---|---|
LCDBASEL | LCDBASEL = ((the frame end address) >>1) + 1 |
the frame end address = fb_base + xresyresbpp/8 ;
the frame end address >>= 1;
the frame end address &= 0x1fffff;
2、引脚的配置
(1)背光驱动引脚
我们来看下 LED+和LED-引脚
在原理图里搜索“KEYBOARD”,GPB0控制LED背光驱动。
GPBCON | val |
---|---|
GPB0 [1:0] | 01 = Output |
(2)其他引脚的配置
3、senable diseable函数
从原理图上看需要将KEYBOARD引脚输出为高电平:
查阅背光驱动芯片的手册,所以是高电平输入:
从MP3202DJ芯片手册看,en引脚高电平使能
GPBDAT | val |
---|---|
GPB0 [1:0] | 0关闭 1输出 |
LCDCON1 | val |
---|---|
ENVID [0] | 1 = Enable the video output and the LCD control signal. |
LCDCON5 | val |
---|---|
PWREN [3]给LCD提供AVDD逻辑电源 | 0 = Disable LEND signal 1 = Enable LEND signal |
三、LCD的设置【lcd_3.4.h】
引脚极性的是normal还是invert去看LCD芯片的时序图
如:
.hsync = INVERT, /* normal: 高脉冲 /
.vsync = INVERT, / normal: 高脉冲 */
要输出高脉冲之前是要先输出低脉冲,所以是 INVERT
引脚时序的要看LCD芯片的时序表
Horizontal signal=525(整个水平周期为525):
Note 1: thd=480CLK, thf= 2CLK, thp= 41CLK, thb= 2CLK
525CLK=480CLK + 2CLK + 41CLK + 2CLK
四、上层调用的文件
s3c2440_lcd_controller.c
void s3c2440_lcd_controller_add(void)
{
register_lcd_controller(&s3c2440_lcd_controller);
}
lcd_3_4.c
void lcd_3_4_add(void)
{
register_lcd(&lcd_4_3_params);
}
lcd.c
#define LCD_NUM 10
static p_lcd_params p_array_lcd[LCD_NUM];
static p_lcd_params g_p_lcd_selected;
int register_lcd(p_lcd_params plcd)
{
int i;
for (i = 0; i < LCD_NUM; i++)
{
if (!p_array_lcd[i])
{
p_array_lcd[i] = plcd;
return i;
}
}
return -1;
}
int select_lcd(char *name)
{
int i;
for (i = 0; i < LCD_NUM; i++)
{
if (p_array_lcd[i] && !strcmp(p_array_lcd[i]->name, name))
{
g_p_lcd_selected = p_array_lcd[i];
return i;
}
}
return -1;
}
int lcd_init(void)
{
/* 注册LCD */
lcd_4_3_add();
/* 注册LCD控制器 */
lcd_contoller_add();
/* 选择某款LCD */
select_lcd("lcd_4.3");
/* 选择某款LCD控制器 */
select_lcd_controller("s3c2440");
/* 使用LCD的参数, 初始化LCD控制器 */
lcd_controller_init(g_p_lcd_selected);
}
lcd.controller.c
#define LCD_CONTROLLER_NUM 10
static p_lcd_controller p_array_lcd_controller[LCD_CONTROLLER_NUM];
static p_lcd_controller g_p_lcd_controller_selected;
int register_lcd_controller(p_lcd_controller plcdcon)
{
int i;
for (i = 0; i < LCD_CONTROLLER_NUM; i++)
{
if (!p_array_lcd_controller[i])
{
p_array_lcd_controller[i] = plcdcon;
return i;
}
}
return -1;
}
int select_lcd_controller(char *name)
{
int i;
for (i = 0; i < LCD_CONTROLLER_NUM; i++)
{
if (p_array_lcd_controller[i] && !strcmp(p_array_lcd_controller[i]->name, name))
{
g_p_lcd_controller_selected = p_array_lcd_controller[i];
return i;
}
}
return -1;
}
/* 向上: 接收不同LCD的参数
* 向下: 使用这些参数设置对应的LCD控制器
*/
int lcd_controller_init(p_lcd_params plcdparams)
{
/* 调用所选择的LCD控制器的初始化函数 */
if (g_p_lcd_controller_selected)
{
g_p_lcd_controller_selected->init(plcdparams);
return 0;
}
return -1;
}
void lcd_contoller_add(void)
{
s3c2440_lcd_contoller_add();
}