目录
title: LCD学习
tags: ARM
date: 2018-10-28 20:18:48:59
---
裸屏,也就是最终接口是RGB的信号线,需要MCU支持液晶驱动或者MCU连接液晶驱动芯片
在JZ2440连接的就是裸屏,接口一般如下:
带驱动芯片的液晶模块,类似STM32就是这么使用的,比如使用STM32连接ili9341
或者RA8875
等驱动芯片,STM32通过FSMC
与RA8875
通信,然后RA8875
本身有相应的RGB信号线
所以在这里,并没有所谓的液晶驱动芯片,液晶驱动控制被集成在s3c2440内部已经. 板载的TFT液晶型号是AT043TN24
,像素点是480*272,自带触摸屏
注意:
在上图中,行信号和列信号中都有3个时间参数,对应显示区的黑框
也就是说
2440外部GPIO如下
2440的手册有寄存器设置的向导TFT LCD CONTROLLER OPERATION
//这里选择9M,9=100M /[(CLKVAL+1) x 2], clkval = 4.5 = 5
// 选择支持 8bpp或者16bpp或者24bpp
8bpp=1011=0x0b
16bpp=1100=0x0c
24bpp=1101=0x0d
int clkval = 5;
int bppmode = plcdparams->bpp == 8 ? 0xb : plcdparams->bpp == 16 ? 0xc : 0xd; /* 0xd: 24,32bpp */
LCDCON1 = (clkval<<8) | (3<<5) | (bppmode<<1) ;
注意,这里的时间参数都是+1
才等于需要的值,所以配置寄存器的时候都要减去1
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;
/* [31:24] : VBPD = tvb - 1
* [23:14] : LINEVAL = line - 1
* [13:6] : VFPD = tvf - 1
* [5:0] : VSPW = tvp - 1
*/
LCDCON2 = ((plcdparams->time_seq.tvb - 1)<<24) | ((plcdparams->yres - 1)<<14) | ((plcdparams->time_seq.tvf - 1)<<6) | ((plcdparams->time_seq.tvp - 1)<<0);
/* [25:19] : HBPD = thb - 1
* [18:8] : HOZVAL = 列 - 1
* [7:0] : HFPD = thf - 1
*/
LCDCON3 = ((plcdparams->time_seq.thb - 1)<<19) | ((plcdparams->xres - 1)<<8) | ((plcdparams->time_seq.thf - 1)<<0);
/*
* [7:0] : HSPW = thp - 1
*/
LCDCON4 = ((plcdparams->time_seq.thp - 1)<<0);
注意选择[1:0]
来选择bpp存放的格式,文档搜索BSWP
即可看到,我们都选择低位优先存储的
pixelplace = plcdparams->bpp == 32 ? (0) : plcdparams->bpp == 16 ? (1) : (1<<1); /* 8bpp */
具体的极性按照lcd参数具体设计
LCDCON5 = (plcdparams->pins_pol.vclk<<10) | (plcdparams->pins_pol.rgb<<7) | (plcdparams->pins_pol.hsync<<9) | (plcdparams->pins_pol.vsync<<8) | (plcdparams->pins_pol.de<<6) | (plcdparams->pins_pol.pwren<<5) | (1<<11) | pixelplace;
地址 | 寄存器 | 解释 | 这里的单位都是半字,也就是2个字节 |
---|---|---|---|
ADDR1 | LCDBANK | 内存起始地址,4M对齐 | 实际内存最大允许使用4M也就是说 |
LCDBASEU | 视窗的起始地址,低4M偏移 | 视窗从这个4M的哪个地方开始 | |
ADDR2 | LCDBASEL | 视窗结束地址,低4M的偏移 | 视窗从这个4M的哪个地方结束 |
ADDR3 | OFFSIZE | 视窗与实际内存的偏差 | 通过该值,计算下一行的像素点对应在内存的位置。当前在x,那么下一行的取值在x+PAGEWIDTH+OFFSIZE |
PAGEWIDTH | 视窗的宽度 |
这里的结束地址我觉得按照手册写的它并不是指的是视窗的结束地址,而是指的是视窗结束地址同行的所在内存空间的结束地址,如下图蓝色标识是手册的位置,实际的地址是在红色箭头的位置,但是设置到蓝色的位置应该也没啥关系
/* framebuffer地址 */
/*
* [29:21] : LCDBANK, A[30:22] of fb
* [20:0] : LCDBASEU, A[21:1] of fb
*/
addr = plcdparams->fb_base & ~(1<<31);
LCDSADDR1 = (addr >> 1);
/*
* [20:0] : LCDBASEL, A[21:1] of end addr
*/
addr = plcdparams->fb_base + plcdparams->xres*plcdparams->yres*plcdparams->bpp/8;
addr >>=1;
addr &= 0x1fffff;
LCDSADDR2 = addr;//
上面的这段代码,结束地址是实际的结束地址,也就是上面红色箭头的位置.
1,2,4,8bpp都是指的调色板,8bpp指的意思就是2^8共256个颜色索引,每个索引值16位的颜色值.
0x4D000400 为调色板开始地址
操作调色板的时候,需要禁止LCD
只需要在内存填充数据,并选择视图位置即可.颜色排序都是RGB的顺序虽然硬件只接了16bpp,但是软件上依然能够使用32bpp,因为硬件上的接法是忽略低位的.
所谓8Bpp就是使用调色板了
所谓字库,其实就是一片小区域的画点,比如在Linux
中搜索font
,打开font_8x16.c
,可以看到A的字库如下,转换为二进制,再把0替换成空白,其实就是在8*16的格子中点亮相应的内存,一个字符占据16个字节
/* 65 0x41 ‘A‘ */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x10, /* 00010000 */ 1
0x38, /* 00111000 */ 111
0x6c, /* 01101100 */ 11 11
0xc6, /* 11000110 */ 11 11
0xc6, /* 11000110 */ 11 11
0xfe, /* 11111110 */ 1111111
0xc6, /* 11000110 */ 11 11
0xc6, /* 11000110 */ 11 11
0xc6, /* 11000110 */ 11 11
0xc6, /* 11000110 */ 11 11
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
点亮字符如下
void fb_print_char(int x, int y, char c, unsigned int color)
{
int i, j;
/* 根据c的ascii码在fontdata_8x16中得到点阵数据 */
// 这里一个字符占据16字节
unsigned char *dots = &fontdata_8x16[c * 16];
unsigned char data;
int bit;
/* 根据点阵来设置对应象素的颜色 */
for (j = y; j < y+16; j++)
{
data = *dots++;
bit = 7;
for (i = x; i < x+8; i++)
{
/* 根据点阵的某位决定是否描颜色 */
if (data & (1<<bit))
fb_put_pixel(i, j, color);
bit--;
}
}
}
中间层1
中间层2
应用层1
原文:https://www.cnblogs.com/zongzi10010/p/10023636.html