瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(驱动基础进阶篇_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
进阶3 驱动代码使用Makefile的宏
在第一章的开头有这样一段内容,module_init 宏定义在内核源码目录下的“include/linux/module.h”文件中,具体内容如下所示:
#ifndef MODULE
#define module_init(x) __initcall(x);
#define module_exit(x) __exitcall(x);
#else /* MODULE */
..........
#define module_init(initfn) \
static inline initcall_t __maybe_unused __inittest(void) \
{ return initfn; } \
int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
..........
#endif
module_init的具体内容由MODULE宏定义来决定,该宏定义在内核源码的顶层Makefile中,在本节课中将对Makefile中的宏进行进一步探究。
3.1 内核模块的编译选项的变量
在Makefile中KBUILD_CFLAGS_MODULE和EXTRA_CFLAGS都是用于指定编译内核模块时的编译选项的变量,下面是两个变量的详细介绍。
(1)KBUILD_CFLAGS_MODULE:
KBUILD_CFLAGS_MODULE是一个makefile变量,用于指定编译内核模块时的编译选项。在makefile中,可以使用KBUILD_CFLAGS_MODULE变量来添加特定于模块的编译选项。
通常,通过在makefile中使用KBUILD_CFLAGS_MODULE变量,可以将特定于模块的编译选项添加到模块的编译命令中。例如,可以使用KBUILD_CFLAGS_MODULE添加宏定义、优化选项、警告选项等。
在给KBUILD_CFLAGS_MODULE赋值时,可以使用+=操作符来追加编译选项,以确保不覆盖已有的编译选项。
例如,KBUILD_CFLAGS_MODULE += -DDEBUG表示将-DDEBUG编译选项添加到模块的编译命令中,定义了一个名为DEBUG的宏。
(2)EXTRA_CFLAGS:
EXTRA_CFLAGS也是一个makefile变量,用于指定额外的编译选项。与KBUILD_CFLAGS_MODULE类似,可以使用EXTRA_CFLAGS变量来添加编译选项。
同样地,在给EXTRA_CFLAGS赋值时,也可以使用+=操作符来追加编译选项,以确保不覆盖已有的编译选项。
例如,EXTRA_CFLAGS += -DDEBUG表示将-DDEBUG编译选项添加到全局的编译命令中,定义了一个名为DEBUG的宏。
注:两个变量的最终效果是相同的,在目前的内核中主要使用KBUILD_CFLAGS_MODULE变量的方式,EXTRA_CFLAGS已经弃之不用了,但仍旧支持这种方法。
3.2 实验程序的编写
本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\50_define\。
本实验将通过KBUILD_CFLAGS_MODULE参数来添加特定于模块的编译选项,根据编译选项的内容来打印不同的值。
编写完成的define.c代码如下所示:
#include <linux/module.h>
#include <linux/kernel.h>
static int __init helloworld_init(void) //驱动入口函数
{
#ifndef DEBUG
printk("helloworld a!\n");
#else
printk("helloworld b!\n");
#endif
return 0;
}
static void __exit helloworld_exit(void) //驱动出口函数
{
printk(KERN_EMERG "helloworld_exit\r\n");
}
module_init(helloworld_init); //注册入口函数
module_exit(helloworld_exit); //注册出口函数
MODULE_LICENSE("GPL v2"); //同意 GPL 开源协议
MODULE_AUTHOR("topeet"); //作者信息
3.3 运行测试
3.3.1 编译驱动程序
在上一小节中的define.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:
KBUILD_CFLAGS_MODULE += -DDEBUG
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m +=define.o #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules #make操作
clean:
make -C $(KDIR) M=$(PWD) clean #make clean操作
对于Makefile的内容注释已在上图添加,保存退出之后,来到存放define.c和Makefile文件目录下,如下图(图3-1)所示:
图 3-1
然后使用命令“make”进行驱动的编译,编译完成如下图(图3-2)所示:
图 3-2
编译完生成define.ko目标文件,如下图(图3-3)所示:
图 3-3
至此驱动模块就编译成功了。
3.3.2 运行测试
开发板启动之后,使用以下命令进行驱动模块的加载,如下图(图3-4)所示:
insmod define.ko
根据打印信息可以确定DEBUG宏定义已经被定义了,所以才会打印“helloworld b!”,如果删除Makefile文件中的第一行内容之后,重新加载内核就会打印“helloworld a!”如下图(图3-5)所示:
图 3-5
最后,使用以下命令对该内核进行卸载,如下图所示:
rmmod define.ko
图 3-6
至此,驱动代码使用Makefile的宏实验就完成了。