SPI LCD 显示驱动
简介
R128 平台提供了 SPI DBI 的 SPI TFT 接口,具有如下特点:
- Supports DBI Type C 3 Line/4 Line Interface Mode
- Supports 2 Data Lane Interface Mode
- Supports data source from CPU or DMA
- Supports RGB111/444/565/666/888 video format
- Maximum resolution of RGB666 240 x 320@30Hz with single data lane
- Maximum resolution of RGB888 240 x 320@60Hz or 320 x 480@30Hz with dual data lane
- Supports tearing effect
- Supports software flexible control video frame rate
同时,提供了SPILCD驱动框架以供 SPI 屏幕使用。
模块驱动
menuconfig配置说明
SPILCD 模块 menuconfig 的配置如下(以选择kld2844b屏为例):
Drivers Options --->
soc related device drivers --->
SPILCD Devices --->
[*] DISP Driver Support(spi_lcd)
[*] spilcd hal APIs test //spilcd模块测试用例
LCD_FB panels select ---> //spilcd屏驱动配置
[*] LCD support kld2844B panel
[ ] LCD support kld35512 panel
Board select --->
[ ] board kld2844b support //板级显示使用显示驱动私有方式的配置项,而使用sys_config.fex方式不用配置
另外可能需依赖的配置项有:
- DRIVERS_SPI
- DRIVERS_DBI
- DRIVERS_PWM
源码结构介绍
源码结构及主要驱动文件如下:
spilcd/
├── lcd_fb/
│ ├── dev_lcd_fb.c # spilcd driver 层
│ ├── disp_display.c
│ ├── disp_lcd.c
│ ├── lcd_fb_intf.c
│ └── panels/ # lcd驱动相关
│ ├── kld2844b.c
│ ├── lcd_source.c
│ ├── panels.c
│ └── panels.h
└── soc/
├── disp_board_config.c # 板级配置解析
└── kld2844b_config.c # 显示私有方式的板级配置文件
模块参数配置
当前板级显示支持两种配置方法,一是使用 sys_config.fex
的方式进行配置,二是在不支持sys_config.fex
情况下,可以通过显示驱动私有的方式进行配置。下面分别对两种方式进行说明。
使用 sys_config.fex 的方式进行配置
FreeRTOS系统路径:board/芯片名/方案名/configs/sys_config.fex
配置文件具体要看芯片方案所实际使用的,也可能使用的配置文件名称为sys_config_xxx.fex(xx是存储方案的标识,例如sys_config_nor.cfg、sys_config_nand.cfg)
具体配置举例如下:
;----------------------------------------------------------------------------------
;lcd_fb0 configuration
;----------------------------------------------------------------------------------
[lcd_fb0]
lcd_used = 1 ; 使用显示屏
lcd_model_name = "spilcd" ; 模型:spilcd
lcd_driver_name = "jlt35031c" ; 屏幕驱动:jlt35031c
lcd_x = 320 ; 屏幕宽分辨率
lcd_y = 480 ; 屏幕高分辨率
lcd_width = 49 ; 屏幕物理宽度
lcd_height = 74 ; 屏幕物理高度
lcd_data_speed = 60 ; SPI 驱动频率 60MHz
lcd_pwm_used = 1 ; lcd使用pwm背光
lcd_pwm_ch = 1 ; lcd使用pwm背光通道1
lcd_pwm_freq = 5000 ; lcd使用pwm背光频率5000Hz
lcd_pwm_pol = 0 ; lcd使用pwm背光相位0
lcd_if = 0 ; lcd使用spi接口,0-spi, 1-dbi
lcd_pixel_fmt = 11
lcd_dbi_fmt = 2
lcd_dbi_clk_mode = 1
lcd_dbi_te = 1
fb_buffer_num = 2
lcd_dbi_if = 4
lcd_rgb_order = 0
lcd_fps = 60
lcd_spi_bus_num = 1
lcd_frm = 2
lcd_gamma_en = 1
lcd_backlight = 100
lcd_power_num = 0
lcd_gpio_regu_num = 0
lcd_bl_percent_num = 0
lcd_spi_dc_pin = port:PA19<1><0><3><0> ; DC脚
;RESET Pin
lcd_gpio_0 = port:PA20<1><0><2><0> ; 复位脚
lcd_driver_name
Lcd屏驱动的名字(字符串),必须与屏驱动中strcut __lcd_panel
变量的name
成员一致。
lcd_model_name
Lcd屏模型名字,非必须,可以用于同个屏驱动中进一步区分不同屏。
lcd_if
Lcd Interface
设置相应值的对应含义为:
0:spi接口
1:dbi接口
spi
接口就是俗称的4线模式,这是因为发送数据时需要额外借助DC
线来区分命令和数据,与sclk
,cs
和sda
共四线。
如果设置了dbi
接口,那么还需要进一步区分dbi
接口,需要设置 lcd_dbi_if
lcd_dbi_if
Lcd dbi 接口设置。
这个参数只有在lcd_if=1
时才有效。
设置相应值的对应含义为:
0:L3I1
1:L3I2
2:L4I1
3:L4I2
4:D2LI
所有模式在发送数据时每个周期的比特数量根据不同像素格式不同而不同。
L3I1
和L3I2
是三线模式(不需要DC
脚),区别是读时序,也就是是否需要额外脚来读寄存器。读写时序图如下:
L4I1
和L4I2
是四线模式,与spi接口协议一样,区别是DC脚的控制是否自动化控制,另外I2和I1的区别是读时序,也就是否需要额外脚来读取寄存器。
D2LI
是两data lane模式。发送命令部分时序与读时序与L3I1
一致,下图是发送数据时的时序,不同像素格式时钟周期数量不一样。
lcd_dbi_fmt
DBI
接口像素格式。
0:RGB111
1:RGB444
2:RGB565
3:RGB666
4:RGB888
选择的依据是接收端屏Driver IC
的支持情况,请查看Driver IC
手册或询问屏厂。
然后必须配合lcd_pixel_fmt
的选择,比如说选RGB565时,lcd_pixel_fmt
也要选565格式。
lcd_dbi_te
使能te触发。
te即(Tearing effect),也就是撕裂的意思,由于读写不同导致撕裂现象,te脚的功能就是用于同步读写,te脚的频率也就是屏的刷新率,所以te脚也可以看做vsync脚(垂直同步脚)
0: 禁止te
1: 下降沿触发
2: 上升沿触发
查看带te脚的屏进一步说明。
lcd_dbi_clk_mode
选择dbi时钟的行为模式。
0:自动停止。有数据就有时钟,没发数据就没有
1:一直保持。无论发不发数据都有时钟
注意上面的选项关系屏兼容性。
lcd_rgb_order
输入图像数据rgb顺序识别设置,仅当lcd_if=1时有效。
0:RGB
1:RBG
2:GRB
3:GBR
4:BRG
5:BGR
6:G_1RBG_0
7:G_0RBG_1
8:G_1BRG_0
9:G_0BRG_1
非RGB565格式用0到5即可。
针对rgb565格式说明如下:
rgb565格式会遇到大小端问题,arm平台和PC平台存储都是小端(little endian,低字节放在低地址,高字节放在高地址),但是许多spi屏都是默认大端(Big Endian)。
也就是存储的字节顺序和发送的字节顺序不对应。
这个时候选择6以下,DBI接口就会自动将小端转成大端。
如果遇到默认是小端的spi屏,则需要选择6以上,DBI接口会自动用回小端方式。
6以上格式这样解释:
R是5比特,G是6比特,B是5比特,再把G拆成高3位(G_1)和低3位(G_0) 所以以下两种顺序:
- R-G_1-G_0-B,大端。
- G_0-B-R-G_1,对应上面的9,小端。
lcd_x
显示屏的水平像素数量,注意如果屏支持横竖旋转,那么lcd_x和lcd_y也要对调。
lcd_y
显示屏的行数,注意如果屏支持横竖旋转,那么lcd_x和lcd_y也要对调。
lcd_data_speed
用于设置spi/dbi接口时钟的速率,单位MHz。
- 发送端(SOC)的最大限制是100MHz。
- 接收端(屏Driver IC)的限制,请查看对应Driver IC手册或者询问屏厂支持。
- 超出以上限制都有可能导致显示异常。
lcd_fps
设置屏的刷新率,单位Hz。当lcd_dbi_te使能时,这个值设置无效。
lcd_pwm_used
是否使用pwm。
此参数标识是否使用pwm 用以背光亮度的控制。
lcd_pwm_ch
Pwm channel used
此参数标识使用的Pwm通道。
lcd_pwm_freq
Lcd backlight PWM Frequency
这个参数配置PWM信号的频率,单位为Hz。
lcd_pwm_pol
Lcd backlight PWM Polarity
这个参数配置PWM信号的占空比的极性。设置相应值对应含义为:
0:active high
1:active low
lcd_pwm_max_limit
Lcd backlight PWM
最高限制,以亮度值表示。
比如150,则表示背光最高只能调到150,0~255范围内的亮度值将会被线性映射到0~150范围内。用于控制最高背光亮度,节省功耗。
lcd_backlight
默认背光值,取值范围0到255,值越大越亮。
lcd_bl_en
背光使能脚定义
lcd_spi_dc_pin
指定作为DC的管脚,用于spi接口时。
lcd_gpio_x
x表示数字。如果有多个gpio脚需要控制,则定义lcd_gpio_0,lcd_gpio_1等。
lcd_spi_bus_num
选择spi总线id,只有spi1支持DBI协议,所以这里一般选择1。
取值范围:0到1。
lcd_pixel_fmt
选择传输数据的像素格式。
可选值如下,当你更换RGB分量顺序的时候,也得相应修改lcd_rgb_order,或者修改屏驱动的rgb分量顺序(一般是3Ah寄存器)。
DBI接口只支持RGB32和RGB16的情况。
SPI接口只支持RGB16的情况。
enum lcdfb_pixel_format {
LCDFB_FORMAT_ARGB_8888 = 0x00, // MSB A-R-G-B LSB
LCDFB_FORMAT_ABGR_8888 = 0x01,
LCDFB_FORMAT_RGBA_8888 = 0x02,
LCDFB_FORMAT_BGRA_8888 = 0x03,
LCDFB_FORMAT_XRGB_8888 = 0x04,
LCDFB_FORMAT_XBGR_8888 = 0x05,
LCDFB_FORMAT_RGBX_8888 = 0x06,
LCDFB_FORMAT_BGRX_8888 = 0x07,
LCDFB_FORMAT_RGB_888 = 0x08,
LCDFB_FORMAT_BGR_888 = 0x09,
LCDFB_FORMAT_RGB_565 = 0x0a,
LCDFB_FORMAT_BGR_565 = 0x0b,
LCDFB_FORMAT_ARGB_4444 = 0x0c,
LCDFB_FORMAT_ABGR_4444 = 0x0d,
LCDFB_FORMAT_RGBA_4444 = 0x0e,
LCDFB_FORMAT_BGRA_4444 = 0x0f,
LCDFB_FORMAT_ARGB_1555 = 0x10,
LCDFB_FORMAT_ABGR_1555 = 0x11,
LCDFB_FORMAT_RGBA_5551 = 0x12,
LCDFB_FORMAT_BGRA_5551 = 0x13,
};
fb_buffer_num
显示framebuffer数量,为了平滑显示,这里一般是2个,为了省内存也可以改成1。
模块 sys_config.fex 配置案例
典型2 data lane配置
一些屏支持双数据线传输以加快数据传输速度,此时需要走DBI协议,典型配置如下:
[lcd_fb0]
lcd_used = 1
lcd_driver_name = "kld2844b"
lcd_if = 1
lcd_dbi_if = 4
lcd_data_speed = 60
lcd_spi_bus_num = 1
lcd_x = 320
lcd_y = 240
lcd_pwm_used = 1
lcd_pwm_ch = 4
lcd_pwm_freq = 5000
lcd_pwm_pol = 0
lcd_pixel_fmt = 0
lcd_dbi_fmt = 3
lcd_rgb_order = 0
fb_buffer_num = 2
lcd_backlight = 200
lcd_fps = 60
lcd_dbi_te = 0
lcd_bl_en = port:PB04<1><0><default><1>
lcd_gpio_0 = port:PB02<1><0><default><1>
- 硬件连接上,第二根数据脚连接到原来1 data lane的DC脚,可以这样理解:2数据线在传输数据时就自带D/C(Data/Commend)信息了,所以原来的DC脚就可以空出来作为第二根数据线了。
- 屏驱动上,需要使能2 data lane模式,具体寄存器查看对应driverIC手册或者询问屏厂。
- 这里的针对对2 data lane的关键参数是lcd_if,lcd_dbi_if,lcd_dbi_fmt和lcd_spi_bus_num。
- lcd_x和lcd_y是屏分辨率。如果屏支持旋转(横竖旋转),这里也需要对调。
- lcd_pwm开头,lcd_backlight和lcd_bl_en的是背光相关设置,如果有相关硬件连接的话。
- lcd_pixel_fmt和fb_buffer_num是显示framebuffer的设置。
- lcd_gpio_开头的是自定义gpio的设置(比如复位脚)。
- lcd_fps和lcd_dbi_te是刷新方式相关的设置。
原SPI接口屏配置
如果IC支持DBI接口,那么就没有必要用SPI接口,DBI接口其协议能覆盖所有情况。
一些IC不支持DBI,那么只能用spi接口(通过设置lcd_if),如果使用spi接口,它有一些限制。
- 不支持2 data lane。
- 必须指定DC脚。这是由于spi协议不会自动控制DC脚来区分数据命令,通过设置lcd_spi_dc_pin可以完成这个目的,这跟管脚不必用spi里面的脚。
- 只支持rgb565的像素格式。由于只有单data lane,速度过慢,rgb565以上格式都不现实。
[lcd_fb0]
lcd_used = 1
lcd_driver_name = "kld2844b"
lcd_if = 0
lcd_data_speed = 60
lcd_spi_bus_num = 1
lcd_x = 320
lcd_y = 240
lcd_pwm_used = 1
lcd_pwm_ch = 4
lcd_pwm_freq = 5000
lcd_pwm_pol = 0
lcd_pixel_fmt = 10
lcd_rgb_order = 0
fb_buffer_num = 2
lcd_backlight = 200
lcd_fps = 60
lcd_dbi_te = 0
lcd_bl_en = port:PB04<1><0><default><1>
lcd_gpio_0 = port:PB02<1><0><default><1>
lcd_spi_dc_pin = port:PA19<1><0><3><1>
带te脚的屏
te即(Tearing effect),也就是撕裂的意思,是由于读写不同步导致撕裂现象,te脚的功能就是用于同步读写,te脚的频率也就是屏的刷新率,所以te脚也可以看做vsync脚(垂直同步脚)。
- 硬件设计阶段,需要将屏的te脚连接到IC的DBI接口的te脚。
- 配置上接口使用dbi接口。
- 然后使能lcd_dbi_te。
- 屏驱动使能te功能,寄存器一般是35h,详情看屏对应的driver IC手册。
- 屏驱动设置帧率,根据屏能接受的传输速度选择合理的帧率(比如ST7789H2里面是通过c6h来设置te频率)。
[lcd_fb0]
lcd_used = 1
lcd_driver_name = "kld2844b"
lcd_if = 1
lcd_dbi_if = 4
lcd_data_speed = 60
lcd_spi_bus_num = 1
lcd_x = 320
lcd_y = 240
lcd_pwm_used = 1
lcd_pwm_ch = 4
lcd_pwm_freq = 5000
lcd_pwm_pol = 0
lcd_pixel_fmt = 0
lcd_dbi_fmt = 3
lcd_rgb_order = 0
fb_buffer_num = 2
lcd_backlight = 200
lcd_fps = 60
lcd_dbi_te = 1
lcd_bl_en = port:PB04<1><0><default><1>
lcd_gpio_0 = port:PB02<1><0><default><1>