嵌入式LINUX驱动开发入门之hello驱动(基于IMX6ULL-MINI开发板)

1.驱动前提

编译驱动程序之前要编译内核,原因主要是:

(1)驱动程序要用到内核文件:

比如驱动程序中这样包含头文件: #include <asm/io.h>, 其中的asm是一个链接文件,指向asm-arm或asm-mips,这需要先配置、编译内核才会生成asm这个链接文件。

(2)编译驱动时用的内核,开发板上运行到内核,要一致:

开发板上运行到内核是出厂时烧录的,你编译驱动时用的内核是你自己编译的,这两个内核不一致时会导致- -些问题。所以我们编译驱动程序前,要把自己编译出来到内核放到板子上去,替代原来的内核。

(3)更换板子上的内核之后,板子上的其他驱动也要更换

板子使用新编译出来的内核时,板子上原来的其他驱动也要更换为新编译出来的。所以在编译我们自己的第1个驱动程序之前,要先编译内核、模块,并且放到板子上去。

2.编译内核

首先切换到内核所在目录

cd /home/xxl/100ask_imx6ull_mini-sdk/Linux-4.9.88

之后进行下面的操作

make mrproper
make 100ask_imx6ull_mini_defconfig
make zImage -j4

编译后生成的文件如下:

然后进行下面操作,也就是

在arch/arm/boot/dts 目 录 下 生 成 设 备 树 的 二 进 制 文 件 100ask_imx6ull_mini.dtb 。把这 2 文件复制到 /home/book/nfs_rootfs 录下备用
make dtbs
cp arch/arm/boot/zImage ~/nfs_rootfs
cp arch/arm/boot/dts/100ask_imx6ull_mini.dtb ~/nfs_rootfs

3.编译安装内核模块

3.1编译内核模块

首先进入内核源码目录,编译内核模块

cd /home/xxl/100ask_imx6ull_mini-sdk/Linux-4.9.88

 然后输入下面的指令,编译完成如下图

make modules

 

 3.2安装内核模块到Ubuntu某个目录下面备用

可以先把内核模块安装到 nfs 目录 (/home/book/nfs_rootfs)
然后:
cd /home/xxl/100ask_imx6ull_mini-sdk/Linux-4.9.88

 然后执行

make ARCH=arm INSTALL_MOD_PATH=/home/xxl/nfs_rootfs modules_install

 安装好如下图所示:

 4.安装内核和模块到开发板上面

假设:在Ubuntu的/home/book/nfs_ _rootfs 目录下,已经有了zImage、dtb文件,并且有1ib/modules子目录(里面含有各种模块)。

接下来要把这些文件复制到开发板上。假设Ubuntu IP 为192.168.5.11, .在开发板上执行以下命令,首先进行挂载,挂载之前记得先检查是否可以“ping 192.168.5.11”可以通顺然后是每次重启开发板之后都要进行这个挂载操作

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/xxl/nfs_rootfs /mnt

然后执行:

cp /mnt/zImage /boot
cp /mnt/100ask_imx6ull_mini.dtb /root
cp /mnt/lib/modules /lib -rfd
sync

最后重启开发板之后,就可以使用zImage、dtb模块了

5.hello驱动

5.1驱动入门知识

1.首先我们通常都是在Linux的终端上打开一个可执行文件,然后可执行文件就会执行程序。那么这个可执行文件做了什么呢?

2.可执行文件先是在应用层读取程序,其中会有很多库函数,库函数是属于内核之中。而内核又会往下调用驱动层程序。最终驱动层控制具体硬件。

    其实应用程序到库是比较容易理解的,比如我们刚学习C语言的时候,使用了printf,scanf等等这些函数。而这些函数就在库中。
    库可以和系统内核相连接,我们写了一个驱动程序,就需要告诉内核,这个过程叫做注册。我们注册了驱动之后,内核里面就会有这个驱动程序的信息,然后上层应用就可以调用。

3.所以我们只需要知道,需要编写两个程序,一个是驱动层的,一个是应用层的最后驱动层需要注册进入内核,应用层才能够使用。其他的先不要管。

4.我们在应用层调用read函数,对应驱动层的read函数。write函数和write函数对应。open函数和open函数对应。close函数和release函数对应(这个为什么不一样我们也不用管)。

5.我们对 Linux 应用程序对驱动程序的调用流程有一个简单了解之后,我得知道整个程序编写流程应该怎么做。至于流程为什么是这样的,我们记住即可。因为这些都是人规定的,如果之后学的深了再进行深究也不迟,现在我们主要是入门。

5.2整体框架和步骤

1.整体框架流程图

编写驱动主要为以下七个步骤:

  1.     确定主设备号,也可以让内核分配
  2.     定义自己的 file_operations 结构体
  3.     实现对应的 drv_open/drv_read/drv_write 等函数,填入 file operations 结构体
  4.     把 file_operations 结构体告诉内核: register_chrdev
  5.     谁来注册驱动程序啊? 得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
  6.     有入口函数就应该有出口函数: 卸载驱动程序时,出口函数调用unregister_chrdev
  7.     其他完善:提供设备信息,自动创建设备节点: class_create,device_create

5.3hello程序的实现

主要包括三个部分,驱动程序,测试程序,MakeFile文件

(1)驱动程序-hello_drv.c

#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>/*确定主设备号*/
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;#define MIN(a,b)(a<b?a:b)/*3.实现对应的open/read/write等函数,填入
file_operations结构体*/
//read
static ssize_t hello_drv_read(struct file *file,char _user *buf,
size_t size,loff_t *offset)
{int err;printk("s line %d\n",_FILE_,_FUNCTION_,_LINE_);err = copy_to_user(buf,kernel_buf,MIN(1024,size));return MIN(1024,size);
}
//write
static ssize_t hello_drv_write(struct file *file,const char _user *buf,
size_t size,loff_t *offset)
{int err;printk("%s %s line %d\n",_FILE_,_FUNCTION_,_LINE_);err = copy_from_user(kernel_buf,buf,MIN(1024,size));return MIN(1024,size);
}
//open
static int hello_drv_open(struct inode *node,struct file *file)
{printk("%s %s line %d\n",_FILE_,_FUNCTION_,_LINE_);return 0;
}
//close
static int hello_drv_open(struct inode *node,struct file *file)
{printk("%s %s line %d\n",_FILE_,_FUNCTION_,_LINE_);return 0;
}/*2.定义自己的file_operations结构体*/
static struct file_operations hello_drv={.owner = THIS_MODULE,.open = hello_drv_open,.read = hello_drv_read,.write = hello_drv_write,.release = hello_drv_close,
};/*4.将file_operations结构体告诉内核:注册驱动程序*/
/*5.需要入口函数,也就是注册驱动程序,安装驱动程序时
就会去调用这个入口函数*/
static int __init hello_init(void)
{int err;printk("%s %s line %d\n",_FILE_,_FUNCTION_,_LINE_);major = register_hrdev(0,"hello",&hello_drv); /*/dev/hello*/hello_class = class_create(THIS_MODULE,"hello_class");err = PTR_ERR(hello_class);if(IS_ERR(hello_class)){printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);unregister_chrdev(major,"hello");return -1;}device_create(hello_class,NULL,MKDEV(major,0),NULL,"hello");/*/dev/hel*/return 0;
}/*6.出口函数,卸载驱动程序时就会调用这个出口函数*/
static void __exit hello_exit(void)
{printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);device_destroy(hello_class,MKDEV(major,0));class_destroy(hello_class);unregister_chrdev(major,"hello");
}/*7.其他完善:提供设备信息,自动创建设备节点*/module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");

(2)测试程序-hello_drv_test.c

//编写测试程序,实现读写功能#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>int main(int argc,char **argv)
{int fd;char buf[1024];int len;/*1.判断参数*/if(argc < 2){printf("Usage: %s -w <string>\n",argv[0]);printf("   %s -r\n",argv[0]);return -1;}/*2.打开文件*/fd = open("/dev/hello",O_RDWR);if(fd == -1){printf("can not open file /dev/hello\n");return -1;}/*3.写文件或者读文件*/if((strcmp(argv[1],"-w"))&&(argc == 3)){len = strlen(argv[2]) +1;len = len < 1024 ? len:1024;write(fd,argv[2],len);}else {len = read(fd,buf,1024);buf[1023] = "\0";printf("App read : %s\n",buf);}close(fd);return 0;
}

(3)Makefile文件

  1 2 # 1. 使用不同的开发板内核时, 一定要修改KERN_DIR3 # 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:4 # 2.1 ARCH,          比如: export ARCH=arm645 # 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-6 # 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc    /ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 7 # 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,8 #       请参考各开发板的高级用户使用手册9 10 KERN_DIR = /home/xxl/100ask_imx6ull_mini-sdk/Linux-4.9.8811 12 all:13     make -C $(KERN_DIR) M=`pwd` modules 14     $(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c 15 16 clean:17     make -C $(KERN_DIR) M=`pwd` modules clean18     rm -rf modules.order19     rm -f hello_drv_test20 21 obj-m   += hello_drv.o

 在make之前要进行以下的检查

也就是对环境变量进行检查(这里以IMX6ULL-MINI为例)

vim ~/.bashrc

在最后三行添加上

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/xxl/100ask_imx6ull_mini-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin

然后输入下面指令确保生效

source ~/.bashrc

然后就可以输入make进行编译

生成如下:

将这两个文件移动到UBUNTU的挂载目录下

cp *.o hello_drv_test /home/xxl/nfs_rootfs

这时候在开发板进行如下操作

挂载操作

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/xxl/nfs_rootfs /mnt

 然后进行下面的操作即可:

 

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

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

相关文章

ZooKeeper 的典型应用场景:从概念到实践

引言 在分布式系统的生态中&#xff0c;ZooKeeper 作为一个协调服务框架&#xff0c;扮演着至关重要的角色。它的设计目的是提供一个简单高效的解决方案来处理分布式系统中常见的协调问题。本文将详细探讨 ZooKeeper 的典型应用场景&#xff0c;包括但不限于配置管理、命名服务…

chrome-mojo C++ Bindings API

概述 Mojo C 绑定 API 利用C 系统 API提供一组更自然的原语&#xff0c;用于通过 Mojo 消息管道进行通信。结合从Mojom IDL 和绑定生成器生成的代码&#xff0c;用户可以轻松地跨任意进程内和进程间边界连接接口客户端和实现。 本文档通过示例代码片段提供了绑定 API 用法的详…

centos 8和centos 9 stream x64的区别

以下是 CentOS 8 与 CentOS Stream 9 的主要区别&#xff0c;从技术架构、更新策略到适用场景等维度进行对比&#xff1a; AI产品独立开发实战营 联系我了解 1. 定位与更新策略 特性CentOS 8CentOS Stream 9定位原为 RHEL 8 的免费稳定复刻版RHEL 9 的上游开发分支&#xff…

物联网软件开发与应用方向应该怎样学习,学习哪些内容,就业方向是怎样?(文末领取整套学习视频,课件)物联网硬件开发与嵌入式系统

随着物联网技术的飞速发展&#xff0c;物联网软件开发与应用方向成为了众多开发者关注的焦点。那么&#xff0c;如何在这个领域中脱颖而出呢&#xff1f;本文将为你提供一份详细的学习指南&#xff0c;帮助你从零开始&#xff0c;逐步掌握物联网软件开发与应用的核心技能。 一…

DeepSeek之于心理学的一点思考

模型和硬件参数对应关系参考 模型参数规模 典型用途 CPU建议 GPU建议 最小内存建议 磁盘空间建议 适用场景 1.5b(15亿) 小型推理、轻量级任务 4核以上(Intel i5/AMD Ryzen5) 可选&#xff0c;入门级GPU(如NVIDIA GTX1650 4GB显存) 8GB 10GB以上SSD 小型NLP任务、文…

常见的前端框架和库有哪些

1. React 描述&#xff1a;由 Facebook 开发的一个 JavaScript 库&#xff0c;用于构建用户界面&#xff0c;尤其是单页面应用&#xff08;SPA&#xff09;。特点&#xff1a; 基于组件的架构&#xff0c;便于重用 UI 组件。使用虚拟 DOM 提升性能。容易与其他库和框架集成。 …

【GIS】本地部署nominatim地理编码服务

参考&#xff1a;https://www.cnblogs.com/nonkicat/p/17222677.html docker 部署命令 4.5 版本 docker 用不了&#xff0c;需要用 4.0 版本 docker run -it -e PBF_PATH/data/你的osm文件.osm.pbf -e FREEZEtrue -e POSTGRES_MAX_CONNECTIONS100 -p 6666:8080 --…

DeepSeek 助力 Vue 开发:打造丝滑的步骤条

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

【用Deepseek搭建免费的个人知识库--综合教程(完整版)】第二篇:Ollama服务器

用Deepseek搭建免费的个人知识库–综合教程&#xff08;完整版&#xff09;&#xff1a;第二篇&#xff1a;Ollama服务器部署 OLLAMA服务器的配置在很多网上都已经介绍的非常清楚了&#xff0c;我们的重点不在于那些简单的步骤&#xff0c;而是在需要为下一步做准备的地方更加…

ubuntu安装VMware报错/dev/vmmon加载失败

ubuntu安装VMware报错/dev/vmmon加载失败&#xff0c;解决步骤如下&#xff1a; step1&#xff1a;为vmmon和vmnet组件生成密钥对 openssl req -new -x509 -newkey rsa:2048 -keyout VMW.priv -outform DER -out VMW.der -nodes -days 36500 -subj "/CNVMware/"ste…

DeepSeek和ChatGPT的优劣或者区别(答案来DeepSeek和ChatGPT)

DeepSeek的答案 DeepSeek与ChatGPT作为当前两大主流AI模型&#xff0c;在架构设计、性能表现、应用场景等方面存在显著差异&#xff0c;以下从多个维度进行对比分析&#xff1a; 一、架构与训练效率 架构设计 DeepSeek&#xff1a;采用混合专家&#xff08;MoE&#xff09;框架…

5 个释放 安卓潜力的 Shizuku 应用

Shizuku 软件推荐&#xff1a;释放安卓潜力的五款应用 Shizuku (日语&#xff1a;雫&#xff0c;意为“水滴”) 正如其名&#xff0c;是一款轻巧但功能强大的安卓工具。它无需 Root 权限&#xff0c;通过 ADB (Android Debug Bridge) 授权&#xff0c;即可让应用调用系统 API&…

微信授权登录接口分析

https://api.weixin.qq.com/sns/jscode2session?grant_typeauthorization_code&appid{appid}&secret{secret}&js_code{code} 你提供的链接是微信小程序进行用户登录的接口&#xff0c;它用于通过 js_code 换取用户的 openid 和 session_key&#xff0c;以实现用户…

【java API】leetcode常用刷题API及ACM模式

文章目录 ACM输入 Scanner**一、字符串高频API****二、集合高频API****三、栈&#xff08;Stack&#xff09;高频API****1. 推荐用Deque替代Stack类**&#xff08;更高效且线程不安全&#xff0c;适合算法场景&#xff09;**2. 核心操作****3. 经典应用场景****4. 避坑指南** *…

云计算——AWS Solutions Architect – Associate(saa)4.安全组和NACL

安全组一充当虚拟防火墙对于关联实例&#xff0c;在实例级别控制入站和出站流量。 网络访问控制列表(NACL)一充当防火墙关联子网&#xff0c;在子网级别控制入站和出站流量。 在专有网络中&#xff0c;安全组和网络ACL(NACL)一起帮助构建分层网络防御。 安全组在实例级别操作…

网络防御高级

接口配置&#xff1a; SW2: [sw2]vlan 10 [sw2]vlan 20 [sw2]interface GigabitEthernet 0/0/1 [sw2-GigabitEthernet0/0/1]port link-type trunk [SW2-GigabitEthernet0/0/1]port trunk allow-pass vlan 10 20 [sw2]interface GigabitEthernet 0/0/2 [sw2-GigabitEthernet0/0/…

在服务器部署JVM后,如何评估JVM的工作能力,比如吞吐量

在服务器部署JVM后&#xff0c;评估其工作能力&#xff08;如吞吐量&#xff09;可以通过以下步骤进行&#xff1a; 1. 选择合适的基准测试工具 JMH (Java Microbenchmark Harness)&#xff1a;适合微基准测试&#xff0c;测量特定代码片段的性能。Apache JMeter&#xff1a;…

Kokoro 开源文本转语音引擎上线!多语言支持,无需联网,浏览器内极速运行

Kokoro 是一款轻量级的开源文本转语音(TTS)引擎,凭借其高效能和轻量化设计,迅速在技术社区中引起关注。本文将详细介绍 Kokoro 的主要特点,并提供在浏览器和 Python 环境中的代码示例,帮助您快速上手。 1. Kokoro:可在浏览器中运行的 TTS 引擎 1.1 简介 Kokoro 是一个…

html为<td>添加标注文本

样式说明&#xff1a; /*为td添加相对定位点*/ .td_text {position: relative; }/*为p添加绝对坐标(相对于父元素中的定位点)*/ .td_text p {position: absolute;top: 80%;font-size: 8px; }参考资料&#xff1a;

鸿蒙音视频播放器:libwlmedia

libwlmedia 跨平台播放器wlmedia现在已经支持了鸿蒙(Harmony)平台了&#xff0c;SDK插件地址&#xff1a;libwlmedia 一、接入SDK 1.1 导入SDK ohpm i ywl5320/libwlmedia1.2 添加权限&#xff08;可选&#xff09; 如果需要播放网络视频&#xff0c;需要添加网络权限 #m…