Linux驱动交叉编译把驱动文件放入开发板,以及printk函数打印级别
上一篇介绍了一个最简单的驱动程序和驱动程序大体结构,但那还是用本地编译只能在Ubuntu上运行,我们该怎么编译一个能加载到开发板上呢,就需要交叉编译,交叉编译通常都是在嵌入式开发中使用到的。
交叉编译
理解交叉编译前先了解下本地编译:是指编译源代码的平台和执行源代码编译后程序的平台是同一个平台。例如在x86平台下编译的程序,就只能在x86平台下运行。
而我们现在是在Ubuntu下(x86)编译,到ARM开发板(arm)上去运行自然不行,所以交叉编译:是指编译源代码的平台和执行源代码编译后程序的平台是两个不同的平台,其中运行编译程序称为宿主机,运行编译程序所产生目标代码的称为目标机。
那为什么不在ARM开发板上编译程序呢,这样就不用转来转去了。之所以要有交叉编译,主要原因是:
1、目标机的运行速度往往比宿主机慢得多,许多专用的嵌入式硬件被设计为低成本和低功耗,没有太高的性能。
2、整个编译过程是非常消耗资源的,嵌入式系统往往没有足够的内存或磁盘空间。
3、 一个完整的Linux编译环境需要很多支持包,交叉编译使我们不需要花时间将各种支持包移植到目标机上。
交叉编译说完了,那怎么宿主机怎么给程序进行交叉编译呢,我们是站在巨人的肩膀上,自然是有现成的工具叫交叉编译器。
根据每个人使用的开发板不同需要下载不同的交叉编译器,大家可自行百度。
其实我们只需要在Makefile中指明交叉编译器的路径就行了,我们来看一个例子。
ifeq ($(KERNELRELEASE),)#内核源代码路径
KERNELDIR ?= /home/xin/6818GEC/kernel
#交叉编译器路径
CROSS_PATH := /home/xin/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
#模块源代码路径
PWD := $(shell pwd)default:$(MAKE) CROSS_COMPILE=$(CROSS_PATH) -C $(KERNELDIR) M=$(PWD) modules
clean:rm -rf *.o *.ko *.mod .*.cmd *.mod.* modules.order Module.symvers .tmp_versionselse
#obj-m表示编译生成可加载模块,obj-y表示直接将模块编译进内核。
obj-m := hello.oendif
这里面的参数上一篇详细解释过了,看不懂可以去看看(初学者的第一个Linux驱动)。其中开发板内核源代码路径和交叉编译器路径需要根据自己的存放位置去改变。
这是Ubuntu上开发板内核源代码的路径和内容。
这是Ubuntu上交叉编译器的路径和内容。 路径中只需要交叉编译器的前缀arm-eabi-
内核打印函数 printk
正常当我们在写应用程序时,都会使用printf函数或相关的打印函数来输出信息,帮助我们调试代码或者打印日志。那内核的驱动程序又没有应用层的库函数,这时候就需要使用我们的printk函数了。先来看一段代码和现象。
#include <linux/init.h>
#include <linux/module.h>//加载函数
int printktest_init(void)
{//内核打印语句printk("<0>""printk level 0!\n");printk("<1>""printk level 1!\n");printk("<2>""printk level 2!\n");printk("<3>""printk level 3!\n");printk("<4>""printk level 4!\n");printk("<5>""printk level 5!\n");printk("<6>""printk level 6!\n");printk("<7>""printk level 7!\n");printk("printk no level!\n");return 0;
}//卸载函数
void printktest_exit(void)
{printk("<0>""printk level 0!\n");printk("<1>""printk level 1!\n");printk("<2>""printk level 2!\n");printk("<3>""printk level 3!\n");printk("<4>""printk level 4!\n");printk("<5>""printk level 5!\n");printk("<6>""printk level 6!\n");printk("<7>""printk level 7!\n");printk("printk no level!\n");
}//声明为模块的入口和出口
module_init(printktest_init);
module_exit(printktest_exit);MODULE_LICENSE("GPL");//GPL模块许可证
MODULE_AUTHOR("xin");//作者
MODULE_VERSION("1.0");//版本
MODULE_DESCRIPTION("printk module!");//描述信息
我们发现代码printk中有0~7,8个数字,而我们加载模块却只打印前5条语句,这是为什么呢?
之前我们说过printk和printf等打印函数用法十分相似,但printk多了打印级别的设置。内核打印通过printk函数,printk打印的内容能否显示取决于打印级别。
printk函数有8个级别,0-7(数字越小优先级越高)
#define KERN_EMERG "<0>" /*系统不可用信息*/
#define KERN_ALERT "<1>" /* 必须立即处理的错误*/
#define KERN_CRIT "<2>" /*严重的错误信息*/
#define KERN_ERR "<3>" /*错误信息*/
#define KERN_WARNING "<4>" /*警告信息*/
#define KERN_NOTICE "<5>" /*需要注意的情况信息*/
#define KERN_INFO "<6>" /*普通信息*/
那什么级别的prink函数中的内容才能显示呢。在Linux中有一个文件用来存放内核默认的打印级别。/proc/sys/kernel/printk,其内容为:
解释一下其中数字含义
5 表示内核打印级别(只有printk打印级别高于5才能显示)
7 表示printk函数默认打印级别(使用printk函数不设置打印级别默认为7)
1 内核打印级别最小值
7 默认内核打印级别
通常只需要改变内核打印级别比printk低就行了。
我们可以直接修改里面的内容。
但这种方法在系统关机或重启后就会失效。我们可以写一个脚本在每次启动时去修改里面的值。有两个方法实现永久修改。
方法1:
写一个shell脚本,内容很简单
然后再放到环境变量(/etc/profile)中去。内容为source 路径/printk.sh。
这样每次启动开发板就都会重新把内容写入/proc/sys/kernel/printk文件里了。
方法2:
在uboot的bootargs中加入“loglevel=X”的语句。首先进入uboot界面。这个可能每个开发板的操作都不太一样,这里演示一下GEC6818。
设置完了要记得保存一下,不然不生效。
通过以上两种方法都能成功设置打印级别。
我们再从新编译加载一下模块,看看效果吧。
Makefile
ifeq ($(KERNELRELEASE),)#内核源代码路径
KERNELDIR ?= /home/xin/6818GEC/kernel
#交叉编译器路径
CROSS_PATH := /home/xin/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
#模块源代码路径
PWD := $(shell pwd)default:$(MAKE) CROSS_COMPILE=$(CROSS_PATH) -C $(KERNELDIR) M=$(PWD) modules
iclean:rm -rf *.o *.ko *.mod .*.cmd *.mod.* modules.order Module.symvers .tmp_versionselse
#obj-m表示编译生成可加载模块,obj-y表示直接将模块编译进内核。
obj-m := print.oendif
print.c
#include <linux/init.h>
#include <linux/module.h>//加载函数
int printktest_init(void)
{//内核打印语句printk("<0>""printk level 0!\n");printk("<1>""printk level 1!\n");printk("<2>""printk level 2!\n");printk("<3>""printk level 3!\n");printk("<4>""printk level 4!\n");printk("<5>""printk level 5!\n");printk("<6>""printk level 6!\n");printk("<7>""printk level 7!\n");printk("printk no level!\n");return 0;
}//卸载函数
void printktest_exit(void)
{printk("<0>""printk level 0!\n");printk("<1>""printk level 1!\n");printk("<2>""printk level 2!\n");printk("<3>""printk level 3!\n");printk("<4>""printk level 4!\n");printk("<5>""printk level 5!\n");printk("<6>""printk level 6!\n");printk("<7>""printk level 7!\n");printk("printk no level!\n");
}//声明为模块的入口和出口
module_init(printktest_init);
module_exit(printktest_exit);MODULE_LICENSE("GPL");//GPL模块许可证
MODULE_AUTHOR("xin");//作者
MODULE_VERSION("1.0");//版本
MODULE_DESCRIPTION("printk module!");//描述信息
以上就是Linux驱动交叉编译把驱动文件放入开发板,以及printk函数打印级别的全部内容,有什么说的不对或者觉得不清楚地方欢迎在评论区提出来。
相关文章:

Linux驱动交叉编译把驱动文件放入开发板,以及printk函数打印级别
上一篇介绍了一个最简单的驱动程序和驱动程序大体结构,但那还是用本地编译只能在Ubuntu上运行,我们该怎么编译一个能加载到开发板上呢,就需要交叉编译,交叉编译通常都是在嵌入式开发中使用到的。 交叉编译 理解交叉编译前先了解…...
力扣(LeetCode)433. 最小基因变化(2023.03.07)
基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 ‘A’、‘C’、‘G’ 和 ‘T’ 之一。 假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如,“AACCGGTT”…...

网络基础(2)
目录1. 端口号2. 套接字socket3. 网络通信3.1 sockaddr与sockaddr_in3.2 接口服务端3.2.1 创建套接字,打开网络文件3.2.2 给该服务器绑定端口和ip(特殊处理)3.2.3 初始化相关服务器3.2.4 提供服务客户端3.2.5 绑定3.2.6 使用服务4. makefile实…...
掌握Spring Cloud Gateway:构建高性能API网关的原理和实践
Spring Cloud Gateway 是一个基于 Spring Boot 的 API 网关,用于构建微服务架构中的网关服务。它提供了统一的路由、请求转发、过滤器、负载均衡、熔断等功能,帮助开发者更好地管理和控制微服务系统的请求流量。 本文将介绍 Spring Cloud Gateway 的原理…...

NAST概述
一、NATS介绍 NATS是由CloudFoundry的架构师Derek开发的一个开源的、轻量级、高性能的,支持发布、订阅机制的分布式消息队列系统。它的核心基于EventMachine开发,代码量不多,可以下载下来慢慢研究。 不同于Java社区的kafka,nats…...

【JS知识点】——原型和原型链
文章目录原型和原型链构造函数原型显式原型(prototype)隐式原型(\_\_proto\_\_)原型链总结原型和原型链 在js中,原型和原型链是一个非常重要的知识点,只有理解原型和原型链,才能深刻理解JS。在…...

c盘怎么清理到最干净?有什么好的清理方法
c盘怎么清理到最干净?有什么好的清理方法?清理C盘空间是电脑维护的重要步骤之一。C盘是Windows操作系统的核心部分,保存了许多重要的系统文件,因此空间不足会影响计算机的性能和稳定性。下面是一些清理C盘空间的方法 一.清理临时文件 在使用…...

day26_HTML
今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、二阶段介绍 二、HTML 零、 复习昨日 见代码 一、二阶段介绍 第一阶段: 基础入门 java基本语法编程基础(方法,数组)面向对象编程常用类高级(IO,线程,新…...

深度剖析C语言预处理
致前行的人: 人生像攀登一座山,而找寻出路,却是一种学习的过程,我们应当在这过程中,学习稳定冷静,学习如何从慌乱中找到生机。 目录 1.程序翻译过程: 2.字符串宏常量 3.用宏定义充当注释符号 4…...

【WPF 值转换器】ValueConverter 进阶用法
【WPF 值转换器】ValueConverter 进阶用法介绍基类实现子类实现效果介绍 值转换器在WPF开发中是非常常见的,当然不仅仅是在WPF开发中。值转换器可以帮助我们很轻松地实现,界面数据展示的问题,如:模块隐藏显示、编码数据展示为可读…...

Vue2的基本使用
一、vue的基本使用 第一步 引入vue.js文件 <script src"https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script> 或者<script src"./js/vue.js"></script> 第二步 在body中设置一个挂载点 {{msg}} <div id"app…...

【云原生kubernetes】k8s数据存储之Volume使用详解
目录 一、什么是Volume 二、k8s中的Volume 三、k8s中常见的Volume类型 四、Volume 之 EmptyDir 4.1 EmptyDir 特点 4.2 EmptyDir 实现文件共享 4.2.1 关于busybox 4.3 操作步骤 4.3.1 创建配置模板文件yaml 4.3.2 创建Pod 4.3.3 访问nginx使其产生访问日志 4.3.4 …...

SerDes---CDR技术
1、为什么需要CDR 时钟数据恢复主要完成两个工作,一个是时钟恢复,一个是数据重定时,也就是数据的恢复。时钟恢复主要是从接收到的 NRZ(非归零码)码中将嵌入在数据中的时钟信息提取出来。 2、CDR种类 PLL-Based CDROve…...

如何实现在on ethernetPacket中自动回复NDP response消息
对于IPv4协议来说,如果主机想通过目标ipv4地址发送以太网数据帧给目的主机,需要在数据链路层填充目的mac地址。根据目标ipv4地址查找目标mac地址,这是ARP协议的工作原理 对于IPv6协议来说,根据目标ipv6地址查找目标mac地址,它使用的不是ARP协议,而是邻居发现NDP(Neighb…...

CSS清楚浮动
先看看关于浮动的一些性质 浮动使元素脱离文档流 浮动元素可以设置宽高,在CSS中,任何元素都可以浮动,浮动元素会生成一个块级框,而不论其本身是何种元素。 如果没有给浮动元素指定高度,,那么它会以内容的…...

HTTPS详解(原理、中间人攻击、CA流程)
摘要我们访问浏览器也经常可以看到https开头的网址,那么什么是https,什么是ca证书,认证流程怎样?这里一一介绍。原理https就是httpssl,即用http协议传输数据,数据用ssl/tls协议加密解密。具体流程如下图&am…...

EventLoop机制
JavaScript 是单线程的语言 JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。 单线程执行任务队列的问题: 如果前一个任务非常耗时,则后续的任务就不得不一直等待,从而导致程序假死的问题。 同步任…...

倒立摆建模
前言 系统由一辆具有动力的小车和安装在小车上的倒立摆组成,系统是不稳定,我们需要通过控制移动小车使得倒立摆保持平衡。 具体地,考虑二维情形如下图,控制力为水平力FFF,输出为角度θ\thetaθ以及小车的位置xxx。 力…...

SpringSecurity支持WebAuthn认证
WebAuthn是无密码身份验证技术,解决了密码泄露的风险,主流的浏览器都支持。有很多开源的类库实现了WebAuthn规范,Java下流行的类库有:webauthn4jjava-webauthn-serververtx-authSpring Security官方暂时未支持WebAuthn,…...

深度学习技巧应用3-神经网络中的超参数搜索
大家好,我是微学AI,今天给大家带来深度学习技巧应用3-神经网络中的超参数搜索。 在深度学习任务中,一个算法模型的性能往往受到很多超参数的影响。超参数是指在模型训练之前需要我们手动设定的参数,例如:学习率、正则…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...