<commit_before>---
layout:     post
title:      "ARM裸机-LCD"
subtitle:   "ARM Tiny210 LCD"
date:       2017-03-03 20:00:00
author:     "陈登龙"
header-img: "img/post-bg-unix-linux.jpg"
catalog: true
tags:
    - ARM裸机
---


# ARM裸机-LCD

**一，LCD简介**

LCD是嵌入式中常用的液晶屏幕，我们显示一般都会使用它，即便是触摸屏(加了触控芯片的LCD)。
本次简单介绍下LCD的基本原理，具体的寄存器配置请参考数据手册，这里即使介绍也只是翻译。

这是S5PV210的LCD原理图：
![210-LCD][1]

**二，LCD控制器**

模型如下：
![LCD-Control][2]

要使一块LCD正常显示文字或图像，不仅需要**LCD驱动器**，还需要相应的**LCD控制器**。LCD控制
器的主要作用是将在系统存储器中的**显示缓冲区(FrameBuffer)**中的LCD图像数据传送到外部LCD驱动器，并产生必要的**控制信号**，例如VSYNC、HSYSNC、VCLK。


**三，FrameBuffer**

FrameBuffer简单说就是一块**内存区域**，用来存储用于LCD显示像素的信息，例如存储调色板的颜色索引。

**四，调色板**

如下模型图所示：
![LCD ind map][3]

是一个**存储颜色的表格**，如果FrameBuffer中的像素是**8bpp(bit per pixels),** 则调色板有**256**种颜色，在显示一个像素的时候，从FrameBuffer拿出一个颜色的**索引**，然后在调色板中找到该**索引对应的颜色**，最后送到LCD进行显示。


**五，LCD扫描原理**

先看一张图：
![LCD-Singal][4]

需要知道**LCD真正显示的位置是中间的区域**，外面的区域是为了进行信号的控制而产生的无效的行和列，因为控制LCD需要时序，图中的时序就是下面的这张LCD时序图的表示：
![LCD-Timing][5]

按照上面的图来分析这个时序是挺简单的。

1.VSYNC开始，这里成为列信号，喷枪(假设有这个东西喷出像素)移动到最左上角，LCD常见的坐标原点都在左上角。

2.等待(VSPW + 1) + (VBPD + 1)。

3.(VBPD + 1)结束后，HSYNC信号开始，也就是行信号。

4.等待(HSPW + 1) + (HBPD + 1)。

5.刷新一行像素，时间：HOZVAL + 1。

6.列信号等待VFPD + 1, 回到VSYNC。

7.行信号等待HFPD + 1, 回到HSYNC。


这样LCD就扫描出**一帧图像**，如果要显示视频，那就要**重复**这个循环了。


下面总结下：
 **每一帧的传输**过程如下:

1) VSYNC 信号有效时,信号宽度为(VSPW+1)个 HSNC 信号周期,即(VSPW+1)个无效行;

2) VSYNC 信号脉冲之后,总共还要经过(VBPD+1)个 HSYNC 信号周期,有效的行数据才出现。所以,在 VSYNC 信号有效之后,还要进过(VSPW+1+VBPD+1)个无效的行;

3) 随即发出(LINEVAL+1)行的有效数据;

4) 最后是(VFPD+1)个无效的行;


**每一行中像素**的传输过程如下:

1) HSNC 信号有效时,表示一行数据的开始,信号宽度为(HSPW+1)个 VCLK 信号周期,即(HSPW+1)个无效像素;

2) HSYNC 信号脉冲之后,还要经过(HBPD+1)个 VCLK 信号周期,有效的像素数据才出现;

3) 随后发出(HOZVAL+1)个像素的有效数据;

4) 最后是(HFPD+1)个无效的像素;

**一行一行的传输，最后形成一帧图像**。

**六，LCD编程思路**

看了上面的时序介绍，你应该对LCD的原理有所了解了吧。
下面就介绍下控制LCD的思路，对于裸机编程，那就是**根据原理图和数据手册来配置寄存器**了。
如果你了解了LCD的时序，那么配置寄存器应该问题不大，你需要**参考开发板的数据手册和LCD的数据手册**。
时序的配置是比较麻烦的，需要认真仔细。

在初始化LCD之后，你需要利用**画点**这个函数来画出一些基本的图形了。在 LCD 上描点的本质就是往**FrameBuffer中指定位置写入颜色值**。
下面我们分析下画点函数：

``` c
/*
 * 在LCD屏幕指定位置花出一个点
 * row：点所在的行
 * col ：点所在的列
 * color：点的颜色
 */
void lcd_draw_pixel(int row, int col, int color)
{
	/* 拿到FrameBuffer的内存地址 */
	unsigned long * buf_base = (unsigned long *)FB_ADDR;
	/*<commit_msg>ModifyLCD<commit_after>---
layout:     post
title:      "ARM裸机-LCD"
subtitle:   "ARM Tiny210 LCD"
date:       2017-03-03 20:00:00
author:     "陈登龙"
header-img: "img/post-bg-unix-linux.jpg"
catalog: true
tags:
    - ARM裸机
---


# ARM裸机-LCD

**一，LCD简介**

LCD是嵌入式中常用的液晶屏幕，我们显示一般都会使用它，即便是触摸屏(加了触控芯片的LCD)。
本次简单介绍下LCD的基本原理，具体的寄存器配置请参考数据手册，这里即使介绍也只是翻译。

这是S5PV210的LCD原理图：
![210-LCD][1]

**二，LCD控制器**

模型如下：
![LCD-Control][2]

要使一块LCD正常显示文字或图像，不仅需要**LCD驱动器**，还需要相应的**LCD控制器**。LCD控制
器的主要作用是将在系统存储器中的**显示缓冲区(FrameBuffer)**中的LCD图像数据传送到外部LCD驱动器，并产生必要的**控制信号**，例如VSYNC、HSYSNC、VCLK。


**三，FrameBuffer**

FrameBuffer简单说就是一块**内存区域**，用来存储用于LCD显示像素的信息，例如存储调色板的颜色索引。

**四，调色板**

如下模型图所示：
![LCD ind map][3]

是一个**存储颜色的表格**，如果FrameBuffer中的像素是**8bpp(bit per pixels),** 则调色板有**256**种颜色，在显示一个像素的时候，从FrameBuffer拿出一个颜色的**索引**，然后在调色板中找到该**索引对应的颜色**，最后送到LCD进行显示。

**注意**：LCD选定后，**像素宽度是固定的**，例如8bpp，16bpp，24bpp等。


**五，LCD扫描原理**

先看一张图：
![LCD-Singal][4]

需要知道**LCD真正显示的位置是中间的区域**，外面的区域是为了进行信号的控制而产生的无效的行和列，因为控制LCD需要时序，图中的时序就是下面的这张LCD时序图的表示：
![LCD-Timing][5]

按照上面的图来分析这个时序是挺简单的。

1.VSYNC开始，这里成为列信号，喷枪(假设有这个东西喷出像素)移动到最左上角，LCD常见的坐标原点都在左上角。

2.等待(VSPW + 1) + (VBPD + 1)。

3.(VBPD + 1)结束后，HSYNC信号开始，也就是行信号。

4.等待(HSPW + 1) + (HBPD + 1)。

5.刷新一行像素，时间：HOZVAL + 1。

6.列信号等待VFPD + 1, 回到VSYNC。

7.行信号等待HFPD + 1, 回到HSYNC。


这样LCD就扫描出**一帧图像**，如果要显示视频，那就要**重复**这个循环了。


下面总结下：
 **每一帧的传输**过程如下:
1) VSYNC 信号有效时,信号宽度为(VSPW+1)个 HSNC 信号周期,即(VSPW+1)个无效行;
2) VSYNC 信号脉冲之后,总共还要经过(VBPD+1)个 HSYNC 信号周期,有效的行数据才出现。所以,在 VSYNC 信号有效之后,还要进过(VSPW+1+VBPD+1)个无效的行;
3) 随即发出(LINEVAL+1)行的有效数据;
4) 最后是(VFPD+1)个无效的行;


**每一行中像素**的传输过程如下:
1) HSNC 信号有效时,表示一行数据的开始,信号宽度为(HSPW+1)个 VCLK 信号周期,即(HSPW+1)个无效像素;
2) HSYNC 信号脉冲之后,还要经过(HBPD+1)个 VCLK 信号周期,有效的像素数据才出现;
3) 随后发出(HOZVAL+1)个像素的有效数据;
4) 最后是(HFPD+1)个无效的像素;

**一行一行的传输，最后形成一帧图像**。

**六，LCD编程思路**

看了上面的时序介绍，你应该对LCD的原理有所了解了吧。
下面就介绍下控制LCD的思路，对于裸机编程，那就是**根据原理图和数据手册来配置寄存器**了。
如果你了解了LCD的时序，那么配置寄存器应该问题不大，你需要**参考开发板的数据手册和LCD的数据手册**。时序的配置是比较麻烦的，需要认真仔细。

**程序思路：**

**1.** 打开背光


**2.** LCD时序设置


**3.** 在LCD Control的Frame Buffer中写入数据


在初始化LCD之后，你需要利用**画点**这个函数来画出一些基本的图形了。在 LCD 上描点的本质就是往**FrameBuffer中指定位置写入颜色值**。
下面我们分析下画点函数：

``` c
/*
 * 在LCD屏幕指定位置花出一个点
 * row：点所在的行
 * col ：点所在的列
 * color：点的颜色
 */
void lcd_draw_pixel(int row, int col, int color)
{
	/* 拿到FrameBuffer的内存地址 */
	unsigned long * buf_base = (unsigned long *)FB_ADDR;
	/*
{'fraction_non_alphanumeric': 0.17539964476021314, 'fraction_numerical': 0.03197158081705151, 'mean_word_length': 7.205828779599272, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6795300', 'n_tokens_mistral': 3500, 'n_tokens_neox': 3809, 'n_words': 271}