適配 ST7789v 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 屏幕使用。
此次適配的SPI屏為 ZJY240S0800TG11
,使用的是 SPI 進行驅動。注意請購買帶 CS 引腳的 SPI 屏幕,由于 ST7789v SPI 時序問題,CS 引腳直接接地可能會導致初始化無法寫入。如果很不幸SPI TFT是不帶 CS 的,請飛線出來連接 CS 引腳(如圖所示)
R128 Devkit
TFT 模塊
PA12
CS(飛線)
PA13
CLK
PA18
MOSI
PA9
BLK
PA20
RES
PA19
3V3
VCC
GND
GND
懸空
MISO
載入方案
我們使用的開發板是 R128-Devkit,需要開發 C906 核心的應用程序,所以載入方案選擇 r128s2_module_c906
$ source envsetup.sh
$ lunch_rtos 1
設置 SPI 驅動
屏幕使用的是SPI驅動,所以需要勾選SPI驅動,運行 mrtos_menuconfig
進入配置頁面。前往下列地址找到 SPI Devices
Drivers Options --- >
soc related device drivers --- >
SPI Devices --- >
-*- enable spi driver
配置 SPI 引腳
打開你喜歡的編輯器,修改文件:board/r128s2/module/configs/sys_config.fex
,在這里我們不需要用到 SPI HOLD與SPI WP引腳,注釋掉即可。
;----------------------------------------------------------------------------------
;SPI controller configuration
;----------------------------------------------------------------------------------
;Please config spi in dts
[spi1]
spi1_used = 1
spi1_cs_number = 1
spi1_cs_bitmap = 1
spi1_cs0 = port:PA12< 6 >< 0 >< 3 >< default >
spi1_sclk = port:PA13< 6 >< 0 >< 3 >< default >
spi1_mosi = port:PA18< 6 >< 0 >< 3 >< default >
spi1_miso = port:PA21< 6 >< 0 >< 3 >< default >
;spi1_hold = port:PA19< 6 >< 0 >< 2 >< default >
;spi1_wp = port:PA20< 6 >< 0 >< 2 >< default >
設置 PWM 驅動
屏幕背光使用的是PWM驅動,所以需要勾選PWM驅動,運行 mrtos_menuconfig
進入配置頁面。前往下列地址找到 PWM Devices
Drivers Options --- >
soc related device drivers --- >
PWM Devices --- >
-*- enable pwm driver
配置 PWM 引腳
打開你喜歡的編輯器,修改文件:board/r128s2/module/configs/sys_config.fex
,增加 PWM1 節點
[pwm1]
pwm_used = 1
pwm_positive = port:PA9< 4 >< 0 >< 3 >< default >
設置 SPI LCD 驅動
SPI LCD 由專門的驅動管理。運行 mrtos_menuconfig
進入配置頁面。前往下列地址找到 SPILCD Devices
,注意同時勾選 spilcd hal APIs test
方便測試使用。
Drivers Options --- >
soc related device drivers --- >
[*] DISP Driver Support(spi_lcd)
[*] spilcd hal APIs test
編寫 SPI LCD 顯示屏驅動
獲取屏幕初始化序列
首先詢問屏廠提供驅動源碼
找到 LCD 的初始化序列代碼
找到屏幕初始化的源碼
整理后的初始化代碼如下:
LCD_WR_REG(0x11);
delay_ms(120); // Delay 120ms
// display and color format setting
LCD_WR_REG(0X36);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0X3A);
LCD_WR_DATA8(0X05);
// ST7789S Frame rate setting
LCD_WR_REG(0xb2);
LCD_WR_DATA8(0x0c);
LCD_WR_DATA8(0x0c);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xb7);
LCD_WR_DATA8(0x35);
// ST7789S Power setting
LCD_WR_REG(0xbb);
LCD_WR_DATA8(0x35);
LCD_WR_REG(0xc0);
LCD_WR_DATA8(0x2c);
LCD_WR_REG(0xc2);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xc3);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xc4);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xc6);
LCD_WR_DATA8(0x0f);
LCD_WR_REG(0xca);
LCD_WR_DATA8(0x0f);
LCD_WR_REG(0xc8);
LCD_WR_DATA8(0x08);
LCD_WR_REG(0x55);
LCD_WR_DATA8(0x90);
LCD_WR_REG(0xd0);
LCD_WR_DATA8(0xa4);
LCD_WR_DATA8(0xa1);
// ST7789S gamma setting
LCD_WR_REG(0xe0);
LCD_WR_DATA8(0xd0);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x0b);
LCD_WR_DATA8(0x2a);
LCD_WR_DATA8(0x3c);
LCD_WR_DATA8(0x55);
LCD_WR_DATA8(0x4b);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x19);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xe1);
LCD_WR_DATA8(0xd0);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x0b);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x4b);
LCD_WR_DATA8(0x0d);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x21);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0x29);
用現成驅動改寫 SPI LCD 驅動
選擇一個現成的 SPI LCD 改寫即可,這里選擇 nv3029s.c
驅動來修改
復制這兩個驅動,重命名為 st7789v.c
先編輯 st7789v.h
將 nv3029s
改成 st7789v
#ifndef _ST7789V_H
#define _ST7789V_H
#include "panels.h"
struct __lcd_panel st7789v_panel;
#endif /*End of file*/
編輯 st7789v.c
將 nv3029s
改成 st7789v
然后將屏廠提供的初始化序列復制進來
然后按照 spi_lcd
框架的接口改寫驅動接口,具體接口如下
屏廠函數
SPILCD框架接口
LCD_WR_REG
sunxi_lcd_cmd_write
LCD_WR_DATA8
sunxi_lcd_para_write
delay_ms
sunxi_lcd_delay_ms
完成驅動如下
#include "st7789v.h"
static void LCD_power_on(u32 sel);
static void LCD_power_off(u32 sel);
static void LCD_bl_open(u32 sel);
static void LCD_bl_close(u32 sel);
static void LCD_panel_init(u32 sel);
static void LCD_panel_exit(u32 sel);
#define RESET(s, v) sunxi_lcd_gpio_set_value(s, 0, v)
#define power_en(sel, val) sunxi_lcd_gpio_set_value(sel, 0, val)
static struct disp_panel_para info[LCD_FB_MAX];
static void address(unsigned int sel, int x, int y, int width, int height)
{
sunxi_lcd_cmd_write(sel, 0x2B); /* Set row address */
sunxi_lcd_para_write(sel, (y > > 8) & 0xff);
sunxi_lcd_para_write(sel, y & 0xff);
sunxi_lcd_para_write(sel, (height > > 8) & 0xff);
sunxi_lcd_para_write(sel, height & 0xff);
sunxi_lcd_cmd_write(sel, 0x2A); /* Set coloum address */
sunxi_lcd_para_write(sel, (x > > 8) & 0xff);
sunxi_lcd_para_write(sel, x & 0xff);
sunxi_lcd_para_write(sel, (width > > 8) & 0xff);
sunxi_lcd_para_write(sel, width & 0xff);
sunxi_lcd_cmd_write(sel, 0x2c);
}
static void LCD_panel_init(unsigned int sel)
{
if (bsp_disp_get_panel_info(sel, &info[sel])) {
lcd_fb_wrn("get panel info fail!n");
return;
}
sunxi_lcd_cmd_write(sel, 0x11);
sunxi_lcd_delay_ms(120);
/* display and color format setting */
sunxi_lcd_cmd_write(sel, 0X36);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_cmd_write(sel, 0X3A);
sunxi_lcd_para_write(sel, 0X05);
/* ST7789S Frame rate setting */
sunxi_lcd_cmd_write(sel, 0xb2);
sunxi_lcd_para_write(sel, 0x0c);
sunxi_lcd_para_write(sel, 0x0c);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_para_write(sel, 0x33);
sunxi_lcd_para_write(sel, 0x33);
sunxi_lcd_cmd_write(sel, 0xb7);
sunxi_lcd_para_write(sel, 0x35);
/* ST7789S Power setting */
sunxi_lcd_cmd_write(sel, 0xbb);
sunxi_lcd_para_write(sel, 0x35);
sunxi_lcd_cmd_write(sel, 0xc0);
sunxi_lcd_para_write(sel, 0x2c);
sunxi_lcd_cmd_write(sel, 0xc2);
sunxi_lcd_para_write(sel, 0x01);
sunxi_lcd_cmd_write(sel, 0xc3);
sunxi_lcd_para_write(sel, 0x13);
sunxi_lcd_cmd_write(sel, 0xc4);
sunxi_lcd_para_write(sel, 0x20);
sunxi_lcd_cmd_write(sel, 0xc6);
sunxi_lcd_para_write(sel, 0x0f);
sunxi_lcd_cmd_write(sel, 0xca);
sunxi_lcd_para_write(sel, 0x0f);
sunxi_lcd_cmd_write(sel, 0xc8);
sunxi_lcd_para_write(sel, 0x08);
sunxi_lcd_cmd_write(sel, 0x55);
sunxi_lcd_para_write(sel, 0x90);
sunxi_lcd_cmd_write(sel, 0xd0);
sunxi_lcd_para_write(sel, 0xa4);
sunxi_lcd_para_write(sel, 0xa1);
/* ST7789S gamma setting */
sunxi_lcd_cmd_write(sel, 0xe0);
sunxi_lcd_para_write(sel, 0xd0);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_para_write(sel, 0x06);
sunxi_lcd_para_write(sel, 0x09);
sunxi_lcd_para_write(sel, 0x0b);
sunxi_lcd_para_write(sel, 0x2a);
sunxi_lcd_para_write(sel, 0x3c);
sunxi_lcd_para_write(sel, 0x55);
sunxi_lcd_para_write(sel, 0x4b);
sunxi_lcd_para_write(sel, 0x08);
sunxi_lcd_para_write(sel, 0x16);
sunxi_lcd_para_write(sel, 0x14);
sunxi_lcd_para_write(sel, 0x19);
sunxi_lcd_para_write(sel, 0x20);
sunxi_lcd_cmd_write(sel, 0xe1);
sunxi_lcd_para_write(sel, 0xd0);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_para_write(sel, 0x06);
sunxi_lcd_para_write(sel, 0x09);
sunxi_lcd_para_write(sel, 0x0b);
sunxi_lcd_para_write(sel, 0x29);
sunxi_lcd_para_write(sel, 0x36);
sunxi_lcd_para_write(sel, 0x54);
sunxi_lcd_para_write(sel, 0x4b);
sunxi_lcd_para_write(sel, 0x0d);
sunxi_lcd_para_write(sel, 0x16);
sunxi_lcd_para_write(sel, 0x14);
sunxi_lcd_para_write(sel, 0x21);
sunxi_lcd_para_write(sel, 0x20);
sunxi_lcd_cmd_write(sel, 0x29);
if (info[sel].lcd_x < info[sel].lcd_y)
address(sel, 0, 0, info[sel].lcd_x - 1, info[sel].lcd_y - 1);
else
address(sel, 0, 0, info[sel].lcd_y - 1, info[sel].lcd_x - 1);
}
static void LCD_panel_exit(unsigned int sel)
{
sunxi_lcd_cmd_write(sel, 0x28);
sunxi_lcd_delay_ms(20);
sunxi_lcd_cmd_write(sel, 0x10);
sunxi_lcd_delay_ms(20);
sunxi_lcd_pin_cfg(sel, 0);
}
static s32 LCD_open_flow(u32 sel)
{
lcd_fb_here;
/* open lcd power, and delay 50ms */
LCD_OPEN_FUNC(sel, LCD_power_on, 50);
/* open lcd power, than delay 200ms */
LCD_OPEN_FUNC(sel, LCD_panel_init, 200);
LCD_OPEN_FUNC(sel, lcd_fb_black_screen, 50);
/* open lcd backlight, and delay 0ms */
LCD_OPEN_FUNC(sel, LCD_bl_open, 0);
return 0;
}
static s32 LCD_close_flow(u32 sel)
{
lcd_fb_here;
/* close lcd backlight, and delay 0ms */
LCD_CLOSE_FUNC(sel, LCD_bl_close, 50);
/* open lcd power, than delay 200ms */
LCD_CLOSE_FUNC(sel, LCD_panel_exit, 10);
/* close lcd power, and delay 500ms */
LCD_CLOSE_FUNC(sel, LCD_power_off, 10);
return 0;
}
static void LCD_power_on(u32 sel)
{
/* config lcd_power pin to open lcd power0 */
lcd_fb_here;
power_en(sel, 1);
sunxi_lcd_power_enable(sel, 0);
sunxi_lcd_pin_cfg(sel, 1);
RESET(sel, 1);
sunxi_lcd_delay_ms(100);
RESET(sel, 0);
sunxi_lcd_delay_ms(100);
RESET(sel, 1);
}
static void LCD_power_off(u32 sel)
{
lcd_fb_here;
/* config lcd_power pin to close lcd power0 */
sunxi_lcd_power_disable(sel, 0);
power_en(sel, 0);
}
static void LCD_bl_open(u32 sel)
{
sunxi_lcd_pwm_enable(sel);
/* config lcd_bl_en pin to open lcd backlight */
sunxi_lcd_backlight_enable(sel);
lcd_fb_here;
}
static void LCD_bl_close(u32 sel)
{
/* config lcd_bl_en pin to close lcd backlight */
sunxi_lcd_backlight_disable(sel);
sunxi_lcd_pwm_disable(sel);
lcd_fb_here;
}
/* sel: 0:lcd0; 1:lcd1 */
static s32 LCD_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3)
{
lcd_fb_here;
return 0;
}
static int lcd_set_var(unsigned int sel, struct fb_info *p_info)
{
return 0;
}
static int lcd_set_addr_win(unsigned int sel, int x, int y, int width, int height)
{
address(sel, x, y, width, height);
return 0;
}
static int lcd_blank(unsigned int sel, unsigned int en)
{
return 0;
}
struct __lcd_panel st7789v_panel = {
/* panel driver name, must mach the name of lcd_drv_name in sys_config.fex
*/
.name = "st7789v",
.func = {
.cfg_open_flow = LCD_open_flow,
.cfg_close_flow = LCD_close_flow,
.lcd_user_defined_func = LCD_user_defined_func,
.blank = lcd_blank,
.set_var = lcd_set_var,
.set_addr_win = lcd_set_addr_win,
},
};
對接驅動框架
完成了屏幕驅動的編寫,接下來需要對接到 SPILCD 驅動框架。首先編輯 Kconfig
增加 st7789v
的配置
config LCD_SUPPORT_ST7789V
bool "LCD support st7789v panel"
default n
---help---
If you want to support st7789v panel for display driver, select it.
然后編輯 panels.c
在 panel_array
里增加 st7789
驅動的引用
如下圖
#ifdef CONFIG_LCD_SUPPORT_ST7789V
&st7789v_panel,
#endif
之后編輯 panels.h
同樣增加引用
如下圖
#ifdef CONFIG_LCD_SUPPORT_ST7789V
extern struct __lcd_panel st7789v_panel;
#endif
最后編輯外層的 Makefile
增加編譯選項
如下所示
obj-${CONFIG_LCD_SUPPORT_ST7789V} += panels/st7789v.o
選擇 ST7789V 驅動
在 SPILCD 驅動選擇界面可以看到 LCD_FB panels select
選擇 SPI 屏幕的驅動
進入 LCD_FB panels select
選項
選擇并勾選 [*] LCD support st7789v panel
配置 SPI LCD 引腳
打開你喜歡的編輯器,修改文件:board/r128s2/module/configs/sys_config.fex
[lcd_fb0]
lcd_used = 1
lcd_model_name = "spilcd"
lcd_driver_name = "st7789v"
lcd_x = 240
lcd_y = 320
lcd_width = 37
lcd_height = 48
lcd_data_speed = 50
lcd_pwm_used = 1
lcd_pwm_ch = 1
lcd_pwm_freq = 5000
lcd_pwm_pol = 0
lcd_if = 0
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 >
;RESET Pin
lcd_gpio_0 = port:PA20< 1 >< 0 >< 2 >< 0 >
編譯打包
運行命令 mp
編譯打包,可以看到編譯了 st7789v.o
測試
燒錄啟動之后,屏幕背光啟動,但是屏幕全黑。
輸入 test_spilcd
,屏幕顯示黃色。
輸入 lv_examples 1
可以顯示 lvgl
界面
常見問題
屏幕白屏
屏幕白屏,但是背光亮起
白屏是因為屏幕沒有初始化,需要檢查屏幕初始化序列或者初始化數據是否正確。
屏幕花屏
屏幕花屏,無法控制
花屏一般是因為屏幕初始化后沒有正確設置 addrwin
,或者初始化序列錯誤。
LVGL 屏幕顏色不正確
出現反色,顏色異常
請配置 LVGL LV_COLOR_DEPTH
參數為 16,LV_COLOR_16_SWAP
為 1,這是由 SPI LCD 的特性決定的。
顯示反色
運行 test_spilcd
,屏幕顯示藍色。
這是由于屏幕啟動了 RB SWAP,一般是 0x36
寄存器修改
正常顯示
sunxi_lcd_cmd_write(sel, 0X36);
sunxi_lcd_para_write(sel, 0x00);
反色顯示
sunxi_lcd_cmd_write(sel, 0X36);
sunxi_lcd_para_write(sel, 0x08);
-
SPI接口
+關注
關注
0文章
258瀏覽量
34373 -
LCD顯示屏
+關注
關注
1文章
91瀏覽量
13295 -
TFT模塊
+關注
關注
0文章
4瀏覽量
6472 -
ST7789V
+關注
關注
3文章
6瀏覽量
6771 -
PWM驅動
+關注
關注
0文章
28瀏覽量
1202 -
R128
+關注
關注
0文章
41瀏覽量
105
發布評論請先 登錄
相關推薦
評論