正点原子RK3568驱动开发:从Kconfig到Makefile的内核编译实战 1. RK3568驱动开发环境搭建第一次接触RK3568驱动开发时我被复杂的编译流程绕晕了。后来发现只要理清SDK目录结构环境搭建其实很简单。正点原子提供的SDK已经帮我们封装好了大部分工具链我们只需要关注几个关键目录kernel/存放Linux内核源码这是我们修改驱动的主要战场uboot/引导程序源码build.sh核心编译脚本封装了各种编译命令rockdev/存放编译生成的固件建议先在Ubuntu 20.04上搭建环境这个版本与RK3568的SDK兼容性最好。安装基础依赖时我踩过一个坑必须安装指定版本的交叉编译工具链。用这个命令安装最稳妥sudo apt-get install gcc-aarch64-linux-gnu验证环境是否就绪有个小技巧在SDK根目录运行./build.sh -h如果能正常显示帮助信息说明基础环境没问题。第一次编译建议用完整编译命令./build.sh all这会自动完成uboot、kernel和rootfs的编译打包。2. 深入理解Kconfig配置系统很多新手看到make menuconfig界面就发怵其实它的本质就是个图形化的配置编辑器。我把它比作餐厅的点菜单Kconfig文件就是菜单本定义了有哪些菜可选.config文件相当于你实际点的菜品清单Makefile就是后厨的烹饪指南在RK3568的kernel目录下每个子目录都有Kconfig文件。比如要给字符设备添加新驱动就要修改drivers/char/Kconfig。这里有个实用技巧用/键可以快速搜索配置项比手动翻找效率高多了。配置项有三种状态*编译进内核像主食必须打包进系统M编译为模块像配菜可以后期再加空不编译不点的菜我建议新手先用make savedefconfig保存精简配置这个命令只会保存你修改过的选项比直接复制.config文件更干净。3. Makefile编写实战技巧第一次写Makefile时我被obj-y、obj-m这些变量搞得晕头转向。后来总结出一个记忆口诀obj-yYes必须编进内核obj-mModule编译成模块obj-nNo坚决不编译obj-$(CONFIG_XXX)看配置决定给RK3568写驱动时最常用的就是条件编译。比如我们要添加一个helloworld驱动Makefile应该这样写obj-$(CONFIG_HELLOWORLD) helloworld.o这里有个容易踩的坑CONFIG_前缀是自动添加的。在Kconfig里定义的配置项是HELLOWORLD但在Makefile里要用CONFIG_HELLOWORLD。我曾在这个问题上浪费了两小时调试时间。4. 完整驱动开发流程演示以开发一个简单的helloworld字符设备驱动为例详细走一遍流程4.1 创建驱动目录首先在drivers/char/下新建目录mkdir drivers/char/helloworld cd drivers/char/helloworld touch helloworld.c Kconfig Makefile驱动源码helloworld.c可以先用最简单的模板#include linux/module.h static int __init hello_init(void) { printk(Hello RK3568!\n); return 0; } static void __exit hello_exit(void) { printk(Goodbye RK3568\n); } module_init(hello_init); module_exit(hello_exit);4.2 编写Kconfig文件Kconfig内容决定了配置界面如何显示config HELLOWORLD tristate Hello World Driver default n help This is a simple hello world driver for RK3568.这里tristate表示支持三种状态编译进内核、编译为模块、不编译default n表示默认不编译。4.3 修改上级Kconfig要让新配置生效必须在上一级的drivers/char/Kconfig中添加source drivers/char/helloworld/Kconfig这个步骤经常被遗忘导致配置项不显示。我习惯用grep -r source drivers/char/命令确认是否包含成功。4.4 更新Makefile在helloworld目录的Makefile中obj-$(CONFIG_HELLOWORLD) helloworld.o同时要修改上级drivers/char/Makefileobj-y helloworld/注意最后的斜杠不能少它表示这是一个目录而非文件。5. 编译与烧录技巧完成代码编写后编译流程有讲究首先执行make menuconfig在Character devices下找到我们的驱动并启用保存配置后必须执行make savedefconfig更新defconfig单独编译内核./build.sh kernel生成boot.img./build.sh firmware烧录时有个省时技巧可以只烧写boot.img不用每次都烧整个系统。用Rockchip的工具加载parameter.txt时要注意校验分区地址是否正确。我习惯先用cat /proc/mtd确认当前系统的分区布局。调试驱动时这几个命令特别有用dmesg | grep hello # 查看驱动打印 lsmod | grep hello # 检查模块是否加载 cat /proc/devices # 查看注册的设备号6. 常见问题排查问题1驱动编译成功但没生效检查.config中CONFIG_HELLOWORLD是否真的设置为y确认Makefile路径和变量名正确用make V1查看详细编译日志问题2menuconfig里找不到配置项检查所有上级Kconfig是否包含你的Kconfig执行make clean后重新配置确认ARCH环境变量设置为arm64问题3驱动打印信息看不到检查printk的日志级别echo 8 /proc/sys/kernel/printk确认串口终端设置正确尝试用dmesg -w实时监控日志记得每次修改内核配置后都要重新打包boot.img。我建议建立一个简单的编译脚本来自动化这个过程#!/bin/bash make savedefconfig cp defconfig arch/arm64/configs/rockchip_linux_defconfig ./build.sh kernel ./build.sh firmware7. 高级调试技巧当驱动比较复杂时光靠printk调试效率太低。我推荐几种更专业的调试方法使用动态调试#define DEBUG #include linux/dynamic_debug.h // 在代码中插入 dynamic_dev_dbg(dev, Debug message: %d\n, value);然后通过echo file helloworld.c p /sys/kernel/debug/dynamic_debug/control启用调试Oops信息分析 发生内核崩溃时用aarch64-linux-gnu-objdump工具反汇编vmlinuxaarch64-linux-gnu-objdump -S vmlinux vmlinux.dis使用ftraceecho function_graph /sys/kernel/debug/tracing/current_tracer echo helloworld_init /sys/kernel/debug/tracing/set_ftrace_filter echo 1 /sys/kernel/debug/tracing/tracing_on这些工具在RK3568上都能完美工作极大提升了驱动开发效率。