当前位置:首页 > 技术 > LINUX > 正文内容

【转】小白自制Linux开发板 六. SPI TFT屏幕修改与移植

Watrt7个月前 (01-06)LINUX6670

本篇通过SPI接口,使用ST7789V TFT焊接屏(13pin)为我们的小开发板进行显示加持,废话不多说了,直接开搞。

1. 硬件设置

我们在第四篇中使用了F1C200s的SPI0通信接口连接了ESP8266作为无线网卡使用,这一篇我们将使用SPI1作为我们的显示接口

 在F1C200s,我们用到了SPI1中的CLK、MOSI、CS三个接口,因为不需要从屏幕返回数据,所以不需要接MISO,另外我们配置PE4作为重置、PE5为DC,如上图。

需要注意的是,在有些原理图中SPI中的CS是直接接地的,这种处理方式并不好,而且还要看硬件是否支持,墨云就在这里踩过坑。

对于屏幕端,接线相对简单,SDA(MOSI)、SCL(CS) ,除了要接线,还需要拉高;VCC为供电,并且需要接一个4.7uf或是10uf的滤波电容;

LEDA(12pin)引脚是控制显示屏灯光的的引脚,如果有必要可以接到一个控制IO上面,这样就可以自定义控制显示屏亮灭了,这里为了图省事,就直接接了3.3v,也就是上电直接亮屏,如下图所示。

2. 软件编写

在Linux内核中是带了ST7789V驱动的,但是因为Linux内核一直在不断升级改进,比如一些申请接口的方式在不断的变化,而对应的驱动代码却没有同步更新,所以造成了很多驱动不兼容问题,所以我们还需要修改ST7789V的驱动才能让屏幕工作起来。

在Linux内核目录drivers/staging/fbtft中可以看到有st7789v的驱动代码,

2.1 修改初始化参数

现在打开fb_st7789v.c文件,然后找到屏幕初始化函数,修改如下:

 1 static int init_display(struct fbtft_par *par) 2 { 3     par->fbtftops.reset(par); 4     mdelay(50); 5     write_reg(par,0x11);//Sleep exit 6     mdelay(12); 7     write_reg(par,0x11); 8     mdelay(10); 9     write_reg(par,0x3A,0x05); //65k mode10     write_reg(par,0xc5,0x1a);11     write_reg(par,0x36,0x70); // 屏幕显示方向设置12 //-------------ST7789V Frame rate setting-----------//13     write_reg(par,0xb2,0x05,0x05,0x00,0x33,0x33);14     write_reg(par,0xb7,0x35);15 //--------------ST7789V Power setting---------------//16     write_reg(par,0xbb,0x3f);17     write_reg(par,0xc0,0x2c);18     write_reg(par,0xc2,0x01);19     write_reg(par,0xc3,0x0f);20     write_reg(par,0xc4,0x20);21     write_reg(par,0xc6,0x11);22     write_reg(par,0xd0,0xa4,0xa1);23     write_reg(par,0xe8,0x03);24     write_reg(par,0xe9,0x09,0x09,0x08);25     write_reg(par,0xe0,0xd0,0x05,0x09,0x09,0x08,0x14,0x28,0x33,0x3f,0x07,0x13,0x14,0x28,0x30);26     write_reg(par,0xe1,0xd0,0x05,0x09,0x09,0x08,0x03,0x24,0x32,0x32,0x3b,0x14,0x13,0x28,0x2f);27     write_reg(par,0x21);28     write_reg(par,0x11);29     mdelay(120);      //Delay 120ms30     write_reg(par,0x29);31     mdelay(200);32     return 0;33 }

2.2 修改分辨率

接下来要修改屏幕分辨率,这里我使用的是1.14寸135*240的液晶屏,找到fbtft_display display结构体,然后修改widthheight

 2.3 修改显示核心代码

然后修改fbtft-core.c文件,

先添加两个头文件:

#include "linux/gpio.h"#include "linux/of_gpio.h"

添加头文件的目的是后面需要用到申请gpio函数。

然后找到fbtft_request_one_gpiofbtft_request_gpios函数,并且修改:

修改fbtft_request_one_gpio,修改gpio申请函数

 1 static int fbtft_request_one_gpio(struct fbtft_par *par, 2                   const char *name, int index, 3                   struct gpio_desc **gpiop) 4 { 5     struct device *dev = par->info->device; 6     struct device_node *node = dev->of_node; 7     int gpio, flags, ret = 0; 8     enum of_gpio_flags of_flags; 9     if (of_find_property(node, name, NULL)) {10         gpio = of_get_named_gpio_flags(node, name, index, &of_flags);11         if (gpio == -ENOENT)12             return 0;13         if (gpio == -EPROBE_DEFER)14             return gpio;15         if (gpio < 0) {16             dev_err(dev,17                 "failed to get '%s' from DT\n", name);18             return gpio;19         }20          //active low translates to initially low21         flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :22                             GPIOF_OUT_INIT_HIGH;23         ret = devm_gpio_request_one(dev, gpio, flags,24                         dev->driver->name);25         if (ret) {26             dev_err(dev,27                 "gpio_request_one('%s'=%d) failed with %d\n",28                 name, gpio, ret);29             return ret;30         }31 32         *gpiop = gpio_to_desc(gpio);33         fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",34                             __func__, name, gpio);35     }36 37     return ret;38 }

修改fbtft_request_gpios,修改设备树匹配字符串

static int fbtft_request_gpios(struct fbtft_par *par)
{    int i;    int ret;
    ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);    if (ret)        return ret;
    ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);    if (ret)        return ret;
    ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);    if (ret)        return ret;
    ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);    if (ret)        return ret;
    ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);    if (ret)        return ret;
    ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);    if (ret)        return ret;    for (i = 0; i < 16; i++) {
        ret = fbtft_request_one_gpio(par, "db-gpios", i,                         &par->gpio.db[i]);        if (ret)            return ret;
        ret = fbtft_request_one_gpio(par, "led-gpios", i,                         &par->gpio.led[i]);        if (ret)            return ret;
        ret = fbtft_request_one_gpio(par, "aux-gpios", i,                         &par->gpio.aux[i]);        if (ret)            return ret;
    }    return 0;
}

修改gpio申请函数的原因在于这里一个不同版本之间的不兼容问题,因为内核版本移植在更新,但是有些驱动却没有即使更新,这就出现了一些内核接口已经更新了,而驱动却还在使用旧的方式,导致即使可以注册成功,但并不能对其操作。

然后修改fbtft复位函数,如下:

static void fbtft_reset(struct fbtft_par *par)
{    if (!par->gpio.reset)        return;
    fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
    gpiod_set_value_cansleep(par->gpio.reset, 1);
    msleep(10);
    gpiod_set_value_cansleep(par->gpio.reset, 0);
    msleep(200);
    gpiod_set_value_cansleep(par->gpio.reset, 1);
    msleep(10);
}

修改复位函数的原因在于原本的函数拉低复位引脚后并为拉高。

FBTFT的部分已经修改完毕,液晶屏使用的是SPI操作的,因此需要将fbtft驱动挂载在spi总线上,幸运的是对于F1C200S来说,内核已经有spi驱动了,因此我们只需要修改设备树就可以了,具体步骤如下:

2.4 修改设备树

打开arch/arm/boot/dts/suniv-f1c100s.dtsi文件,添加spi节点和pio节点

spi1:spi@1c06000 {
            compatible = "allwinner,suniv-spi", "allwinner,sun8i-h3-spi";
            reg =<0x1c06000 0x1000>;
            interrupts =<0xb>;
            clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_BUS_SPI1>;
            clock-names = "ahb", "mod";
            resets = <&ccu RST_BUS_SPI1>;
            status = "okay";
            #address-cells =<1>;
            #size-cells =<0>;
            bias-pull-up;
            pinctrl-names = "default";
            pinctrl-0 = <&spi1_pins>;
        };
pio: pinctrl@1c20800 {
    compatible = "allwinner,suniv-f1c100s-pinctrl";
    reg = <0x01c20800 0x400>;
    interrupts =<38>,<39>,<40>;
    clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
    clock-names = "apb", "hosc", "losc";
    gpio-controller;
    interrupt-controller;
    #interrupt-cells =<3>;
    #gpio-cells =<3>;
    uart0_pe_pins: uart0-pe-pins {
        pins = "PE0", "PE1";
        function = "uart0";
    }; 
    mmc0_pins: mmc0-pins {
        pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
        function = "mmc0";
    };
    spi1_pins: spi1-pins{
         pins = "PA2","PA0","PA3","PA1";
         function = "spi1";
    };
};

添加SPI节点,主要看spi1节点即可

添加pio节点

然后打开arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts在spi1中添加st7789v子节点

&spi1 {
    st7789v@0 {
        status = "okay";
        compatible = "sitronix,st7789v";
               reg = <0>;
               spi-max-frequency =<32000000>;        //SPI时钟32M
               rotate =<90>;                    //屏幕旋转90度
               spi-cpol;
               spi-cpha;
               rgb;                           //颜色格式RGB
               fps =<30>;                      //刷新30帧率
               buswidth =<8>;                   //总线宽度8
               reset-gpios=<&pio 4 4 GPIO_ACTIVE_LOW>;   //GPIOE4
               dc-gpios  =<&pio 4 5 GPIO_ACTIVE_LOW>;   //GPIOE5
               debug =<0>;                     //不开启调试        };
};

现在所有的修改都完成了,剩下的就是编译内核了,在内核根目录下执行

make menuconfig

启动图形配置界面, 

2.5 内核配置

由于FC1000S的SPI中有一个BUG,因此我们在开启SPI驱动的时候必须选择A31(Device Drivers -> SPI support)
如图所示

现在选择ST7789V驱动并编译进内核中,如下:

Device Drivers  --->  
    [*] Staging drivers  --->  
        <*>   Support for small TFT LCD display modules  --->
              <*>   FB driver for the ST7789V LCD Controller

保存退出,然后执行make命令编译内核,然后将镜像拷贝到tf卡第一分区中,此时可以看到屏幕已经可以驱动起来了,并且/dev目录下有fb0设备。


 注意

对于1.14寸液晶屏而言,其屏幕有偏移,这里需要修改fbtft-core.c文件中的fbtft_set_addr_win函数

static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,                   int ye)
{
    write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,(xs+40) >> 8, xs+40, ((xe+40) >> 8) & 0xFF, (xe+40) & 0xFF);
    write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,((ys+52) >> 8) & 0xFF, (ys+52) & 0xFF, ((ye+52) >> 8) & 0xFF, (ye+52) & 0xFF);
    write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
}

效果如下:

 是的,还是这张图……我能放N次^_^

打赏 支付宝打赏 微信打赏
分享给朋友:

相关文章

Linux 压缩解压命令备忘

Linux 压缩解压命令备忘

01-.tar格式解包:[*******]$ tar xvf FileName.tar 打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩!) 02-.gz格式 解压1:[*******]$ gunzip FileName.gz 解压2:[*******]$ gzip -d FileName.gz 压 缩:[*******]$ gzip...

荔枝派Nano 全流程指南

荔枝派Nano 全流程指南

u-boot 初体验安装交叉编译链首先需要安装交叉编译链:# 此处为获取7.2.1版本,您可获取其他版本或者通过链接直接下载 wget http://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/arm-linux-gnueabi/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz tar -vxJf gcc-li...

Linux没有最小只有更小----迷你Linux版本大集合

Linux没有最小只有更小----迷你Linux版本大集合

    自从去年到现在已经收集了上百种版本的Linux和Unix,至于Unix就不想说了,没有Linux的功底是很难驾驭Unix的,我在这里只把小于360M的Linux以及一些非Linux但是很像Linux的版本也发布一下,我本人喜欢安静,如果你想要这些迷你版本的Linux光盘的话,建议去官网下载就OK了。英语不行的话随时带个字典。有些没有桌面,想知道哪些没有桌面的话请自己网上查资料!下面就是绝大部分小于361M的Linux及其非Linux名单,参考时间为...

[转]《保姆级教程》全志F1C100S/F1C200S spi-flash 启动全流程适配烧录及踩坑指南

[转]《保姆级教程》全志F1C100S/F1C200S spi-flash 启动全流程适配烧录及踩坑指南

转自哇酷网=丨晋丨通过参考荔枝派nano官方和论坛大佬的帖子,总结了烧录 spi-flash 启动的方法。通过搜寻资料,把其中有错误或者做了多余的操作的步骤做了修正,以免大家再次踩坑,耗费青春。以下包括 uboot、kernel、buildroot 和 烧录的详细步骤和需要注意的问题,尽量精简方法,以期容易上手和理解。各种配置项也做了详细注释,要知其然,也知其所以然。最理想的状态应该是是:有的坑,踩的人多了,也便没有了坑。论坛不太好排版,有需要的也可以去我的博客看:P:全志F1C100S/F1C...

老是提示:newer kernel available 解决方法

老是提示:newer kernel available 解决方法

这个是由于没有正确的安装内核造成的。可以直接关掉提示 sudo apt purge needrestart...

f1c100s编译启动所需的uboot,kernel,rootfs

f1c100s编译启动所需的uboot,kernel,rootfs

 https://github.com/Icenowy/linux.git 有f1c100s-480272lcd-test和f1c100s分支, 然后自己手动修复一个 USB 问题,驱动就比较全了https://github.com/Lichee-Pi/linux.git 有nano-4.14-exp和nano-5.2-flash分支,用哪个合适个人画了块没有连接任何其他模块的F1C100S开发板,没有链接任何外设,本文是编译所有启动所需的三大件。(只要编...

从Ubuntu-base构建ubuntu rootfs系统

从Ubuntu-base构建ubuntu rootfs系统

1.介绍ubuntu-base 是Ubuntu官方构建的ubuntu最小文件系统,包含debain软件包管理器,基础包大小通常只有几十兆,其背后有整个ubuntu软件源支持,ubuntu软件一般稳定性比较好,基于ubuntu-base按需安装Linux软件,深度可定制…,常用于嵌入式rootfs构建。嵌入式常见的几种文件系统构建方法:busybox、yocto、builroot,我觉得它们都不如Ubuntu方便,强大的包管系统,有强大的社区支持,可以直接apt-get install来安装新软件...

如何使用 Ubuntu 安装和配置 Openbox

如何使用 Ubuntu 安装和配置 Openbox

Openbox是一个相当简单的窗口管理器,我们可以根据需要构建和自定义。本教程向我们展示了在 Ubuntu 中设置 Openbox 的基础知识、如何更改菜单、如何添加扩展坞以及如何设置墙纸。安装 Openbox要安装 Openbox,请同时打开终端窗口(按 CTRL 、 ALT 和 T )或者在破折号中搜索“TERM”并选择图标。输入以下命令:sudo apt install openbox obconf单击右上角的图标,然后注销。如何切换到 Openbo...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。