树莓派驱动编译

news2025/2/26 11:40:26

        驱动编译前提:驱动代码的编译需要提前编译号的内核

驱动(3种实现方法,2条路线)_驱动编写三种方法-CSDN博客

驱动的编写_驱动编写-CSDN博客

一、概念

1.1、驱动认识
        1、裸机程序中是直接操控硬件的,操作系统中必须通过驱动来操控硬件。这两个的本质区别就是分层
        2、linux驱动本身做了模块化设计,linux驱动本身和linux内核不是强耦合的
        3、驱动的设计中有一个关键数据结构(结构体),结构体中包含一些变量和一些函数指针
                变量用来记录驱动相关的一些属性,函数指针用来记录驱动相关的操作方法
                这些变量和函数指针加起来就构成了驱动。驱动就被抽象为这个结构体
        4、一个驱动工作时主要就分几部分:驱动构建(构建一个struct mmc然后填充它)
                驱动运行时(调用这些函数指针指针的函数和变量)
        5、分离思想
                分离思想就是说在驱动中将操作方法和数据分开
                操作方法就是函数,数据就是变量
                在不同的地方来存储和管理驱动的操作方法和变量,这样的优势就是驱动便于移植。
        6、分层思想
                分层思想是指一个整个的驱动分为好多个层次
                简单理解就是驱动分为很多个源文件,放在很多个文件夹中

1.2、什么是驱动

        1、设备和用户之间的桥梁,内核结构由用户级,内核级,硬件级

        2、驱动,操作硬件部分代码

1.3、驱动分为3种,及区别

        1、字符设备,以字节为单位读写串口,led等        

        2、块设备,以块为单位读写,sd卡等

        3、网络设备,网卡,socket等

1.4、模块化

        1、宏内核:操作系统是整体,紧耦合,直接调用函数,简单高效

                微内核:相当于是多个进程,一个错误不会影响其他,Windows

        2、静态模块化:程序编译内核,编译时可裁剪,加模块要重新编译烧录

                动态模块化:加模块,不需要重新编译

1.5、安全性

        1、驱动程序崩溃,内核可能崩溃

        2、驱动效率影响内核效率

        3、安全,漏洞
                未初始化,例如函数指针
                恶意用户程序,利用驱动的漏洞,例如传参
                缓冲区溢出,例如超出缓存区大小
                竞争状态,自旋锁等

1.6、应用驱动硬件的流程

        APP------>调用C库种(open,write,read)等函数产生软中断(中断号0x80),从用户空间进入到内核空间--------->sys_call函数根据驱动被设备名去找到设备号---------->虚拟文件系统VAFS(sys_open,sys_write)去找相应驱动引脚的驱动文件open------------->驱动文件open直接操作寄存器

1.7、设备文件

        1、各种设备以文件的形式存放在**/dev目录,称设备文件**

        2、主设备号,次设备号

                1、主设备号:不同的设备(硬盘,led)

                2、次设备号:同一类的多个设备(led1,led2)

1.8、驱动链表,数组        (驱动插入链表的顺序由设备号检索)

        1、管理所有设备的驱动

        2、添加(驱动插入链表顺序由设备号检索)
                编写驱动,加载到内核
                设备名,设备号,设备驱动函数:操作寄存器来驱动I/O

        3、查找 调用
                调用驱动程序,用户应用去open

1.9、

1.9、udev机制
        1、udev是一个设备管理工具,udev以守护进程的形式运行
        2、通过侦听内核发出来的uevent来管理/dev目录下的设备文件。
        3、udev在用户空间运行,而不在内核空间运行。
        4、它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。
        5、udev会根据/etc/udev/udev.conf文件中的udev_rules指定的目录,逐个检查该目录下的

                文件,这个目录下的文件都是针对某类或某个设备应该施行什么措施的规则文件。

二、实现一个驱动代码

        1、添加驱动需要什么

                1、设备名

                2、设备号

                3、驱动代码

        2、假设树莓派dev目录下已经存在了一个 pin4的驱动

                应用层访问/dev/pin4驱动代码           

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <stdio.h>

int main()
{
        int fd;
        char ch = '1';

        fd = open("/dev/pin4" ,O_RDWR);
        if (-1 == fd)
        {
                perror("erron");
                printf("open failed!\n");
        }
        else
        {
                printf("open success\n");
        }

        fd = write(fd , (void *)&ch ,1);

        return 0;
}

                3、写一个字符设备驱动

                        因为驱动程序是通过驱动链表进行添加的,首先开发需要拿到固定驱动框架,下面是一个字符驱动框架

#include <linux/fs.h>                    //file_operations声明
#include <linux/module.h>                //module_init module_exit声明
#include <linux/init.h>                  //__init __exit 宏定义声明
#include <linux/device.h>                //class device声明
#include <linux/uaccess.h>               //copy_from_user的头文件
#include <linux/types.h>                 //设备号 dev_t 类型声明
#include <asm/io.h>                      //iorsemap iorsemap的头文件

static struct class *pin4_class;
static struct device *pin4_class_dev;

static dev_t devno;                      //设备号
static int major=231;                     //主设备号
static int minor = 0;                    //次设备号
static char *module_name = "pin4";       //模块名

static ssize_t pin4_read(struct file *file ,char __user *buf,size_t size ,loff_t *ppos)
{
    printk("pin4_read\n");
    return 0;
}

// led_open函数
static int pin4_open(struct inode *inode, struct file *file)
{
    printk("pin4_open\n");  //内和打印函数和printf差不多,可以用dmesg命令查看内核的打印
    return 0;
}

//led_write函数
static ssize_t pin4_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
    printk("pin4_write\n");
    return 0;
}

//    这个结构结构体会被注册进驱动链表
static struct file_operations pin4_fops ={    
      .owner = THIS_MODULE,

      //将对应的函数关联在file_operations的结构体中
      .open  = pin4_open,
      .write = pin4_write,
      .read  = pin4_read,
};



int __init pin4_drv_init(void)       //真实驱动入口
{  
       int ret;
       devno = MKDEV(major,minor);      //创建设备号
       ret = register_chrdev(major, module_name, &pin4_fops);  //注册驱动,告诉内核 把这个驱动加到内核的链表中

       pin4_class = class_create( THIS_MODULE,"myfirstdemo");   //让代码在dev自动生成设备  
       pin4_class_dev = device_create(pin4_class,NULL,devno,NULL,module_name);//创建设备文件


       return 0;
}

void __exit pin4_drv_exit(void)
{
	device_destroy(pin4_class,devno);
	class_destroy(pin4_class);
	unregister_chrdev(major,module_name);   //卸载驱动

}

module_init(pin4_drv_init);     // 入口,内核加载该驱动的时候,这个宏会被调用
module_exit(pin4_drv_exit);     
MODULE_LICENSE("GPL v2");

        3、对驱动代码进行编译(驱动可以编译成模块或编译进内核)

        把写的驱动代码复制到下载的Linux源码文件里的drviers/char字符驱动设备下

        更改Makefile文件                将驱动编译成模块

        编译驱动代码

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules

         交叉编译调用该驱动的应用层文件,并将驱动模块文件和应用层文件都考入树莓派

        加载内核驱动

sudo insmod pin4drivers.ko

lsmod       //这个命令可以查看内核驱动模块
rmmod       //删除驱动模块  例:rmmod pin4drivers  

         运行驱动测试代码

    sudo ~/pin4test

    dmesg  查看内核打印的信息

        应用层调用驱动

         引用层open通过文件名找到驱动的设备号————>产生软中断,调用sys_call————>调用虚拟文件系统的sys_open通过设备号去驱动链表找到相应的硬件驱动文件————>执行驱动文件里面的open。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1477405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文笔记】Attention Is All You Need

【论文笔记】Attention Is All You Need 文章目录 【论文笔记】Attention Is All You NeedAbstract1 Introduction2 Background补充知识&#xff1a;软注意力 soft attention 和硬注意力 hard attention&#xff1f;补充知识&#xff1a;加法注意力机制和点乘注意力机制Extende…

JavaScript的书写方式

JavaScript的书写方式 目前较为流行的是第二种和第三种&#xff0c;第一种很少见。在第二种和第三种推荐使用第三种&#xff0c;因为在日常开发/工作中&#xff0c;第三种是最为常见的 1.行内式 把JS代码嵌入到html元素内部 示例代码 运行效果 由于JS中字符串常量可以使用单引…

如何让电脑待机而wifi不关的操作方法!!

1、一台电脑如果一天不关机&#xff0c;大约消耗0.3度电。 一般一台电脑的功耗约为250-400W&#xff08;台式机&#xff09;。 一台电脑每月的耗电量&#xff1a;如果是每小时300W每天10小时每月30天90KW&#xff0c;即90千瓦时的电。 这只是保守估计。 2、使用完毕后正常关闭…

微调(Fine-tuning)技术概念

——微调&#xff0c;像化妆&#xff0c;一种“精细化、风格性调整”的人工美颜技能。 微调&#xff08;Fine-tuning&#xff09;是指在深度学习领域中&#xff0c;特别是针对预训练模型的一种训练策略。预先训练好的模型通常是在大规模无标注数据上通过自监督学习得到的&#…

Python股票数据,指数月线涨跌幅回测系统

1.这是我用Python写的&#xff0c;目前无法给大家直接使用exe&#xff0c;因为编译后软件不能正常使用。但是py源码可以先开源&#xff0c;给大家学习一下&#xff0c;里面的代码&#xff0c;都有我的注释&#xff0c;需要你有编程基础就可以看懂&#xff0c;自己可以在这个基础…

nginx(三)实现反向代理客户端 IP透传

正常情况下&#xff0c;客户端去访问代理服务器&#xff0c;然后代理服务器再取访问真实服务器&#xff0c;在真实服务器上&#xff0c;只能显示代理服务器的ip地址&#xff0c;而不显示客户端的ip地址&#xff0c;如果想让客户端的ip地址也能在真实服务端看见&#xff0c;这一…

程序员缺乏经验的 7 种表现!

程序员缺乏经验的 7 种表现&#xff01; 一次性提交大量代码 代码写的很烂 同时开展多项工作 性格傲慢 不能从之前的错误中学到经验 工作时间处理私人事务 盲目追逐技术潮流 知道这些表现&#xff0c;你才能在自己的程序员职业生涯中不犯相同的错误。 软件行业的工作经…

FastAPI框架整理

文章目录 一、Starlette、Pydanatic与FastAPI的关系1.Starlette1.1ASGI框架 2.Pydantic2.1基础教程1.定义接受实体2.请求参数3.可以安装插件辅助数据定义和矫正4.处理校验失败的例子5.模型的属性和方法6.解析文件7.递归模型8.ORM模型&#xff1a;从类实例创建符合ORM对象的模型…

FPGA高端项目:FPGA基于GS2971的SDI视频接收转HDMI输出,提供3套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI图像缩放应用本方案的SDI纯verilog图像缩放视频拼接应用本方案的SDI HLS图像缩放视频拼接应用本方案的SDI视频编码动态字符叠加输出应用本方案的SDI视频编码多路视频融合视频叠加应用本方案的SDI视频…

追踪Jira中项目成本与工时,更符合国人使用习惯——TimeWise工时管理

近日&#xff0c;龙智联合Atlassian举办的DevSecOps研讨会年终专场“趋势展望与实战探讨&#xff1a;如何打好DevOps基础、赋能创新”在上海圆满落幕。龙智Atlassian技术与顾问咨询团队&#xff0c;以及清晖、JamaSoftware、CloudBees等生态伙伴的嘉宾发表了主题演讲&#xff0…

opencv中的rgb转gray的计算方法

转换原理 在opencv中&#xff0c;可以使用cv2.cvtColor函数将rgb图像转换为gray图像。示例代码如下&#xff0c; import cv2img_path "image.jpg" image cv2.imread(img_path) gray_image cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) mean gray_image.mean() pri…

Transformer之Residuals Decoder

The Residuals 我们需要提到的编码器架构中的一个细节是&#xff0c;每个编码器中的每个子层(self-attention,&#xff0c;ffnn)周围都有一个残余连接&#xff0c;然后是 layer-normalization 步骤。 如果我们要可视化向量和与 self attention 相关的 layer-norm 运算&#x…

计算机专业大学四年应该如何规划(Java方向)

计算机专业的学生&#xff0c;如何在大学四年内提高自己的竞争力&#xff0c;毕业之后直接进大厂工作&#xff1f; 以下将从大学四年计算机专业的学习规划、课程设置、能力提升、参考书籍等方面&#xff0c;为同学们提供一些建议和指导。 大一&#xff1a; 主攻技能学习并且达…

Excel中使用ROW函数自动更新行号或编号

操作步骤&#xff1a; 1、在编号“1”的单元格输入公式“ROW()-1”&#xff1b; 2、在上一步填好公式的单元格基础上下拉填充&#xff0c;即可批量得到编号&#xff0c;如果删掉其中的一行或几行&#xff0c;编号会自动进行更新。

nginx 日志,压缩,https功能介绍

一&#xff0c; 自定义访问日志 &#xff08;一&#xff09;日志位置存放 1&#xff0c;格式 2&#xff0c; 级别 level: debug, info, notice, warn, error, crit, alert, emerg 3&#xff0c;示例 服务机定义 错误日志存放位置 客户机错误访问 查看错误日志 4&#xff…

[云原生] k8s之pod容器

一、pod的相关知识 1.1 Pod基础概念 Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的&#xff0c;例如&#xff0c;用于管理…

虚拟机安装+固定ip地址

一、下载CentOS 二、安装CentOS 1、打开你的VMware Workstation Pro&#xff0c;并点击“创建新的虚拟机” 2、点选典型(推荐)(T)&#xff0c;并点击“下一步” 3、点选稍后安装操作系统(S)&#xff0c;并点击“下一步” 4、点选Linux&#xff0c;并点击“下一步” 6、点击“…

【探索AI】十一 深度学习之第1周:深度学习概述与基础

深度学习概述与基础 深度学习的发展历史与现状神经网络的基本原理前向传播与反向传播算法常见的激活函数与优化算法深度学习框架&#xff08;如TensorFlow或PyTorch&#xff09;进行基础操作 深度学习的发展历史与现状 深度学习的发展历史可以追溯到上世纪40年代&#xff0c;当…

java上机编程题面试,记一次美团Java研发岗的面试经历

第一篇&#xff1a;SpringBoot面试篇 1.1 35常见SpringBoot知识点 问题一&#xff1a;Spring Boot、Spring MVC 和 Spring 有什么区别&#xff1f; 问题二&#xff1a;什么是自动配置&#xff1f; 问题三&#xff1a;什么是 Spring Boot Stater &#xff1f; 问题四&#x…

uniapp生成app包引导用户开启通知权限和热更新

uniapp生成app包引导用户开启通知权限和热更新 引导用户开启通知权限 export function setPermissions() {// #ifdef APP-PLUS if (plus.os.name Android) {var main plus.android.runtimeMainActivity();var pkName main.getPackageName();var uid main.getApplicationI…