硬件平台:Luckfox Pico不带网口的那个硬件版本,LCD采用的是2.0in SPI驱动的LCD,显示芯片为ST7789VW,显示分辨率为320*240
软件平台:虚拟机中运行Ubuntu 22.04LTS
1. 首先第一步是移植LCD的驱动
下面的步骤是参与的官方tutorial:https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-LVGL
(1) 首先确定LCD模块与Luckfox开发板的连接线,然后修改设备树文件,设备树文件的目录在:
/luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts
这个luckfox-pico是下载的SDK解压后的根目录。Luckfox Pico对应的设备树文件为:
rv1103g-luckfox-pico.dts
要处理的管脚包括LCD的控制引脚:
// LCD_DC pin
gpio1pa2:gpio1pa2 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pa2>;
regulator-name = "gpio1_pa2";
regulator-always-on;
};
// LCD_CS pin
gpio1pc0:gpio1pc0 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pc0>;
regulator-name = "gpio1_pc0";
regulator-always-on;
};
// LCD_RST pin
gpio1pc3:gpio1pc3 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pc3>;
regulator-name = "gpio1_pc3";
regulator-always-on;
};
// LCD_BL pin
gpio0pa4:gpio0pa4 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio0_pa4>;
regulator-name = "gpio0_pa4";
regulator-always-on;
};
&pinctrl {
// for LCD control
gpio1-pa2 {
gpio1_pa2:gpio1-pa2 {
rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
gpio1-pc0 {
gpio1_pc0:gpio1-pc0 {
rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
gpio1-pc3 {
gpio1_pc3:gpio1-pc3 {
rockchip,pins = <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
gpio0-pa4 {
gpio0_pa4:gpio0-pa4 {
rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
以及与SPI通信的管脚:
// /**********SPI**********/
&spi0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi0m0_pins>;
//cs-gpios = <&gpio1 RK_PC0 1>;
// cs-gpios = <&gpio1 26 1>;
#address-cells = <1>;
#size-cells = <0>;
//spidev@0 {
// compatible = "rockchip,spidev";
// spi-max-frequency = <1000000000>;
// reg = <0>;
//};
lcd: lcd@0{
status = "okay";
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <20000000>;
spi-cpol;
spi-cpha;
rotate = <0>;
fps = <30>;
rgb;
buswidth = <8>;
cs = <&gpio1 RK_PC0 GPIO_ACTIVE_LOW>; //spi0_miso
led = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; //BL
dc = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; //DC
reset = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>; //RES
debug = <0x7>;
};
};
&pinctrl{
spi0{
spi0m0_pins: spi0m0-pins{
rockchip,pins =
// SPI0 CLK0
<1 RK_PC1 4 &pcfg_pull_none>,
// SPIO MISO is not useful hence can not be set
// <1 RK_PC3 6 &pcfg_pull_none>,
// SPIO MOSI
<1 RK_PC2 6 &pcfg_pull_none>;
};
};
};
有一点要注意的是它这里LCD的CS与主机的SPI管脚的MISO冲突了,在配置SPI的时候,千万不要打开MISO了,否则驱动异常(可通过dmesg查看打印信息看到冲突)。
另个,这块LCD屏上还有4个按键,为了使用它们,也把它们的管脚给使能了。设备树中添加的文件如下:
// for key control
gpio1pc7:gpio1pc7 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pc7>;
regulator-name = "gpio1_pc7";
regulator-always-on;
};
gpio1pc6:gpio1pc6 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pc6>;
regulator-name = "gpio1_pc6";
regulator-always-on;
};
gpio1pd1:gpio1pd1 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pd1>;
regulator-name = "gpio1_pd1";
regulator-always-on;
};
gpio4pb0:gpio4pb0 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&gpio4_pb0>;
regulator-name = "gpio4_pb0";
regulator-always-on;
};
&pinctrl {
gpio1-pc7 {
gpio1_pc7:gpio1-pc7 {
rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio1-pc6 {
gpio1_pc6:gpio1-pc6 {
rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio1-pd1 {
gpio1_pd1:gpio1-pd1 {
rockchip,pins = <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio4-pb0 {
gpio4_pb0:gpio4-pb0 {
rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
多余的IO口跟不需要的功能,如IIC等,能去掉的就去掉
(2) 添加FB的支持:
在下面的目录中找到config文件:
luckfox-pico/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
添加FB的支持:
CONFIG_SPI_MASTER=y
CONFIG_FB=y
(3)完成上述步骤后,可以make image了,将生成的Image烧录到SD卡上后启动系统。然后将开发板上电,利用adb shell登陆到开发板上后可以查看FB驱动是否正常:
如果先前有在LCD上显示过内容,那么输入下面的指令后会看到大量的输出:
dmesg | grep fb_
输出如下:
[ 62.298523] fb_st7789v spi0.0: Display update: 1520 kB/s, fps=1
[ 62.335201] fb_st7789v spi0.0: fbtft_update_display(start_line=34, end_line=290)
[ 62.335249] fb_st7789v spi0.0: fbtft_write_reg8_bus8: 2a 00 00 00 ef
[ 62.335296] fb_st7789v spi0.0: fbtft_write_spi(len=1): 2a
[ 62.335372] fb_st7789v spi0.0: fbtft_write_spi(len=4): 00 00 00 ef
[ 62.339520] fb_st7789v spi0.0: fbtft_write_reg8_bus8: 2b 00 22 01 22
[ 62.339555] fb_st7789v spi0.0: fbtft_write_spi(len=1): 2b
[ 62.339612] fb_st7789v spi0.0: fbtft_write_spi(len=4): 00 22 01 22
[ 62.341238] fb_st7789v spi0.0: fbtft_write_reg8_bus8: 2c
[ 62.341278] fb_st7789v spi0.0: fbtft_write_spi(len=1): 2c
[ 62.341326] fb_st7789v spi0.0: fbtft_write_vmem16_bus8(offset=16320, len=123360)
[ 62.341387] fb_st7789v spi0.0: fbtft_write_spi(len=4096): f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be f7 be ...
[ 62.346744] fb_st7789v spi0.0: fbtft_write_spi(len=4096): 21 49 21 49 19 49 29 8a 29 8b 29 ab 39 ec 42 4d 29 8a 29 8a 21 49 42 2c 29 69 29 69 21 48 31 aa ...
[ 62.348924] fb_st7789v spi0.0: fbtft_write_spi(len=4096): 18 e7 18 e8 18 c7 18 e7 20 e8 21 09 29 29 39 8b 41 cd 49 ee 41 cd 41 cd 39 8c 31 6b 39 ac 4a 0e ...
[ 62.351013] fb_st7789v spi0.0: fbtft_write_spi(len=4096): 31 ab 42 0d 39 cc 31 ab 31 8b 41 ed 42 2d 41 ec 39 cc 41 ed 52 90 42 0d 42 0e 39 ed 42 2e 42 0e ...
[ 62.353523] fb_st7789v spi0.0: fbtft_write_spi(len=4096): 41 ad 31 2b 29 09 39 cc 39 cc 31 8b 29 29 31 6a 31 8b 29 09 29 29 31 6a 31 49 29 28 31 49 39 cc ...
[ 62.355524] fb_st7789v spi0.0: fbtft_write_spi(len=4096): 94 37 9c 98 4a 2e 39 8b 39 8b 39 8a 31 6a 39 ab 41 ab 39 ab 39 ab 39 aa 39 aa 39 8a 31 69 31 49 ...
利用下面的指令可以检测屏上显示是否正常,下面的指令可以令屏幕显示花屏:
cat /dev/urandom > /dev/fb0
下面的指令可以清屏:
cat /dev/zero > /dev/fb0
由于是采用SPI驱动显示的,在更新屏幕的时候,是明显的可以看到屏幕的扫描过程中,比较的慢。上述过程完成了LCD的驱动移植,下面移植LVGL
2. 移植LVGL
LVGL的移植相对容易,官方给出了基于FB的一个demo,直接clone到本地编译就能成功。地址为:Embedded GUI Using Linux Frame Buffer Device with LVGL | LVGL’s Blog
输入以下指令,先把demo工程拷贝下来:
git clone https://github.com/lvgl/lv_port_linux_frame_buffer.git
git clone --recurse-submodules
这样就能下载所有的LVGL相关的库文件,如果编译环境搭得没有问题的话,那个这个时候,在Makefile里面指定好GCC编译器的位置后,就能直接编译出demo程序了:
为了偷个懒,不去移植硬件相 关的驱动程序,我这里直接把Luckfox pico官方的那个LVGL 8.1版本的文件都拷到了demo工程来了,除了与lvgl配置相关的文件,包括lv_conf.h以及lv_drv_conf.h,这两个文件要用新,老版本跟新版本差别很大:
利用LVGL新版本,即8.3库里面自带的template来做配置
cp lvgl/lvgl/lv_conf_template.h ./lv_conf.h
cp lvgl/lv_drivers/lv_drv_conf_template.h ./lv_drv_conf.h
第一个要改的是使能文件配置:
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/
再来修改下LCD的color depth,这里用的是65K的LCD,那么是16bit的,所以这个也要改:
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
将TICK的函数名与main.c中的函数名写得一致:
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE <stdint.h> /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (custom_tick_get()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
使能文件系统:
/*API for open, read, etc*/
#define LV_USE_FS_POSIX 1
#if LV_USE_FS_POSIX
#define LV_FS_POSIX_LETTER 'A' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
#define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
使能一些第三方的解码库文件:
/*PNG decoder library*/
#define LV_USE_PNG 1
/*BMP decoder library*/
#define LV_USE_BMP 1
/* JPG + split JPG decoder library.
* Split JPG is a custom format optimized for embedded systems. */
#define LV_USE_SJPG 1
/*GIF decoder library*/
#define LV_USE_GIF 1
/*QR code library*/
#define LV_USE_QRCODE 1
再在lv_drv_conf.h中使能FB并指定FB的名称:
/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 1
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
FB的设备名称可以这么来看
ls /dev/fb*
最后一步是在Makefile中加一项编译项:
CFLAGS += -D_DEFAULT_SOURCE
如果你是用的官方的makefile文件,那么下面的一行也要改一下,官方只有一个main source,其它的文件都没有加的:
#Collect the files to compile
MAINSRC = $(wildcard ./*.c)
main.c函数里面还有些要改的内容,就是LCD显示的大小:
#define DISP_BUF_SIZE (320 * 240)
/*Initialize and register a display driver*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.draw_buf = &disp_buf;
disp_drv.flush_cb = fbdev_flush;
disp_drv.hor_res = 240;
disp_drv.ver_res = 320;
lv_disp_drv_register(&disp_drv);
至此,可以make生成工程。
大家可以看下我的显示效果,按不同的键可以显示不同的照片: