SPI驅(qū)動(dòng)ST7789V1.47寸LCD
R128 平臺(tái)提供了 SPI DBI 的 SPI TFT 接口,具有如下特點(diǎn):
- 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
同時(shí),提供了 SPILCD 驅(qū)動(dòng)框架以供 SPI 屏幕使用。
此次適配的SPI屏為 ZJY147S0800TG01
,使用的是 SPI 進(jìn)行驅(qū)動(dòng)。
引腳配置如下:
載入方案
我們使用的開發(fā)板是 R128-Devkit,需要開發(fā) C906 核心的應(yīng)用程序,所以載入方案選擇 r128s2_module_c906
$ source envsetup.sh
$ lunch_rtos 1
設(shè)置 SPI 驅(qū)動(dòng)
屏幕使用的是SPI驅(qū)動(dòng),所以需要勾選SPI驅(qū)動(dòng),運(yùn)行 mrtos_menuconfig
進(jìn)入配置頁面。前往下列地址找到 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 >
設(shè)置 PWM 驅(qū)動(dòng)
屏幕背光使用的是PWM驅(qū)動(dòng),所以需要勾選PWM驅(qū)動(dòng),運(yùn)行 mrtos_menuconfig
進(jìn)入配置頁面。前往下列地址找到 PWM Devices
Drivers Options --- >
soc related device drivers --- >
PWM Devices --- >
-*- enable pwm driver
配置 PWM 引腳
打開你喜歡的編輯器,修改文件:board/r128s2/module/configs/sys_config.fex
,增加 PWM1 節(jié)點(diǎn)
[pwm1]
pwm_used = 1
pwm_positive = port:PA9< 4 >< 0 >< 3 >< default >
設(shè)置 SPI LCD 驅(qū)動(dòng)
SPI LCD 由專門的驅(qū)動(dòng)管理。運(yùn)行 mrtos_menuconfig
進(jìn)入配置頁面。前往下列地址找到 SPILCD Devices
,注意同時(shí)勾選 spilcd hal APIs test
方便測(cè)試使用。
Drivers Options --- >
soc related device drivers --- >
[*] DISP Driver Support(spi_lcd)
[*] spilcd hal APIs test
編寫 SPI LCD 顯示屏驅(qū)動(dòng)
獲取屏幕初始化序列
首先詢問屏廠提供驅(qū)動(dòng)源碼
找到 LCD 的初始化序列代碼
找到屏幕初始化的源碼
整理后的初始化代碼如下:
LCD_WR_REG(0x11);
delay_ms(120);
LCD_WR_REG(0x36);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
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);
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(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xD6);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3E);
LCD_WR_DATA8(0x38);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3E);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x32);
LCD_WR_REG(0x21);
LCD_WR_REG(0x11);
delay_ms(120);
LCD_WR_REG(0x29);
用現(xiàn)成驅(qū)動(dòng)改寫 SPI LCD 驅(qū)動(dòng)
選擇一個(gè)現(xiàn)成的 SPI LCD 改寫即可,這里選擇 nv3029s.c
驅(qū)動(dòng)來修改
復(fù)制這兩個(gè)驅(qū)動(dòng),重命名為 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
編寫初始化序列
先刪除 static void LCD_panel_init(unsigned int sel)
中的初始化函數(shù)。
然后將屏廠提供的初始化序列復(fù)制進(jìn)來
然后按照 spi_lcd
框架的接口改寫驅(qū)動(dòng)接口,具體接口如下
屏廠函數(shù)
SPILCD框架接口
LCD_WR_REG
sunxi_lcd_cmd_write
LCD_WR_DATA8
sunxi_lcd_para_write
delay_ms
sunxi_lcd_delay_ms
可以直接進(jìn)行替換
完成后如下
然后對(duì)照屏廠提供的驅(qū)動(dòng)修改 address
函數(shù)
做如下修改
static void address(unsigned int sel, int x, int y, int width, int height)
{
sunxi_lcd_cmd_write(sel, 0x2A); /* Set coloum address */
sunxi_lcd_para_write(sel, (x + 34) > > 8);
sunxi_lcd_para_write(sel, (x + 34));
sunxi_lcd_para_write(sel, (width + 34) > > 8);
sunxi_lcd_para_write(sel, (width + 34));
sunxi_lcd_cmd_write(sel, 0x2B); /* Set row address */
sunxi_lcd_para_write(sel, y > > 8);
sunxi_lcd_para_write(sel, y);
sunxi_lcd_para_write(sel, height > > 8);
sunxi_lcd_para_write(sel, height);
sunxi_lcd_cmd_write(sel, 0x2c);
}
完成驅(qū)動(dòng)如下
#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, 0x2A); /* Set coloum address */
sunxi_lcd_para_write(sel, (x + 34) > > 8);
sunxi_lcd_para_write(sel, (x + 34));
sunxi_lcd_para_write(sel, (width + 34) > > 8);
sunxi_lcd_para_write(sel, (width + 34));
sunxi_lcd_cmd_write(sel, 0x2B); /* Set row address */
sunxi_lcd_para_write(sel, y > > 8);
sunxi_lcd_para_write(sel, y);
sunxi_lcd_para_write(sel, height > > 8);
sunxi_lcd_para_write(sel, height);
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);
sunxi_lcd_cmd_write(sel, 0x36);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_cmd_write(sel, 0x3A);
sunxi_lcd_para_write(sel, 0x05);
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);
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, 0xD0);
sunxi_lcd_para_write(sel, 0xA4);
sunxi_lcd_para_write(sel, 0xA1);
sunxi_lcd_cmd_write(sel, 0xD6);
sunxi_lcd_para_write(sel, 0xA1);
sunxi_lcd_cmd_write(sel, 0xE0);
sunxi_lcd_para_write(sel, 0xF0);
sunxi_lcd_para_write(sel, 0x00);
sunxi_lcd_para_write(sel, 0x04);
sunxi_lcd_para_write(sel, 0x04);
sunxi_lcd_para_write(sel, 0x04);
sunxi_lcd_para_write(sel, 0x05);
sunxi_lcd_para_write(sel, 0x29);
sunxi_lcd_para_write(sel, 0x33);
sunxi_lcd_para_write(sel, 0x3E);
sunxi_lcd_para_write(sel, 0x38);
sunxi_lcd_para_write(sel, 0x12);
sunxi_lcd_para_write(sel, 0x12);
sunxi_lcd_para_write(sel, 0x28);
sunxi_lcd_para_write(sel, 0x30);
sunxi_lcd_cmd_write(sel, 0xE1);
sunxi_lcd_para_write(sel, 0xF0);
sunxi_lcd_para_write(sel, 0x07);
sunxi_lcd_para_write(sel, 0x0A);
sunxi_lcd_para_write(sel, 0x0D);
sunxi_lcd_para_write(sel, 0x0B);
sunxi_lcd_para_write(sel, 0x07);
sunxi_lcd_para_write(sel, 0x28);
sunxi_lcd_para_write(sel, 0x33);
sunxi_lcd_para_write(sel, 0x3E);
sunxi_lcd_para_write(sel, 0x36);
sunxi_lcd_para_write(sel, 0x14);
sunxi_lcd_para_write(sel, 0x14);
sunxi_lcd_para_write(sel, 0x29);
sunxi_lcd_para_write(sel, 0x32);
sunxi_lcd_cmd_write(sel, 0x21);
sunxi_lcd_cmd_write(sel, 0x11);
sunxi_lcd_delay_ms(120);
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,
},
};
對(duì)接驅(qū)動(dòng)框架
完成了屏幕驅(qū)動(dòng)的編寫,接下來需要對(duì)接到 SPILCD 驅(qū)動(dòng)框架。首先編輯 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
驅(qū)動(dòng)的引用
如下圖
#ifdef CONFIG_LCD_SUPPORT_ST7789V
&st7789v_panel,
#endif
之后編輯 panels.h
同樣增加引用
如下圖
#ifdef CONFIG_LCD_SUPPORT_ST7789V
extern struct __lcd_panel st7789v_panel;
#endif
最后編輯外層的 Makefile
增加編譯選項(xiàng)
如下所示
obj-${CONFIG_LCD_SUPPORT_ST7789V} += panels/st7789v.o
選擇 ST7789V 驅(qū)動(dòng)
在 SPILCD 驅(qū)動(dòng)選擇界面可以看到 LCD_FB panels select
選擇 SPI 屏幕的驅(qū)動(dòng)
進(jìn)入 LCD_FB panels select
選項(xiàng)
選擇并勾選 [*] 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 = 172
lcd_y = 320
lcd_width = 17
lcd_height = 32
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 >
編譯打包
運(yùn)行命令 mp
編譯打包,可以看到編譯了 st7789v.o
測(cè)試
燒錄啟動(dòng)之后,屏幕背光啟動(dòng),但是屏幕全黑。
輸入 test_spilcd
,屏幕顯示黃色。
輸入 lv_examples 1
可以顯示 lvgl
界面
常見問題
LVGL 出現(xiàn) DMA OVER SIZE
這是由于 LVGL 配置的 LV_COLOR_DEPTH
為 32,但是 SPI 屏配置為16位。請(qǐng)修改 lv_conf.h
-
SPI接口
+關(guān)注
關(guān)注
0文章
258瀏覽量
34317 -
SDA
+關(guān)注
關(guān)注
0文章
124瀏覽量
28083 -
LCD顯示屏
+關(guān)注
關(guān)注
1文章
91瀏覽量
13246 -
TFT模塊
+關(guān)注
關(guān)注
0文章
4瀏覽量
6466 -
PWM驅(qū)動(dòng)
+關(guān)注
關(guān)注
0文章
28瀏覽量
1180 -
R128
+關(guān)注
關(guān)注
0文章
41瀏覽量
93
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論