1# LCD
2
3## 概述
4
5### 功能简介
6
7LCD(Liquid Crystal Display)驱动编程,通过对显示器上电、初始化显示器驱动IC(Integrated Circuit)内部寄存器等操作,使其可以正常工作。
8
9基于HDF(Hardware Driver Foundation)[驱动框架](driver-overview-foundation.md)构建的Display驱动模型作用如下:
10
11- 为LCD器件驱动开发提供了基础驱动框架,提升驱动开发效率。
12
13- 便于开发的器件驱动实现跨OS、跨芯片平台迁移。
14
15基于HDF驱动框架的Display驱动模型如下所示:
16
17
18  **图1** 基于HDF驱动框架的Display驱动模型
19
20  ![image](figures/基于HDF驱动框架的Display驱动模型.png "基于HDF驱动框架的Display驱动模型")
21
22Display驱动模型主要由平台驱动层、芯片平台适配层、LCD器件驱动层三部分组成。驱动模型基于HDF驱动框架开发,通过Platform层和OSAL层提供的接口,屏蔽内核形态的差异,使得器件驱动可以便利的迁移到不同OS及芯片平台。模型向上对接Display公共HAL层,支撑HDI(Hardware Device Interface)接口的实现,通过Display-HDI对图形服务提供各类驱动能力接口。
23
24- Display平台驱动层:通过HDF提供的IOService数据通道,与公共HAL层对接,集中接收并处理各类上层调用指令。
25
26- SoC平台驱动适配层:借助此SoC适配层,实现Display驱动和SoC侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层。
27
28- LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。
29
30基于Display驱动模型开发LCD驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发周期和难度,提升开发效率。
31
32### 基本概念
33
34LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口,下面对常用的MIPI DSI接口和TTL接口作简要介绍。
35
36- MIPI DSI接口
37
38    **图2** MIPI DSI接口
39
40    ![image](figures/MIPI-DSI接口.png "MIPI-DSI接口")
41
42    MIPI DSI接口是MIPI(Mobile Industry Processor Interface)联盟定义的显示接口,主要用于移动终端显示屏接口,接口数据传输遵循MIPI协议,MIPI DSI接口为数据接口,传输图像数据,通常情况下MIPI DSI接口的控制信息以MIPI包形式通过MIPI DSI接口发送到对端IC,不需要额外的外设接口。
43
44- TTL接口
45
46    **图3** TTL接口
47
48    ![image](figures/TTL接口.png "TTL接口")
49
50    ​TTL(Transistor Transistor Logic)即晶体管-晶体管逻辑,TTL电平信号由TTL器件产生,TTL器件是数字集成电路的一大门类,它采用双极型工艺制造,具有高速度、低功耗和品种多等特点。
51
52    TTL接口是并行方式传输数据的接口,有数据信号、时钟信号和控制信号(行同步、帧同步、数据有效信号等),在控制信号控制下完成数据传输。通常TTL接口的LCD,内部寄存器读写需要额外的外设接口,比如SPI接口、I2C接口等。
53
54### 约束与限制
55
56开发者在进行LCD驱动编程过程中,除了要关注IC的型号,还要关注LCD外围电路设计、基带芯片的LCD接口单元、背光IC的控制等多个方面,同时包括软件的上层程序。这些都是影响开发者在调试LCD驱动的影响因素。
57
58## 开发指导
59
60### 场景介绍
61
62LCD驱动模型属于驱动基础适配模块,第三方需要适配OpenHarmony系统时,需要进行LCD驱动适配。LCD驱动适配基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。
63
64### 接口说明
65
66为了能够调整液晶显示屏的各项参数,与display建立显示通道,实现显示器的显示效果,LCD驱动需要通过`display :: host`注册PanelInfo结构体、接口信息,添加描述设备;LcdResetOn读取的pin脚信息,由SampleEntryInit初始化入口函数,并注册器件驱动接口,供平台驱动调用。
67
68表1 LCD驱动适配所需接口
69
70| 接口名                                                  | 描述                |
71| :------------------------------------------------------ | ------------------- |
72| static int32_t MipiDsiInit(struct PanelInfo *info)      | 适配对应的芯片平台驱动 |
73| static int32_t LcdResetOn(void)                         | 设置Reset Pin脚状态 |
74| int32_t SampleEntryInit(struct HdfDeviceObject *object) | 器件驱动入口函数    |
75
76### 开发步骤
77
78
791. 添加LCD驱动相关的设备描述配置。
80
812. 在SoC平台驱动适配层中适配对应的芯片平台驱动。
82
833. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要实现下述特性:
84   - LCD上下电
85
86      根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。
87
88   - 发送初始化序列
89
90      根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。
91
924. (可选)根据需求实现HDF框架其他接口。
93
945. (可选)根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。
95
96### 开发实例
97
98以Hi35xx系列芯片为例,根据开发步骤所述,介绍LCD驱动的详细适配过程。
99
1001. 添加设备描述配置(vendor/bearpi/bearpi_hm_micro/hdf_config/device_info/device_info.hcs101
102   ```c++
103   /* Display驱动相关的设备描述配置 */
104   display :: host {
105       hostName = "display_host";
106       /* Display平台驱动设备描述 */
107       device_hdf_disp :: device {
108           device0 :: deviceNode {
109               policy = 2;
110               priority = 200;
111               permission = 0660;
112               moduleName = "HDF_DISP";
113               serviceName = "hdf_disp";
114           }
115       }
116       /* SoC适配层驱动设备描述 */
117       device_hi35xx_disp :: device {
118           device0 :: deviceNode {
119               policy = 0;
120               priority = 199;
121               moduleName = "HI351XX_DISP";
122           }
123       }
124       /* LCD器件驱动设备描述 */
125       device_lcd :: device {
126           device0 :: deviceNode {
127               policy = 0;
128               priority = 100;
129               preload = 0;
130               moduleName = "LCD_Sample";
131           }
132           device1 :: deviceNode {
133               policy = 0;
134               priority = 100;
135               preload = 2;
136               moduleName = "LCD_SampleXX";
137           }
138       }
139   }
140   ```
141
1422. SoC平台驱动适配层中适配对应的芯片平台驱动(drivers/hdf_core/framework/model/display/driver/adapter_soc/hi35xx_disp.c143
144   ```c++
145   /* Display驱动适配MIPI等和芯片平台相关的配置 */
146   static int32_t MipiDsiInit(struct PanelInfo *info)
147   {
148       int32_t ret;
149       struct DevHandle *mipiHandle = NULL;
150       struct MipiCfg cfg;
151
152       mipiHandle = MipiDsiOpen(0);
153       if (mipiHandle == NULL) {
154           HDF_LOGE("%s: MipiDsiOpen failure", __func__);
155           return HDF_FAILURE;
156       }
157       cfg.lane = info->mipi.lane;
158       cfg.mode = info->mipi.mode;
159       cfg.format = info->mipi.format;
160       cfg.burstMode = info->mipi.burstMode;
161       cfg.timing.xPixels = info->width;
162       cfg.timing.hsaPixels = info->hsw;
163       cfg.timing.hbpPixels = info->hbp;
164       cfg.timing.hlinePixels = info->width + info->hbp + info->hfp + info->hsw;
165       cfg.timing.vsaLines = info->vsw;
166       cfg.timing.vbpLines = info->vbp;
167       cfg.timing.vfpLines = info->vfp;
168       cfg.timing.ylines = info->height;
169       /* 0 : no care */
170       cfg.timing.edpiCmdSize = 0;
171       cfg.pixelClk = CalcPixelClk(info);
172       cfg.phyDataRate = CalcDataRate(info);
173       /* config mipi device */
174       ret = MipiDsiSetCfg(mipiHandle, &cfg);
175       if (ret != HDF_SUCCESS) {
176           HDF_LOGE("%s:MipiDsiSetCfg failure", __func__);
177       }
178       MipiDsiClose(mipiHandle);
179       HDF_LOGI("%s:pixelClk = %d, phyDataRate = %d\n", __func__,
180           cfg.pixelClk, cfg.phyDataRate);
181       return ret;
182   }
183   ```
184
1853. 添加器件
186
187   - 驱动定义相关接口信息(drivers/hdf_core/framework/model/display/driver/panel/mipi_icn9700.c188
189     ```c++
190     #define RESET_GPIO                5
191     #define MIPI_DSI0                 0
192     #define BLK_PWM1                  1
193     #define PWM_MAX_PERIOD            100000
194     /* backlight setting */
195     #define MIN_LEVEL                 0
196     #define MAX_LEVEL                 255
197     #define DEFAULT_LEVEL             100
198     #define WIDTH                     480
199     #define HEIGHT                    960
200     #define HORIZONTAL_BACK_PORCH     20
201     #define HORIZONTAL_FRONT_PORCH    20
202     #define HORIZONTAL_SYNC_WIDTH     10
203     #define VERTICAL_BACK_PORCH       14
204     #define VERTICAL_FRONT_PORCH      16
205     #define VERTICAL_SYNC_WIDTH       2
206     #define FRAME_RATE                60
207     ```
208
209   - 定义PanelInfo结构体(drivers/hdf_core/framework/model/display/driver/hdf_disp.h210
211     ```c++
212     struct PanelInfo {
213         uint32_t width;	     // 水平尺寸
214         uint32_t height;	     // 垂直尺寸
215         uint32_t hbp;		     // 水平同步信号的后肩
216         uint32_t hfp;		     // 水平同步信号的前肩
217         uint32_t hsw;		     // 水平同步信号的脉宽
218         uint32_t vbp;		     // 垂直同步信号的后肩
219         uint32_t vfp;		     // 垂直同步信号的前肩
220         uint32_t vsw;		     // 垂直同步信号的脉宽
221         uint32_t frameRate;	     // 帧率
222         enum LcdIntfType intfType;  // LCD接口类型
223         enum IntfSync intfSync;     // 用户时序参数
224         struct MipiDsiDesc mipi;
225         struct BlkDesc blk;
226         struct PwmCfg pwm;
227     };
228     ```
229
230   - 初始化LCD屏(drivers/hdf_core/framework/model/display/driver/panel/mipi_icn9700.c231
232     ```c++
233     static uint8_t g_payLoad0[] = { 0xF0, 0x5A, 0x5A };
234     static uint8_t g_payLoad1[] = { 0xF1, 0xA5, 0xA5 };
235     static uint8_t g_payLoad2[] = { 0xB3, 0x03, 0x03, 0x03, 0x07, 0x05, 0x0D, 0x0F, 0x11, 0x13, 0x09, 0x0B };
236     static uint8_t g_payLoad3[] = { 0xB4, 0x03, 0x03, 0x03, 0x06, 0x04, 0x0C, 0x0E, 0x10, 0x12, 0x08, 0x0A };
237     static uint8_t g_payLoad4[] = { 0xB0, 0x54, 0x32, 0x23, 0x45, 0x44, 0x44, 0x44, 0x44, 0x60, 0x00, 0x60, 0x1C };
238     static uint8_t g_payLoad5[] = { 0xB1, 0x32, 0x84, 0x02, 0x87, 0x12, 0x00, 0x50, 0x1C };
239     static uint8_t g_payLoad6[] = { 0xB2, 0x73, 0x09, 0x08 };
240     static uint8_t g_payLoad7[] = { 0xB6, 0x5C, 0x5C, 0x05 };
241     static uint8_t g_payLoad8[] = { 0xB8, 0x23, 0x41, 0x32, 0x30, 0x03 };
242     static uint8_t g_payLoad9[] = { 0xBC, 0xD2, 0x0E, 0x63, 0x63, 0x5A, 0x32, 0x22, 0x14, 0x22, 0x03 };
243     static uint8_t g_payLoad10[] = { 0xb7, 0x41 };
244     static uint8_t g_payLoad11[] = { 0xC1, 0x0c, 0x10, 0x04, 0x0c, 0x10, 0x04 };
245     static uint8_t g_payLoad12[] = { 0xC2, 0x10, 0xE0 };
246     static uint8_t g_payLoad13[] = { 0xC3, 0x22, 0x11 };
247     static uint8_t g_payLoad14[] = { 0xD0, 0x07, 0xFF };
248     static uint8_t g_payLoad15[] = { 0xD2, 0x63, 0x0B, 0x08, 0x88 };
249     static uint8_t g_payLoad16[] = { 0xC6, 0x08, 0x15, 0xFF, 0x10, 0x16, 0x80, 0x60 };
250     static uint8_t g_payLoad17[] = { 0xc7, 0x04 };
251     static uint8_t g_payLoad18[] = {
252         0xC8, 0x7C, 0x50, 0x3B, 0x2C, 0x25, 0x16, 0x1C, 0x08, 0x27, 0x2B, 0x2F, 0x52, 0x43, 0x4C, 0x40,
253         0x3D, 0x30, 0x1E, 0x06, 0x7C, 0x50, 0x3B, 0x2C, 0x25, 0x16, 0x1C, 0x08, 0x27, 0x2B, 0x2F, 0x52,
254         0x43, 0x4C, 0x40, 0x3D, 0x30, 0x1E, 0x06
255     };
256     static uint8_t g_payLoad19[] = { 0x11 };
257     static uint8_t g_payLoad20[] = { 0x29 };
258     static DevHandle g_mipiHandle = NULL;
259     static DevHandle g_pwmHandle = NULL;
260     ```
261
262   - 设置Reset Pin脚状态(/drivers_hdf_core/framework/model/display/driver/panel/mipi_icn9700.c263
264     ```c++
265     static int32_t LcdResetOn(void)
266     {
267         int32_t ret;
268	 /*设置管脚方向*/
269         ret = GpioSetDir(RESET_GPIO, GPIO_DIR_OUT);
270         if (ret != HDF_SUCCESS) {
271             HDF_LOGE("GpioSetDir failure, ret:%d", ret);
272             return HDF_FAILURE;
273         }
274	 /*写入管脚*/
275         ret = GpioWrite(RESET_GPIO, GPIO_VAL_HIGH);
276         if (ret != HDF_SUCCESS) {
277             HDF_LOGE("GpioWrite failure, ret:%d", ret);
278             return HDF_FAILURE;
279         }
280         /* delay 20ms */
281         OsalMSleep(20);
282         return HDF_SUCCESS;
283     }
284     ```
285
286   - 器件驱动入口函数(/drivers_hdf_core/framework/model/display/driver/panel/mipi_icn9700.c287
288     ```c++
289     /*初始化入口函数*/
290     int32_t SampleEntryInit(struct HdfDeviceObject *object)
291     {
292         HDF_LOGI("%s: enter", __func__);
293         if (object == NULL) {
294             HDF_LOGE("%s: param is null!", __func__);
295             return HDF_FAILURE;
296         }
297         /* 器件驱动接口注册,ops提供给平台驱动调用 */
298         if (PanelDataRegister(&g_panelData) != HDF_SUCCESS) {
299             HDF_LOGE("%s: PanelDataRegister error!", __func__);
300             return HDF_FAILURE;
301         }
302         return HDF_SUCCESS;
303     }
304
305     /*实现驱动*/
306     struct HdfDriverEntry g_sampleDevEntry = {
307         .moduleVersion = 1,
308         .moduleName = "LCD_SAMPLE",
309         .Init = SampleEntryInit,
310     };
311
312     HDF_INIT(g_sampleDevEntry);
313     ```
314