树莓派——linux内核与驱动

树莓派(十一)树莓派驱动开发入门:从读懂框架到自己写驱动(上) 阅读详情

Linux内核基础框架

  • 对内核结构框图有个总体的把握,有助于理解为什么驱动要这样写,为什么写应用程序所用的C库接口(文件、进程、线程、网络等)能够完成相应的功能。

内核结构框图

在这里插入图片描述

名词解释:

  • 【用户程序】:基础C + 函数库

  • 【函数库】:利用linux C库提供的API去支配内核(也可以调用第三方库例如wiringPi库:树莓派的IO库)【是对系统调用接口的封装】

  • 【系统调用接口】:会调用sys_call。linux C库与系统调用接口打交道,系统调用接口是最小功能函数

  • 【虚拟文件VFS接口】:会调用sys_open、sys_read等函数

  • 【硬件】可以分为磁盘或设备,虚拟文件系统会识别用户输入的指令是操作磁盘还是设备,若操作设备还会经过设备驱动程序,设备驱动里面会有硬件控制的代码

  • linux系统内核相当于是超级裸机,直接操作硬件,但会把硬件底层的东西抽象化,对用户来说只需要调API就好了,根本不需要管寄存器,协议,总线…(单片机会去直接操作),这些全部由操作系统做好。

linux系统架构

在这里插入图片描述

  • 为了方便调用内核,Linux将内核的功能接口制作成系统调用(system call)。用户不需要了解内核的复杂结构,就可以使用内核。系统调用是操作系统的最小功能单位。一个操作系统,以及基于操作系统的应用,都不可能实现超越系统调用的功能。

  • 系统调用提供的功能非常庞大,所以使用起来很麻烦。一个简单的给变量分配内存空间的操作,就需要动用多个系统调用。Linux定义一些库函数(library routine)来将系统调用组合成某些常用的功能。上面的分配内存的操作,可以定义成一个库函数,比如常用的malloc。

  • linux中有两百多个系统调用,在命令中输入man 2 syscalls可以查询,2表示在2类(系统调用类)中查询,具体各类是什么可以在man man中查询
    -在这里插入图片描述

  • c库是对系统调用的封装,可以完成进程,线程,网络编程,文件IO等操作【进程、线程、文件IO可以统称“系统编程”】

  • 设备驱动需要使用第三方库,比如wiringPi库,将引脚进行重新配置【wiringPi库中也有线程进程API等,但是不采用】

shell

  • shell(壳)是一个特殊的应用,也经常被称为命令行 。可以理解为是一个命令解释器
  • 一个shell对应一个终端,在终端输入的文本会给shell程序分析,shell程序可以运行库函数或系统调用等
  • 本质就是提供和内核交互的程序

驱动

为什么要学习写驱动

  • 原来树莓派开发使用厂家提供的wiringPi库,开发简单。

  • 但未来做开发时,不一定都是用树莓派,没有wiringPi库可以用。但只要能运行Linux,Linux的标准C库一定有。

  • 学会根据标准C库编写驱动,只要能拿到linux内核源码,拿到芯片手册,电路等就能做开发。

什么是驱动:

  • 驱动就是对底层硬件设备的操作进行封装,并向上层提供函数接口。

硬件设备分类:

linux系统将设备分为3类:字符设备、块设备、网络设备。

  1. 字符设备:指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序。字符设备是面向流的设备常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。
  2. 块设备: 指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。
  3. 网络设备: 网络设备可以是一个硬件设备,如网卡; 但也可以是一个纯粹的软件设备, 比如回环接口(lo).一个网络接口负责发送和接收数据报文。

文件名与设备号

linux一切皆为文件,其设备管理同样是和文件系统紧密结合,各种设备都以文件的形式存放在/dev目录下,称为设备文件

硬件要有相对应的驱动,那么open怎样区分这些硬件对应的驱动程序

  • 依靠文件名(设备名)与设备号

  • 查询设备号:依靠文件名(设备名)与设备号。在/dev下ls -l可以看到
    在这里插入图片描述

对于常用设备

  • Linux有约定俗成的编号,如硬盘的主设备号是3。 一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。

设备号又分为:

  • 主设备号:用于区别不同种类的设备;
  • 次设备号:区别同种类型的多个设备。

设备号的作用:

  • 区分不同种类的设备和不同类型的设备

  • 驱动插入到链表的位置(顺序)由设备号检索

驱动结构框图的认知

在这里插入图片描述

字符驱动代码执行流程:

  1. 应用层调用C库函数open(“/dev/pin4”,O_RDWR);
  2. 触发软中断(系统调用专用,触发cpu异常,中断号是0x80,0x80代表发生了一个系统调用) ,进入系统内核
  3. 内核层中系统调用接口sys_call(汇编语言,执行效率高),通过设备名找到设备号
  4. 内核层中虚拟文件系统 VFS会区分是操作磁盘还是设备,根据设备号调用指定链表节点(驱动程序)内的sys_open ,即在内核的驱动链表里面根据设备名和设备号查找到相关的设备驱动函数(每一个驱动函数是一个节点)
  5. 驱动函数里面有通过寄存器操控IO口的代码,进而可以控制IO口实现相关功能。

注意:

  • 从用户态到内核态会携带参数进入,通过指令携带参数的方式,或在寄存器里面存值
    在这里插入图片描述
    内核根据用户态传递进入的值去判断调用什么函数, sys_call_table 是函数指针数组
    在这里插入图片描述

内核的 sys_open 、sys_read 会做什么?

在这里插入图片描述

驱动程序开发步骤

驱动开发无非以下两件事:

  1. 编写完驱动程序,加载到内核 ,为其添加设备号和设备名、 设备驱动函数
  2. 用户空间open设备名后,调用驱动程序,驱动程序通过操作寄存器来驱动IO口

Linux 内核就是由各种驱动组成的,内核源码中有大约 85%是各种驱动程序的代码。内核中驱动程序种类齐全,可以在同类驱动的基础上进行修改以符合要求的驱动。

编写驱动程序的难点并不是硬件的具体操作,而是弄清楚现有【驱动程序的框架】,在这个框架中加入这个硬件。

一般来说,编写一个 linux 设备驱动程序的大致流程如下:

  • 查看原理图、数据手册,了解设备的操作方法;
  • 在内核中找到相近的驱动程序,以它为模板进行开发,有时候需要从零开始;
  • 实现驱动程序的初始化:比如向内核注册这个驱动程序,这样应用程序传入文件名时,内核才能找到相应的驱动程序;
  • 设计所要实现的操作,比如 open、close、read、write 等函数;
  • 实现中断服务(中断并不是每个设备驱动所必须的);
  • 编译该驱动程序到内核中,或者用 insmod 命令加载;
  • 测试驱动程序;

字符设备驱动

下面就以一个简单的字符设备驱动框架代码来进行驱动程序的开发、编译等。

基于驱动框架的代码开发【不涉及硬件操作】

上层调用代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
void main()
{
   
   
        int fd,data;
        fd = open("/dev/pin4",O_RDWR);
        if(fd<0){
   
   
                printf("open fail\n");
                perror("reson:");
        }
        else{
   
   
                printf("open success\n");
        }
        data = write(fd,'1',1);
}

驱动框架代码

#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  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件
 
//确定主设备、变量定义
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";   //模块名
 
//led_open函数
stat
树莓派(五)驱动开发 常见字符设备有鼠标、键盘、串口、控制台等。常见的块设备有各种硬盘、flash磁盘、RAM磁盘等。在Linux里一个网络设备也可以叫做一个网络接口,如eth0,应用程序是通过Socket而不是设备节点来访问网络设备,在系统里根本就不存在网络设备节点。网络接口没有像字符设备和块设备一样的设备号,只有一个唯一的名字,如eth0、eth1等,而这个名字也不需要设备文件节点对应。 阅读详情

相关推荐

详细到吐血 —— 树莓派驱动开发入门:从读懂框架到自己写驱动

师承陈立臣 目录驱动初步认知为什么要学会写驱动?主设备号次设备号从open到电灯,从上层到底层,经历了什么? 驱动初步认知 为什么要学会写驱动? c标准库时一定有的,而wiringPi库不一定有。树莓派开发简单是因为有库,实现超声波,实现继电器操作,做灯的点亮 未来换一块板子,不用树莓派,只要能拿到linux内核源码,拿到芯片手册,电路图 主设备号次设备号 一切皆为文件 cd /dev open为什么能够区分是鼠标,键盘,还是屏幕?文件名,设备号ls -l 10,235 10.234 设备节点,主设备号

华天朱 1万+

超详细--树莓派基于Linux内核驱动入门开发(从会读到会写)

驱动是为了操作IO口,实现自己的wiringpi库,跟硬件打交道。弄清楚寄存器的分组其中寄存器的0表示的是分组,目标操作的IO是pin4,由文档可知,属于寄存器分组0。volatile的使用加volatile作用是 : 1、防止编译器优化(你给的这个地址编译器可能认为不好,可能会省略,也可能会进行更改)这些寄存器变量;2、要求每次直接从寄存器里读值。由于随着程序的执行,会改变寄存器当中的数据,而读取的都是内存里面的备份数据,数据的时效性没有那么强,读的可能是一个老数据。

番茄的博客 6830

Linux驱动开发(四)---树莓派内核编译

树莓派上搭建驱动开发环境

小人物的编程 3021

树莓派基于Linux内核驱动开发入门指南

驱动是为了操作IO口,实现自己的wiringpi库,跟硬件打交道。

m0_51430584的博客 5288

树莓派基于Linux内核驱动开发

一、驱动认知 1.1 为什么要学习写驱动 树莓派开发简单是因为有厂家提供的wiringPi库,实现超声波,实现继电器操作,做灯的点亮…都非常简单。 但未来做开发时,不一定都是用树莓派,则没有wiringPi库可以用。但只要能运行Linuxlinux的标准C库一定有。 学会根据标准C库编写驱动,只要能拿到linux内核源码,拿到芯片手册,电路图…就能做开发。 用树莓派学习的目的不仅是为是体验其强大便捷的wiringPi库,更要通过树莓派学会linux内核开发,驱动编写等,做一个属于自己的库。 1.2 文件名

m0_52986396的博客 1819

树莓派基于Linux内核驱动开发详解

目录一、驱动认知为什么要学习写驱动文件名设备号open函数打通上层到底层硬件的详细过程二、基于框架编写驱动代码三、驱动代码编译和测试四、三种地址介绍五、IO口操控代码编程 一、驱动认知 为什么要学习写驱动 树莓派开发简单是因为有厂家提供的wiringPi库,实现超声波,实现继电器操作,做灯的点亮…都非常简单。 但未来做开发时,不一定都是用树莓派,则没有wiringPi库可以用。但只要能运行Linuxlinux的标准C库一定有。 学会根据标准C库编写驱动,只要能拿到linux内核源码,拿到芯片手册,电

zhuguanlin121的博客 5064

树莓派基础之Linux内核驱动认知

驱动代码编写:把驱动代码拷贝至 driver/char修改Makefile ,告诉编译器,要编译该驱动文件,驱动代码文件放在哪个目录下就修改哪个目录下的Makefile文件内核驱动装载:内核驱动卸载:sodu rmmod xxx 不需要写ko查看内核模块:lsmod装载驱动驱动装载后生成设备,比如:/dev/pin4,通过sudo chmod 666 /dev/pin4 添加访问权限运行测试程序pin4text调用驱动

weixin_55374007的博客 450

Linux内核驱动基础框架(在树莓派中运行)

Linux内核驱动基础框架(在树莓派中运行) ==首先要有一个驱动的框架,然后再有一个可执行驱动框架的程序。== 一、首先自己写一个驱动的框架以模块的形式模块的形式(在Linux中写一个框架名为pin4drver2.c) 1.驱动框架的代码如下: #include <linux/fs.h> #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #inclu

weixin_47932709的博客 888

Linux内核驱动入门-编译树莓派内核

内核驱动内核版本号之间是强相关的,因为编译内核模块的时候,需要基于内核源码来编译 假设我们自己编译一个属于自己的树莓派内核,根据官方的内核来进行更改。 将官方的内核解压到虚拟机上,最好放在根目录的work下,要不然会空间不足 //安装工具 sudo apt-get install git bison flex libssl-dev //安装配置内核menuconfig的辅助工具 sudo a...

weixin_44263604的博客 899

实现树莓派基于Linux内核驱动GPIO

首先理解树莓派基于Linux内核驱动流程和框架 树莓派基于Linux内核驱动开发详解 一、树莓派基于Linux内核驱动GPIO前提工作 树莓派能够执行自己做好的设备文件(设备文件由驱动加载得到),那我们就可以往驱动里加入对GPIO操作,实现点灯,PWM,I2C,SPI等等 对GPIO操作,那我们就需要有芯片手册、板子的电路图。对树莓派来讲,芯片手册已经写的足够详细了 所以没用到电路图。 我们要点灯,所以要看芯片手册的点灯寄存器,有 GPFSEL0寄存器(设置GPIO模式) GPSET0寄存器(GPIO置1

weixin_46691155的博客 1224

Linux内核模块:树莓派LED驱动程序开发

Linux内核作为操作系统的核心,负责管理系统资源和设备。其架构包括进程调度、内存管理、文件系统、网络功能以及硬件设备通信的接口。在硬件通信方面,内核通过提供驱动程序接口(Driver API),实现外部硬件的交互。这种方式能够有效地抽象硬件细节,使得硬件操作更加系统化和标准化。树莓派是一款基于ARM处理器设计的小巧电脑,其硬件架构集成了处理器、内存、外设接口等多种功能。最常见的是树莓派4B模型,它搭载了ARM Cortex-A72处理器,具备4个主核心,主频高达1.5GHz。

weixin_42590539的博客 984

树莓派Linux内核编译、文件系统、Linux内核驱动基础框架、驱动测试步骤、总线地址

树莓派高阶开发课程 1. ubuntu18.04版本安装 让程序猿搭建环境太搞笑了,轻松easy! ========================================================================= 2. 树莓派等芯片带操作系统的启动过程 C51,STM32(裸机)》》》》》》C直接操控底层寄存器实现相关业务。 业务流程型的裸机代码 遥控灯: while(1) ...

weixin_57301742的博客 325

linux系统-树莓派内核驱动

树莓派驱动编辑驱动模块概述用户空间APP应用层C library & C库内核空间硬件 驱动模块概述 用户空间 linux 一切皆文件 设备文件: 鼠标、键盘、LED、屏幕、Flash、内存、网卡 对于文件的API的控制有:open、read、write 这些API能打开不同硬件设备,并控制,是因为不同设备有不同的设备驱动 编辑设备驱动就只有两个功能: 1、添加驱动 设备名 设备号 设备驱动函数 操作寄存器来驱动IO口 2、调用驱动 驱动实现路径: 用户层:open(”/dev/pin4

Yangyingchungood的博客 373

树莓派Linux驱动开发:从内核模块到GPIO实战指南

Linux设备驱动是操作系统内核的核心组件,负责在硬件设备软件系统之间建立通信桥梁。其工作原理是通过实现标准接口函数,将应用程序的抽象请求转换为具体的硬件操作指令。在嵌入式开发领域,掌握驱动开发技术具有重要价值,能够实现对硬件资源的精细控制和性能优化。特别是在树莓派这样的开源硬件平台上,驱动开发广泛应用于GPIO控制、传感器数据采集、外设通信等物联网和嵌入式场景。内核模块作为驱动的动态加载形式,提供了开发效率和灵活性的优势,而设备树机制则解决了硬件描述标准化的问题。本文基于树莓派平台,系统讲解从环境搭建、

weixin_30509393的博客 415

实战指南:树莓派Linux内核GPIO驱动开发从零到精通

本文提供了一份从零开始的树莓派Linux内核GPIO驱动开发实战指南。通过剖析驱动框架、地址映射(ioremap)和寄存器操作等核心概念,手把手教你编写一个完整的字符设备驱动,实现从用户空间到硬件(GPIO)的完整控制,帮助开发者深入理解Linux驱动模型并掌握底层硬件操作能力。

weixin_28278377的博客 336

树莓派Linux驱动开发实战:从内核模块到GPIO/PWM应用

Linux设备驱动是操作系统内核的核心组件,负责硬件设备用户空间应用程序之间的通信桥梁。其工作原理基于模块化机制,通过系统调用接口将应用层请求转换为具体的硬件操作指令。在嵌入式开发领域,驱动技术的价值在于实现对各种外设的精准控制,为物联网、智能硬件等应用场景提供底层支持。树莓派作为嵌入式Linux开发的理想平台,其丰富的GPIO接口和完整的生态体系使得驱动开发学习更加直观高效。通过GPIO控制、PWM调光等实战案例,开发者可以深入理解字符设备驱动的工作机制,掌握内核模块编译、设备树配置等关键技能。本文基于

weixin_34417200的博客 491
上一篇: 树莓派——linux文件系统、文件系统结构、虚拟文件系统
下一篇: 树莓派——总线地址、物理地址、虚拟地址
Is Fang
博客等级 码龄7年 773粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值