• 【全志T113-S3_100ask】15-1 内核5.4驱动spi屏幕——ILI9341


    背景

    • 本来想直接驱动mipi屏幕的,但是发现有一点点难度,所以想先研究一下小屏幕如何驱动。
    • 本文章使用的芯片为全志T113-s3,目前使用的核心板是100ask的,但是官方开发板上面的spi接口不齐全,所以自制了一块板子进一步学习。

    (一)spi设备树

    1、修改设备树

    在原本的设备树中,配置是错误的,引脚都对不上,应该是参考D1-H的文档,然后拷贝过来的。
    然后看了芯片的手册,引脚配置如下:
    在这里插入图片描述
    在 Function4 中有spi1相关的配置,从PD10到PD15
    修改设备树 spi1 的引脚,如下:

    	spi1_pins_a: spi1@0 {
    		pins = "PD11", "PD12", "PD13","PD14", "PD15"; /*clk mosi miso hold wp*/
    		function = "spi1";
    		drive-strength = <10>;
    	};
    
    	spi1_pins_b: spi1@1 {
    		pins = "PD10";
    		function = "spi1";
    		drive-strength = <10>;
    		bias-pull-up;   // only CS should be pulled up
    	};
    
    	spi1_pins_c: spi1@2 {
    		allwinner,pins = "PD10", "PD11", "PD12", "PD13","PD14", "PD15";
    		allwinner,function = "gpio_in";
    		allwinner,muxsel = <0>;
    		drive-strength = <10>;
    	};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    此时spi总线已经配置好了

    2、完善设备树

    因为我们本次驱动的屏幕为ili9341,改屏幕的驱动已经在内核里,直接使能使用即可,但是我们要修改设备树,参考修改手册:
    在这里插入图片描述
    手册上说明,一定要配置
    - compatible: "adafruit,yx240qv29", "ilitek,ili9341"
    - dc-gpios: D/C pin
    - reset-gpios: Reset pin
    但是可以参考一下配置进行设置:
    在 spi1 节点下:

    ili9341@0{
    		#address-cells = <1>;
    		#size-cells = <1>;
            compatible = "ilitek,ili9341";
            reg = <0>;
            spi-max-frequency = <32000000>;
            dc-gpios = <&pio PD 16 GPIO_ACTIVE_HIGH>;
            reset-gpios = <&pio PD 17 GPIO_ACTIVE_HIGH>;
    		rotate = <90>;
    		spi-cpol;  //SPI引脚模式
    		spi-cpha; //SPI引脚模式
    		bgr;//颜色格式为RGB
            fps = <30>;
            buswidth = <8>;
            // backlight = <&backlight>;
    		status = "okay";
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如下所示:
    在这里插入图片描述
    我们还用到了dc和rst引脚,这两个引脚可以随便找个io,但是不能和其他引脚冲突。
    需要在pio节点下配置

    	lcd_dc: lcd_dc{
    				allwinner,pins = "PD16"; 
    			};
    	lcd_rst: lcd_rst{
    				allwinner,pins = "PD17"; 
    			};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如下所示:
    在这里插入图片描述

    此时已经将设备树修改完毕。

    (二)使能内核

    1、在内核目录下如 linux-origin_master ,输入make menuconfig 进入内核菜单设置页面
    在这里插入图片描述
    2、然后左斜杠 / 进入搜索,输入 ili9341,回车即可找到相关的驱动

    在这里插入图片描述
    在这里插入图片描述
    然后使能该项(别问我怎么使能)

    或者一步步找到该驱动

     Location:                                                                                                                             │
      │     -> Device Drivers                                                                                                                   │
      │       -> Staging drivers (STAGING [=y])                                                                                                 │
      │         -> Support for small TFT LCD display modules (FB_TFT [=y])  
    
    • 1
    • 2
    • 3
    • 4

    (三)兼容性修改

    • 对于比较高版本的内核比如我现在的5.4,如果直接编译的话,是使用不了屏幕的,因为内核在不断更新,但是对于屏幕的驱动,并没有及时更新,甚至这个驱动代码可能是八年前的代码。
    • 主要修改的文件为 fbtft-core.c
    • 参考路径:build/linux-origin_master/drivers/staging/fbtft/fbtft-core.c

    1- 在 fbtft-core.c 添加头文件

    #include "linux/gpio.h"
    #include "linux/of_gpio.h"
    
    • 1
    • 2

    2- 找到里面的 fbtft_request_one_gpio()函数,替换该函数的内容,修改后如下:

    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\n", 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\n",
                    name, gpio, ret);
                return ret;
            }
    
            *gpiop = gpio_to_desc(gpio);
            fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
                                __func__, name, gpio);
        }
    
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    3- 找到里面的 fbtft_request_gpios_dt()函数,替换该函数的内容,修改后如下:

    static int fbtft_request_gpios_dt(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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    4- 找到里面的 fbtft_reset()函数,替换该函数的内容,修改后如下:

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    修改完以上三个函数,就可以编译内核和buildroot。后续步骤省略。

    (四)测试

    1、接线
    按照屏幕的接线方案进行接线,一一对应就好没啥好说的。
    2、上电
    上电之后屏幕由白到黑,应该是驱动加载成功了。
    3、查看启动时的内核信息

    # dmesg | grep "fb"
    [    4.470009] fbtft_of_value: buswidth = 8
    [    4.474498] fbtft_of_value: rotate = 90
    [    4.478946] fbtft_of_value: fps = 30
    [    4.950907] graphics fb0: fb_ili9341 frame buffer, 320x240, 150 KiB video memory, 16 KiB buffer memory, fps=33, spi1.0 at 32 MHz
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4、花点测试(随机填充)

     cat /dev/urandom > /dev/fb0
    
    • 1

    在这里插入图片描述

    5、自带工具测试

    # fb-test
    fb-test 1.1.1 (rosetta)
    fb res 320x240 virtual 320x240, line_len 640, bpp 16
    
    • 1
    • 2
    • 3

    现象如下:

    在这里插入图片描述

    # fb-test-rect
    rect 1.1.1 (rosetta)
    
    • 1
    • 2

    现象如下:
    在这里插入图片描述

    至此,屏幕驱动完毕。可以进一步研究c语言驱动屏幕,或者lvgl驱动。

    END.

  • 相关阅读:
    【贪心 || 动态规划】最长对数链
    mybatisplus-MybatisX插件
    太可了,刷透这份“架构师养成手册”成就自己的架构之路
    SpringMvc内置的九大组件
    WPS/word 表格跨行如何续表、和表的名称
    binlog的三种格式
    分页查询的SQL优化
    Scala面向对象
    解决uniapp组件uni-file-picker设置:disable-preview=“true“关闭预览不生效的问题 - 禁用图片预览无效的手动解决办法
    【不限框架】超好用的3d开源图片预览插件推荐
  • 原文地址:https://blog.csdn.net/qq_46079439/article/details/128019639