• Linux驱动开发(十五)---如何使用内核现有驱动(显示屏)


    前文回顾

    《Linux驱动开发(一)—环境搭建与hello world》
    《Linux驱动开发(二)—驱动与设备的分离设计》
    《Linux驱动开发(三)—设备树》
    《Linux驱动开发(四)—树莓派内核编译》
    《Linux驱动开发(五)—树莓派设备树配合驱动开发》
    《Linux驱动开发(六)—树莓派配合硬件进行字符驱动开发》
    《Linux驱动开发(七)—树莓派按键驱动开发》
    《Linux驱动开发(八)—树莓派SR04驱动开发》
    《Linux驱动开发(九)—树莓派I2C设备驱动开发(BME280)》
    《Linux驱动开发(十)—树莓派输入子系统学习(红外接收)》
    《Linux驱动开发(十一)—树莓派SPI驱动学习(OLED)》
    《Linux驱动开发(十二)—树莓派framebuffer学习(改造OLED)》
    《Linux驱动开发(十三)—USB驱动HID开发学习(鼠标)》
    《Linux驱动开发(十四)—USB驱动开发学习(键盘+鼠标)》
    继续宣传一下韦老师的视频

    70天30节Linux驱动开发快速入门系列课程【实战教学、技术讨论、直播答疑】

    在这里插入图片描述
    内核中目前存在了大量的设备驱动,如何能够快速利用起来,也是驱动工程师需要掌握的,毕竟人家都写好了,再从头去写,何苦呢?
    在这里插入图片描述

    本章目的

    如果我们需要在自己的linux设备上增加一个外设,例如一个屏幕,一个键盘,首先要想到的不是去写驱动,而是看一下系统有没有带驱动。例如这块SPI的TFT屏幕,驱动芯片是ili9341。
    在这里插入图片描述
    都是学习单片机遗留下来的东西,现在学驱动又能玩一波了。

    寻找驱动

    那么首先要在内核中查询是否有该芯片的屏幕驱动。通过在menuconfig中搜索关键词ili9341,我们就发现了它本身已经动态编译了ili9341的fb驱动,并且是支持framebuffer的。
    在这里插入图片描述
    进入开发板看一下,连我们之前开发的ssd1306的驱动都存在了。
    在这里插入图片描述
    不过不要觉得写驱动就没有意义了,写驱动一方面能够将单片机的知识应用到linux上,熟悉驱动的逻辑架构,还能够让你更快速的了解一个别人写好的驱动。万一遇到bug,也知道从哪里入手。
    在这里插入图片描述

    设备树

    既然驱动已经存在了。那么按照总线设备驱动模型,要想正常工作,就需要增加设备信息,提供给驱动使用,才能完成设备的驱动。
    那么这个设备树如何编写,两个思路,

    • 参考已有的设备树中别人怎么写的
    • 查看内核的设备树文档了。
      来查找一下有没有介绍文档
    root@ubuntu:/home/pgg/shumeipai/linux/Documentation# find ./ -name "*ili9341*"                                  
    ./devicetree/bindings/display/ilitek,ili9341.txt
    ./devicetree/bindings/display/panel/ilitek,ili9341.yaml
    
    • 1
    • 2
    • 3

    发现了描述文档《ilitek,ili9341.txt》,内容如下,告诉了你它是一个SPI模式控制器,需要三个关键参数,
    compatile,dc-gpios和rest-gpios,还有一个例子。

    在这里插入图片描述
    多么的贴心
    在这里插入图片描述

    那么我们就按照这个来尝试一下修改设备树。
    在这里插入图片描述
    然后更新一下设备树。结果发现屏幕亮,但是手动加载驱动没有任何反应,打印信息中也没有看到。
    在/sys/bus/spi/devices/中没有发现任何spi设备。
    怀疑设备树有问题。
    在这里插入图片描述

    于是发现了一个对于新手来说很重要的设备树配置

    status = "okay";
    
    • 1

    在增加了这条语句之后,重新编译设备树,发现了错误提示,原来刚才根本就没有编译上这个设备

    root@ubuntu:/home/pgg/shumeipai/linux# ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make dtbs
      DTC     arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dtb
    arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts:222.13-231.4: ERROR (phandle_references): /soc/spi@7e204000/myili9341@0: Reference to non-existent node or label "gpio0"
    
    arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts:222.13-231.4: ERROR (phandle_references): /soc/spi@7e204000/myili9341@0: Reference to non-existent node or label "gpio0"
    
    arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts:222.13-231.4: ERROR (phandle_references): /soc/spi@7e204000/myili9341@0: Reference to non-existent node or label "backlight"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    重新修改设备树
    在这里插入图片描述
    再次更新设备树。能够看到spi设备了

    root@raspberrypi:/home/pgg# ls /sys/bus/spi/devices/
    spi0.0
    
    • 1
    • 2

    在这里插入图片描述

    连接硬件

    然后按照引脚接好电路,和之前的oled小屏幕是一样的。
    在这里插入图片描述
    重启设备。驱动会自动根据设备树里面的描述进行加载。直接就能显示桌面了!真是个小惊喜。
    在这里插入图片描述
    直接就启动了。然后插上usb鼠标,加载上自己的驱动。走你!没毛病

    在这里插入图片描述

    OLED同理

    之前我们的OLED是SPI的oled,还有一部分相同芯片ssd1306采用的是iic通讯,那么我们同样可以找到相关的驱动
    在这里插入图片描述
    以及搜索到相关的设备树范例:
    Documentation\devicetree\bindings\display\ssd1307fb.txt
    在这里插入图片描述
    改天试一下这个驱动,感觉要比自己写的,用起来更踏实呢。
    在这里插入图片描述

    学习源码

    在drivers\staging\fbtft路径下,我们可以看到针对大量显示屏的驱动源码,这里采用了一个框架,每一种屏幕驱动,有一个私有的文件例如fb_ili9341.c,中间围绕这一个结构体进行特殊配置

    static struct fbtft_display display = {
    	.regwidth = 8,
    	.width = WIDTH,
    	.height = HEIGHT,
    	.txbuflen = TXBUFLEN,
    	.gamma_num = 2,
    	.gamma_len = 15,
    	.gamma = DEFAULT_GAMMA,
    	.fbtftops = {
    		.init_display = init_display,
    		.set_addr_win = set_addr_win,
    		.set_var = set_var,
    		.set_gamma = set_gamma,
    	},
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    每个屏幕差异的操作,由fbtftops结构中的函数来定义,结构中的函数会有默认操作。

    struct fbtft_ops {
    	int (*write)(struct fbtft_par *par, void *buf, size_t len);
    	int (*read)(struct fbtft_par *par, void *buf, size_t len);
    	int (*write_vmem)(struct fbtft_par *par, size_t offset, size_t len);
    	void (*write_register)(struct fbtft_par *par, int len, ...);
    
    	void (*set_addr_win)(struct fbtft_par *par,
    			     int xs, int ys, int xe, int ye);
    	void (*reset)(struct fbtft_par *par);
    	void (*mkdirty)(struct fb_info *info, int from, int to);
    	void (*update_display)(struct fbtft_par *par,
    			       unsigned int start_line, unsigned int end_line);
    	int (*init_display)(struct fbtft_par *par);
    	int (*blank)(struct fbtft_par *par, bool on);
    
    	unsigned long (*request_gpios_match)(struct fbtft_par *par,
    					     const struct fbtft_gpio *gpio);
    	int (*request_gpios)(struct fbtft_par *par);
    	int (*verify_gpios)(struct fbtft_par *par);
    
    	void (*register_backlight)(struct fbtft_par *par);
    	void (*unregister_backlight)(struct fbtft_par *par);
    
    	int (*set_var)(struct fbtft_par *par);
    	int (*set_gamma)(struct fbtft_par *par, u32 *curves);
    };
    
    • 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

    函数意义

    函数意义
    write写入接口总线
    read从接口总线读取
    write_vmem将视频内存写入显示
    write_reg写入控制器寄存器
    set_addr_win设置GRAM更新窗口
    reset重置LCD控制器
    mkdirty标记要更新的显示行
    update_display更新显示
    init_display初始化显示
    blank空白显示(可选)
    request_gpios_matchDo pinname to gpio匹配
    request_gpios从内核请求gpios
    free_gpios释放以前请求的gpios
    verify_gpios验证是否存在必要的gpios(可选)
    register_backlight用于注册背光设备(可选)
    unregister_backlight取消注册背光设备(可选)
    set_var使用诸如@rotate和@bgr的变量值配置LCD(可选)
    set_gamma设置gamma曲线(可选)

    框架有四个核心的文件
    fbtft-core.c
    fbtft-bus.c
    fbtft-io.c
    fbtft-sysfs.c
    愿意了解的可以去解读一下。

    总结思路

    使用第三方驱动外设步骤:

    1. 查找关键驱动并启用
    2. 查找相关设备树资料
    3. 修改设备树
    4. 编译更新设备树和内核

    现在的内核驱动库相当丰富,大部分常用的外设都能找到相关的驱动。
    在这里插入图片描述

    结束语

    昨晚一夜没睡好,其实大家心里都憋着一股火气,各种抱怨的声音充斥着微信群,朋友圈。正所谓是爱之深,责之切,不过有些事,并不是头脑一热,就能够干的。处理这些危机,靠的也得是冷静的头脑。
    在这里插入图片描述
    无论是什么统,那都是内部矛盾,最后容易受伤的还是普通人。
    所以要深刻认识到,谁才是真正的坏人。
    不过坏人也干了一件好事,你能去,那我也能去咯,我离得近,还能天天去。日久天长,我就不走了。
    在这里插入图片描述

  • 相关阅读:
    19 视图定义 union 是根据第一个 select 字段列表顺序,来进行 merge 的
    使用feign调用记录日志篇
    springboot集成Quartz定时任务组件
    【OPC UA】基于OpcUaFx的OPC客户端读写KEPServerEx6服务器节点
    劲松中西医医院谭巍主任在线分析:HPV复阳的三大祸首
    Servlet | ServletConfig接口、ServletContext接口详解
    k8s集群离线部署
    微信小程序轮播
    网易有道上线“易魔声” 开源语音合成引擎 用户可免费下载使用
    Rancher安装并部署Kubernetes高可用集群
  • 原文地址:https://blog.csdn.net/baidu_19348579/article/details/126133948