【Linux】Petalinux驱动开发基础

基于Petalinux做Linux驱动开发。

部分图片和经验来源于网络,若有侵权麻烦联系我删除,主要是做笔记的时候忘记写来源了,做完笔记很久才写博客。

 专栏目录:记录自己的嵌入式学习之路-CSDN博客


目录

1    一个完整的Linux系统(针对Zynq)

1.1    PS部分

1.2    PL部分(若没用到PL就不需要这个部分):

2    Petalinux的内核源码获取

3    系统编译过程

4    NFS挂载根文件系统(Rootfs)的条件

5    交叉编译

6    驱动模块的开发

6.1    驱动的运行方式

6.2    file_operations结构体

6.3    驱动模块的加载和卸载

6.4    一个驱动程序必须有的东西

6.5    字符设备的注册和注销

6.6    一个字符设备驱动必须有的东西

6.7    设备号

6.8    内核空间与用户空间

7    地址映射

7.1    相关函数

8    设备树

8.1    是什么

8.2    为什么

8.3    设备树相关概念

8.4    一个典型的设备树文件

8.5    设备树节点的基本格式

8.6    节点属性

8.7    特殊节点

8.8    如何定位一个节点

8.9    内核启动过程中设备树的解析过程

8.10    如何添加一个设备树节点

8.11    如何引用一个节点

8.12    驱动与设备树交互的函数

8.13    设备树使用注意事项

9    内核的内存申请

9.1    常见的作用域

9.2    驱动程序中常使用static的原因

9.3    动态内存申请

9.4    kmalloc函数

9.5    kzalloc函数

9.6    vmalloc函数

9.7    devm_kmalloc/devm_kzalloc函数

9.8    devm_kmalloc_array/kmalloc_array

10    驱动与用户空间的交互函数

10.1    read函数

10.2    write函数

10.3    unlocked_ioctl

10.4    对比

11    ioctl详解

11.1    ioctl协议的命令组成

11.2    ioctl的宏

11.3    用于输入输出的时候需要注意的点

12    Linux开发常用的头文件

12.1    驱动开发头文件

12.2    Linux应用开发头文件

13    Linux驱动开发常用的宏


1    一个完整的Linux系统(针对Zynq)

1.1    PS部分

        五大要素:

(1)fsbl(First Stage Boot Loader) -> zynq_fsbl.elf

        负责初始化PS部分的硬件并加载第二阶段的引导加载程序。

(2)uboot(Universal Boot Loader) -> u-boot.elf、boot.scr(boot引导)

        Bootloader 是在操作系统运行之前执行的一段小程序。通过这段小程序,可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
        boot.scr文件则是用于给uboot执行和启动相关的行为的脚本,其中包含了加载内核、设备树、根文件系统等操作,我个人感觉和uboot中的bootm、bootz等命令类似。而这个文件整体又和uboot中bootargs、bootcmd这两个环境变量的作用类似。

(3)设备树文件 -> system.dtb

        一种描述硬件的数据结构。

(4)linux内核 -> image.ub、(zImage)、(uImage)

        内核是Linux系统的核心,负责管理系统的硬件和软件资源。其中,image.ub可以直接通过uboot上的bootm命令进行Linux的引导启动,也是放在SD卡BOOT分区就能自动引导的内核镜像文件;zImage是一种经过gzip压缩的Linux内核镜像格式;uImage是U-Boot引导加载程序专用的内核镜像格式。它是在zImage或Image(不加压缩的内核镜像)的基础上加上一个U-Boot头部信息(U-BootHeader),使U-Boot能够识别并加载内核镜像。

        注:image.ub其实包含了system.bit,zImage,system.dtb三者。

(5)根文件系统 -> rootfs.tar.gz

        根文件系统提供了操作系统运行所需的文件和程序。

1.2    PL部分(若没用到PL就不需要这个部分):

(1)比特流(Bitstream)文件 -> system.bit

        FPGA的配置文件,用于初始化PL部分的硬件。


2    Petalinux的内核源码获取

        进行驱动开发时往往需要Linux的源码,但在Xilinx的Github中不一定有指定版本(petalinux编译时的版本)的Linux内核源码,例petalinux 2023.1的6.1.5版本的内核就没有打包在那里。

        而petalinux编译的过程中,默认是会删除掉其解压出来的源码的。要拿到它编译的源码,可以修改<plnx_proj>/project-spec/meta-user/conf/petalinuxbsp.conf,加上RM_WORK_EXCLUDE += "linux-xlnx",编译后可以在<plnx_proj>/build/tmp/work-shared/zynq-generic-7z020/kernel-source中获取源码。

        若需要uboot源码,则加上RM_WORK_EXCLUDE += “u-boot-xlnx”。


3    系统编译过程

        普通的petalinux开发,最后会将fsbl、比特流文件、uboot、设备树这四个部分都打包到一个BOOT.BIN的文件中去。常用命令是:

        petalinux-package --boot --fsbl --fpga --u-boot –-force

        若进行Linux驱动开发,设备树文件、linux内核、根文件系统以及比特流文件都是有可能经常发生改动的,因此要尽量将这些分离出来。

(1)首先,是在编译时,仅将fsbl和uboot编译并打包进BOOT.BIN中,因为这两个文件基本不会变:

petalinux-build -c bootloader        //编译fsbl
petalinux-build -c u-boot            //编译uboot
petalinux-package --boot --fsbl --u-boot --dtb no –force//打包两者进BOOT.BIN,并放过其他成员。

(2)其次,是petalinux-build后修改boot.scr,因为以这样的方式编译出来的boot.scr脚本的内容是不对的,具体就是:

        将部分对uImage的操作改为对zImage的操作(这里主要就是不使用image.ub改用zImage了);

        并添加对system.bit的操作(添加关于比特流的内容是因为没有将比特流打包进BOOT.BIN,过程中生成的boot.sc也因此没有与其相关的操作,所以要手动添加);

        具体可以看正点原子的教程或看正常用petalinux整合编译时的boot.scr文件,这里其实就是将其修改为正常boot.scr该有的样子。最后是将原版改名为boot.cmd.default,并删掉第一行(包含乱码的行)再使用以下命令重新生成为boot.scr:

mkimage -c none -A arm -T script -d boot.cmd.default boot.scr

        要重新生成一个boot.scr的理由也很简单,就是因为boot.scr文件的头部带有一些生成的二进制数据,直接修改boot.scr是不行的。

(3)接着,给Linux源码增加设备树文件,从上面编译到的文件中取(路径为<petalinux项目根目录>/components/plnx_workspace/device-tree/device-tree),具体需要pcw.dtsi,pl.dtsi,system-top.dts,zynq-7000.dtsi和system-conf.dtsi这五个。将其放置到源码/arch/arm/boot/dts目录中并根据需要对system-user.dtsi和该目录下的MAKEFILE进行修改。

(4)然后,利用make xilinx_zynq_defconfig命令设置内核配置;并使用make -j8编译内核。该步会在arch/arm/boot中生成所需的内核镜像文件zImage,在arch/arm/boot/dts生成设备树二进制文件system-top.dtb。若仅修改了设备树文件,可以仅编译它,用命令make dts。

(5)其后,回到petalinux项目中,用petalinux-config -c rootfs命令和petalinux-build -c rootfs命令配置并编译根文件系统得到rootfs.tar.gz。

(6)最后,在SD卡的BOOT分区,放入文件。用BOOT.BIN,boot.scr,system.bit,zImage,system.dtb五个文件代替普通Petalinux开发的BOOT.BIN,boot.scr和image.ub三个文件的方案:
        BOOT.BIN     :来自步骤(1),是仅包含fsbl和uboot的启动引导文件;
        boot.scr        :来自步骤(2),是添加比特流操作行为且更改boot内核行为后的boot脚本;
        system.bit    :来自步骤(1),是petalinux项目生成的比特流文件;
        zImage          :来自步骤(4),是Linux内核;
        system.dtb   :来自步骤(4),由system-top.dtb文件改名获得,是设备树二进制文件。

(7)最最后,将根文件系统解压后放入SD卡的rootfs分区:
        rootfs.tar.gz :来自步骤(5),根文件系统的压缩包。

(附加)使用NFS挂载根文件系统会更好,因为不用经常将SD卡拿出来修改rootfs分区,而boot分区则是进入Linux后随便改,反正进系统后该分区就没有实际的用处了。


4    NFS挂载根文件系统(Rootfs)的条件

(1)Ubuntu安装NFS

sudo apt install nfs-kernel-server

(2)Ubuntu一个创建NFS的挂载路径

        假设为/home/xxx/workspace/nfs

(3)Ubuntu修改NFS配置文件

sudo vi /etc/exports

        在文件末添加如下内容:

/home/xxx/workspace/nfs *(rw,sync,no_root_squash)

(4)Ubuntu重启rpcbind服务和NFS服务(其实重启系统最好)

sudo /etc/init.d/rpcbind restart
sudo systemctl start nfs-kernel-server.service

(5)网络硬件设置

        Zynq开发板(用网线PS口)与Ubuntu(用网络桥接)连接到同一路由器上。

(6)Ubuntu网络软件设置

        通过ifconfig命令查看Ubuntu的局域网IP地址、网关地址、掩码等。

(7)Zynq网络软件设置

        开机并在倒计时前回车进入uboot,使用dhcp命令自动获取IP,依次使用以下命令将相关配置写入开发板,具体IP要根据实际情况更改:

setenv ipaddr 192.168.100.10         //开发板 ip 地址
setenv gatewayip 192.168.100.1       //开发板网关
setenv netmask 255.255.255.0         //开发板 ip 地址掩码
setenv serverip 192.168.100.2        //ubuntu ip地址

最后使用saveenv命令将其保存。

(8)Zynq boot命令参数设置

        使用以下命令设置boot要执行的参数:

setenv bootargs 'console=ttyPS0,115200 root=/dev/nfs rw nfsroot=192.168.100.2:/home/XXX/RootFS_NFS,nfsvers=3 ip=192.168.100.10:192.168.100.2:192.168.100.1:255.255.255.0::eth0:off'

        最后使用saveenv命令保存。

        至此,设置完毕。后续调试时,只有boot分区需要提前放好在SD卡中,rootfs直接解压在Ubuntu的/home/xxx/workspace/nfs/rootfs目录后,打开Zynq开发板就能自动挂载根文件系统。


5    交叉编译

        当主机平台(运行编译器的平台)和目标平台(产生的程序将在其上运行的平台)不兼容时,该过程就叫做交叉编译。

        petalinux装好后的编译环境:

        由none可以看出,这些编译器是没有编译linux的能力的。而Petalinux在构建linux系统过程中会编译生成linux交叉编译工具链,然后使用其构建 linux 系统,可以在Petalinux工程下使用“find . -name "arm-xilinx-linux-gnueabi-gcc"”命令找到相应的痕迹:

        需要拿到交叉编译的SDK,需要对某一个petalinux项目执行petalinux-build --sdk,编译好的sdk安装脚本是/项目/image/linux中的sdk.sh,安装到某一地方后安装程序会提示后续需要配置sdk环境的命令,可以写个别名放到~/.bashrc中方便使用。

        安装了SDK后的arm包:


6    驱动模块的开发

6.1    驱动的运行方式

        (1)编译进内核;

        (2)编译成模块,在内核启动后使用insmod命令加载驱动模块;

        一般在调试开发时是编译成模块,开发完成后就可以在编译成模块和编译进内核中选择了。

6.2    file_operations结构体

        位于Linux内核/include/linux/fs.h中,其中fs是file system的缩写。该结构体是Linux内核驱动操作函数集合。

6.3    驱动模块的加载和卸载

(1)加载

        insmod:加载指定的.ko模块,但不能解决模块的依赖关系,比如 drv.ko依赖 first.ko这个模块,就必须先使用 insmod命令加载 first.ko这个模块,然后再加载 drv.ko 这个模块;

        modprobe(推荐):modprobe 会分析模块的依赖关系,然后将所有依赖的模块都加载到内核中,因此 modprobe命令相比 insmod 要智能一些。其次modprobe还有错误检查、错误报告等功能;

        注意:modprobe命令默认会去/lib/modules/<kernel-version>目录中查找模块,如果没有的话需要自行创建,如petalinux2020.2就需要创建/lib/modules/5.4.0-150-generic目录。

        注意:使用modprobe命令前,需先运行depmod建立系统的模块依赖关系。

(2)卸载

        rmmod(推荐):卸载某个模块;

        modprobe:卸载某个模块及其依赖的模块,而因为该模块依赖的模块也有可能在被其他模块所使用,卸载会出问题,所以不推荐使用modprobe来卸载模块;

6.4    一个驱动程序必须有的东西

        (1)    驱动入口函数:static int __init xxx_init(void)

        (2)    驱动出口函数:static void __exit xxx_exit(void)

        (3)    指定驱动入口函数的语句:module_init(xxx_init);    // 指定后加载模块就会自动运行驱动入口函数

        (4)    指定驱动出口函数的语句:module_exit(xxx_exit);   // 指定后卸载模块就会自动运行驱动出口函数

        (5)    开源许可证类型:MODULE_LICENSE(str)              //添加模块LICENSE信息(必须)

        (6)    作者信息:MODULE_AUTHOR(str

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

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

相关文章

JAVA刷题记录: 递归,搜索与回溯

专题一 递归 面试题 08.06. 汉诺塔问题 - 力扣&#xff08;LeetCode&#xff09; class Solution {public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {dfs(A, B, C, A.size());}public void dfs(List<Integer> a, List<In…

YOLOv11改进:利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测

这里写自定义目录标题 YOLOv11改进&#xff1a;利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测1. 介绍2. 引言3. 技术背景3.1 YOLOv11概述3.2 RT-DETR与PPHGNetV23.3 相关工作 4. 应用使用场景5. 详细代码实现5.1 环境准备5.2 PPHGNetV2主干网络实现5.3 YOLOv11与PPHGNetV2集…

WPF之Button控件详解

文章目录 1. 引言2. Button控件基础Button类定义 3. Button控件的核心属性3.1 Content属性3.2 IsDefault属性3.3 IsCancel属性3.4 其他常用属性 4. 按钮样式与模板自定义4.1 简单样式设置4.2 使用Style对象4.3 触发器使用4.4 使用ControlTemplate完全自定义4.5 按钮视觉状态 5.…

【Java】2025 年 Java 学习路线:从入门到精通

文章目录 一、Java基础阶段(4-8周)1. 开发环境搭建2. 核心语法基础3. 面向对象编程(OOP)4. 核心类库二、Java进阶阶段(6-10周)1. JVM深度理解2. 并发编程3. 新特性掌握4. 设计模式三、开发框架与中间件(8-12周)1. Spring生态2. 持久层框架3. 常用中间件四、项目实战阶段…

虚幻引擎入门笔记

【虚幻5】UE5新手入门尝试 虚幻引擎的基础设置 1.验证-当文件误删的时候&#xff0c;对其进行验证&#xff0c;可以恢复。 2.虚幻引擎极其强大&#xff0c;可以实现多种复合技能&#xff0c;所在创建项目页面可以看见不只是创建游戏的项目 3.更改虚幻引擎默认的缓存地址。有些…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】1.1 数据库核心概念与PostgreSQL技术优势

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 深度解析PostgreSQL核心架构与技术优势&#xff1a;从数据库原理到实战场景1.1 数据库核心概念与PostgreSQL技术优势1.1.1 关系型数据库核心架构解析1.1.1.1 数据库系统的底…

详解SLAM中的李群和李代数(上)

1 概述 最近阅读高翔大神的《视觉SLAM十四讲》这本书&#xff0c;感觉整本书写的非常的平实&#xff0c;用非常接地气的语言毫无保留的介绍了视觉SLAM的相关知识&#xff0c;非常值得一读。不过&#xff0c;在第4章出现的李群和李代数的相关概念就有点令人难以费解了。其实这段…

libevent库详解:高性能异步IO的利器

目录 一、libevent 简介 主要特点&#xff1a; 二、事件模型原理 1. event_base 2. event 3. evconnlistener&#xff08;TCP监听器&#xff09; 4. bufferevent 简化流程如下&#xff1a; 三、libevent 使用示例 1. 创建事件主循环 2. 创建监听器&#xff08;TCP&a…

从 “零” 做个开源音乐软件“SteadyBeat”吧!<1> 准备

换换脑子&#xff0c;做个音乐软件&#xff0c;根据调性、和弦走向&#xff08;情感&#xff09;、节拍、速度等需求&#xff0c;结合AI和一众工具&#xff0c;自动生成伴奏、Solo等&#xff0c;有点像库乐队&#xff01;自己平时也用得着&#xff0c;暂时取名叫《SteadyBeat》…

npm error code CERT_HAS_EXPIRED

npm error code CERT_HAS_EXPIRED 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人 擅长.net、C、python开发&#xff0c; 如果遇到技术问题&#xff0c;即可私…

数字世界的“私人车道“:网络切片如何用Python搭建专属通信高速路?

数字世界的"私人车道"&#xff1a;网络切片如何用Python搭建专属通信高速路&#xff1f; 2024年6月&#xff0c;中国移动宣布在浙江某智能工厂完成全球首个"5G工业网络切片"规模商用——这条为生产线定制的"数字专属车道"&#xff0c;将设备控制…

VSCode Verilog编辑仿真环境搭建

VSCode Verilog环境搭建 下载Iverilog安装Iverilog验证安装VS Code安装插件 下载Iverilog 官网下载Iverilog 安装Iverilog 一定要勾选这两项 建议勾选这两项 验证安装 运行Windows PowerShell输入命令&#xff1a;iverilog输入命令&#xff1a;Get-Command gtkwave …

C++ - 数据容器之 list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)

一、创建与初始化 引入 <list> 并使用 std 命名空间 #include <list>using namespace std;创建一个空 list list<int> my_list;创建一个包含 5 个元素&#xff0c;每个元素初始化为 0 的 list list<int> my_list(5);创建一个包含 5 个元素&#xf…

自动化测试项目1 --- 唠嗑星球 [软件测试实战 Java 篇]

目录 项目介绍 项目源码库地址 项目功能测试 1.自动化实施步骤 1.1 编写测试用例 1.2 自动化测试脚本开发 1.2.1 配置相关环境, 添加相关依赖 1.2.2 相关代码编写 2. 自动化功能测试总结 2.1 弹窗的解决相关问题 2.2 断言的使用和说明 2.3 重新登录问题 项目性能…

Codeforces Round 1022 (Div. 2)(ABC)

A. Permutation Warm-Up 翻译&#xff1a; 对于长度为 n 的排列 p&#xff0c;我们定义函数&#xff1a; 给你一个数 n。你需要计算函数 f(p) 在考虑从 1 到 n 的所有可能的数字排列时&#xff0c;可以取多少个不同的值。 思路&#xff1a; 按序排列时和为0&…

数据结构------C语言经典题目(6)

1.数据结构都学了些什么&#xff1f; 1.基本数据类型 算数类型&#xff1a; char&#xff08;字符&#xff09;、int&#xff08;整数&#xff09;、float&#xff08;单精度浮点数&#xff09;、double&#xff08;双精度浮点数&#xff09;等。 枚举类型&#xff1a; enum…

如何封装一个线程安全、可复用的 HBase 查询模板

目录 一、前言&#xff1a;原生 HBase 查询的痛点 &#xff08;一&#xff09;连接管理混乱&#xff0c;容易造成资源泄露 &#xff08;二&#xff09;查询逻辑重复&#xff0c;缺乏统一的模板 &#xff08;三&#xff09;多线程/高并发下的线程安全性隐患 &#xff08;四…

【中间件】bthread_基础_TaskControl

TaskControl 1 Definition2 Introduce**核心职责** 3 成员解析**3.1 数据结构与线程管理****3.2 任务调度与负载均衡****3.3 线程停放与唤醒&#xff08;ParkingLot&#xff09;****3.4 统计与监控** 4 **工作流程**5 **设计亮点**6 **使用场景示例**7 **总结**8 学习过程中的疑…

win11 终端 安装ffmpeg 使用终端Scoop

1、安装scoop (Windows 包管理器) Set-ExecutionPolicy RemoteSigned -Scope CurrentUser iwr -useb get.scoop.sh | iex 2、使用scoop来安装ffmpeg scoop install ffmpeg 3、测试一下ffmpeg&#xff0c;将Mp3文件转为Wav文件 ffmpeg -i A.mp3 A.wav 然后我们就看到A.wav生成…

力扣838.推多米诺随笔

“生活就像海洋&#xff0c;只有意志坚强的人&#xff0c;才能到达彼岸。”—— 马克思 题目 n 张多米诺骨牌排成一行&#xff0c;将每张多米诺骨牌垂直竖立。在开始时&#xff0c;同时把一些多米诺骨牌向左或向右推。 每过一秒&#xff0c;倒向左边的多米诺骨牌会推动其左侧…