本文章参考:
https://www.bilibili.com/read/cv9947785?spm_id_from=333.999.0.0

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

2.2 修改分辨率

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

2.3 修改显示核心代码

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

先添加两个头文件:

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

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

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

修改fbtft_request_one_gpio,修改gpio申请函数

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

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

  1. static int fbtft_request_gpios(struct fbtft_par *par)
  2. {
  3. int i;
  4. int ret;
  5.  
  6. ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
  7. if (ret)
  8. return ret;
  9. ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
  10. if (ret)
  11. return ret;
  12. ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
  13. if (ret)
  14. return ret;
  15. ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
  16. if (ret)
  17. return ret;
  18. ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
  19. if (ret)
  20. return ret;
  21. ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
  22. if (ret)
  23. return ret;
  24. for (i = 0; i < 16; i++) {
  25. ret = fbtft_request_one_gpio(par, "db-gpios", i,
  26. &par->gpio.db[i]);
  27. if (ret)
  28. return ret;
  29. ret = fbtft_request_one_gpio(par, "led-gpios", i,
  30. &par->gpio.led[i]);
  31. if (ret)
  32. return ret;
  33. ret = fbtft_request_one_gpio(par, "aux-gpios", i,
  34. &par->gpio.aux[i]);
  35. if (ret)
  36. return ret;
  37. }
  38.  
  39. return 0;
  40. }

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

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

  1. static void fbtft_reset(struct fbtft_par *par)
  2. {
  3. if (!par->gpio.reset)
  4. return;
  5. fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
  6. gpiod_set_value_cansleep(par->gpio.reset, 1);
  7. msleep(10);
  8. gpiod_set_value_cansleep(par->gpio.reset, 0);
  9. msleep(200);
  10. gpiod_set_value_cansleep(par->gpio.reset, 1);
  11. msleep(10);
  12. }

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

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

2.4 修改设备树

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

  1. spi1:spi@1c06000 {
  2. compatible = "allwinner,suniv-spi", "allwinner,sun8i-h3-spi";
  3. reg =<0x1c06000 0x1000>;
  4. interrupts =<0xb>;
  5. clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_BUS_SPI1>;
  6. clock-names = "ahb", "mod";
  7. resets = <&ccu RST_BUS_SPI1>;
  8. status = "okay";
  9. #address-cells =<1>;
  10. #size-cells =<0>;
  11. bias-pull-up;
  12. pinctrl-names = "default";
  13. pinctrl-0 = <&spi1_pins>;
  14. };
  15. pio: pinctrl@1c20800 {
  16. compatible = "allwinner,suniv-f1c100s-pinctrl";
  17. reg = <0x01c20800 0x400>;
  18. interrupts =<38>,<39>,<40>;
  19. clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
  20. clock-names = "apb", "hosc", "losc";
  21. gpio-controller;
  22. interrupt-controller;
  23. #interrupt-cells =<3>;
  24. #gpio-cells =<3>;
  25.  
  26. uart0_pe_pins: uart0-pe-pins {
  27. pins = "PE0", "PE1";
  28. function = "uart0";
  29. };
  30.  
  31. mmc0_pins: mmc0-pins {
  32. pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
  33. function = "mmc0";
  34. };
  35.  
  36. spi1_pins: spi1-pins{
  37. pins = "PA2","PA0","PA3","PA1";
  38. function = "spi1";
  39. };
  40.  
  41. };

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

添加pio节点

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

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

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

  1. make menuconfig

启动图形配置界面,

2.5 内核配置

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

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

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

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


注意

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

  1. static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
  2. int ye)
  3. {
  4. write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,(xs+40) >> 8, xs+40, ((xe+40) >> 8) & 0xFF, (xe+40) & 0xFF);
  5.  
  6. write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,((ys+52) >> 8) & 0xFF, (ys+52) & 0xFF, ((ye+52) >> 8) & 0xFF, (ye+52) & 0xFF);
  7.  
  8. write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
  9. }

效果如下:

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

小白自制Linux开发板 六. SPI TFT屏幕修改与移植的更多相关文章

  1. 小白自制Linux开发板 二. u-boot移植

    上一篇:小白自制Linux开发板 一. 瞎抄原理图与乱画PCB  中我们做了一个小型而没用的开发板,用的是Licheepi Nano的镜像,那从本篇开始我们开始自己构建它的灵魂吧. 我们都知道,PC在 ...

  2. 小白自制Linux开发板 三. Linux内核与文件系统移植

    上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...

  3. 小白自制Linux开发板 四. 通过SPI使用ESP8266做无线网卡

    本文章基于 WhyCan Forum(哇酷开发者社区) https://whycan.com/t_4149.htmlhttps://whycan.com/t_5870.html整理而成. 为了尊重原作 ...

  4. 小白自制Linux开发板 一. 瞎抄原理图与乱画PCB

    因为墨云是基于高中物理水平的电路知识来学习.而且此前也就玩过树莓派.Esp8266之类的开发板,水平基础趋近于零,所以在写这个系列的时候抱着记录的心态.还望不足之处还望大佬们指正. <论语> ...

  5. 小白自制Linux开发板(第二季 V3s篇) 一. 换个核心再来一次

    1.前言 大家心心念念(个人认为)的小白自制开发板全新系列正式来了,之前我们使用全志的F1C200s芯片制作了一个小电脑,众所周知,调试很艰难,坑也很多,以至于墨云到现在还是没找到对应的补救方案,为了 ...

  6. 小白自制Linux开发板 八. Linux音频驱动配置

    不知不觉小白自制开发板系列已经到第八篇了,本篇要配置的是音频驱动,也算是硬件部分的最后一片了,积攒的文章也差不多全放完了,后续更新可能会放缓,还请见谅. 对于F1C200s是自带了多媒体处理功能的,所 ...

  7. 小白自制Linux开发板 九. 修改开机Logo

    许久不见啊,今天我们继续来修改我们的系统. 通过前面的几篇文章我们已经能轻松驾驭我们的开发板了,但是现在都是追求个性化的时代,我们在开发板上打上了自己的Logo,那我们是否可以改变开机启动的Logo呢 ...

  8. 小白自制Linux开发板 十. NES游戏玩起来

    本篇基于我们制作的Debian文件系统而展开,而且我们这会玩一些高级的操作方式--用我们的小电脑进行程序编译.   所以本篇操作全部都在我们个的开发板上完成.   1. 开发环境搭建 首先安装gcc, ...

  9. 小白自制Linux开发板 番外篇 一 modprobe加载驱动问题(转载整理)

    使用modprobe加载驱动 转载地址:https://blog.csdn.net/qq_39101111/article/details/78773362 前面我们提到,modprobe并不需要指定 ...

随机推荐

  1. vue 引用高德地图

    vue 引用地图之傻瓜式教程(复制粘贴即可用) npm 下载 npm install vue-amap --save main.js 代码 import AMap from 'vue-amap'; V ...

  2. react + layui 坑总结

    与react 结合的时候,layui 是纯dom操作,而react是虚拟dom ,二者的结合难免会出现诸多问题. 1 select 下拉框 默认值的修改要通过defaultValue 属性来修改,并且 ...

  3. MySQL——MySQL安装

    1.rpm yum安装:安装方便.速度快.无法定制 2.二进制安装:解压即可使用,不能定制功能 3.编译安装: 可定制.安装慢: MySQL5.5之前:./configure make make in ...

  4. HCNP Routing&Switching之IS-IS报文结构和类型

    前文我们了解了IS-IS动态路由协议基础相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15249328.html:今天我们来聊一聊IS-IS动态路由协 ...

  5. bean的作用域和生命周期

    一.Bean作用域 二.生命周期 其中,这个类实现各种接口重写各种方法,会按bean的声明周期按序执行: 其中,自定义的初始化和自定义销毁的方法不是实现接口重写,而是成员方法,并且在装配bean即在x ...

  6. Nginx-初见

    目录 产品出现瓶颈? 什么是Nginx? Nginx作用 正向代理 反向代理 负载均衡策略(Nignx) 轮询 加权轮询 IP hash 动静分离 参考链接 产品出现瓶颈? 项目刚刚上线的时候,并发量 ...

  7. Tars | 第8篇 TarsJava Subset最终代码的执行流程与原理分析

    目录 前言 1. SubsetConf配置项的结构 1.1 SubsetConf 1.2 RatioConfig 1.3 KeyConfig 1.4 KeyRoute 1.5 SubsetConf的结 ...

  8. Java 语法学习2

    Java基础语法二 类型转换 public class demo03 { public static void main(String[] args) { int i=128; byte a=(byt ...

  9. Java技术开发专题系列之【Guava RateLimiter】针对于限流器的入门到精通(针对于源码分析介绍)

    Guava包中限流实现分析 RateLimiter 之前的文章中已经介绍了常用的限流算法,而google在Java领域中使用Guava包中的限流工具进行服务限流. 回顾使用案例 Google开源工具包 ...

  10. linux错误: locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory

    命令 locate my.cnf 产生以上错误 此时执行 # updatedb 更新下数据库即可