首先,之前添加了ch9434.c,修改了Kconfig和Makefile,然后通过menuconfig启用了该驱动,选项前有星号。可能对内核配置符号(*、M、空格)的含义不太清楚,需要详细解释。
有时候在编译后发现没有生成.ko文件,或者在加载模块时遇到问题,所以想确认配置是否正确。我需要明确说明,选择<*>会将驱动编译进内核,而不是作为模块,因此不会生成.ko文件。如果他们希望生成模块,应该选择。
另外,可能混淆了内核镜像和模块的概念。需要解释不同配置选项的结果,以及如何验证驱动是否被正确编译进内核。还要指导他们如何检查内核的.config文件,确保配置正确生效。
此外,可能在之前的步骤中遇到了问题,比如没有生成.ko文件,所以需要检查配置是否正确,并解释为什么即使驱动被编译进内核,也不会产生.ko文件。可能需要建议如何调整配置以生成模块,或者确认驱动确实内建到了内核中。
一、内核编译区别
将【驱动编译进内核】与将【驱动编译成.ko驱动模块】的区别
1.make menuconfig 配置符号分析
符号 | 含义 | 编译结果 |
---|---|---|
< > | 未选中 | 不编译 |
<M> | 模块方式编译 | 生成 .ko 文件 |
<*> | 内置到内核镜像 | 直接编译进 Image |
2 将驱动代码编译进内核镜像Image
2.1 例如下面是我当前的配置:
< * > SERIAL_CH9434 serial support前面是 * 号
配置了内核选项
①make menuconfig
②Device Drivers
-> Character devices
-> Serial drivers
-> < * > SERIAL_CH9434 serial support
当前我的配置的影响(结果):
-
编译结果:
• 驱动代码:会被直接编译进内核镜像文件里面arch/arm64/boot/Image
• 模块文件:不会生成ch9434.ko
文件 -
运行时加载:
• 驱动会随内核启动自动加载,无需手动执行modprobe
或insmod
进行加载驱动ch9434.ko
文件。
2.2 验证配置
步骤 1:检查 .config
文件
grep CONFIG_SERIAL_CH9434 .config
正确输出:
CONFIG_SERIAL_CH9434=y
步骤 2:验证编译过程
重新编译内核后,检查驱动目标文件:
# 查看目标文件是否生成
ls drivers/tty/serial/ch9434.o
# 检查内核镜像是否包含驱动符号
nm arch/arm64/boot/Image | grep ch9434_probe
预期输出:
ffffff8000123456 T ch9434_probe
3. 如果需要生成 .ko
文件
如果希望驱动以模块形式存在,需重新配置
步骤 1:修改配置为模块
配置了内核选项
通过menuconfig
将 <*> 改为 < M > SERIAL_CH9434 serial support
①make menuconfig
②Device Drivers
-> Character devices
-> Serial drivers
-> < M > SERIAL_CH9434 serial support
make menuconfig
步骤 2:验证配置
grep CONFIG_SERIAL_CH9434 .config
正确输出:
CONFIG_SERIAL_CH9434=m
步骤 3:单独编译驱动模块
make -j 8 modules
hugo@hugo-virtual-machine:~/IMX8/Kernel/Linux-5.4.70$ make -j 8 modules
4. 关键差异对比及操作建议
特性 | 内置到内核 (=y ) | 编译为模块 (=m ) |
---|---|---|
启动时加载 | 自动 | 需手动加载 |
修改驱动后 | 需重新编译整个内核 | 只需编译模块 |
内核镜像大小 | 增大 | 不变 |
适用场景 | 核心关键驱动 | 可选功能驱动 |
操作建议
- 硬件关键驱动(如SPI控制器)建议使用
<*>
内置到内核 - 外设扩展驱动(如CH9434)建议使用
<M>
模块方式 - 调试阶段优先使用模块,方便快速迭代
二、【实战】配置CH9434 SPI驱动
1、硬件配置阶段
做了什么
- 引脚复用:在设备树中把GPIO5_6到GPIO5_9配置成SPI信号线(SCLK/MOSI/MISO/CS0),GPIO4_27配置成中断引脚。
• 通俗解释:就像给电脑插USB设备前要插对接口一样,这一步告诉芯片哪些针脚用来传SPI信号,哪个针脚用来通知中断。
2、把驱动编译进内核(关键步骤)
① 驱动代码放对位置:
cd到 IMX8/Kernel/Linux-5.4.70/drivers/tty/serial
把ch9434.c
放到hugo@hugo-virtual-machine:~/IMX8/Kernel/Linux-5.4.70/drivers/tty/serial
目录。
② 修改编译配置:
vi Kconfig在/Kernel/Linux-5.4.70/drivers/tty/serial/Kconfig
里加选项SERIAL_CH9434
,让内核知道有9434这个驱动。
。。。。。。。
config SERIAL_ARC_NR_PORTS
int "Number of ARC UART ports"
depends on SERIAL_ARC
range 1 3
default "1"
help
Set this to the number of serial ports you want the driver
to support.
config SERIAL_CH9434
tristate "SERIAL_CH9434 serial support"
depends on SPI
select SERIAL_CORE
help
This selects support for ch9434 serial ports.
config SERIAL_RP2
tristate "Comtrol RocketPort EXPRESS/INFINITY support"
。。。。。。。
在/Kernel/Linux-5.4.70/drivers/tty/serial/Makefile
里加一行obj-$(CONFIG_SERIAL_CH9434) += ch9434.o
,告诉编译器要编译这个文件。
obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_CH9434) += ch9434.o
③ make menuconfig配置内核选项:
在/Kernel/Linux-5.4.70
内核路径下用make menuconfig
命令,找到Serial drivers
,把SERIAL_CH9434
标为<*>
(直接编译进内核)。
①make menuconfig
②Device Drivers
-> Character devices
-> Serial drivers
-> < * > SERIAL_CH9434 serial support
④ 使能交叉编译工具链:
在/Kernel/Linux-5.4.70
内核路径下source环境变量,使能交叉编译工具链,为下面make -j 8 Image进行编译内核镜像做准备
source /home/hugo/SDK/environment-setup-aarch64-poky-linux
⑤ **不用make distclean清除编译结果
(可选,如果清除了,就要再从新去步骤③make menucofig)**:
接下来是make distclean
。
如果之前编译过模块.ko,现在改为内置驱动,可能需要执行,在/Kernel/Linux-5.4.70
路径下使用make distclean清理.ko文件来确保配置正确。
但make distclean会删除所有配置和中间文件,包括.config文件,这可能导致需要重新配置所有选项。
因此,建议不要使用make distclean,而是使用make clean来保留.config文件,避免重复配置。
⑥ 不用make imx_v8_defconfig
然后是make imx_v8_defconfig
。这会将内核配置重置为默认的内核配置,覆盖我们之前通过menuconfig所做的修改。
但是如果已经执行了⑤清理了配置,可以在在/Kernel/Linux-5.4.70
路径下使用这个make imx_v8_defconfig来设置默认的配置,然后再这基础上再去③make menuconfig去设置9434的驱动
如果我们已经配置过内核,并且想保留这些配置,应该避免执行这一步。
正确的做法是备份当前的.config文件,或者在现有配置的基础上进行调整。
⑦ 再次执行make menuconfig
如果做了步骤⑤⑥,就要再次运行make menuconfig
来修改内核配置,确保驱动被选中为内置( * )
。
⑧ 编译内核镜像Image
在/Kernel/Linux-5.4.70
路径下使用make -j 8 Image
。这里需要注意的是,当驱动被编译进内核时,编译整个Image是必要的,
但通常建议使用make all来编译所有必要的部分,包括设备树。
另外,-j8参数指定并行编译的线程数,根据用户机器的CPU核心数调整,这里没问题。
⑨ 不用make modules
,不用sudo make modules_install
是否需要编译模块(make modules)。由于驱动现在被编译进内核,不需要生成.ko文件,所以不需要编译模块。但如果有其他模块需要编译,就需要。
最后,不需要执行sudo make modules_install,因为驱动已经内置到Image中,没有生成.ko文件,不需要安装模块。
3、如果把驱动成.ko文件(关键步骤)
调整策略
① 改为模块编译:把配置从<*>
改成<M>
(生成.ko模块文件)。
sed -i 's/=y/=m/' .config # 直接修改配置文件
② 重新编译模块:
make modules -j8 # 只编译模块,速度更快
③ 验证生成文件:
ls drivers/tty/serial/ch9434.ko # 看到这个文件说明成功
④ 驱动加载与验证
操作步骤
- 安装模块到开发板:
sudo cp ch9434.ko /lib/modules/$(uname -r)/ # 复制模块文件 depmod -a # 更新模块依赖
- 加载驱动:
modprobe ch9434 # 加载模块
- 检查加载结果:
dmesg | grep ch9434 # 看到"CH9434 initialized"表示成功 ls /dev/ttyWCH* # 出现4个串口设备节点(ttyWCH0~3)
发现问题
• 如果设备节点没出现:
• 检查设备树里的SPI总线地址是否正确(比如ecspi1
节点)。
• 用示波器测量SCLK和CS引脚是否有信号。
4、调试技巧总结
- 模块 vs 内置:
• 模块(.ko)调试灵活,改代码后只需重新编译模块。
• 内置驱动(直接进Image)适合最终产品,但调试麻烦。 - 验证三板斧:
• 看日志:dmesg | grep ch9434
• 查设备节点:ls /dev/ttyWCH*
• 测硬件信号:示波器量SCLK/CS是否有波形。 - 设备树是硬件字典:
• 驱动通过设备树知道硬件怎么连接,就像地图告诉司机路线。
5、最终成果
• 成功现象:加载驱动后,扩展的4个串口可直接用/dev/ttyWCH0~3
操作,就像普通串口一样收发数据。