zoukankan      html  css  js  c++  java
  • F1C100S添加SPI LCD液晶驱动

    在使用F1C100S的时候常常会使用小尺寸的液晶屏,比如市场上比较常见的1.14寸液晶屏,下面我们来为该液晶屏添加驱动。

    下面以内核Linux-5.7内核版本,液晶驱动芯片为ST7789V,四线SPI接口为例:(例中液晶引脚接到SPI1上)

    注意:SPI总线的SCLK和SDA两个引脚必须接上拉电阻,10k即可。

    这里说明下硬件连接,因为有部分人遇到无法成功问题

    LCD液晶引脚 F1C100S板子
    SCLK PA2
    SDA PA1
    CS GND
    RESET PE7
    DC PE10

    1.设备树中添加SPI节点和ST7789V节点:

            spi0:spi@1c05000 {
               compatible = "allwinner,suniv-spi", "allwinner,sun8i-h3-spi";
                reg = <0x1c05000 0x1000>;
                interrupts = <0xa>;
                clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_BUS_SPI0>;
                clock-names = "ahb", "mod";
                resets = <&ccu RST_BUS_SPI0>;
                status = "disabled";
                #address-cells = <1>;
                #size-cells = <0>;
                pinctrl-names = "default";
                pinctrl-0 = <&spi0_pins>;
            };
    
            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 = "disabled";
                #address-cells = <1>;
                #size-cells = <0>;
                bias-pull-up;
                pinctrl-names = "default";
                pinctrl-0 = <&spi1_pins>;
            };

    同时在IO节点中申明引脚定义,如下所示:

    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";
                };
                
                lcd_rgb666_pins: lcd-rgb666-pins {
                    pins = "PD0", "PD1", "PD2", "PD3", "PD4",
                           "PD5", "PD6", "PD7", "PD8", "PD9",
                           "PD10", "PD11", "PD12", "PD13", "PD14",
                           "PD15", "PD16", "PD17", "PD18", "PD19",
                           "PD20", "PD21";
                    function = "lcd";
                };
                
                mmc0_pins: mmc0-pins {
                    pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
                    function = "mmc0";
                };
    
                spi0_pins: spi0-pins{
                    pins = "PC0", "PC1", "PC2", "PC3";
                    function = "spi0";
                };
    
                spi1_pins: spi1-pins{
                    pins = "PA2","PA0","PA3","PA1";
                    function = "spi1";
                };
    
            };

    在设备树中添加ST7789V节点:

    &spi1 {
        st7789v@0 {
            status = "okay";
            compatible = "sitronix,st7789v";
                   reg = <0>;
                   spi-max-frequency = <32000000>;  //最大速度32M
                   rotate = <0>;       //屏幕旋转角度
                   spi-cpol;      //SPI引脚模式
                   spi-cpha;     //SPI引脚模式
                   rgb;        //颜色格式为RGB
                   fps = <30>;              //刷新帧数30
                   buswidth = <8>;       //总线宽度8位
                   reset-gpios = <&pio 4 7 GPIO_ACTIVE_LOW>;  //GPIOE7
                   dc-gpios = <&pio 4 10 GPIO_ACTIVE_LOW>;    //GPIOE10
                   debug = <0>;
            };
        };  

    2.修改drivers/staging/fbtft/fbtft-core.c文件中的gpio申请函数:

    这里简单说下原因:因为在5.2版本之后使用的是另一种方式申请gpio,但是这种方式只是简单的给出了接口,实际并没有申请到gpio,因此当不去修改申请方式的时候,即使内核log提示已经申请成功并注册了驱动,但是实际并没有,导致液晶屏无法驱动起来。

    先添加如下头文件:

    #include <linux/gpio.h>
    #include <linux/of_gpio.h>

    然后修改两个函数:

    static int fbtft_request_one_gpio(struct fbtft_par *par,
                      const char *name, int index,
                      struct gpio_desc **gpiop)
    {
        struct device *dev = par->info->device;
        struct device_node *node = dev->of_node;
        int gpio, flags, ret = 0;
        enum of_gpio_flags of_flags;
    
        if (of_find_property(node, name, NULL)) {
            gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
            if (gpio == -ENOENT)
                return 0;
            if (gpio == -EPROBE_DEFER)
                return gpio;
            if (gpio < 0) {
                dev_err(dev,
                    "failed to get '%s' from DT
    ", name);
                return gpio;
            }
    
             //active low translates to initially low 
            flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
                                GPIOF_OUT_INIT_HIGH;
            ret = devm_gpio_request_one(dev, gpio, flags,
                            dev->driver->name);
            if (ret) {
                dev_err(dev,
                    "gpio_request_one('%s'=%d) failed with %d
    ",
                    name, gpio, ret);
                return ret;
            }
    
            *gpiop = gpio_to_desc(gpio);
            fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d
    ",
                                __func__, name, gpio);
        }
    
        return ret;
    }
    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;
    }

    3.由于5.7版本的fbtft复位部分有问题,最后没有拉高,所以我们需要修改drivers/staging/fbtft/fbtft-core.c中的fbtft_reset函数:

    static void fbtft_reset(struct fbtft_par *par)
    {
        if (!par->gpio.reset)
            return;
        fbtft_par_dbg(DEBUG_RESET, par, "%s()
    ", __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);
    }

    4.最后由于fbtft提供的ST7789V的初始化代码部分有问题,导致颜色对不上,因此我们这里使用STM32中的初始化,修改如下:

      修改drivers/staging/fbtft/fb_st7789v.c中的init_display函数:

    static int init_display(struct fbtft_par *par)
    {
        par->fbtftops.reset(par);
        mdelay(50);
        write_reg(par,0x36,0x00);
        write_reg(par,0x3A,0x05);
        write_reg(par,0xB2,0x0C,0x0C,0x00,0x33,0x33);
        write_reg(par,0xB7,0x35);
        write_reg(par,0xBB,0x19);
        write_reg(par,0xC0,0x2C);
        write_reg(par,0xC2,0x01);
        write_reg(par,0xC3,0x12);
        write_reg(par,0xC4,0x20);
        write_reg(par,0xC6,0x0F);
        write_reg(par,0xD0,0xA4,0xA1);
        write_reg(par,0xE0,0xD0,0x04,0x0D,0x11,0x13,0x2B,0x3F,0x54,0x4C,0x18,0x0D,0x0B,0x1F,0x23);
        write_reg(par,0xE1,0xD0,0x04,0x0C,0x11,0x13,0x2C,0x3F,0x44,0x51,0x2F,0x1F,0x1F,0x20,0x23);
        write_reg(par,0x21);
        write_reg(par,0x11);
        mdelay(50);
        write_reg(par,0x29);
        mdelay(200);
        return 0;
    }

    由于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 -j4编译镜像:

  • 相关阅读:
    010editor爆破与注册机
    [FlareOn4]notepad
    [FlareOn6]Snake(NES逆向)
    [FlareOn6]Memecat Battlestation
    [FlareOn6]FlareBear
    回车符和换行符之间的区别
    docker配置搭建elasticsearch集群
    docker部署安装harbor
    ansible的get_url模块
    ansible的lineinfile与blockinfile模块
  • 原文地址:https://www.cnblogs.com/listenscience/p/13619930.html
Copyright © 2011-2022 走看看